discord-player-deezer
Advanced tools
Comparing version 2.3.0 to 2.3.1-dev.0
@@ -18,2 +18,3 @@ import { Track, ExtractorStreamable, BaseExtractor, SearchQueryType, ExtractorSearchContext, Playlist as Playlist$1, ExtractorInfo, Player } from 'discord-player'; | ||
searchLimit?: number; | ||
reloadUserInterval?: number; | ||
}; | ||
@@ -31,4 +32,5 @@ type DeezerUserInfo = { | ||
declare class DeezerExtractor extends BaseExtractor<DeezerExtractorOptions> { | ||
static identifier: string; | ||
static readonly identifier: string; | ||
userInfo: DeezerUserInfo; | ||
__interval?: ReturnType<typeof setInterval>; | ||
activate(): Promise<void>; | ||
@@ -35,0 +37,0 @@ deactivate(): Promise<void>; |
@@ -66,4 +66,4 @@ "use strict"; | ||
try { | ||
new URL(query); | ||
return true; | ||
const url = new URL(query); | ||
return url.protocol === "http" || url.protocol === "https"; | ||
} catch { | ||
@@ -206,5 +206,23 @@ return false; | ||
// src/DeezerExtractor.ts | ||
var import_promises = require("timers/promises"); | ||
var Warnings = { | ||
MissingDecryption: "Decryption Key missing! This is needed for extracting streams." | ||
}; | ||
async function fetchDeezerAnonUser() { | ||
const crypto = await getCrypto(); | ||
const randomToken = crypto.randomBytes(16).toString("hex"); | ||
const deezerUsrDataUrl = `https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData&input=3&api_version=1.0&api_token=${randomToken}`; | ||
const usrDataRes = await fetch(deezerUsrDataUrl); | ||
const usrData = await usrDataRes.json(); | ||
const licenseToken = usrData.results.USER.OPTIONS.license_token; | ||
if (typeof licenseToken !== "string") throw new Error("Unable to get licenseToken"); | ||
const csrfToken = usrData.results.checkForm; | ||
if (typeof csrfToken !== "string") throw new Error("Unable to get csrf token which is required for decryption"); | ||
return { | ||
cookie: usrDataRes.headers.get("set-cookie"), | ||
licenseToken, | ||
csrfToken, | ||
mediaUrl: usrData.results.URL_MEDIA || "https://media.deezer.com" | ||
}; | ||
} | ||
var DeezerExtractor = class extends import_discord_player2.BaseExtractor { | ||
@@ -215,25 +233,32 @@ async activate() { | ||
else { | ||
const crypto = await getCrypto(); | ||
const randomToken = crypto.randomBytes(16).toString("hex"); | ||
const deezerUsrDataUrl = `https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData&input=3&api_version=1.0&api_token=${randomToken}`; | ||
const usrDataRes = await fetch(deezerUsrDataUrl); | ||
const usrData = await usrDataRes.json(); | ||
const licenseToken = usrData.results.USER.OPTIONS.license_token; | ||
if (typeof licenseToken !== "string") throw new Error("Unable to get licenseToken"); | ||
const csrfToken = usrData.results.checkForm; | ||
if (typeof csrfToken !== "string") throw new Error("Unable to get csrf token which is required for decryption"); | ||
this.userInfo = { | ||
mediaUrl: usrData.results.URL_MEDIA || "https://media.deezer.com", | ||
cookie: usrDataRes.headers.get("set-cookie"), | ||
licenseToken, | ||
csrfToken | ||
}; | ||
this.userInfo = await fetchDeezerAnonUser(); | ||
this.context.player.debug("USER INFO EXT: " + JSON.stringify(this.userInfo)); | ||
} | ||
this.__interval = setInterval( | ||
async () => { | ||
try { | ||
this.userInfo = await fetchDeezerAnonUser(); | ||
} catch { | ||
this.context.player.debug("[DEEZER_EXTRACTOR_ERR]: Unable to fetch user information from Deezer. Retrying in 3 seconds ..."); | ||
await (0, import_promises.setTimeout)( | ||
3e3 | ||
/* 3 seconds */ | ||
); | ||
try { | ||
this.userInfo = await fetchDeezerAnonUser(); | ||
} catch (err) { | ||
this.context.player.debug("[DEEZER_EXTRACTOR_ERR]: Retry failed. Using old user ..."); | ||
} | ||
} | ||
}, | ||
this.options.reloadUserInterval || 864e5 | ||
/* one day */ | ||
).unref(); | ||
} | ||
async deactivate() { | ||
if (this.__interval) clearInterval(this.__interval); | ||
this.protocols = []; | ||
} | ||
async validate(query, type) { | ||
return validate(query) || type === "deezer"; | ||
return validate(query) || type === "deezer" || !isUrl(query); | ||
} | ||
@@ -259,3 +284,3 @@ buildPlaylistData(data, handleContext) { | ||
async handle(query, context) { | ||
if (context.protocol === "deezer" && !isUrl(query)) { | ||
if (!isUrl(query)) { | ||
const rawSearch = await search(query); | ||
@@ -262,0 +287,0 @@ const tracks = buildTrackFromSearch(rawSearch, this.context.player, context.requestedBy); |
{ | ||
"name": "discord-player-deezer", | ||
"version": "2.3.0", | ||
"version": "2.3.1-dev.0", | ||
"description": "A custom extractor made for discord-player that enables you to extract from Deezer.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
import { BaseExtractor, ExtractorSearchContext, ExtractorStreamable, Track, Playlist, Util as DPUtil, ExtractorInfo, SearchQueryType } from "discord-player" | ||
import { Playlist as DeezerPlaylist, Track as DeezerTrack, getData } from "@mithron/deezer-music-metadata"; | ||
import { buildTrackFromSearch, deezerRegex, getCrypto, isUrl, search, searchOneTrack, streamTrack, validate } from "./utils/util"; | ||
import { setTimeout } from "node:timers/promises" | ||
@@ -18,2 +19,3 @@ /** | ||
searchLimit?: number; | ||
reloadUserInterval?: number; | ||
} | ||
@@ -33,5 +35,31 @@ | ||
async function fetchDeezerAnonUser(): Promise<DeezerUserInfo> { | ||
// extract deezer username | ||
// dynamically load crypto because some might not want streaming | ||
const crypto = await getCrypto() | ||
const randomToken = crypto.randomBytes(16).toString("hex") | ||
const deezerUsrDataUrl = `https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData&input=3&api_version=1.0&api_token=${randomToken}` | ||
const usrDataRes = await fetch(deezerUsrDataUrl) | ||
const usrData = await usrDataRes.json() | ||
const licenseToken = usrData.results.USER.OPTIONS.license_token | ||
if(typeof licenseToken !== "string") throw new Error("Unable to get licenseToken") | ||
const csrfToken = usrData.results.checkForm | ||
if(typeof csrfToken !== "string") throw new Error("Unable to get csrf token which is required for decryption") | ||
return { | ||
cookie: usrDataRes.headers.get("set-cookie")!, | ||
licenseToken, | ||
csrfToken, | ||
mediaUrl: usrData.results.URL_MEDIA || "https://media.deezer.com", | ||
} | ||
} | ||
export class DeezerExtractor extends BaseExtractor<DeezerExtractorOptions> { | ||
static identifier: string = "com.retrouser955.discord-player.deezr-ext" | ||
static readonly identifier: string = "com.retrouser955.discord-player.deezr-ext" | ||
userInfo!: DeezerUserInfo | ||
/* tslint:disable-next-line */ | ||
__interval?: ReturnType<typeof setInterval> | ||
@@ -42,29 +70,24 @@ async activate(): Promise<void> { | ||
else { | ||
// extract deezer username | ||
// dynamically load crypto because some might not want streaming | ||
const crypto = await getCrypto() | ||
const randomToken = crypto.randomBytes(16).toString("hex") | ||
const deezerUsrDataUrl = `https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData&input=3&api_version=1.0&api_token=${randomToken}` | ||
this.userInfo = await fetchDeezerAnonUser() | ||
const usrDataRes = await fetch(deezerUsrDataUrl) | ||
const usrData = await usrDataRes.json() | ||
this.context.player.debug('USER INFO EXT: ' + JSON.stringify(this.userInfo)) | ||
} | ||
const licenseToken = usrData.results.USER.OPTIONS.license_token | ||
if(typeof licenseToken !== "string") throw new Error("Unable to get licenseToken") | ||
const csrfToken = usrData.results.checkForm | ||
if(typeof csrfToken !== "string") throw new Error("Unable to get csrf token which is required for decryption") | ||
this.userInfo = { | ||
mediaUrl: usrData.results.URL_MEDIA || "https://media.deezer.com", | ||
cookie: usrDataRes.headers.get("set-cookie")!, | ||
licenseToken, | ||
csrfToken | ||
this.__interval = setInterval(async () => { | ||
try { | ||
this.userInfo = await fetchDeezerAnonUser() | ||
} catch { | ||
this.context.player.debug("[DEEZER_EXTRACTOR_ERR]: Unable to fetch user information from Deezer. Retrying in 3 seconds ...") | ||
await setTimeout(3000/* 3 seconds */) | ||
try { | ||
this.userInfo = await fetchDeezerAnonUser() | ||
} catch (err) { | ||
this.context.player.debug("[DEEZER_EXTRACTOR_ERR]: Retry failed. Using old user ...") | ||
} | ||
this.context.player.debug('USER INFO EXT: ' + JSON.stringify(this.userInfo)) | ||
} | ||
} | ||
}, this.options.reloadUserInterval || 8.64e+7/* one day */).unref() | ||
} | ||
async deactivate() { | ||
if(this.__interval) clearInterval(this.__interval) | ||
this.protocols = [] | ||
@@ -74,3 +97,3 @@ } | ||
async validate(query: string, type: SearchQueryType & "deezer"): Promise<boolean> { | ||
return validate(query) || type === "deezer" | ||
return validate(query) || type === "deezer" || !isUrl(query) | ||
} | ||
@@ -99,3 +122,3 @@ | ||
async handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo> { | ||
if(context.protocol === "deezer" && !isUrl(query)) { | ||
if(!isUrl(query)) { | ||
const rawSearch = await search(query) | ||
@@ -102,0 +125,0 @@ const tracks = buildTrackFromSearch(rawSearch, this.context.player, context.requestedBy) |
@@ -21,5 +21,4 @@ import { type Player, Track, Util } from "discord-player"; | ||
try { | ||
/* tslint:disable-next-line no-unused-expression */ | ||
new URL(query) | ||
return true | ||
const url = new URL(query) | ||
return url.protocol === "http" || url.protocol === "https" | ||
} catch { | ||
@@ -26,0 +25,0 @@ return false |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
280094
748
2