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 { PlayerErrorEventCodes, PlayerEvents } from './utils/Constants';
|
||||||
import PlayerError from './utils/PlayerError';
|
import PlayerError from './utils/PlayerError';
|
||||||
import ytdl from 'discord-ytdl-core';
|
import ytdl from 'discord-ytdl-core';
|
||||||
|
import { ExtractorModel } from "./Structures/ExtractorModel";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import spotify from 'spotify-url-info';
|
import spotify from 'spotify-url-info';
|
||||||
|
@ -24,6 +25,7 @@ export class Player extends EventEmitter {
|
||||||
public queues: Collection<Snowflake, Queue>;
|
public queues: Collection<Snowflake, Queue>;
|
||||||
private _resultsCollectors: Collection<string, Collector<Snowflake, Message>>;
|
private _resultsCollectors: Collection<string, Collector<Snowflake, Message>>;
|
||||||
private _cooldownsTimeout: Collection<string, NodeJS.Timeout>;
|
private _cooldownsTimeout: Collection<string, NodeJS.Timeout>;
|
||||||
|
public Extractors = new Collection<string, ExtractorModel>();
|
||||||
|
|
||||||
constructor(client: Client, options?: PlayerOptions) {
|
constructor(client: Client, options?: PlayerOptions) {
|
||||||
super();
|
super();
|
||||||
|
@ -62,6 +64,35 @@ export class Player extends EventEmitter {
|
||||||
return AudioFilters;
|
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> {
|
private _searchTracks(message: Message, query: string, firstResult?: boolean): Promise<Track> {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
let tracks: Track[] = [];
|
let tracks: Track[] = [];
|
||||||
|
@ -83,7 +114,7 @@ export class Player extends EventEmitter {
|
||||||
requestedBy: message.author,
|
requestedBy: message.author,
|
||||||
fromPlaylist: false,
|
fromPlaylist: false,
|
||||||
source: 'soundcloud',
|
source: 'soundcloud',
|
||||||
engine: data
|
engine: data.engine
|
||||||
});
|
});
|
||||||
|
|
||||||
tracks.push(track);
|
tracks.push(track);
|
||||||
|
@ -342,7 +373,31 @@ export class Player extends EventEmitter {
|
||||||
source: 'youtube'
|
source: 'youtube'
|
||||||
});
|
});
|
||||||
} else {
|
} 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 { downloadOptions } from 'ytdl-core';
|
||||||
import { User } from 'discord.js';
|
import { User } from 'discord.js';
|
||||||
|
import { Readable, Duplex } from "stream";
|
||||||
|
|
||||||
export interface PlayerOptions {
|
export interface PlayerOptions {
|
||||||
leaveOnEnd?: boolean;
|
leaveOnEnd?: boolean;
|
||||||
|
@ -75,3 +76,15 @@ export type QueryType =
|
||||||
| 'reverbnation'
|
| 'reverbnation'
|
||||||
| 'attachment'
|
| 'attachment'
|
||||||
| 'youtube_search';
|
| '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