[READ-ONLY] Mirror of https://github.com/flo-bit/youtube-party-dj. democratic youtube player, everyone can vote and add songs, uni project, made with uix
2.7 kB
86 lines
1import { Innertube } from "https://deno.land/x/youtubei@v10.0.0-deno/deno.ts";
2import uniqBy from 'https://cdn.skypack.dev/lodash/uniqBy';
3import shuffle from 'https://cdn.skypack.dev/lodash/shuffle';
4import take from 'https://cdn.skypack.dev/lodash/take';
5
6const youtube = await Innertube.create();
7
8export async function search(q: string) {
9 try {
10
11 const result = await youtube.search(q, {type: 'video', sort_by: 'relevance'})
12
13 // filter out videos without duration (live?), then get first 10 videos
14 // @ts-ignore - no type for duration
15 const videos = result.videos.filter((item) => item.duration?.seconds).slice(0, 10);
16
17 return videos.map(item => normalizeVideo(item));
18 } catch (error) {
19 console.error(error);
20 return [];
21 }
22}
23
24const normalizeVideo = (video: any) => {
25 console.log(video);
26 return {
27 title: video.title.text ?? 'Untitled',
28 // @ts-ignore - no type for thumbnails
29 thumbnail: video.thumbnails?.[0].url,
30 // @ts-ignore - no type for id
31 id: video.id,
32 likes: new Set<string>(),
33 added: Date.now(),
34 // @ts-ignore - no type for duration
35 duration: video.duration?.text ?? '-',
36 }
37}
38
39async function getRelatedVideos(videoId: string) {
40 try {
41 const videoDetails = await youtube.getInfo(videoId);
42 const related = videoDetails.watch_next_feed.map(related => normalizeVideo(related));
43 return related;
44 } catch (error) {
45 console.error("Error fetching related videos:", error);
46 throw error;
47 }
48}
49
50export async function getRecommendations(queue: { id: string }[], maxRecommendations = 5) {
51 let allRecommendations: string[] = [];
52
53 for (const video of queue) {
54 try {
55 const relatedVideos = await getRelatedVideos(video.id);
56 allRecommendations.push(...relatedVideos.slice(0, maxRecommendations));
57 } catch (error) {
58 console.error(`Error processing video ID ${video.id}:`, error);
59 }
60 }
61
62 // filter out duplicates that are in queue
63 const newRecommendations = allRecommendations.filter((video) => !queue.some((item) => item.id === video.id));
64
65 const uniqueRecommendations = uniqBy(newRecommendations, 'id');
66
67 const shuffledRecommendations = shuffle(uniqueRecommendations);
68
69 const finalRecommendations = take(shuffledRecommendations, maxRecommendations);
70
71 console.log("FINDAL RECOMMENDATIONS", finalRecommendations);
72 return finalRecommendations;
73}
74
75export async function updateRecommendations(session: any, code: string) {
76 const recommendations = await getRecommendations(session.queue);
77
78 recommendations.forEach(() => {
79 session?.recommendedQueue.pop()
80 })
81 recommendations.forEach((video) => {
82 session?.recommendedQueue.push(video)
83 })
84
85 return session;
86}