Skip to content

Commit

Permalink
feat: add fallback stream routing
Browse files Browse the repository at this point in the history
  • Loading branch information
twlite committed Aug 24, 2024
1 parent fce7253 commit 19e9628
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 54 deletions.
10 changes: 5 additions & 5 deletions apps/eris-bot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ const client = Eris(process.env.DISCORD_TOKEN!, {

const player = new Player(createErisCompat(client));

player.extractors.loadDefault((ext) => ext !== 'YouTubeExtractor');

player.on('debug', console.log).events.on('debug', (queue, msg) => console.log(`[${queue.guild.name}] ${msg}`));

player.extractors.loadDefault();

client.once('ready', () => {
console.log('Ready!');
console.log(player.scanDeps());
Expand All @@ -21,13 +21,13 @@ client.once('ready', () => {
player.events.on('playerStart', async (queue, track) => {
const meta = queue.metadata as { channel: string };

await client.createMessage(meta.channel, `Now playing: ${track.title}`);
await client.createMessage(meta.channel, `Now playing: ${track.title} (Extractor: \`${track.extractor?.identifier}\`/Bridge: \`${track.bridgedExtractor?.identifier}\`)`);
});

player.events.on('playerFinish', async (queue, track) => {
const meta = queue.metadata as { channel: string };

await client.createMessage(meta.channel, `Finished track: ${track.title}`);
await client.createMessage(meta.channel, `Finished track: ${track.title} (Extractor: \`${track.extractor?.identifier}\`)/Bridge: \`${track.bridgedExtractor?.identifier}\`)`);
});

client.on('messageCreate', async (message) => {
Expand All @@ -54,7 +54,7 @@ client.on('messageCreate', async (message) => {
}
});

return client.createMessage(message.channel.id, `Loaded: ${track.title}`);
return client.createMessage(message.channel.id, `Loaded: ${track.title} (Extractor: \`${track.extractor?.identifier}\`)/Bridge: \`${track.bridgedExtractor?.identifier}\`)`);
}
case 'pause': {
const queue = player.queues.get(message.guildID);
Expand Down
12 changes: 6 additions & 6 deletions packages/discord-player/__test__/Player.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ describe('Player', () => {
expect(response).toBeInstanceOf(SearchResult);
});

test("should set process.env.FFMPEG_PATH to given path", () => {
test('should set process.env.FFMPEG_PATH to given path', () => {
// not actual ffmpeg path. just dummy
new Player(client, {
ffmpegPath: "./packages/ffmpeg",
ffmpegPath: './packages/ffmpeg',
ignoreInstance: true
})
expect(process.env.FFMPEG_PATH).toBe("./packages/ffmpeg")
})
});

expect(process.env.FFMPEG_PATH).toBe('./packages/ffmpeg');
});
});
10 changes: 5 additions & 5 deletions packages/discord-player/__test__/QueryResolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ describe('QueryResolver', () => {
expect(qr.resolve(query).type).toBe(QueryType.VIMEO);
});

it("should be soundcloud", async () => {
const query = "https://on.soundcloud.com/YVLyjzk2mmp5TJF99"
const rediected = await qr.preResolve(query)
expect(rediected).toMatch(qr.regex.soundcloudTrackRegex)
})
it('should be soundcloud', async () => {
const query = 'https://on.soundcloud.com/YVLyjzk2mmp5TJF99';
const rediected = await qr.preResolve(query);
expect(rediected).toMatch(qr.regex.soundcloudTrackRegex);
});

it('should be soundcloudTrack', () => {
const query = 'https://soundcloud.com/rick-astley-official/never-gonna-give-you-up-4';
Expand Down
2 changes: 1 addition & 1 deletion packages/discord-player/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "discord-player",
"version": "6.8.0-dev.0",
"version": "6.8.0-dev.1",
"description": "Complete framework to facilitate music commands using discord.js",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
18 changes: 12 additions & 6 deletions packages/discord-player/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,35 @@ const DiscordPlayerErrors = {
name: 'ERR_SERIALIZATION_FAILED',
type: Error,
createError() {
return `[${this.constructor.name}]` + "Don't know how to serialize this data";
return `[${this.type.name}]` + "Don't know how to serialize this data";
}
},
ERR_DESERIALIZATION_FAILED: {
name: 'ERR_DESERIALIZATION_FAILED',
type: Error,
createError() {
return `[${this.constructor.name}]` + "Don't know how to deserialize this data";
return `[${this.type.name}]` + "Don't know how to deserialize this data";
}
},
ERR_ILLEGAL_HOOK_INVOCATION: {
name: 'ERR_ILLEGAL_HOOK_INVOCATION',
type: Error,
createError(target: string, message?: string) {
return `[${this.constructor.name}]` + `Illegal invocation of ${target} hook.${message ? ` ${message}` : ''}`;
return `[${this.type.name}]` + `Illegal invocation of ${target} hook.${message ? ` ${message}` : ''}`;
}
},
ERR_NOT_EXISTING_MODULE: {
name: 'ERR_NOT_EXISTING_MODULE',
type: Error,
createError(target: string, description = '') {
return `[${this.constructor.name}]` + `${target} module does not exist. Install it with \`npm install ${target}\`.${description ? ' ' + description : ''}`;
return `[${this.type.name}]` + `${target} module does not exist. Install it with \`npm install ${target}\`.${description ? ' ' + description : ''}`;
}
},
ERR_BRIDGE_FAILED: {
name: 'ERR_BRIDGE_FAILED',
type: Error,
createError(id: string | null, error: string) {
return `[${this.type.name}]` + `${id ? `(Extractor Execution Context ID is ${id})` : ''}Failed to bridge this query:\n${error}`;
}
}
} as const;
Expand All @@ -160,8 +167,7 @@ const handler: ProxyHandler<typeof target> = {
return (...args: Parameters<(typeof err)['createError']>) => {
// @ts-expect-error
const exception = new err.type(err.createError(...args));
const originalName = exception.name;
exception.name = `${err.name} [${originalName}]`;
exception.name = err.name;

return exception;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Util } from '../utils/Util';
import { PlayerEventsEmitter } from '../utils/PlayerEventsEmitter';
import { TypeUtil } from '../utils/TypeUtil';
import { Track } from '../fabric';
import { createContext } from '../hooks';
import { Exceptions } from '../errors';

// prettier-ignore
const knownExtractorKeys = [
Expand All @@ -23,6 +25,12 @@ export type ExtractorLoaderOptionDict = {
[K in (typeof knownExtractorKeys)[number]]?: ConstructorParameters<typeof import('@discord-player/extractor')[K]>[1];
};

export interface ExtractorSession {
id: string;
attemptedExtractors: Set<string>;
bridgeAttemptedExtractors: Set<string>;
}

export interface ExtractorExecutionEvents {
/**
* Emitted when a extractor is registered
Expand Down Expand Up @@ -62,10 +70,26 @@ export class ExtractorExecutionContext extends PlayerEventsEmitter<ExtractorExec
*/
public store = new Collection<string, BaseExtractor>();

public readonly context = createContext<ExtractorSession>();

public constructor(public player: Player) {
super(['error']);
}

/**
* Get the current execution id
*/
public getExecutionId(): string | null {
return this.context.consume()?.id ?? null;
}

/**
* Get the current execution context
*/
public getContext() {
return this.context.consume() ?? null;
}

/**
* Load default extractors from `@discord-player/extractor`
*/
Expand Down Expand Up @@ -228,12 +252,26 @@ export class ExtractorExecutionContext extends PlayerEventsEmitter<ExtractorExec
* @param sourceExtractor The source extractor of the track
*/
public async requestBridge(track: Track, sourceExtractor: BaseExtractor | null = track.extractor) {
return this.run<ExtractorStreamable>(async (ext) => {
const previouslyAttempted = this.getContext()?.bridgeAttemptedExtractors ?? new Set<string>();

const result = await this.run<ExtractorStreamable>(async (ext) => {
if (sourceExtractor && ext.identifier === sourceExtractor.identifier) return false;
if (previouslyAttempted.has(ext.identifier)) return false;

previouslyAttempted.add(ext.identifier);

const result = await ext.bridge(track, sourceExtractor);

if (!result) return false;

return result;
});

if (!result?.result) throw Exceptions.ERR_BRIDGE_FAILED(this.getExecutionId(), result?.error?.stack || result?.error?.message || 'No extractors available to bridge');

track.bridgedExtractor = result.extractor;

return result;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/discord-player/src/fabric/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ export class Track<T = unknown> {
public requestedBy: User | null = null;
public playlist?: Playlist;
public queryType: SearchQueryType | null | undefined = null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public raw: any;
public extractor: BaseExtractor | null = null;
public readonly id = SnowflakeUtil.generate().toString();
private __metadata: T | null = null;
private __reqMetadataFn: () => Promise<T | null>;
public cleanTitle: string;
public live: boolean = false;
public bridgedExtractor: BaseExtractor | null = null;
public bridgedTrack: Track | null = null;

/**
* Track constructor
Expand Down
6 changes: 5 additions & 1 deletion packages/discord-player/src/queue/GuildNodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface GuildNodeCreateOptions<T = unknown> {
disableFilterer?: boolean;
disableBiquad?: boolean;
disableResampler?: boolean;
disableFallbackStream?: boolean;
}

export type NodeResolvable = GuildQueue | GuildResolvable;
Expand Down Expand Up @@ -87,6 +88,7 @@ export class GuildNodeManager<Meta = unknown> {
options.disableFilterer ??= false;
options.disableVolume ??= false;
options.disableResampler ??= true;
options.disableFallbackStream ??= false;

if (getGlobalRegistry().has('@[onBeforeCreateStream]') && !options.onBeforeCreateStream) {
options.onBeforeCreateStream = getGlobalRegistry().get('@[onBeforeCreateStream]') as OnBeforeCreateStreamHandler;
Expand Down Expand Up @@ -128,7 +130,8 @@ export class GuildNodeManager<Meta = unknown> {
disableEqualizer: options.disableEqualizer,
disableFilterer: options.disableFilterer,
disableResampler: options.disableResampler,
disableVolume: options.disableVolume
disableVolume: options.disableVolume,
disableFallbackStream: options.disableFallbackStream
});

this.cache.set(server.id, queue);
Expand Down Expand Up @@ -168,6 +171,7 @@ export class GuildNodeManager<Meta = unknown> {

queue.setTransitioning(true);
queue.node.stop(true);
// @ts-ignore
queue.connection?.removeAllListeners();
queue.dispatcher?.removeAllListeners();
queue.dispatcher?.disconnect();
Expand Down
1 change: 1 addition & 0 deletions packages/discord-player/src/queue/GuildQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface GuildNodeInit<Meta = unknown> {
disableFilterer: boolean;
disableBiquad: boolean;
disableResampler: boolean;
disableFallbackStream: boolean;
}

export interface VoiceConnectConfig {
Expand Down
Loading

0 comments on commit 19e9628

Please sign in to comment.