diff --git a/package.json b/package.json index 79a9cbf7..aa3f1b95 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "@ffmpeg/core": "^0.8.5", "@ffmpeg/ffmpeg": "^0.9.7", "YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.1", - "axios": "^0.21.1", "async-mutex": "^0.3.1", "browser-id3-writer": "^4.4.0", "discord-rpc": "^3.2.0", diff --git a/plugins/last-fm/back.js b/plugins/last-fm/back.js index 4e238469..a34a0a19 100644 --- a/plugins/last-fm/back.js +++ b/plugins/last-fm/back.js @@ -1,35 +1,24 @@ const fetch = require('node-fetch'); const md5 = require('md5'); const open = require("open"); -const axios = require('axios'); const { setOptions } = require('../../config/plugins'); const getSongInfo = require('../../providers/song-info'); - -const defaultSettings = { - enabled: true, - api_root: "http://ws.audioscrobbler.com/2.0/", - api_key: "04d76faaac8726e60988e14c105d421a", // api key registered by @semvis123 - secret: "a5d2a36fdf64819290f6982481eaffa2", - suffixesToRemove: [' - Topic', 'VEVO'] -} +const defaultConfig = require('../../config/defaults'); const cleanupArtistName = (config, artist) => { // removes the suffixes of the artist name for more recognition by last.fm - let { suffixesToRemove } = config; - if (suffixesToRemove === undefined) { - suffixesToRemove = defaultSettings.suffixesToRemove; - config.suffixesToRemove = suffixesToRemove; - setOptions('last-fm', config); - } + const { suffixesToRemove } = config; + if (suffixesToRemove === undefined) return artist; + for (suffix of suffixesToRemove) { artist = artist.replace(suffix, ''); } - return artist + return artist; } const createFormData = params => { // creates the body for in the post request - let formData = new URLSearchParams(); + const formData = new URLSearchParams(); for (key in params) { formData.append(key, params[key]); } @@ -40,14 +29,14 @@ const createQueryString = (params, api_sig) => { const queryData = []; params.api_sig = api_sig; for (key in params) { - queryData.push(`${key}=${params[key]}`); + queryData.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`); } return '?'+queryData.join('&'); } const createApiSig = (params, secret) => { // this function creates the api signature, see: https://www.last.fm/api/authspec - let keys = []; + const keys = []; for (key in params) { keys.push(key); } @@ -65,12 +54,12 @@ const createApiSig = (params, secret) => { const createToken = async ({ api_key, api_root, secret }) => { // creates and stores the auth token - data = { + const data = { method: 'auth.gettoken', api_key: api_key, format: 'json' }; - let api_sig = createApiSig(data, secret); + const api_sig = createApiSig(data, secret); let response = await fetch(`${api_root}${createQueryString(data, api_sig)}`); response = await response.json(); return response?.token; @@ -86,14 +75,14 @@ const authenticate = async config => { const getAndSetSessionKey = async config => { // get and store the session key - data = { + const data = { api_key: config.api_key, format: 'json', method: 'auth.getsession', token: config.token, }; - api_sig = createApiSig(data, config.secret); - res = await fetch(`${config.api_root}${createQueryString(data, api_sig)}`); + const api_sig = createApiSig(data, config.secret); + let res = await fetch(`${config.api_root}${createQueryString(data, api_sig)}`); res = await res.json(); if (res.error) await authenticate(config); @@ -102,23 +91,23 @@ const getAndSetSessionKey = async config => { return config; } - -const addScrobble = async (songInfo, config) => { - // this adds one scrobbled song to last.fm +const postSongDataToAPI = async (songInfo, config, data) => { + // this sends a post request to the api, and adds the common data if (!config.session_key) await getAndSetSessionKey(config); - data = { + + const postData = { track: songInfo.title, + duration: songInfo.songDuration, artist: songInfo.artist, api_key: config.api_key, sk: config.session_key, format: 'json', - method: 'track.scrobble', - timestamp: ~~((Date.now() - songInfo.elapsedSeconds) / 1000), - duration: songInfo.songDuration, + ...data, }; - data.api_sig = createApiSig(data, config.secret); - axios.post('https://ws.audioscrobbler.com/2.0/', createFormData(data)) + + postData.api_sig = createApiSig(postData, config.secret); + fetch('https://ws.audioscrobbler.com/2.0/', {method: 'POST', body: createFormData(postData)}) .catch(res => { if (res.response.data.error == 9) { // session key is invalid, so remove it from the config and reauthenticate @@ -129,29 +118,21 @@ const addScrobble = async (songInfo, config) => { }); } -const setNowPlaying = async (songInfo, config) => { - // this sets the now playing status in last.fm - if (!config.session_key) - await getAndSetSessionKey(config); - data = { - track: songInfo.title, - artist: songInfo.artist, - api_key: config.api_key, - sk: config.session_key, - format: 'json', - method: 'track.updateNowPlaying', - duration: songInfo.songDuration, +const addScrobble = (songInfo, config) => { + // this adds one scrobbled song to last.fm + const data = { + method: 'track.scrobble', + timestamp: ~~((Date.now() - songInfo.elapsedSeconds) / 1000), }; - data.api_sig = createApiSig(data, config.secret); - axios.post('https://ws.audioscrobbler.com/2.0/', createFormData(data)) - .catch(res => { - if (res.response.data.error == 9) { - // session key is invalid, so remove it from the config and reauthenticate - config.session_key = undefined; - setOptions('last-fm', config); - authenticate(config); - } - }); + postSongDataToAPI(songInfo, config, data); +} + +const setNowPlaying = (songInfo, config) => { + // this sets the now playing status in last.fm + const data = { + method: 'track.updateNowPlaying', + }; + postSongDataToAPI(songInfo, config, data); } @@ -161,9 +142,10 @@ let scrobbleTimer = undefined; const lastfm = async (win, config) => { const registerCallback = getSongInfo(win); - if (!config.api_root) { + if (!config.api_root || !config.suffixesToRemove) { // settings are not present, creating them with the default values - config = defaultSettings; + config = defaultConfig.plugins['last-fm']; + config.enabled = true; setOptions('last-fm', config); } @@ -179,10 +161,11 @@ const lastfm = async (win, config) => { songInfo.artist = cleanupArtistName(config, songInfo.artist); if (!songInfo.isPaused) { setNowPlaying(songInfo, config); - let scrobbleTime = Math.min(Math.ceil(songInfo.songDuration / 2), 4 * 60); + // scrobble when the song is half way through, or has passed the 4 minute mark + const scrobbleTime = Math.min(Math.ceil(songInfo.songDuration / 2), 4 * 60); if (scrobbleTime > songInfo.elapsedSeconds) { // scrobble still needs to happen - timeToWait = (scrobbleTime - songInfo.elapsedSeconds) * 1000; + const timeToWait = (scrobbleTime - songInfo.elapsedSeconds) * 1000; scrobbleTimer = setTimeout(addScrobble, timeToWait, songInfo, config); } } diff --git a/yarn.lock b/yarn.lock index f1a14d40..f428bd55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1708,6 +1708,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" @@ -2223,6 +2230,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -2587,6 +2599,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -2756,6 +2773,11 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -3961,6 +3983,11 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== +follow-redirects@^1.10.0: + version "1.13.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" + integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -4686,7 +4713,7 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-buffer@^1.1.5: +is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -4747,7 +4774,7 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== @@ -6023,6 +6050,15 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + memory-fs@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" @@ -6519,6 +6555,15 @@ open@^7.3.0: is-docker "^2.0.0" is-wsl "^2.1.1" +open@^8.0.3: + version "8.0.5" + resolved "https://registry.yarnpkg.com/open/-/open-8.0.5.tgz#92ee3faafef4ddbe78006f7881572f3e81430b8f" + integrity sha512-hkPXCz7gijWp2GoWqsQ4O/5p7F6d5pIQ/+9NyeWG1nABJ4zvLi9kJRv1a44kVf5p13wK0WMoiRA+Xey68yOytA== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"