From fa2913a4acbf03dd578f8884184bf3e9e98fb694 Mon Sep 17 00:00:00 2001 From: Sayem Chowdhury Date: Sat, 16 Oct 2021 15:12:42 +0600 Subject: [PATCH] update lints --- .eslintrc.js | 20 ++- .prettierrc.js | 5 +- __tests__/api.ts | 12 +- __tests__/converter/parse.ts | 4 +- __tests__/converter/youtube.ts | 2 +- package.json | 16 +- src/api/request.ts | 8 +- src/converter/deezer.ts | 6 +- src/converter/parse.ts | 7 +- src/converter/spotify.ts | 6 +- src/converter/tidal.ts | 18 +-- src/converter/youtube.ts | 2 +- src/lib/decrypt.ts | 20 ++- src/lib/get-url.ts | 13 +- src/lib/metaflac-js.ts | 8 +- src/lib/request.ts | 4 +- src/metadata-writer/abumCover.ts | 2 +- src/metadata-writer/musixmatchLyrics.ts | 10 +- yarn.lock | 196 +++++++++++++++++++----- 19 files changed, 249 insertions(+), 110 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d134775..4546a66 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,22 @@ module.exports = { - plugins: ['prettier'], + env: { + node: true, + }, + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 8, + }, + plugins: ['@typescript-eslint', 'prettier'], rules: { - 'prettier/prettier': 'error', + 'prettier/prettier': ['error'], + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + 'no-empty': 'off', + 'no-case-declarations': 'off', + 'no-useless-escape': 'off', + 'no-irregular-whitespace': 'off', }, }; diff --git a/.prettierrc.js b/.prettierrc.js index 4ca13e8..1bc6f61 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,8 +1,7 @@ module.exports = { printWidth: 120, bracketSpacing: false, - jsxBracketSameLine: true, singleQuote: true, - trailingComma: "all", - endOfLine: "lf", + trailingComma: 'all', + endOfLine: 'lf', }; diff --git a/__tests__/api.ts b/__tests__/api.ts index 802ea16..3827226 100644 --- a/__tests__/api.ts +++ b/__tests__/api.ts @@ -147,8 +147,8 @@ if (process.env.CI) { test('DOWNLOAD TRACK128 & ADD METADATA', async (t) => { const track = await api.getTrackInfo(SNG_ID); const trackData = await getTrackDownloadUrl(track, 1); - if (!trackData) throw new Error("Selected track+quality are unavailable"); - const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); + if (!trackData) throw new Error('Selected track+quality are unavailable'); + const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); t.truthy(data); t.true(Buffer.isBuffer(data)); @@ -187,8 +187,8 @@ if (process.env.CI) { test('DOWNLOAD TRACK320 & ADD METADATA', async (t) => { const track = await api.getTrackInfo(SNG_ID); const trackData = await getTrackDownloadUrl(track, 3); - if (!trackData) throw new Error("Selected track+quality are unavailable"); - const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); + if (!trackData) throw new Error('Selected track+quality are unavailable'); + const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); t.truthy(data); t.true(Buffer.isBuffer(data)); @@ -206,8 +206,8 @@ if (process.env.CI) { test('DOWNLOAD TRACK1411 & ADD METADATA', async (t) => { const track = await api.getTrackInfo(SNG_ID); const trackData = await getTrackDownloadUrl(track, 9); - if (!trackData) throw new Error("Selected track+quality are unavailable"); - const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); + if (!trackData) throw new Error('Selected track+quality are unavailable'); + const {data} = await axios.get(trackData.trackUrl, {responseType: 'arraybuffer'}); t.truthy(data); t.true(Buffer.isBuffer(data)); diff --git a/__tests__/converter/parse.ts b/__tests__/converter/parse.ts index eb41e44..7760d50 100644 --- a/__tests__/converter/parse.ts +++ b/__tests__/converter/parse.ts @@ -142,7 +142,7 @@ test('SHOULD FAIL STRING', async (t) => { try { await parseInfo(str); t.fail(); - } catch (err) { + } catch (err: any) { t.is(err.message, 'Unknown URL: ' + str); } }); @@ -152,7 +152,7 @@ test('SHOULD FAIL URL', async (t) => { try { await parseInfo(url); t.fail(); - } catch (err) { + } catch (err: any) { t.is(err.message, 'Unknown URL: ' + url); } }); diff --git a/__tests__/converter/youtube.ts b/__tests__/converter/youtube.ts index 4a543cf..33edc92 100644 --- a/__tests__/converter/youtube.ts +++ b/__tests__/converter/youtube.ts @@ -21,7 +21,7 @@ if (!process.env.CI) { try { await youtube.track2deezer(INVALID_VIDEO); t.fail(); - } catch (err) { + } catch (err: any) { t.true(err.message.includes('No track found for youtube video ' + INVALID_VIDEO)); } }); diff --git a/package.json b/package.json index b2cd55e..8874e88 100644 --- a/package.json +++ b/package.json @@ -14,23 +14,25 @@ "author": "Sayem Chowdhury", "license": "MIT", "dependencies": { - "axios": "^0.21.1", + "axios": "^0.23.0", "browser-id3-writer": "^4.4.0", "delay": "^5.0.0", - "node-html-parser": "^4.1.3", + "node-html-parser": "^5.0.0", "p-queue": "^6.6.2", "spotify-uri": "^2.2.0", "spotify-web-api-node": "^5.0.2" }, "devDependencies": { - "@types/node": "^16.7.2", + "@types/node": "^16.11.0", "@types/spotify-web-api-node": "^5.0.3", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", "ava": "^3.15.0", "eslint": "^7.32.0", - "eslint-plugin-prettier": "^3.4.1", - "prettier": "^2.3.2", - "ts-node": "^10.2.1", - "typescript": "^4.3.5" + "eslint-plugin-prettier": "^4.0.0", + "prettier": "^2.4.1", + "ts-node": "^10.3.0", + "typescript": "^4.4.4" }, "ava": { "extensions": [ diff --git a/src/api/request.ts b/src/api/request.ts index b8146e9..3edc39f 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -15,7 +15,7 @@ export const request = async (body: object, method: string) => { const { data: {error, results}, - } = await axios.post('/gateway.php', body, {params: {method}}); + } = await axios.post('/gateway.php', body, {params: {method}}); if (Object.keys(results).length > 0) { lru.set(cacheKey, results); @@ -31,7 +31,7 @@ export const request = async (body: object, method: string) => { * @param {String} method request method * @param {Object} params request parameters */ -export const requestGet = async (method: string, params: object = {}, key: string = 'get_request') => { +export const requestGet = async (method: string, params: Record = {}, key = 'get_request') => { const cacheKey = method + key; const cache = lru.get(cacheKey); if (cache) { @@ -40,7 +40,7 @@ export const requestGet = async (method: string, params: object = {}, key: strin const { data: {error, results}, - } = await axios.get('/gateway.php', {params: {method, ...params}}); + } = await axios.get('/gateway.php', {params: {method, ...params}}); if (Object.keys(results).length > 0) { lru.set(cacheKey, results); @@ -61,7 +61,7 @@ export const requestPublicApi = async (slug: string) => { return cache; } - const {data} = await axios.get('https://api.deezer.com' + slug); + const {data} = await axios.get('https://api.deezer.com' + slug); if (data.error) { const errorMessage = Object.entries(data.error).join(', '); diff --git a/src/converter/deezer.ts b/src/converter/deezer.ts index 215594c..6053138 100644 --- a/src/converter/deezer.ts +++ b/src/converter/deezer.ts @@ -10,7 +10,7 @@ export const isrc2deezer = async (name: string, isrc?: string) => { throw new Error('ISRC code not found for ' + name); } - const {data} = await instance('track/isrc:' + isrc); + const {data} = await instance.get('track/isrc:' + isrc); if (data.error) { throw new Error(`No match on deezer for ${name} (ISRC: ${isrc})`); } @@ -25,7 +25,7 @@ export const upc2deezer = async (name: string, upc?: string): Promise<[albumType upc = upc.slice(-12); } - const {data} = await instance('album/upc:' + upc); + const {data} = await instance.get('album/upc:' + upc); if (data.error) { throw new Error(`No match on deezer for ${name} (UPC: ${upc})`); } @@ -36,7 +36,7 @@ export const upc2deezer = async (name: string, upc?: string): Promise<[albumType }; // Retry on rate limit error -instance.interceptors.response.use(async (response) => { +instance.interceptors.response.use(async (response: Record) => { if (response.data.error && Object.keys(response.data.error).length > 0) { if (response.data.error.code === 4) { await delay.range(1000, 1500); diff --git a/src/converter/parse.ts b/src/converter/parse.ts index 74c1e6d..ee690e4 100644 --- a/src/converter/parse.ts +++ b/src/converter/parse.ts @@ -89,19 +89,20 @@ export const getUrlParts = async (url: string, setToken = false): Promise { - let info = await getUrlParts(url, true); + const info = await getUrlParts(url, true); if (!info.id) { throw new Error('Unable to parse id'); } let linktype: linkType = 'track'; - let linkinfo: trackType | albumType | playlistInfo | artistInfoType | {} = {}; + let linkinfo: trackType | albumType | playlistInfo | artistInfoType | Record = {}; let tracks: trackType[] = []; switch (info.type) { - case 'track': + case 'track': { tracks.push(await getTrackInfo(info.id)); break; + } case 'album': case 'audiobook': diff --git a/src/converter/spotify.ts b/src/converter/spotify.ts index 50d97a6..4acbd75 100644 --- a/src/converter/spotify.ts +++ b/src/converter/spotify.ts @@ -77,9 +77,9 @@ export const playlist2Deezer = async ( onError?: (item: SpotifyApi.PlaylistTrackObject, index: number, err: Error) => void, ): Promise<[playlistInfo, trackType[]]> => { const {body} = await spotifyApi.getPlaylist(id); + const tracks: trackType[] = []; let items = body.tracks.items; let offset = getOffset(body.tracks.next); - let tracks: trackType[] = []; while (offset !== 0) { const {body} = await spotifyApi.getPlaylistTracks(id, {limit: 100, offset: offset ? offset : 0}); @@ -96,7 +96,7 @@ export const playlist2Deezer = async ( track.TRACK_POSITION = index + 1; tracks.push(track); } - } catch (err) { + } catch (err: any) { if (onError) { onError(item, index, err); } @@ -149,7 +149,7 @@ export const artist2Deezer = async ( try { const track = await isrc2deezer(item.name, item.external_ids.isrc); tracks.push(track); - } catch (err) { + } catch (err: any) { if (onError) { onError(item, index, err); } diff --git a/src/converter/tidal.ts b/src/converter/tidal.ts index 3420983..b2cec8a 100644 --- a/src/converter/tidal.ts +++ b/src/converter/tidal.ts @@ -97,7 +97,7 @@ const queue = new PQueue({concurrency: 25}); * @example tidal.getTrack('64975224') */ export const getTrack = async (id: string): Promise => { - const {data} = await client(`tracks/${id}`); + const {data} = await client.get(`tracks/${id}`); return data; }; @@ -116,7 +116,7 @@ export const track2deezer = async (id: string) => { * @example tidal.getAlbum('80216363') */ export const getAlbum = async (id: string): Promise => { - const {data} = await client(`albums/${id}`); + const {data} = await client.get(`albums/${id}`); return data; }; @@ -135,7 +135,7 @@ export const album2deezer = async (id: string) => { * @example tidal.getAlbumTracks('80216363') */ export const getAlbumTracks = async (id: string): Promise => { - const {data} = await client(`albums/${id}/tracks`); + const {data} = await client.get(`albums/${id}/tracks`); return data; }; @@ -145,7 +145,7 @@ export const getAlbumTracks = async (id: string): Promise * @example tidal.getArtistAlbums('3575680') */ export const getArtistAlbums = async (id: string): Promise => { - const {data} = await client(`artists/${id}/albums`); + const {data} = await client.get(`artists/${id}/albums`); data.items = data.items.filter((item: any) => item.artist.id.toString() === id); return data; }; @@ -156,7 +156,7 @@ export const getArtistAlbums = async (id: string): Promise => { - const {data} = await client(`artists/${id}/toptracks`); + const {data} = await client.get(`artists/${id}/toptracks`); data.items = data.items.filter((item: any) => item.artist.id.toString() === id); return data; }; @@ -167,7 +167,7 @@ export const getArtistTopTracks = async (id: string): Promise => { - const {data} = await client(`playlists/${uuid}`); + const {data} = await client.get(`playlists/${uuid}`); return data; }; @@ -177,7 +177,7 @@ export const getPlaylist = async (uuid: string): Promise => { * @example tidal.getPlaylistTracks('1c5d01ed-4f05-40c4-bd28-0f73099e9648') */ export const getPlaylistTracks = async (uuid: string): Promise => { - const {data} = await client(`playlists/${uuid}/tracks`); + const {data} = await client.get(`playlists/${uuid}/tracks`); return data; }; @@ -216,7 +216,7 @@ export const artist2Deezer = async ( const track = await isrc2deezer(item.title, item.isrc); // console.log(signale.success(`Track #${index}: ${item.name}`)); tracks.push(track); - } catch (err) { + } catch (err: any) { if (onError) { onError(item, index, err); } @@ -249,7 +249,7 @@ export const playlist2Deezer = async ( // console.log(signale.success(`Track #${index}: ${item.track.name}`)); track.TRACK_POSITION = index + 1; tracks.push(track); - } catch (err) { + } catch (err: any) { if (onError) { onError(item, index, err); } diff --git a/src/converter/youtube.ts b/src/converter/youtube.ts index 75bcd99..1a4ae7f 100644 --- a/src/converter/youtube.ts +++ b/src/converter/youtube.ts @@ -3,7 +3,7 @@ import {parse} from 'node-html-parser'; import {searchAlternative, searchMusic} from '../api'; const getTrack = async (id: string) => { - const response = await axios.get(`https://www.youtube.com/watch?v=${id}&hl=en`); + const response = await axios.get(`https://www.youtube.com/watch?v=${id}&hl=en`); const script = parse(response.data) .querySelectorAll('script') .find((script) => script.childNodes.find((node) => node.rawText.includes('responseText'))); diff --git a/src/lib/decrypt.ts b/src/lib/decrypt.ts index 1f7fca8..fb9f51c 100644 --- a/src/lib/decrypt.ts +++ b/src/lib/decrypt.ts @@ -17,8 +17,8 @@ export const getSongFileName = ({MD5_ORIGIN, SNG_ID, MEDIA_VERSION}: trackType, }; const getBlowfishKey = (trackId: string) => { - let SECRET = 'g4el58wc' + '0zvf9na1'; - let idMd5 = md5(trackId); + const SECRET = 'g4el58wc' + '0zvf9na1'; + const idMd5 = md5(trackId); let bfKey = ''; for (let i = 0; i < 16; i++) { bfKey += String.fromCharCode(idMd5.charCodeAt(i) ^ idMd5.charCodeAt(i + 16) ^ SECRET.charCodeAt(i)); @@ -27,10 +27,9 @@ const getBlowfishKey = (trackId: string) => { }; const decryptChunk = (chunk: Buffer, blowFishKey: string) => { - let cipher = crypto.createDecipheriv('bf-cbc', blowFishKey, Buffer.from([0, 1, 2, 3, 4, 5, 6, 7])); + const cipher = crypto.createDecipheriv('bf-cbc', blowFishKey, Buffer.from([0, 1, 2, 3, 4, 5, 6, 7])); cipher.setAutoPadding(false); - // @ts-ignore - return cipher.update(chunk, 'binary', 'binary') + cipher.final(); + return cipher.update(chunk as any, 'binary', 'binary') + cipher.final(); }; /** @@ -41,18 +40,17 @@ const decryptChunk = (chunk: Buffer, blowFishKey: string) => { export const decryptDownload = (source: Buffer, trackId: string) => { // let part_size = 0x1800; let chunk_size = 2048; - let blowFishKey = getBlowfishKey(trackId); + const blowFishKey = getBlowfishKey(trackId); let i = 0; let position = 0; - let destBuffer = Buffer.alloc(source.length); + const destBuffer = Buffer.alloc(source.length); destBuffer.fill(0); while (position < source.length) { - let chunk; - if (source.length - position >= 2048) chunk_size = 2048; - else chunk_size = source.length - position; - chunk = Buffer.alloc(chunk_size); + const chunk = Buffer.alloc(chunk_size); + const size = source.length - position; + chunk_size = size >= 2048 ? 2048 : size; let chunkString; chunk.fill(0); diff --git a/src/lib/get-url.ts b/src/lib/get-url.ts index 15fa36d..e959922 100644 --- a/src/lib/get-url.ts +++ b/src/lib/get-url.ts @@ -29,7 +29,7 @@ export class GeoBlocked extends Error { let user_data: userData | null = null; const dzAuthenticate = async (): Promise => { - const {data} = await instance.get('https://www.deezer.com/ajax/gw-light.php', { + const {data} = await instance.get('https://www.deezer.com/ajax/gw-light.php', { params: { method: 'deezer.getUserData', api_version: '1.0', @@ -51,7 +51,7 @@ const getTrackUrlFromServer = async (track_token: string, format: string): Promi throw new WrongLicense(format); } - const {data} = await instance.post('https://media.deezer.com/v1/get_url', { + const {data} = await instance.post('https://media.deezer.com/v1/get_url', { license_token: user.license_token, media: [ { @@ -78,7 +78,10 @@ const getTrackUrlFromServer = async (track_token: string, format: string): Promi * @param track Track info json returned from `getTrackInfo` * @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps) */ -export const getTrackDownloadUrl = async (track: trackType, quality: number): Promise<{trackUrl: string, isEncrypted: boolean, fileSize: number} | null> => { +export const getTrackDownloadUrl = async ( + track: trackType, + quality: number, +): Promise<{trackUrl: string; isEncrypted: boolean; fileSize: number} | null> => { let wrongLicense: WrongLicense | null = null; let geoBlocked: GeoBlocked | null = null; let formatName: string; @@ -141,8 +144,8 @@ export const getTrackDownloadUrl = async (track: trackType, quality: number): Pr const testUrl = async (url: string): Promise => { try { - let response = await axios.head(url); - return Number(response.headers['content-length']); + const {headers} = await axios.head(url); + return Number(headers['content-length']); } catch (err) { return 0; } diff --git a/src/lib/metaflac-js.ts b/src/lib/metaflac-js.ts index 083ae93..cfe0b92 100644 --- a/src/lib/metaflac-js.ts +++ b/src/lib/metaflac-js.ts @@ -74,7 +74,7 @@ class Metaflac { let isLastBlock = false; while (!isLastBlock) { blockType = this.buffer.readUInt8(offset++); - isLastBlock = blockType > 128; + isLastBlock = blockType >= 128; blockType = blockType % 128; const blockLength = this.buffer.readUIntBE(offset, 3); @@ -354,7 +354,7 @@ class Metaflac { ]); } - buildMetadataBlock(type: number, block: Buffer, isLast: boolean = false) { + buildMetadataBlock(type: number, block: Buffer, isLast = false) { const header = Buffer.alloc(4); if (isLast) { type += 128; @@ -375,7 +375,9 @@ class Metaflac { this.pictures.forEach((block: Buffer) => { bufferArray.push(this.buildMetadataBlock(PICTURE, block)); }); - if (this.padding == null) this.padding = Buffer.alloc(16384); + if (this.padding == null) { + this.padding = Buffer.alloc(16384); + } bufferArray.push(this.buildMetadataBlock(PADDING, this.padding, true)); return bufferArray; } diff --git a/src/lib/request.ts b/src/lib/request.ts index 14a1424..8c8d87b 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -33,7 +33,7 @@ export const initDeezerApi = async (arl: string): Promise => { throw new Error(`Invalid arl. Length should be 192 characters. You have provided ${arl.length} characters.`); } user_arl = arl; - const {data} = await instance.get('https://www.deezer.com/ajax/gw-light.php', { + const {data} = await instance.get('https://www.deezer.com/ajax/gw-light.php', { params: {method: 'deezer.ping', api_version: '1.0', api_token: ''}, headers: {cookie: 'arl=' + arl}, }); @@ -42,7 +42,7 @@ export const initDeezerApi = async (arl: string): Promise => { }; // Add a request interceptor -instance.interceptors.response.use(async (response) => { +instance.interceptors.response.use(async (response: Record) => { if (response.data.error && Object.keys(response.data.error).length > 0) { if (response.data.error.NEED_API_AUTH_REQUIRED) { await initDeezerApi(user_arl); diff --git a/src/metadata-writer/abumCover.ts b/src/metadata-writer/abumCover.ts index bf361c7..cd2a4a6 100644 --- a/src/metadata-writer/abumCover.ts +++ b/src/metadata-writer/abumCover.ts @@ -27,7 +27,7 @@ export const downloadAlbumCover = async (track: trackType, albumCoverSize: cover try { const url = `https://e-cdns-images.dzcdn.net/images/cover/${track.ALB_PICTURE}/${albumCoverSize}x${albumCoverSize}-000000-80-0-0.jpg`; - const {data} = await axios.get(url, {responseType: 'arraybuffer'}); + const {data} = await axios.get(url, {responseType: 'arraybuffer'}); lru.set(track.ALB_PICTURE + albumCoverSize, data); return data; } catch (err) { diff --git a/src/metadata-writer/musixmatchLyrics.ts b/src/metadata-writer/musixmatchLyrics.ts index 2234d3d..c66fb86 100644 --- a/src/metadata-writer/musixmatchLyrics.ts +++ b/src/metadata-writer/musixmatchLyrics.ts @@ -5,16 +5,16 @@ import {randomUseragent} from './useragents'; const baseUrl = 'https://musixmatch.com'; const getUrlMusixmatch = async (query: string) => { - const {data} = await axios.get(`${baseUrl}/search/${encodeURI(query)}/tracks`, { + const {data} = await axios.get(`${baseUrl}/search/${encodeURI(query)}/tracks`, { headers: { 'User-Agent': randomUseragent(), referer: 'https://l.facebook.com/', }, }); - // @ts-ignore - const url = parse(data).querySelector('h2').childNodes[0].attributes.href.replace('/add', ''); - if (url.includes('/lyrics/')) { + const childNode = parse(data).querySelector('h2')?.childNodes.at(0); + const url: string | undefined = (childNode as any)?.attributes.href.replace('/add', ''); + if (url && url.includes('/lyrics/')) { return url.startsWith('/lyrics/') ? baseUrl + url : url; } @@ -23,7 +23,7 @@ const getUrlMusixmatch = async (query: string) => { export const getLyricsMusixmatch = async (query: string): Promise => { const url = await getUrlMusixmatch(query); - const {data} = await axios.get(url, { + const {data} = await axios.get(url, { headers: { 'User-Agent': randomUseragent(), referer: baseUrl + '/', diff --git a/yarn.lock b/yarn.lock index 18f7700..f4db6ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,10 +42,10 @@ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== -"@cspotcode/source-map-support@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" - integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== dependencies: "@cspotcode/source-map-consumer" "0.8.0" @@ -131,10 +131,15 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/node@^16.7.2": - version "16.7.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.2.tgz#0465a39b5456b61a04d98bd5545f8b34be340cb7" - integrity sha512-TbG4TOx9hng8FKxaVrCisdaxKxqEwJ3zwHoCWXZ0Jw6mnvTInpaB99/2Cy4+XxpXtjNv9/TgfGSvZFyfV/t8Fw== +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/node@^16.11.0": + version "16.11.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.0.tgz#4b95f2327bacd1ef8f08d8ceda193039c5d7f52e" + integrity sha512-8MLkBIYQMuhRBQzGN9875bYsOhPnf/0rgXGo66S2FemHkhbn9qtsz9ywV1iCG+vbjigE4WUNVvw37Dx+L0qsPg== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -153,6 +158,76 @@ dependencies: "@types/spotify-api" "*" +"@typescript-eslint/eslint-plugin@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.0.0.tgz#ecc7cc69d1e6f342beb6ea9cf9fbc02c97a212ac" + integrity sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg== + dependencies: + "@typescript-eslint/experimental-utils" "5.0.0" + "@typescript-eslint/scope-manager" "5.0.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.0.0.tgz#c7d7e67443dfb9fd93a5d060fb72c9e9b5638bbc" + integrity sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "5.0.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/typescript-estree" "5.0.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.0.0.tgz#50d1be2e0def82d73e863cceba74aeeac9973592" + integrity sha512-B6D5rmmQ14I1fdzs71eL3DAuvnPHTY/t7rQABrL9BLnx/H51Un8ox1xqYAchs0/V2trcoyxB1lMJLlrwrJCDgw== + dependencies: + "@typescript-eslint/scope-manager" "5.0.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/typescript-estree" "5.0.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.0.0.tgz#aea0fb0e2480c1169a02e89d9005ac3f2835713f" + integrity sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ== + dependencies: + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/visitor-keys" "5.0.0" + +"@typescript-eslint/types@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.0.0.tgz#25d93f6d269b2d25fdc51a0407eb81ccba60eb0f" + integrity sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w== + +"@typescript-eslint/typescript-estree@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.0.0.tgz#bc20f413c6e572c7309dbe5fa3be027984952af3" + integrity sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q== + dependencies: + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/visitor-keys" "5.0.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.0.0.tgz#b789f7cd105e59bee5c0983a353942a5a48f56df" + integrity sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw== + dependencies: + "@typescript-eslint/types" "5.0.0" + eslint-visitor-keys "^3.0.0" + acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" @@ -369,12 +444,12 @@ ava@^3.15.0: write-file-atomic "^3.0.3" yargs "^16.2.0" -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.23.0.tgz#b0fa5d0948a8d1d75e3d5635238b6c4625b05149" + integrity sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.4" balanced-match@^1.0.0: version "1.0.0" @@ -940,10 +1015,10 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== +eslint-plugin-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== dependencies: prettier-linter-helpers "^1.0.0" @@ -962,6 +1037,13 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" @@ -972,6 +1054,11 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== +eslint-visitor-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" + integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== + eslint@^7.32.0: version "7.32.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" @@ -1159,10 +1246,10 @@ 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.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" - integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== +follow-redirects@^1.14.4: + version "1.14.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" + integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== form-data@^3.0.0: version "3.0.1" @@ -1285,6 +1372,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -1364,7 +1463,7 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: +ignore@^5.1.4, ignore@^5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -1807,10 +1906,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -node-html-parser@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-4.1.3.tgz#993f42273c97bc0b1171f3c7e4d2f7959defc96a" - integrity sha512-jWFd9TBxDJ0hXkvPKxiWXy4R87ZoIjYj5P2twbef3q/E4vJyFt8TTRQ68ssHYW5Aozwth4SWHOPT6yfDd/gzQQ== +node-html-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.0.0.tgz#a398d6d27459346c517dc1b1e3dd779e12d685c3" + integrity sha512-TTcYevvxqIyRfc1Y/3O6EwzmPFmN9fykfdP3DewtDaVMzft4HFfs21ogw5LGDYhieIq8QBFG+PSBNd5x3n0WZQ== dependencies: css-select "^4.1.3" he "1.2.0" @@ -2076,10 +2175,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" - integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prettier@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" + integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== pretty-ms@^7.0.1: version "7.0.1" @@ -2283,6 +2382,13 @@ semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: dependencies: lru-cache "^6.0.0" +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -2542,12 +2648,12 @@ trim-off-newlines@^1.0.1: resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= -ts-node@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" - integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== +ts-node@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.3.0.tgz#a797f2ed3ff50c9a5d814ce400437cb0c1c048b4" + integrity sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw== dependencies: - "@cspotcode/source-map-support" "0.6.1" + "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" @@ -2560,6 +2666,18 @@ ts-node@^10.2.1: make-error "^1.1.1" yn "3.1.1" +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -2594,10 +2712,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@^4.4.4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== unique-string@^2.0.0: version "2.0.0"