Start music plugin

- New plugin music
- Moved imports and util functions
- Pass base=0 to disable all base options
This commit is contained in:
lowlighter
2020-10-25 19:25:51 +01:00
parent 8494636ffa
commit 5f4e27c920
19 changed files with 696 additions and 67 deletions

View File

@@ -56,6 +56,24 @@ inputs:
plugin_followup: plugin_followup:
description: Enable owned repositories issues and pull requests metrics description: Enable owned repositories issues and pull requests metrics
default: no 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: debug:
description: Enable debug logs description: Enable debug logs
default: no default: no

View File

@@ -79,13 +79,26 @@
selfskip:{enabled:bool(core.getInput("plugin_selfskip"))}, selfskip:{enabled:bool(core.getInput("plugin_selfskip"))},
languages:{enabled:bool(core.getInput("plugin_languages"))}, languages:{enabled:bool(core.getInput("plugin_languages"))},
followup:{enabled:bool(core.getInput("plugin_followup"))}, 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])) 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(", ")}`) console.log(`Plugins enabled | ${Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key).join(", ")}`)
//Additional plugins options
//Pagespeed
if (plugins.pagespeed.enabled) { if (plugins.pagespeed.enabled) {
plugins.pagespeed.token = core.getInput("pagespeed_token") plugins.pagespeed.token = core.getInput("pagespeed_token")
console.log(`Pagespeed token | ${plugins.pagespeed.token ? "provided" : "missing"}`) 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 //Repositories to use
const repositories = Number(core.getInput("repositories")) || 100 const repositories = Number(core.getInput("repositories")) || 100

349
package-lock.json generated
View File

@@ -145,6 +145,15 @@
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" "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": { "@vercel/ncc": {
"version": "0.24.1", "version": "0.24.1",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz", "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz",
@@ -166,6 +175,11 @@
"negotiator": "0.6.2" "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": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "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", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" "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": { "before-after-hook": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", "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==", "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==",
"dev": true "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": { "body-parser": {
"version": "1.19.0", "version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@@ -276,6 +322,20 @@
"concat-map": "0.0.1" "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": { "bytes": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -294,8 +354,7 @@
"chownr": { "chownr": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
"dev": true
}, },
"clipboard": { "clipboard": {
"version": "2.0.6", "version": "2.0.6",
@@ -508,6 +567,11 @@
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true "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": { "dom-serializer": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", "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", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" "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": { "entities": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz",
"integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA==" "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": { "filelist": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
@@ -673,6 +779,15 @@
"unpipe": "~1.0.0" "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": { "follow-redirects": {
"version": "1.13.0", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", "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", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" "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": { "fs-minipass": {
"version": "1.2.7", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
@@ -700,8 +820,7 @@
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"dev": true
}, },
"function-bind": { "function-bind": {
"version": "1.1.1", "version": "1.1.1",
@@ -724,11 +843,18 @@
"wide-align": "^1.1.0" "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": { "glob": {
"version": "7.1.6", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@@ -783,6 +909,30 @@
"toidentifier": "1.0.0" "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": { "iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -791,6 +941,11 @@
"safer-buffer": ">= 2.1.2 < 3" "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": { "ignore-walk": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
@@ -812,7 +967,6 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": { "requires": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
@@ -916,6 +1070,14 @@
"node-pre-gyp": "~0.11.0" "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": { "mdn-data": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
@@ -999,6 +1161,11 @@
"minimist": "^1.2.5" "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": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -1239,22 +1406,60 @@
"os-tmpdir": "^1.0.0" "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": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" "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": { "path-is-absolute": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
"dev": true
}, },
"path-to-regexp": { "path-to-regexp": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" "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": { "prismjs": {
"version": "1.22.0", "version": "1.22.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz",
@@ -1269,6 +1474,11 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true "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": { "proxy-addr": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@@ -1278,6 +1488,62 @@
"ipaddr.js": "1.9.1" "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": { "q": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -1524,7 +1790,6 @@
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": { "requires": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@@ -1587,6 +1852,46 @@
"yallist": "^3.0.3" "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": { "tiny-emitter": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
@@ -1612,6 +1917,15 @@
"mime-types": "~2.1.24" "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": { "universal-user-agent": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
@@ -1630,8 +1944,7 @@
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"dev": true
}, },
"util.promisify": { "util.promisify": {
"version": "1.0.1", "version": "1.0.1",
@@ -1678,11 +1991,25 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}, },
"ws": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
},
"yallist": { "yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true "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"
}
} }
} }
} }

View File

@@ -32,6 +32,7 @@
"image-to-base64": "^2.1.1", "image-to-base64": "^2.1.1",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"prismjs": "^1.22.0", "prismjs": "^1.22.0",
"puppeteer": "^5.4.0",
"svgo": "^1.3.2", "svgo": "^1.3.2",
"vue": "^2.6.12", "vue": "^2.6.12",
"vue-prism-component": "^1.2.0" "vue-prism-component": "^1.2.0"

View File

@@ -29,11 +29,15 @@
"enabled":false, "//":"Enable or disable coding habits metrics", "enabled":false, "//":"Enable or disable coding habits metrics",
"from":100, "//":"Number of activity events to base habits on (up to 100)" "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" "enabled":true, "//":"Enable or disable most used languages metrics"
}, },
"followup":{ "//":"Follow-up plugin", "followup":{ "//":"Follow-up plugin",
"enabled":true, "//":"Enable owned repositories issues and pull requests metrics" "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)"
} }
} }
} }

View File

@@ -28,12 +28,14 @@
lines:"Lines of code changed", lines:"Lines of code changed",
habits:"Coding habits", habits:"Coding habits",
selfskip:"Skip metrics commits", selfskip:"Skip metrics commits",
music:"Music plugin",
"base.header":"Header", "base.header":"Header",
"base.activity":"Account activity", "base.activity":"Account activity",
"base.community":"Community stats", "base.community":"Community stats",
"base.repositories":"Repositories metrics", "base.repositories":"Repositories metrics",
"base.metadata":"Metadata", "base.metadata":"Metadata",
}, },
options:{},
}, },
templates:{ templates:{
list:templates, list:templates,
@@ -59,11 +61,15 @@
}, },
//Endpoint to use for computed metrics //Endpoint to use for computed metrics
url() { url() {
//Plugins enabled
const plugins = Object.entries(this.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]]) .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) .filter(([key, value]) => /^base[.]\w+$/.test(key) ? !value : value)
.map(([key, value]) => `${key}=${+value}`) .map(([key, value]) => `${key}=${+value}`)
const params = [...(this.templates.selected !== templates[0] ? [`template=${this.templates.selected}`] : []), ...plugins].join("&") //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}` : ""}` return `${window.location.protocol}//${window.location.host}/${this.user}${params.length ? `?${params}` : ""}`
}, },
//Embedded generated code //Embedded generated code
@@ -144,6 +150,7 @@
licenses:{favorite:`########`}, licenses:{favorite:`########`},
plugins:Object.fromEntries(Object.entries(this.plugins.enabled).filter(([key, enabled]) => (key !== "base")&&(enabled)).map(([key]) => { plugins:Object.fromEntries(Object.entries(this.plugins.enabled).filter(([key, enabled]) => (key !== "base")&&(enabled)).map(([key]) => {
return [key, proxify({ 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}))}, pagespeed:{scores:["Performance", "Accessibility", "Best Practices", "SEO"].map(title => ({title, score:NaN}))},
followup:{issues:{count:0}, pr:{count:0}}, followup:{issues:{count:0}, pr:{count:0}},
habits:{indents:{style:`########`}}, habits:{indents:{style:`########`}},

View File

@@ -2,8 +2,10 @@
import ejs from "ejs" import ejs from "ejs"
import SVGO from "svgo" import SVGO from "svgo"
import imgb64 from "image-to-base64" import imgb64 from "image-to-base64"
import axios from "axios"
import Plugins from "./plugins/index.mjs" import Plugins from "./plugins/index.mjs"
import Templates from "./templates/index.mjs" import Templates from "./templates/index.mjs"
import puppeteer from "puppeteer"
//Setup //Setup
export default async function metrics({login, q}, {graphql, rest, plugins, conf}) { export default async function metrics({login, q}, {graphql, rest, plugins, conf}) {
@@ -33,13 +35,15 @@
//Base parts //Base parts
data.base = {} 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) for (const part of conf.settings.plugins.base.parts)
data.base[part] = (`base.${part}` in q) ? !!q[`base.${part}`] : true data.base[part] = (`base.${part}` in q) ? !!q[`base.${part}`] : true
//Template //Template
console.debug(`metrics/compute/${login} > compute`) console.debug(`metrics/compute/${login} > compute`)
const computer = Templates[template].default || Templates[template] 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) await Promise.all(pending)
console.debug(`metrics/compute/${login} > compute > success`) console.debug(`metrics/compute/${login} > compute > success`)
@@ -69,3 +73,18 @@
throw error throw error
} }
} }
/** 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
}

View File

@@ -1,5 +1,5 @@
//Setup //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.followup = null return computed.plugins.followup = null

View File

@@ -1,5 +1,5 @@
//Setup //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.habits = null return computed.plugins.habits = null
@@ -7,11 +7,10 @@
return computed.plugins.habits = null return computed.plugins.habits = null
console.debug(`metrics/compute/${login}/plugins > habits`) console.debug(`metrics/compute/${login}/plugins > habits`)
//Parameter override //Parameters override
if (typeof q["habits.from"] === "number") { //Events
from = Math.max(0, Math.min(from, q["habits.from"])) 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}`) console.debug(`metrics/compute/${login}/plugins > habits > events = ${from}`)
}
//Plugin execution //Plugin execution
pending.push(new Promise(async solve => { pending.push(new Promise(async solve => {

View File

@@ -3,6 +3,7 @@
import habits from "./habits/index.mjs" import habits from "./habits/index.mjs"
import languages from "./languages/index.mjs" import languages from "./languages/index.mjs"
import lines from "./lines/index.mjs" import lines from "./lines/index.mjs"
import music from "./music/index.mjs"
import pagespeed from "./pagespeed/index.mjs" import pagespeed from "./pagespeed/index.mjs"
import selfskip from "./selfskip/index.mjs" import selfskip from "./selfskip/index.mjs"
import traffic from "./traffic/index.mjs" import traffic from "./traffic/index.mjs"
@@ -13,6 +14,7 @@
habits, habits,
languages, languages,
lines, lines,
music,
pagespeed, pagespeed,
selfskip, selfskip,
traffic, traffic,

View File

@@ -1,5 +1,5 @@
//Setup //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.languages = null return computed.plugins.languages = null

View File

@@ -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 //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.lines = null return computed.plugins.lines = null
@@ -33,8 +25,8 @@
contributor.weeks.forEach(({a, d}) => (lines.added += a, lines.deleted += d)) contributor.weeks.forEach(({a, d}) => (lines.added += a, lines.deleted += d))
}) })
//Format values //Format values
lines.added = format(lines.added) lines.added = imports.format(lines.added)
lines.deleted = format(lines.deleted) lines.deleted = imports.format(lines.deleted)
//Save results //Save results
computed.plugins.lines = {...lines} computed.plugins.lines = {...lines}
console.debug(`metrics/compute/${login}/plugins > lines > success`) console.debug(`metrics/compute/${login}/plugins > lines > success`)

184
src/plugins/music/index.mjs Normal file
View File

@@ -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()
}
}))
}

View File

@@ -1,8 +1,5 @@
//Imports
import axios from "axios"
//Setup //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.pagespeed = null return computed.plugins.pagespeed = null
@@ -21,7 +18,7 @@
//Load scores from API //Load scores from API
const scores = new Map() const scores = new Map()
await Promise.all(["performance", "accessibility", "best-practices", "seo"].map(async category => { 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}) scores.set(category, {score, title})
})) }))
//Save results //Save results

View File

@@ -1,5 +1,5 @@
//Setup //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.selfskip = null return computed.plugins.selfskip = null

View File

@@ -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 //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 //Check if plugin is enabled and requirements are met
if (!enabled) if (!enabled)
return computed.plugins.traffic = null return computed.plugins.traffic = null
@@ -24,8 +16,8 @@
//Compute views //Compute views
response.filter(({data}) => data).map(({data:{count, uniques}}) => (views.count += count, views.uniques += uniques)) response.filter(({data}) => data).map(({data:{count, uniques}}) => (views.count += count, views.uniques += uniques))
//Format values //Format values
views.count = format(views.count) views.count = imports.format(views.count)
views.uniques = format(views.uniques) views.uniques = imports.format(views.uniques)
//Save results //Save results
computed.plugins.traffic = {views} computed.plugins.traffic = {views}
console.debug(`metrics/compute/${login}/plugins > traffic > success`) console.debug(`metrics/compute/${login}/plugins > traffic > success`)

View File

@@ -8,6 +8,7 @@
+ (!!computed.plugins.pagespeed)*126 + (!!computed.plugins.pagespeed)*126
+ (!!computed.plugins.habits)*68 + (!!computed.plugins.habits)*68
+ (!!computed.plugins.languages)*96 + (!!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)
%>"> %>">
<defs><style><%= fonts %></style></defs> <defs><style><%= fonts %></style></defs>
@@ -351,6 +352,50 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.music) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg>
<%= computed.plugins.music.mode %>
</h2>
<div class="row fill-width">
<section>
<% if (computed.plugins.music.provider) { %>
<div class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.002 2.725a.75.75 0 01.797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 11-1.497.098 10.502 10.502 0 00-9.776-9.776.75.75 0 01-.7-.798zM2 13a1 1 0 112 0 1 1 0 01-2 0zm.84-5.95a.75.75 0 00-.179 1.489c2.509.3 4.5 2.291 4.8 4.8a.75.75 0 101.49-.178A7.003 7.003 0 002.838 7.05z"></path></svg>
From <%= computed.plugins.music.provider %>
</div>
<% } %>
<% if (computed.plugins.music.error) { %>
<div class="field error">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.47.22A.75.75 0 015 0h6a.75.75 0 01.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 01-.22.53l-4.25 4.25A.75.75 0 0111 16H5a.75.75 0 01-.53-.22L.22 11.53A.75.75 0 010 11V5a.75.75 0 01.22-.53L4.47.22zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5H5.31zM8 4a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 4zm0 8a1 1 0 100-2 1 1 0 000 2z"></path></svg>
<%= computed.plugins.music.error %>
</div>
<% } else { %>
<% if (computed.plugins.music.tracks.length) { %>
<div class="tracklist">
<% for (const {name = "", artist = "", artwork = ""} of computed.plugins.music.tracks) { %>
<div class="track">
<img src="data:image/png;base64,<%= artwork %>" width="32" height="32" alt=""/>
<div class="infos">
<div class="name"><%= name %></div>
<div class="artist"><%= artist %></div>
</div>
</div>
<% } %>
</div>
<% } else { %>
<div class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h6.5a.25.25 0 00.25-.25v-9.5a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0114.25 13H8.06l-2.573 2.573A1.457 1.457 0 013 14.543V13H1.75A1.75 1.75 0 010 11.25v-9.5zM9 9a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z"></path></svg>
No music recently listened
</div>
<% } %>
<% } %>
</section>
</div>
</section>
<% } %>
<% if (base.metadata) { %> <% if (base.metadata) { %>
<footer> <footer>
<span>These metrics <%= !computed.token.scopes.includes("repo") ? "does not include" : "includes" %> private contributions</span> <span>These metrics <%= !computed.token.scopes.includes("repo") ? "does not include" : "includes" %> private contributions</span>

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -189,6 +189,34 @@
} }
} }
/* Music plugin */
.tracklist {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-left: 28px;
margin-top: 4px;
width: 100%;
}
.track {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 4px;
}
.track img {
margin: 0 10px;
border-radius: 7px;
}
.track .name {
font-size: 14px;
line-height: 14px;
}
.track .artist {
font-size: 12px;
opacity: .7;
}
/* Fade animation */ /* Fade animation */
.af { .af {
opacity: 0; opacity: 0;

View File

@@ -7,13 +7,14 @@
//Plugins //Plugins
if (data.user.websiteUrl) if (data.user.websiteUrl)
imports.plugins.pagespeed({login, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed) imports.plugins.pagespeed({login, imports, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed)
imports.plugins.lines({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines) imports.plugins.music({login, imports, data, computed, pending, q}, plugins.music)
imports.plugins.traffic({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic) imports.plugins.lines({login, imports, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines)
imports.plugins.habits({login, rest, computed, pending, q}, plugins.habits) imports.plugins.traffic({login, imports, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic)
imports.plugins.selfskip({login, rest, computed, pending, q}, plugins.selfskip) imports.plugins.habits({login, imports, rest, computed, pending, q}, plugins.habits)
imports.plugins.languages({login, data, computed, pending, q}, plugins.languages) imports.plugins.selfskip({login, imports, rest, computed, pending, q}, plugins.selfskip)
imports.plugins.followup({login, data, computed, pending, q}, plugins.followup) imports.plugins.languages({login, imports, data, computed, pending, q}, plugins.languages)
imports.plugins.followup({login, imports, data, computed, pending, q}, plugins.followup)
//Iterate through user's repositories //Iterate through user's repositories
for (const repository of data.user.repositories.nodes) { for (const repository of data.user.repositories.nodes) {