Skip to content

Commit

Permalink
fix: Replace youtube-sr with youtubei. (#463)
Browse files Browse the repository at this point in the history
  • Loading branch information
vxern authored Nov 24, 2024
2 parents 18d2537 + 616612f commit d4f11b0
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 49 deletions.
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"shoukaku": "^4.1.1",
"tinyld": "^1.3.4",
"wiktionary-scraper": "^0.0.2-patch.1",
"youtube-sr": "^4.3.11"
"youtubei": "^1.6.7"
},
"devDependencies": {
"@biomejs/biome": "1.8.3",
Expand Down
2 changes: 1 addition & 1 deletion source/constants/licences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ You must also include, in your app or site, wherever you provide attributions or
shoukaku: mit("Copyright (c) 2023 Deivu (Saya)"),
tinyld: mit("Copyright (c) 2021 Komodo"),
"wiktionary-scraper": mit('Copyright (c) 2023 Dorian "vxern" Oszczęda'),
"youtube-sr": mit("Copyright (c) 2020 DevAndromeda"),
youtubei: mit("Copyright (c) 2020 Vincent Jonathan"),
},
} as const);
type LicensedDictionary = keyof (typeof licences)["dictionaries"];
Expand Down
2 changes: 2 additions & 0 deletions source/constants/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ export default Object.freeze({
wordnikDefinitionLink: (lemma: string) => `https://wordnik.com/words/${lemma}`,
wordsAPIDefinition: () => "https://wordsapi.com",
dicolinkDefinition: (lemma: string) => `https://dicolink.com/mots/${encodeURIComponent(lemma)}`,
youtubeVideo: (id: string) => `https://www.youtube.com/watch?v=${id}`,
youtubePlaylist: (id: string) => `https://www.youtube.com/watch?list=${id}`,
} as const satisfies Record<string, (...args: string[]) => string>);
97 changes: 50 additions & 47 deletions source/library/commands/resolvers/youtube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { trim } from "logos:constants/formatting";
import type { Client } from "logos/client";
import { InteractionCollector } from "logos/collectors";
import { Song, SongCollection, SongListing } from "logos/services/music";
import * as YouTubeSearch from "youtube-sr";
import * as youtubei from "youtubei";

const youtube = new youtubei.Client();

async function resolveYouTubeSongListings(
client: Client,
Expand All @@ -13,26 +15,30 @@ async function resolveYouTubeSongListings(
return search(client, interaction, query);
}

if (query.includes("list=")) {
const playlist = await YouTubeSearch.YouTube.getPlaylist(query);
if (playlist == null) {
const result = await youtube.findOne(query);
if (result === undefined) {
return undefined;
}

if (result instanceof youtubei.VideoCompact) {
return getSongListingFromVideo(result, interaction.user.id);
}

if (result instanceof youtubei.PlaylistCompact) {
const playlist = await youtube.getPlaylist(result.id);
if (playlist === undefined) {
return undefined;
}

return getSongListingFromPlaylist(playlist, interaction.user.id);
}

const video = await YouTubeSearch.YouTube.getVideo(query);
if (video === null) {
return undefined;
}

return getSongListingFromVideo(video, interaction.user.id);
return undefined;
}

async function search(client: Client, interaction: Logos.Interaction, query: string): Promise<SongListing | undefined> {
const resultsAll = await YouTubeSearch.YouTube.search(query, { limit: 20, type: "all", safeSearch: false });
const results = resultsAll.filter((element) => isPlaylist(element) || isVideo(element));
const resultsAll = await youtube.search(query, { limit: 20, type: "all", safeSearch: false });
const results = resultsAll.items.filter((element) => isPlaylist(element) || isVideo(element));
if (results.length === 0) {
return undefined;
}
Expand Down Expand Up @@ -60,13 +66,8 @@ async function search(client: Client, interaction: Logos.Interaction, query: str
}

if (isPlaylist(result)) {
const url = result.url;
if (url === undefined) {
return resolve(undefined);
}

const playlist = await YouTubeSearch.YouTube.getPlaylist(url);
if (playlist === null) {
const playlist = await youtube.getPlaylist(result.id);
if (playlist === undefined) {
return resolve(undefined);
}

Expand All @@ -81,7 +82,7 @@ async function search(client: Client, interaction: Logos.Interaction, query: str
await client.registerInteractionCollector(selectMenuSelection);

const options: Discord.SelectOption[] = [];
for (const [result, index] of results.map<[YouTubeSearch.Playlist | YouTubeSearch.Video, number]>(
for (const [result, index] of results.map<[youtubei.PlaylistCompact | youtubei.VideoCompact, number]>(
(result, index) => [result, index],
)) {
const title = result.title;
Expand Down Expand Up @@ -125,48 +126,50 @@ async function search(client: Client, interaction: Logos.Interaction, query: str
return promise;
}

type Result = YouTubeSearch.Playlist | YouTubeSearch.Video | YouTubeSearch.Channel;
type Result = youtubei.PlaylistCompact | youtubei.VideoCompact | youtubei.BaseChannel;

function isPlaylist(result: Result): result is YouTubeSearch.Playlist {
return result.type === "playlist";
function isPlaylist(result: Result): result is youtubei.PlaylistCompact {
return result instanceof youtubei.Playlist;
}

function isVideo(result: Result): result is YouTubeSearch.Video {
return result.type === "video";
function isVideo(result: Result): result is youtubei.VideoCompact {
return result instanceof youtubei.VideoCompact;
}

function getSongListingFromPlaylist(playlist: YouTubeSearch.Playlist, requestedBy: bigint): SongListing | undefined {
if (playlist.id === undefined) {
return undefined;
}

const { title } = playlist;
if (title === undefined) {
return undefined;
function getSongListingFromPlaylist(
playlist: youtubei.Playlist | youtubei.MixPlaylist,
requestedBy: bigint,
): SongListing | undefined {
let videos: youtubei.VideoCompact[];
if (playlist instanceof youtubei.Playlist) {
videos = playlist.videos.items;
} else {
videos = playlist.videos;
}

const songs: Song[] = [];
for (const video of playlist.videos) {
const { title, url } = video;
if (title === undefined || url === undefined) {
continue;
}

songs.push(new Song({ title, url }));
for (const video of videos) {
songs.push(new Song({ title: video.title, url: constants.links.youtubeVideo(video.id) }));
}

return new SongListing({
queueable: new SongCollection({ title, url: playlist.url!, songs }),
queueable: new SongCollection({
title: playlist.title,
url: constants.links.youtubePlaylist(playlist.id),
songs,
}),
userId: requestedBy,
});
}

function getSongListingFromVideo(video: YouTubeSearch.Video, requestedBy: bigint): SongListing | undefined {
if (video.id === undefined) {
return undefined;
}

return new SongListing({ queueable: new Song({ title: video.title!, url: video.url }), userId: requestedBy });
function getSongListingFromVideo(
video: youtubei.VideoCompact | youtubei.Video | youtubei.LiveVideo,
requestedBy: bigint,
): SongListing | undefined {
return new SongListing({
queueable: new Song({ title: video.title, url: constants.links.youtubeVideo(video.id) }),
userId: requestedBy,
});
}

export { resolveYouTubeSongListings as resolveYouTubeListings };

0 comments on commit d4f11b0

Please sign in to comment.