Skip to content

Instantly share code, notes, and snippets.

@Sans3108
Last active May 3, 2023 11:57
Show Gist options
  • Save Sans3108/80950adef9d5970bf2bceac7cd850619 to your computer and use it in GitHub Desktop.
Save Sans3108/80950adef9d5970bf2bceac7cd850619 to your computer and use it in GitHub Desktop.
import { BaseExtractor, ExtractorInfo, ExtractorSearchContext, Playlist, QueryType, SearchQueryType, Track, Util } from 'discord-player';
import SoundCloud from 'soundcloud.ts';
//@ts-ignore Idk why but it doesnt work if I just do `new SoundCloud()`
const soundcloud: SoundCloud = new SoundCloud.default();
export class SoundCloudExtractor extends BaseExtractor {
public static identifier = 'apiBasedSoundCloudExtractor' as const;
public async validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean> {
if (typeof query !== 'string') return false;
// prettier-ignore
const queryTypes = [
QueryType.SOUNDCLOUD,
QueryType.SOUNDCLOUD_PLAYLIST,
QueryType.SOUNDCLOUD_SEARCH,
QueryType.SOUNDCLOUD_TRACK,
QueryType.AUTO,
QueryType.AUTO_SEARCH
] as SearchQueryType[];
return queryTypes.some(r => r === type);
}
public async handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo> {
switch (context.type) {
case QueryType.SOUNDCLOUD_TRACK: {
const trackInfo = await soundcloud.tracks.getV2(query).catch(Util.noop);
if (!trackInfo) return this.emptyResponse();
const track = new Track(this.context.player, {
title: trackInfo.title,
url: trackInfo.permalink_url,
duration: Util.buildTimeCode(Util.parseMS(trackInfo.duration)),
description: trackInfo.description ?? '',
thumbnail: trackInfo.artwork_url,
views: trackInfo.playback_count,
author: trackInfo.user.username,
requestedBy: context.requestedBy,
source: 'soundcloud',
engine: trackInfo,
queryType: context.type
});
track.extractor = this;
return { playlist: null, tracks: [track] };
}
case QueryType.SOUNDCLOUD_PLAYLIST: {
const data = await soundcloud.playlists.getV2(query).catch(Util.noop);
if (!data) return { playlist: null, tracks: [] };
const res = new Playlist(this.context.player, {
title: data.title,
description: data.description ?? '',
thumbnail: data.artwork_url ?? data.tracks[0].artwork_url,
type: 'playlist',
source: 'soundcloud',
author: {
name: data.user.username,
url: data.user.permalink_url
},
tracks: [],
id: `${data.id}`,
url: data.permalink_url,
rawPlaylist: data
});
for (const song of data.tracks) {
const track = new Track(this.context.player, {
title: song.title,
description: song.description ?? '',
author: song.user.username,
url: song.permalink_url,
thumbnail: song.artwork_url,
duration: Util.buildTimeCode(Util.parseMS(song.duration)),
views: song.playback_count,
requestedBy: context.requestedBy,
playlist: res,
source: 'soundcloud',
engine: song,
queryType: context.type
});
track.extractor = this;
res.tracks.push(track);
}
return { playlist: res, tracks: res.tracks };
}
default: {
const tracks = await soundcloud.tracks.searchV2({ q: query }).catch(Util.noop);
if (!tracks || !tracks.collection.length) return this.emptyResponse();
const resolvedTracks: Track[] = [];
for (const searchedTrack of tracks.collection) {
const trackInfo = await soundcloud.tracks.getV2(searchedTrack.permalink_url).catch(Util.noop);
if (!trackInfo) continue;
const track = new Track(this.context.player, {
title: trackInfo.title,
url: trackInfo.permalink_url,
duration: Util.buildTimeCode(Util.parseMS(trackInfo.duration)),
description: trackInfo.description ?? '',
thumbnail: trackInfo.artwork_url,
views: trackInfo.playback_count,
author: trackInfo.user.username,
requestedBy: context.requestedBy,
source: 'soundcloud',
engine: trackInfo,
queryType: 'soundcloudTrack'
});
track.extractor = this;
resolvedTracks.push(track);
}
return { playlist: null, tracks: resolvedTracks };
}
}
}
public async getRelatedTracks(track: Track) {
if (track.queryType === QueryType.SOUNDCLOUD_TRACK)
return this.handle(track.author || track.title, {
requestedBy: track.requestedBy,
type: QueryType.SOUNDCLOUD_SEARCH
});
return this.createResponse();
}
public emptyResponse(): ExtractorInfo {
return { playlist: null, tracks: [] };
}
public async stream(info: Track) {
const url = await soundcloud.util.streamLink(info.url).catch(Util.noop);
if (!url) throw new Error('Could not extract stream from this track source');
return url;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment