diff --git a/action.yml b/action.yml index edb756e8..dd648f8a 100644 --- a/action.yml +++ b/action.yml @@ -56,6 +56,24 @@ inputs: plugin_followup: description: Enable owned repositories issues and pull requests metrics default: no + plugin_music: + description: Enable music + default: no + plugin_music_provider: + description: Name of the music provider you're using (*required if music plugin is enabled) + default: "" + plugin_music_token: + description: Music provider personal token (*may be required depending on used provider) + default: "" + plugin_music_mode: + description: Use "recent" to display recently played music and "playlist" to display tracks randomly from a given playlist (*required if music plugin is enabled) + default: "" + plugin_music_playlist: + description: Embed playlist url (*required if music plugin mode is "playlist") + default: "" + plugin_music_limit: + description: Number of tracks to display + default: 4 debug: description: Enable debug logs default: no diff --git a/action/index.mjs b/action/index.mjs index 233374b4..f33a9718 100644 --- a/action/index.mjs +++ b/action/index.mjs @@ -79,13 +79,26 @@ selfskip:{enabled:bool(core.getInput("plugin_selfskip"))}, languages:{enabled:bool(core.getInput("plugin_languages"))}, followup:{enabled:bool(core.getInput("plugin_followup"))}, + music:{enabled:bool(core.getInput("plugin_music"))} } const q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true])) console.log(`Plugins enabled | ${Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key).join(", ")}`) - if (plugins.pagespeed.enabled) { - plugins.pagespeed.token = core.getInput("pagespeed_token") - console.log(`Pagespeed token | ${plugins.pagespeed.token ? "provided" : "missing"}`) - } + //Additional plugins options + //Pagespeed + if (plugins.pagespeed.enabled) { + plugins.pagespeed.token = core.getInput("pagespeed_token") + console.log(`Pagespeed token | ${plugins.pagespeed.token ? "provided" : "missing"}`) + } + //Music + if (plugins.music.enabled) { + for (const option of ["provider", "token", "mode", "playlist", "limit"]) + q[`music.${option}`] = core.getInput(`plugin_music_${option}`) || "" + console.log(`Music provider | ${q["music.provider"]}`) + console.log(`Music token | ${q["music.token"] ? "provided" : "missing"}`) + console.log(`Music plugin mode | ${q["music.mode"]}`) + console.log(`Music playlist | ${q["music.playlist"]}`) + console.log(`Music tracks limit | ${q["music.limit"]}`) + } //Repositories to use const repositories = Number(core.getInput("repositories")) || 100 diff --git a/package-lock.json b/package-lock.json index 16669d95..f4cddea7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -145,6 +145,15 @@ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@vercel/ncc": { "version": "0.24.1", "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz", @@ -166,6 +175,11 @@ "negotiator": "0.6.2" } }, + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -227,6 +241,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, "before-after-hook": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", @@ -238,6 +257,33 @@ "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==", "dev": true }, + "bl": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -276,6 +322,20 @@ "concat-map": "0.0.1" } }, + "buffer": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.1.tgz", + "integrity": "sha512-2z15UUHpS9/3tk9mY/q+Rl3rydOi7yMp5XWNQnRvoz+mJwiv8brqYwp9a+nOCtma6dwuEIxljD8W3ysVBZ05Vg==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -294,8 +354,7 @@ "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "clipboard": { "version": "2.0.6", @@ -508,6 +567,11 @@ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true }, + "devtools-protocol": { + "version": "0.0.809251", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.809251.tgz", + "integrity": "sha512-pf+2OY6ghMDPjKkzSWxHMq+McD+9Ojmq5XVRYpv/kPd9sTMQxzEt21592a31API8qRjro0iYYOc3ag46qF/1FA==" + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -556,6 +620,14 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, "entities": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", @@ -651,6 +723,40 @@ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz", "integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA==" }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, "filelist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz", @@ -673,6 +779,15 @@ "unpipe": "~1.0.0" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -688,6 +803,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-minipass": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", @@ -700,8 +820,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { "version": "1.1.1", @@ -724,11 +843,18 @@ "wide-align": "^1.1.0" } }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -783,6 +909,30 @@ "toidentifier": "1.0.0" } }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "requires": { + "agent-base": "5", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -791,6 +941,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "ignore-walk": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", @@ -812,7 +967,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -916,6 +1070,14 @@ "node-pre-gyp": "~0.11.0" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -999,6 +1161,11 @@ "minimist": "^1.2.5" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1239,22 +1406,60 @@ "os-tmpdir": "^1.0.0" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, "prismjs": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz", @@ -1269,6 +1474,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -1278,6 +1488,62 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "puppeteer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.4.0.tgz", + "integrity": "sha512-LgTqVW2ClEP4XGAT64FLQ0QWVhdNSRwJp9HfMFVfoJlZHGQu3HUbuBhR1hBow3DXZH1K3b/WfHxt1n8hr2uayw==", + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.809251", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^4.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -1524,7 +1790,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -1587,6 +1852,46 @@ "yallist": "^3.0.3" } }, + "tar-fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", + "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", @@ -1612,6 +1917,15 @@ "mime-types": "~2.1.24" } }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -1630,8 +1944,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.1", @@ -1678,11 +1991,25 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } } } } diff --git a/package.json b/package.json index 1a2f6406..075d4ec6 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "image-to-base64": "^2.1.1", "memory-cache": "^0.2.0", "prismjs": "^1.22.0", + "puppeteer": "^5.4.0", "svgo": "^1.3.2", "vue": "^2.6.12", "vue-prism-component": "^1.2.0" diff --git a/settings.example.json b/settings.example.json index ca6e0f5a..0e2fe4de 100644 --- a/settings.example.json +++ b/settings.example.json @@ -29,11 +29,15 @@ "enabled":false, "//":"Enable or disable coding habits metrics", "from":100, "//":"Number of activity events to base habits on (up to 100)" }, - "languages":{ "//":"Languages plugins", + "languages":{ "//":"Languages plugin", "enabled":true, "//":"Enable or disable most used languages metrics" }, "followup":{ "//":"Follow-up plugin", "enabled":true, "//":"Enable owned repositories issues and pull requests metrics" + }, + "music":{ "//":"Music plugin", + "enabled":false, "//":"Enable music plugin", + "token":null, "//":"Music provider token (may be required depending on provider)" } } } \ No newline at end of file diff --git a/src/html/app.js b/src/html/app.js index 5d3198ca..d8f57853 100644 --- a/src/html/app.js +++ b/src/html/app.js @@ -28,12 +28,14 @@ lines:"Lines of code changed", habits:"Coding habits", selfskip:"Skip metrics commits", + music:"Music plugin", "base.header":"Header", "base.activity":"Account activity", "base.community":"Community stats", "base.repositories":"Repositories metrics", "base.metadata":"Metadata", }, + options:{}, }, templates:{ list:templates, @@ -59,13 +61,17 @@ }, //Endpoint to use for computed metrics url() { - const plugins = Object.entries(this.plugins.enabled) - .flatMap(([key, value]) => key === "base" ? Object.entries(value).map(([key, value]) => [`base.${key}`, value]) : [[key, value]]) - .filter(([key, value]) => /^base[.]\w+$/.test(key) ? !value : value) - .map(([key, value]) => `${key}=${+value}`) - const params = [...(this.templates.selected !== templates[0] ? [`template=${this.templates.selected}`] : []), ...plugins].join("&") - return `${window.location.protocol}//${window.location.host}/${this.user}${params.length ? `?${params}` : ""}` - }, + //Plugins enabled + const plugins = Object.entries(this.plugins.enabled) + .flatMap(([key, value]) => key === "base" ? Object.entries(value).map(([key, value]) => [`base.${key}`, value]) : [[key, value]]) + .filter(([key, value]) => /^base[.]\w+$/.test(key) ? !value : value) + .map(([key, value]) => `${key}=${+value}`) + //Template + const template = (this.templates.selected !== templates[0]) ? [`template=${this.templates.selected}`] : [] + //Generated url + const params = [...template, ...plugins, ...options].join("&") + return `${window.location.protocol}//${window.location.host}/${this.user}${params.length ? `?${params}` : ""}` + }, //Embedded generated code embed() { return `[](https://github.com/lowlighter/metrics)` @@ -144,6 +150,7 @@ licenses:{favorite:`########`}, plugins:Object.fromEntries(Object.entries(this.plugins.enabled).filter(([key, enabled]) => (key !== "base")&&(enabled)).map(([key]) => { return [key, proxify({ + music:{provider:"########", tracks:new Array(4).fill({name:"##########", artist:"######", artwork:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg=="})}, pagespeed:{scores:["Performance", "Accessibility", "Best Practices", "SEO"].map(title => ({title, score:NaN}))}, followup:{issues:{count:0}, pr:{count:0}}, habits:{indents:{style:`########`}}, diff --git a/src/metrics.mjs b/src/metrics.mjs index ce5236cb..6e433be3 100644 --- a/src/metrics.mjs +++ b/src/metrics.mjs @@ -2,8 +2,10 @@ import ejs from "ejs" import SVGO from "svgo" import imgb64 from "image-to-base64" + import axios from "axios" import Plugins from "./plugins/index.mjs" import Templates from "./templates/index.mjs" + import puppeteer from "puppeteer" //Setup export default async function metrics({login, q}, {graphql, rest, plugins, conf}) { @@ -33,13 +35,15 @@ //Base parts data.base = {} + if (("base" in q)&&(!q.base)) + conf.settings.plugins.base.parts.map(part => q[`base.${part}`] = false) for (const part of conf.settings.plugins.base.parts) data.base[part] = (`base.${part}` in q) ? !!q[`base.${part}`] : true //Template console.debug(`metrics/compute/${login} > compute`) const computer = Templates[template].default || Templates[template] - await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, imgb64}}) + await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, imgb64, axios, puppeteer, format, shuffle}}) await Promise.all(pending) console.debug(`metrics/compute/${login} > compute > success`) @@ -68,4 +72,19 @@ //Generic error throw error } - } \ No newline at end of file + } + +/** Formatter */ + function format(n) { + for (const {u, v} of [{u:"b", v:10**9}, {u:"m", v:10**6}, {u:"k", v:10**3}]) + if (n/v >= 1) + return `${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` + return n + } + +/** Array shuffler */ + function shuffle(array) { + for (let i = array.length-1, j = Math.floor(Math.random()*(i+1)); i > 0; i--) + [array[i], array[j]] = [array[j], array[i]] + return array + } diff --git a/src/plugins/followup/index.mjs b/src/plugins/followup/index.mjs index c931c976..d0bd9621 100644 --- a/src/plugins/followup/index.mjs +++ b/src/plugins/followup/index.mjs @@ -1,5 +1,5 @@ //Setup - export default function ({login, data, computed, pending, q}, {enabled = false} = {}) { + export default function ({login, imports, data, computed, pending, q}, {enabled = false} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.followup = null diff --git a/src/plugins/habits/index.mjs b/src/plugins/habits/index.mjs index ca720f86..9c71dfad 100644 --- a/src/plugins/habits/index.mjs +++ b/src/plugins/habits/index.mjs @@ -1,5 +1,5 @@ //Setup - export default function ({login, rest, computed, pending, q}, {enabled = false, from = 100} = {}) { + export default function ({login, imports, rest, computed, pending, q}, {enabled = false, from:_from = 100} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.habits = null @@ -7,11 +7,10 @@ return computed.plugins.habits = null console.debug(`metrics/compute/${login}/plugins > habits`) - //Parameter override - if (typeof q["habits.from"] === "number") { - from = Math.max(0, Math.min(from, q["habits.from"])) + //Parameters override + //Events + const from = Math.max(1, Math.min(100, "habits.from" in q ? Number(q["habits.from"])||0 : _from)) console.debug(`metrics/compute/${login}/plugins > habits > events = ${from}`) - } //Plugin execution pending.push(new Promise(async solve => { diff --git a/src/plugins/index.mjs b/src/plugins/index.mjs index 8a38c931..58309a1f 100644 --- a/src/plugins/index.mjs +++ b/src/plugins/index.mjs @@ -3,6 +3,7 @@ import habits from "./habits/index.mjs" import languages from "./languages/index.mjs" import lines from "./lines/index.mjs" + import music from "./music/index.mjs" import pagespeed from "./pagespeed/index.mjs" import selfskip from "./selfskip/index.mjs" import traffic from "./traffic/index.mjs" @@ -13,6 +14,7 @@ habits, languages, lines, + music, pagespeed, selfskip, traffic, diff --git a/src/plugins/languages/index.mjs b/src/plugins/languages/index.mjs index e3446e67..2b338762 100644 --- a/src/plugins/languages/index.mjs +++ b/src/plugins/languages/index.mjs @@ -1,5 +1,5 @@ //Setup - export default function ({login, data, computed, pending, q}, {enabled = false} = {}) { + export default function ({login, imports, data, computed, pending, q}, {enabled = false} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.languages = null diff --git a/src/plugins/lines/index.mjs b/src/plugins/lines/index.mjs index 279fa6df..ae8dcaac 100644 --- a/src/plugins/lines/index.mjs +++ b/src/plugins/lines/index.mjs @@ -1,13 +1,5 @@ -//Formatter - function format(n) { - for (const {u, v} of [{u:"b", v:10**9}, {u:"m", v:10**6}, {u:"k", v:10**3}]) - if (n/v >= 1) - return `${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` - return n - } - //Setup - export default function ({login, repositories = [], rest, computed, pending, q}, {enabled = false} = {}) { + export default function ({login, imports, repositories = [], rest, computed, pending, q}, {enabled = false} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.lines = null @@ -33,8 +25,8 @@ contributor.weeks.forEach(({a, d}) => (lines.added += a, lines.deleted += d)) }) //Format values - lines.added = format(lines.added) - lines.deleted = format(lines.deleted) + lines.added = imports.format(lines.added) + lines.deleted = imports.format(lines.deleted) //Save results computed.plugins.lines = {...lines} console.debug(`metrics/compute/${login}/plugins > lines > success`) diff --git a/src/plugins/music/index.mjs b/src/plugins/music/index.mjs new file mode 100644 index 00000000..e89fddae --- /dev/null +++ b/src/plugins/music/index.mjs @@ -0,0 +1,184 @@ +//Supported providers + const providers = { + apple:"Apple Music", + spotify:"Spotify", + } + +//Supported modes + const modes = { + playlist:"Suggested tracks", + recent:"Recently played", + } + +//Setup + export default function ({login, imports, rest, computed, pending, q}, {enabled = false, token = ""} = {}) { + //Check if plugin is enabled and requirements are met + if (!enabled) + return computed.plugins.music = null + if (!q.music) + return computed.plugins.music = null + console.debug(`metrics/compute/${login}/plugins > music`) + + //Parameters override and checks + //Provider + const provider = q["music.provider"]||"" + if (!(provider in providers)) + return computed.plugins.music = {error:provider ? `Unsupported provider "${provider}"` : `Missing provider`, mode:"Unconfigured music plugin"} + console.debug(`metrics/compute/${login}/plugins > music > provider "${provider}"`) + //Mode + const mode = q["music.mode"]||"" + if (!(mode in modes)) + return computed.plugins.music = {error:mode ? `Unsupported mode "${mode}"` : `Missing mode`, provider:providers[provider], mode:"Unconfigured music plugin"} + console.debug(`metrics/compute/${login}/plugins > music > mode "${mode}"`) + //Playlist mode + const playlist = q["music.playlist"]||"" + if (mode === "playlist") { + if (!playlist) + return computed.plugins.music = {error:`Missing playlist url`, provider:providers[provider], mode:modes[mode]} + if ((provider === "spotify")&&(!/^https:..open.spotify.com.embed.playlist/.test(playlist))) + return computed.plugins.music = {error:`Unsupported playlist url format`, provider:providers[provider], mode:modes[mode]} + if ((provider === "apple")&&(!/^https:..embed.music.apple.com.\w+.playlist/.test(playlist))) + return computed.plugins.music = {error:`Unsupported playlist url format`, provider:providers[provider], mode:modes[mode]} + console.debug(`metrics/compute/${login}/plugins > music > playlist = ${playlist}`) + } + //Limit + const limit = Math.max(1, Math.min(100, "music.limit" in q ? Number(q["music.limit"])||0 : 4)) + console.debug(`metrics/compute/${login}/plugins > music > limit = ${limit}`) + + //Plugin execution + pending.push(new Promise(async solve => { + //Retrieve music data + try { + //Initialization + let tracks = null + //Handle mode + switch (mode) { + //Playlist mode + case "playlist":{ + //Start puppeteer and navigate to playlist + console.debug(`metrics/compute/${login}/plugins > music > starting browser`) + const browser = await imports.puppeteer.launch() + const page = await browser.newPage() + console.debug(`metrics/compute/${login}/plugins > music > loading page`) + await page.goto(playlist) + const frame = page.mainFrame() + //Handle provider + switch (provider) { + //Apple music + case "apple":{ + //Parse tracklist + await frame.waitForSelector(".tracklist.playlist") + tracks = [...await frame.evaluate(() => [...document.querySelectorAll(".tracklist li")].map(li => ({ + name:li.querySelector(".tracklist__track__name").innerText, + artist:li.querySelector(".tracklist__track__sub").innerText, + artwork:li.querySelector(".tracklist__track__artwork img").src + })))] + break + } + //Spotify + case "spotify":{ + //Parse tracklist + await frame.waitForSelector("table") + tracks = [...await frame.evaluate(() => [...document.querySelectorAll("table tr")].map(tr => ({ + name:tr.querySelector("td:nth-child(2) div:nth-child(1)").innerText, + artist:tr.querySelector("td:nth-child(2) div:nth-child(2)").innerText, + //Spotify doesn't provide artworks so we fallback on playlist artwork instead + artwork:window.getComputedStyle(document.querySelector("button[title=Play]").parentNode, null).backgroundImage.match(/^url\("(https:...+)"\)$/)[1] + })))] + break + } + //Unsupported + default:{ + throw {status:`Unsupported mode "${mode}" for provider "${provider}"`} + } + } + //Close browser + console.debug(`metrics/compute/${login}/plugins > music > closing browser`) + await browser.close() + //Format tracks + if (Array.isArray(tracks)) { + //Tracks + console.debug(`metrics/compute/${login}/plugins > music > found ${tracks.length} tracks`) + console.debug(JSON.stringify(tracks)) + //Shuffle tracks + tracks = imports.shuffle(tracks) + } + break + } + //Recently played + case "recent":{ + //Initialisation + const timestamp = Date.now()-24*60*60*1000 + //Handle provider + switch (provider) { + //Spotify + case "spotify":{ + //API call and parse tracklist + try { + tracks = (await imports.axios(`https://api.spotify.com/v1/me/player/recently-played?limit=${limit}&after=${timestamp}`, {headers:{ + "Accept":"application/json", + "Content-Type":"application/json", + "Authorization":`Bearer ${token}`} + })).data.items.map(({track}) => ({ + name:track.name, + artist:track.artists[0].name, + artwork:track.album.images[0].url, + })) + } + //Handle errors + catch (error) { + console.debug(error) + if ((error.response)&&(error.response.status)) + throw {status:`API call returned ${error.response.status}`} + } + break + } + //Unsupported + default:{ + throw {status:`Unsupported mode "${mode}" for provider "${provider}"`} + } + } + break + } + //Unsupported + default:{ + throw {status:`Unsupported mode "${mode}"`} + } + } + //Format tracks + if (Array.isArray(tracks)) { + //Limit tracklist + if (limit > 0) { + console.debug(`metrics/compute/${login}/plugins > music > keeping only ${limit} tracks`) + tracks = tracks.slice(0, limit) + } + //Convert artworks to base64 + console.debug(`metrics/compute/${login}/plugins > music > loading artworks`) + for (const track of tracks) { + console.debug(`metrics/compute/${login}/plugins > music > processing ${track.name}`) + track.artwork = await imports.imgb64(track.artwork) + } + //Save results + console.debug(`metrics/compute/${login}/plugins > music > success`) + computed.plugins.music = {provider:providers[provider], mode:modes[mode], tracks} + solve() + return + } + //Unhandled error + throw {status:`An error occured (unhandled)`} + } + catch (error) { + //Plugin error + if (error.status) { + computed.plugins.music = {provider:providers[provider], mode:modes[mode], error:error.status} + console.debug(`metrics/compute/${login}/plugins > music > error > ${error.status}`) + return solve() + } + //Generic error + computed.plugins.music = {provider:providers[provider], mode:modes[mode], error:`An error occured`} + console.debug(`metrics/compute/${login}/plugins > music > error`) + console.debug(error) + solve() + } + })) + } diff --git a/src/plugins/pagespeed/index.mjs b/src/plugins/pagespeed/index.mjs index cae64fa4..7ab1b286 100644 --- a/src/plugins/pagespeed/index.mjs +++ b/src/plugins/pagespeed/index.mjs @@ -1,8 +1,5 @@ -//Imports - import axios from "axios" - //Setup - export default function ({login, url, computed, pending, q}, {enabled = false, token = null} = {}) { + export default function ({login, imports, url, computed, pending, q}, {enabled = false, token = null} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.pagespeed = null @@ -21,7 +18,7 @@ //Load scores from API const scores = new Map() await Promise.all(["performance", "accessibility", "best-practices", "seo"].map(async category => { - const {score, title} = (await axios.get(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?category=${category}&url=${url}&key=${token}`)).data.lighthouseResult.categories[category] + const {score, title} = (await imports.axios.get(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?category=${category}&url=${url}&key=${token}`)).data.lighthouseResult.categories[category] scores.set(category, {score, title}) })) //Save results diff --git a/src/plugins/selfskip/index.mjs b/src/plugins/selfskip/index.mjs index 0d6f554b..268d3c92 100644 --- a/src/plugins/selfskip/index.mjs +++ b/src/plugins/selfskip/index.mjs @@ -1,5 +1,5 @@ //Setup - export default function ({login, rest, computed, pending, q}, {enabled = false} = {}) { + export default function ({login, imports, rest, computed, pending, q}, {enabled = false} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.selfskip = null diff --git a/src/plugins/traffic/index.mjs b/src/plugins/traffic/index.mjs index 744c24ff..c9e75c02 100644 --- a/src/plugins/traffic/index.mjs +++ b/src/plugins/traffic/index.mjs @@ -1,13 +1,5 @@ -//Formatter - function format(n) { - for (const {u, v} of [{u:"b", v:10**9}, {u:"m", v:10**6}, {u:"k", v:10**3}]) - if (n/v >= 1) - return `${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` - return n - } - //Setup - export default function ({login, repositories = [], rest, computed, pending, q}, {enabled = false} = {}) { + export default function ({login, imports, repositories = [], rest, computed, pending, q}, {enabled = false} = {}) { //Check if plugin is enabled and requirements are met if (!enabled) return computed.plugins.traffic = null @@ -24,8 +16,8 @@ //Compute views response.filter(({data}) => data).map(({data:{count, uniques}}) => (views.count += count, views.uniques += uniques)) //Format values - views.count = format(views.count) - views.uniques = format(views.uniques) + views.count = imports.format(views.count) + views.uniques = imports.format(views.uniques) //Save results computed.plugins.traffic = {views} console.debug(`metrics/compute/${login}/plugins > traffic > success`) diff --git a/src/templates/classic/image.svg b/src/templates/classic/image.svg index d5d430e0..0608fa21 100644 --- a/src/templates/classic/image.svg +++ b/src/templates/classic/image.svg @@ -8,6 +8,7 @@ + (!!computed.plugins.pagespeed)*126 + (!!computed.plugins.habits)*68 + (!!computed.plugins.languages)*96 + + (!!computed.plugins.music)*64 + (computed.plugins.music ? computed.plugins.music.tracks ? 14+Math.max(0, computed.plugins.music.tracks.length-1)*36 : 0 : 0) %>"> @@ -351,6 +352,50 @@ <% } %> + <% if (computed.plugins.music) { %> + + + + <%= computed.plugins.music.mode %> + + + + <% if (computed.plugins.music.provider) { %> + + + From <%= computed.plugins.music.provider %> + + <% } %> + <% if (computed.plugins.music.error) { %> + + + <%= computed.plugins.music.error %> + + <% } else { %> + <% if (computed.plugins.music.tracks.length) { %> + + <% for (const {name = "", artist = "", artwork = ""} of computed.plugins.music.tracks) { %> + + + + <%= name %> + <%= artist %> + + + <% } %> + + <% } else { %> + + + No music recently listened + + <% } %> + <% } %> + + + + <% } %> + <% if (base.metadata) { %>