discord-player-deezer
Advanced tools
Comparing version 2.0.0-beta.2 to 2.0.0-beta.3
@@ -1,2 +0,2 @@ | ||
import { Track, ExtractorStreamable, BaseExtractor, ExtractorSearchContext, Playlist as Playlist$1, ExtractorInfo } from 'discord-player'; | ||
import { Track, ExtractorStreamable, BaseExtractor, ExtractorSearchContext, Playlist as Playlist$1, ExtractorInfo, Player } from 'discord-player'; | ||
import { Playlist, Track as Track$1 } from '@mithron/deezer-music-metadata'; | ||
@@ -31,3 +31,4 @@ import * as crypto from 'crypto'; | ||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>; | ||
buildTrack(track: Track$1, handleContext: ExtractorSearchContext): Track<unknown>; | ||
buildTrack(track: Track$1, { requestedBy }: ExtractorSearchContext): Track<unknown>; | ||
bridge(track: Track): Promise<ExtractorStreamable | null>; | ||
stream(info: Track): Promise<ExtractorStreamable>; | ||
@@ -37,2 +38,23 @@ } | ||
declare function getCrypto(): Promise<typeof crypto>; | ||
type ArrayOrObject<T> = T | T[]; | ||
interface DeezerSearchTrackResponse { | ||
data: { | ||
link: string; | ||
title: string; | ||
album: { | ||
cover_xl?: string; | ||
cover_medium?: string; | ||
cover_small?: string; | ||
cover?: string; | ||
}; | ||
artist: { | ||
name: string; | ||
}; | ||
duration: number; | ||
type: "track"; | ||
}[]; | ||
} | ||
declare function buildTrackFromSearch(track: DeezerSearchTrackResponse, player: Player, requestedBy?: Track['requestedBy']): Track<unknown>[]; | ||
declare function extractTrackId(query: string): string; | ||
declare function searchOneTrack(query: string): Promise<DeezerSearchTrackResponse | undefined>; | ||
declare function streamTrack(track: Track, ext: DeezerExtractor): Promise<PassThrough>; | ||
@@ -46,2 +68,2 @@ declare const deezerRegex: { | ||
export { DeezerExtractor, type DeezerExtractorOptions, type DeezerUserInfo, deezerRegex, getCrypto, streamTrack, validate }; | ||
export { type ArrayOrObject, DeezerExtractor, type DeezerExtractorOptions, type DeezerSearchTrackResponse, type DeezerUserInfo, buildTrackFromSearch, deezerRegex, extractTrackId, getCrypto, searchOneTrack, streamTrack, validate }; |
@@ -34,4 +34,7 @@ "use strict"; | ||
DeezerExtractor: () => DeezerExtractor, | ||
buildTrackFromSearch: () => buildTrackFromSearch, | ||
deezerRegex: () => deezerRegex, | ||
extractTrackId: () => extractTrackId, | ||
getCrypto: () => getCrypto, | ||
searchOneTrack: () => searchOneTrack, | ||
streamTrack: () => streamTrack, | ||
@@ -43,6 +46,7 @@ validate: () => validate | ||
// src/DeezerExtractor.ts | ||
var import_discord_player = require("discord-player"); | ||
var import_discord_player2 = require("discord-player"); | ||
var import_deezer_music_metadata = require("@mithron/deezer-music-metadata"); | ||
// src/utils/util.ts | ||
var import_discord_player = require("discord-player"); | ||
var import_stream = require("stream"); | ||
@@ -58,9 +62,39 @@ var IV = Buffer.from(Array.from({ length: 8 }, (_, x) => x)); | ||
} | ||
var DeezerAPIRoutes = { | ||
searchTrack(query, limit) { | ||
const url = `https://api.deezer.com/search/track?q=${encodeURIComponent(query)}&${limit ? `limit=${limit}` : ""}`; | ||
return url; | ||
} | ||
}; | ||
function buildTrackFromSearch(track, player, requestedBy) { | ||
return track.data.map((v) => new import_discord_player.Track(player, { | ||
source: "arbitrary", | ||
duration: import_discord_player.Util.buildTimeCode(import_discord_player.Util.parseMS(v.duration * 1e3)), | ||
author: Array.isArray(v.artist) ? v.artist.map((a) => a.name).join(", ") : v.artist.name, | ||
url: v.link, | ||
title: v.title, | ||
thumbnail: v.album.cover_xl || v.album.cover_medium || v.album.cover || v.album.cover_small || "https://play-lh.googleusercontent.com/xtIOV8iPeAY4GrldTDo3CbLAEpbea2DqnfxaB4Nn2p5qz6KAiumY74qH86pgu1HA1A", | ||
live: false, | ||
requestedBy | ||
})); | ||
} | ||
function extractTrackId(query) { | ||
if (!validate(query)) throw new Error("Invalid track url"); | ||
const trackIdWithUrlParams = query.split("/").at(-1); | ||
if (!trackIdWithUrlParams) throw new Error("Cannot find track ID"); | ||
return trackIdWithUrlParams.split("?")[0]; | ||
} | ||
async function searchOneTrack(query) { | ||
const url = DeezerAPIRoutes.searchTrack(query, 1); | ||
const trackRes = await fetch(url); | ||
if (trackRes.status !== 200) throw new Error("Fetch failed"); | ||
const trackData = await trackRes.json(); | ||
const track = trackData; | ||
return track; | ||
} | ||
async function streamTrack(track, ext) { | ||
const trackIdWithUrlParams = track.url.split("/").at(-1); | ||
if (!trackIdWithUrlParams || !validate(track.url)) throw new Error("INVALID TRACK"); | ||
const decryptionKey = ext.options.decryptionKey; | ||
if (!decryptionKey) throw new Error("MISSING DEEZER DECRYPTION KEY"); | ||
const crypto = await getCrypto(); | ||
const trackId = trackIdWithUrlParams.split("?")[0]; | ||
const trackId = extractTrackId(track.url); | ||
const trackHash = crypto.createHash("md5").update(trackId, "ascii").digest("hex"); | ||
@@ -159,3 +193,3 @@ const trackKey = Buffer.alloc(16); | ||
// src/DeezerExtractor.ts | ||
var DeezerExtractor = class extends import_discord_player.BaseExtractor { | ||
var DeezerExtractor = class extends import_discord_player2.BaseExtractor { | ||
async activate() { | ||
@@ -185,3 +219,3 @@ if (!this.options.decryptionKey) process.emitWarning("Decryption Key missing! This is needed for extracting streams."); | ||
const identifier = raw[raw.length - 1].split("?")[0]; | ||
return new import_discord_player.Playlist(this.context.player, { | ||
return new import_discord_player2.Playlist(this.context.player, { | ||
title: data.name, | ||
@@ -210,4 +244,4 @@ thumbnail: data.thumbnail[0].url, | ||
} | ||
buildTrack(track, handleContext) { | ||
return new import_discord_player.Track(this.context.player, { | ||
buildTrack(track, { requestedBy }) { | ||
return new import_discord_player2.Track(this.context.player, { | ||
title: track.name, | ||
@@ -218,6 +252,13 @@ author: track.author.map((v) => v.name).join(", "), | ||
thumbnail: track.thumbnail[0].url, | ||
duration: import_discord_player.Util.buildTimeCode(import_discord_player.Util.parseMS(track.duration)), | ||
requestedBy: handleContext.requestedBy | ||
duration: import_discord_player2.Util.buildTimeCode(import_discord_player2.Util.parseMS(track.duration)), | ||
requestedBy | ||
}); | ||
} | ||
async bridge(track) { | ||
const deezerTrack = await searchOneTrack(`${track.author} ${track.source === "youtube" ? track.cleanTitle : track.title}`); | ||
if (!deezerTrack || !deezerTrack?.data[0]) return null; | ||
const dpTrack = buildTrackFromSearch(deezerTrack, this.context.player, track.requestedBy); | ||
const stream = this.stream(dpTrack[0]); | ||
return stream; | ||
} | ||
stream(info) { | ||
@@ -231,6 +272,9 @@ return streamTrack(info, this); | ||
DeezerExtractor, | ||
buildTrackFromSearch, | ||
deezerRegex, | ||
extractTrackId, | ||
getCrypto, | ||
searchOneTrack, | ||
streamTrack, | ||
validate | ||
}); |
{ | ||
"name": "discord-player-deezer", | ||
"version": "2.0.0-beta.2", | ||
"version": "2.0.0-beta.3", | ||
"description": "A custom extractor made for discord-player that enables you to extract from Deezer.", | ||
@@ -14,3 +14,2 @@ "main": "dist/index.js", | ||
"@discord-player/extractor": "^4.5.1", | ||
"cross-env": "^7.0.3", | ||
"discord-player": "^6.7.1", | ||
@@ -26,3 +25,3 @@ "prettier": "^3.4.2", | ||
"lint": "tslint -p tsconfig.json", | ||
"npm:publish": "cross-env NODE_OPTIONS=--openssl-legacy-provider yarn build && npm publish --access public" | ||
"npm:publish": "yarn build && npm publish --access public" | ||
}, | ||
@@ -29,0 +28,0 @@ "repository": { |
@@ -1,65 +0,43 @@ | ||
# Discord Player Deezer Extractor | ||
# Discord Player Deezer | ||
Discord Player Deezer Extractor. An extractor made for discord-player for **Deezer** support. Deezer extractor works by either making a request to the Deezer API or extracting metadata from the Deezer site. Because we cannot get streams from deezer itself, the extractor uses the extracted data to stream from youtube! | ||
Discord Player Deezer is a Deezer platform plugin for discord-player | ||
## Installing the extractor | ||
# Installation | ||
```bash | ||
npm install discord-player-deezer | ||
# or | ||
yarn add discord-player-deezer | ||
$ npm install discord-player-deezer | ||
``` | ||
## Loading the extractor | ||
# Register the extractor | ||
### CJS | ||
```js | ||
const DeezerExtractor = require("discord-player-deezer").default // or const { default: DeezerExtractor } = require("discord-player-deezer") | ||
const player = getMainPlayerSomehow() | ||
```ts | ||
import { DeezerExtractor } from "discord-player-deezer" | ||
import { Player } from "discord-player" | ||
player.extractors.register(DeezerExtractor) | ||
const player = new Player(...) | ||
await player.extractors.register(DeezerExtractor, {}) | ||
``` | ||
### ESM | ||
```js | ||
import { default as DeezerExtractor } from "discord-player-deezer" | ||
# Extracting Streams | ||
const player = getMainPlayerSomehow() | ||
As Deezer sends DMCA to repositories containing the hard-coded decryption key, it is not provided. You can find this key in the code of related projects (deezer downloaders) and your client-side JavaScript code. | ||
player.extractors.register(DeezerExtractor) | ||
``` | ||
### Typescript | ||
```ts | ||
import DeezerExtractor from "discord-player-deezer" | ||
import { DeezerExtractor } from "discord-player-deezer" | ||
import { Player } from "discord-player" | ||
const player = getMainPlayerSomehow() | ||
const player = new Player(...) | ||
player.extractors.register(DeezerExtractor) | ||
await player.extractors.register(DeezerExtractor, { | ||
decryptionKey: "master-decryption-key" | ||
}) | ||
``` | ||
*note: be sure to register it before loading the default extractors to make sure any conflicts with discord-player's default attachment extractor is resolved!* | ||
# Important information | ||
That's it! See the magic happen as you bot is now able to play from Deezer URLs | ||
As Node has migrated from openssl for decryption, we must use the `--openssl-legacy-provider` flag when starting our application with stream extraction | ||
# Options | ||
DP Deezer accepts the following options. | ||
```ts | ||
interface DeezerOptions { | ||
forceEngine?: EngineType; | ||
createStream?: () => Promise<string|Readable>; | ||
beforeCreateStream?: () => Promise<unknown>|unknown; | ||
} | ||
``` | ||
One thing to keep in mind is, while using the two functions, if you want to access track data, you must you `useTrack()` function exported by the library. For example ... | ||
```ts | ||
player.extractors.register(DeezerExtractor, { | ||
createStream: () => { | ||
const track = useTrack() | ||
return getStreamSomehow(track) | ||
} | ||
}) | ||
```bash | ||
$ node --openssl-legacy-provider yourfile.js | ||
``` |
23905
7
364
43
5