Skip to content

Commit

Permalink
refactor: remove SearchType in favor of TrackSource
Browse files Browse the repository at this point in the history
BREAKING CHANGE: remove `SearchType` in favor of `TrackSource`
  • Loading branch information
larsrickert committed May 23, 2022
1 parent 159477d commit 32cb323
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 100 deletions.
4 changes: 4 additions & 0 deletions src/engines/file.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { StreamType } from "@discordjs/voice";
import { PlayerEngine } from "../types/engines";

/**
* Player engine to search/stream tracks that are stored in the file system.
* Search is currently not supported.
*/
export const fileEngine: PlayerEngine = {
search: async () => {
return [];
Expand Down
59 changes: 5 additions & 54 deletions src/engines/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
PlayerEngine,
SearchType,
SearchTypeInfo,
TrackSource,
} from "../types/engines";
import { PlayerEngine, TrackSource } from "../types/engines";
import { fileEngine } from "./file";
import { spotifyEngine } from "./spotify";
import { youtubeEngine } from "./youtube";
Expand All @@ -14,55 +9,11 @@ export const playerEngines: Record<TrackSource, PlayerEngine> = {
spotify: spotifyEngine,
};

const searchTypeInfos: Record<
Exclude<SearchType, SearchType.AUTO>,
SearchTypeInfo
> = {
[SearchType.YOUTUBE_TRACKS]: {
type: SearchType.YOUTUBE_TRACKS,
isPlaylist: false,
source: "youtube",
},
[SearchType.YOUTUBE_PLAYLIST]: {
type: SearchType.SPOTIFY_PLAYLIST,
isPlaylist: true,
source: "spotify",
},
[SearchType.SPOTIFY_TRACKS]: {
type: SearchType.SPOTIFY_TRACKS,
isPlaylist: false,
source: "spotify",
},
[SearchType.SPOTIFY_PLAYLIST]: {
type: SearchType.SPOTIFY_PLAYLIST,
isPlaylist: true,
source: "spotify",
},
};

export function getSearchTypeInfo(
query: string,
searchType?: SearchType
): SearchTypeInfo {
if (searchType == null || searchType === SearchType.AUTO) {
searchType = detectSearchType(query);
}

return searchTypeInfos[searchType];
}

/**
* Automatically detect the query type
*/
function detectSearchType(query: string): Exclude<SearchType, SearchType.AUTO> {
if (query.startsWith("https://open.spotify.com/track")) {
return SearchType.SPOTIFY_TRACKS;
}
if (query.startsWith("https://open.spotify.com/playlist")) {
return SearchType.SPOTIFY_PLAYLIST;
}
if (query.startsWith("https://www.youtube.com") && query.includes("list=")) {
return SearchType.YOUTUBE_PLAYLIST;
}
return SearchType.YOUTUBE_TRACKS;
export function detectTrackSource(query: string): TrackSource {
if (!query.startsWith("https://")) return "file";
if (query.startsWith("https://open.spotify.com/")) return "spotify";
return "youtube";
}
26 changes: 14 additions & 12 deletions src/engines/spotify.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import { getTracks, Tracks } from "spotify-url-info";
import { PlayerEngine, SearchResult, Track } from "../types/engines";
import { PlayerEngine, Track } from "../types/engines";
import { youtubeEngine } from "./youtube";

/**
* Player engine to search/stream tracks from Spotify.
* Spotify does not provide a web api to stream tracks so the track will be streamed from YouTube instead.
*/
export const spotifyEngine: PlayerEngine = {
search: async (query, isPlaylist) => {
const results: SearchResult[] = [];

search: async (query, options) => {
// TODO: check how to get playlist info
const tracks = await getTracks(query);

results.push({
tracks: tracks.map((track) => mapSpotifyTrack(track)),
source: "spotify",
});

return results;
return [
{
tracks: tracks.map((track) => mapSpotifyTrack(track)),
source: "spotify",
},
];
},
getStream: async (track, playerOptions, streamOptions) => {
// TODO: add limit 1
const searchResults = await youtubeEngine.search(
`${track.title} ${track.artist}`
`${track.title} ${track.artist}`,
{ limit: 1 }
);

if (!searchResults.length || !searchResults[0].tracks.length) return null;
Expand Down
29 changes: 18 additions & 11 deletions src/engines/youtube.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import playdl, { YouTubeVideo } from "play-dl";
import { PlayerEngine, Playlist, SearchResult, Track } from "../types/engines";

/**
* Player engine to search/stream tracks from YouTube.
*/
export const youtubeEngine: PlayerEngine = {
search: async (query, isPlaylist) => {
const results: SearchResult[] = [];
search: async (query, options) => {
const isPlaylist =
query.startsWith("https://www.youtube.com/watch") &&
query.includes("list=");

if (isPlaylist) {
return await searchPlaylist(query);
} else {
const videos = await playdl.search(query, {
source: { youtube: "video" },
});
results.push({
tracks: videos.map((video) => mapYouTubeVideo(video)),
source: "youtube",
});
}

return results;
const videos = await playdl.search(query, {
source: { youtube: "video" },
limit: options?.limit,
});

return [
{
tracks: videos.map((video) => mapYouTubeVideo(video)),
source: "youtube",
},
];
},
getStream: async (track, playerOptions, streamOptions) => {
return await playdl.stream(track.url, {
Expand Down
8 changes: 4 additions & 4 deletions src/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "@discordjs/voice";
import { VoiceBasedChannel } from "discord.js";
import { TypedEmitter } from "tiny-typed-emitter";
import { getSearchTypeInfo, playerEngines } from "./engines";
import { detectTrackSource, playerEngines } from "./engines";
import { SearchOptions, SearchResult, Track } from "./types/engines";
import {
AudioPlayerMetadata,
Expand Down Expand Up @@ -284,9 +284,9 @@ export class Player extends TypedEmitter<PlayerEvents> {
if (customResult) return customResult;
}

const searchTypeInfo = getSearchTypeInfo(query, options?.type);
const playerEngine = playerEngines[searchTypeInfo.source];
return await playerEngine.search(query, searchTypeInfo.isPlaylist);
const trackSource = detectTrackSource(query);
const playerEngine = playerEngines[trackSource];
return await playerEngine.search(query, options);
}

/**
Expand Down
24 changes: 5 additions & 19 deletions src/types/engines.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PlayerOptions, StreamOptions, TrackStream } from "./player";

export interface PlayerEngine {
search(query: string, isPlaylist?: boolean): Promise<SearchResult[]>;
search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
getStream(
track: Track,
playerOptions: PlayerOptions,
Expand All @@ -11,11 +11,11 @@ export interface PlayerEngine {

export interface SearchOptions {
/**
* The search mode to be used for searching tracks.
*
* @default `SearchType.AUTO`
* The source where tracks should be searched. If not provided, will automatically detect the source or fall back to YouTube.
*/
type?: SearchType;
source?: TrackSource;
/** Limit number of tracks to search. */
limit?: number;
}

export interface SearchResult {
Expand Down Expand Up @@ -43,17 +43,3 @@ export interface Playlist {
}

export type TrackSource = "file" | "youtube" | "spotify";

export enum SearchType {
AUTO,
YOUTUBE_TRACKS,
YOUTUBE_PLAYLIST,
SPOTIFY_TRACKS,
SPOTIFY_PLAYLIST,
}

export interface SearchTypeInfo {
type: Exclude<SearchType, SearchType.AUTO>;
isPlaylist: boolean;
source: TrackSource;
}

0 comments on commit 32cb323

Please sign in to comment.