custom extractors support
This commit is contained in:
parent
72af2eb46b
commit
7d19bae727
3 changed files with 114 additions and 2 deletions
|
@ -8,6 +8,7 @@ import { Track } from './Structures/Track';
|
|||
import { PlayerErrorEventCodes, PlayerEvents } from './utils/Constants';
|
||||
import PlayerError from './utils/PlayerError';
|
||||
import ytdl from 'discord-ytdl-core';
|
||||
import { ExtractorModel } from "./Structures/ExtractorModel";
|
||||
|
||||
// @ts-ignore
|
||||
import spotify from 'spotify-url-info';
|
||||
|
@ -24,6 +25,7 @@ export class Player extends EventEmitter {
|
|||
public queues: Collection<Snowflake, Queue>;
|
||||
private _resultsCollectors: Collection<string, Collector<Snowflake, Message>>;
|
||||
private _cooldownsTimeout: Collection<string, NodeJS.Timeout>;
|
||||
public Extractors = new Collection<string, ExtractorModel>();
|
||||
|
||||
constructor(client: Client, options?: PlayerOptions) {
|
||||
super();
|
||||
|
@ -62,6 +64,35 @@ export class Player extends EventEmitter {
|
|||
return AudioFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define custom extractor in this player
|
||||
* @param extractorName The extractor name
|
||||
* @param extractor The extractor itself
|
||||
*/
|
||||
use(extractorName: string, extractor: any) {
|
||||
if (!extractorName) throw new PlayerError("Missing extractor name!", "PlayerExtractorError");
|
||||
|
||||
const methods = ["validate", "getInfo"];
|
||||
|
||||
for (const method of methods) {
|
||||
if (typeof extractor[method] !== "function") throw new PlayerError("Invalid extractor supplied!", "PlayerExtractorError");
|
||||
}
|
||||
|
||||
this.Extractors.set(extractorName, new ExtractorModel(extractorName, extractor));
|
||||
|
||||
return Player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing extractor from this player
|
||||
* @param extractorName The extractor name
|
||||
*/
|
||||
unuse(extractorName: string) {
|
||||
if (!extractorName) throw new PlayerError("Missing extractor name!", "PlayerExtractorError");
|
||||
|
||||
return this.Extractors.delete(extractorName);
|
||||
}
|
||||
|
||||
private _searchTracks(message: Message, query: string, firstResult?: boolean): Promise<Track> {
|
||||
return new Promise(async (resolve) => {
|
||||
let tracks: Track[] = [];
|
||||
|
@ -83,7 +114,7 @@ export class Player extends EventEmitter {
|
|||
requestedBy: message.author,
|
||||
fromPlaylist: false,
|
||||
source: 'soundcloud',
|
||||
engine: data
|
||||
engine: data.engine
|
||||
});
|
||||
|
||||
tracks.push(track);
|
||||
|
@ -342,7 +373,31 @@ export class Player extends EventEmitter {
|
|||
source: 'youtube'
|
||||
});
|
||||
} else {
|
||||
track = await this._searchTracks(message, query, firstResult);
|
||||
for (const [_, extractor] of this.Extractors) {
|
||||
if (extractor.validate(query)) {
|
||||
const data = await extractor.handle(query);
|
||||
if (data) {
|
||||
console.log(data)
|
||||
track = new Track(this, {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
duration: Util.durationString(Util.parseMS(data.duration)),
|
||||
thumbnail: data.thumbnail,
|
||||
author: data.author,
|
||||
views: data.views,
|
||||
engine: data.engine,
|
||||
source: 'arbitrary',
|
||||
fromPlaylist: false,
|
||||
requestedBy: message.author,
|
||||
url: data.url
|
||||
});
|
||||
|
||||
if (extractor.important) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!track) track = await this._searchTracks(message, query, firstResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
src/Structures/ExtractorModel.ts
Normal file
44
src/Structures/ExtractorModel.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { ExtractorModelData } from "../types/types";
|
||||
|
||||
class ExtractorModel {
|
||||
name: string;
|
||||
private _raw: any;
|
||||
|
||||
constructor(extractorName: string, data: any) {
|
||||
this.name = extractorName;
|
||||
|
||||
Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
|
||||
}
|
||||
|
||||
async handle(query: string) {
|
||||
const data = await this._raw.getInfo(query);
|
||||
if (!data) return null;
|
||||
|
||||
return {
|
||||
title: data.title,
|
||||
duration: data.duration,
|
||||
thumbnail: data.thumbnail,
|
||||
engine: data.engine,
|
||||
views: data.views,
|
||||
author: data.author,
|
||||
description: data.description,
|
||||
url: data.url
|
||||
} as ExtractorModelData;
|
||||
}
|
||||
|
||||
validate(query: string) {
|
||||
return Boolean(this._raw.validate(query));
|
||||
}
|
||||
|
||||
get version() {
|
||||
return this._raw.version ?? "0.0.0";
|
||||
}
|
||||
|
||||
get important() {
|
||||
return Boolean(this._raw.important);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractorModel;
|
||||
export { ExtractorModel };
|
|
@ -1,5 +1,6 @@
|
|||
import { downloadOptions } from 'ytdl-core';
|
||||
import { User } from 'discord.js';
|
||||
import { Readable, Duplex } from "stream";
|
||||
|
||||
export interface PlayerOptions {
|
||||
leaveOnEnd?: boolean;
|
||||
|
@ -75,3 +76,15 @@ export type QueryType =
|
|||
| 'reverbnation'
|
||||
| 'attachment'
|
||||
| 'youtube_search';
|
||||
|
||||
export interface ExtractorModelData {
|
||||
title: string;
|
||||
duration: number;
|
||||
thumbnail: string;
|
||||
engine: string | Readable | Duplex;
|
||||
views: number;
|
||||
author: string;
|
||||
description: string;
|
||||
url: string;
|
||||
version?: string;
|
||||
}
|
Loading…
Reference in a new issue