Spaces:
Sleeping
Sleeping
| import YTMusic from "ytmusic-api" | |
| import ystream from 'yt-stream' | |
| import fs from 'fs' | |
| import process from 'process' | |
| import express, { Request, Response } from 'express' | |
| const ytmusic = new YTMusic() | |
| ytmusic.initialize() | |
| const app = express() | |
| const PORT = process.env.PORT || 7860 | |
| interface SongType { | |
| type: "SONG"; | |
| name: string; | |
| videoId: string; | |
| artist: { | |
| artistId: string | null; | |
| name: string; | |
| }; | |
| album: { | |
| name: string; | |
| albumId: string; | |
| } | null; | |
| duration: number | null; | |
| thumbnails: { | |
| url: string; | |
| width: number; | |
| height: number; | |
| }[]; | |
| } | |
| interface VideoType { | |
| type: "VIDEO"; | |
| name: string; | |
| videoId: string; | |
| artist: { | |
| artistId: string | null; | |
| name: string; | |
| }; | |
| duration: number | null; | |
| thumbnails: { | |
| url: string; | |
| width: number; | |
| height: number; | |
| }[]; | |
| } | |
| type MusicType = SongType | |
| function bestMatch(query: MusicType[], targetName: string, duration?: number) { | |
| // Helper function to calculate a match score | |
| const calculateScore = (song: MusicType) => { | |
| let score = 0; | |
| // Prioritize exact name match | |
| if (song.name === targetName) score += 50; | |
| else if (song.name.includes(targetName)) score += 20; | |
| // Bonus for artist or album relevance | |
| if (song.artist.name === "Phong Max") score += 20; | |
| if(song.artist.name.includes("Phong Max")) score += 10; | |
| if(song.album) { | |
| score += 5 | |
| if(song.album.name.includes(targetName)) score += 10; | |
| } | |
| if(duration) { | |
| // Duration proximity (ideal around 200-250 seconds) | |
| const idealDuration = 211; | |
| if(song.duration === null) return 0 | |
| score -= Math.abs(song.duration - idealDuration) / 10; // Penalize for duration deviation | |
| } | |
| return score; | |
| }; | |
| // Rank songs by score | |
| query.sort((a, b) => calculateScore(b) - calculateScore(a)); | |
| // Return the best match | |
| return query[0]; | |
| } | |
| // Middleware to parse JSON bodies | |
| app.use(express.json()) | |
| app.post('/search-stream', async (req: Request, res: Response) => { | |
| try { | |
| // Extract query from request body | |
| const { query } = req.body | |
| if (!query) { | |
| return res.status(400).json({ error: 'Query is required' }) | |
| } | |
| // Search for songs | |
| let songs = await ytmusic.searchSongs(query) | |
| console.log(songs) | |
| let musics: MusicType[] = songs.filter((song) => { | |
| return song.duration !== null && song.name.toLowerCase().includes(query.toLowerCase()) | |
| }) | |
| // sort song by their duration | |
| musics.sort((a, b) => { | |
| if (!a.duration || !b.duration) { | |
| return 0 | |
| } | |
| return b.duration - a.duration | |
| }) | |
| console.log(musics) | |
| const firstSong = bestMatch(musics, query) | |
| if (!firstSong) { | |
| return res.status(404).json({ error: 'No songs found' }) | |
| } | |
| if (firstSong.type !== "SONG" && firstSong.type !== "VIDEO") { | |
| return res.status(400).json({ error: 'Invalid song type' }) | |
| } | |
| // console.log(firstSong) | |
| const ystreamAgent = new ystream.YTStreamAgent([{ | |
| key: 'SOCS', | |
| value: 'CAI', | |
| domain: 'youtube.com', | |
| expires: 'Infinity', | |
| sameSite: 'lax', | |
| httpOnly: false, | |
| hostOnly: false, | |
| secure: true, | |
| path: '/' | |
| }], { | |
| localAddress: '0.0.0.0', | |
| keepAlive: true, | |
| keepAliveMsecs: 5e3 | |
| }) | |
| ystreamAgent.syncFile(__dirname + "/../cookies.json") | |
| ystream.setGlobalAgent(ystreamAgent) | |
| ystream.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" | |
| // Get stream URL | |
| const stream = await ystream.stream(`https://www.youtube.com/watch?v=` + firstSong.videoId, { | |
| quality: 'high', | |
| type: 'audio', | |
| highWaterMark: 1048576 * 32, | |
| download: false | |
| }) | |
| // Return stream URL and song details | |
| res.json({ | |
| streamUrl: stream.url, | |
| songDetails: firstSong | |
| }) | |
| } catch (error: any) { | |
| // if (error.response) { | |
| // console.log('Error status:', error.response.status) | |
| // // console.log('Error message:', error.response) | |
| // } else if (error.request) { | |
| // console.log('Error:', error.request) | |
| // } else { | |
| // console.log('Error:', error.message) | |
| // } | |
| console.error(error) | |
| res.status(500).json({ error: 'Internal server error' }) | |
| } | |
| }) | |
| app.get("/", (req, res) => { | |
| res.send("Youtube API Stream are working properly") | |
| }) | |
| // Start the server | |
| app.listen(PORT, () => { | |
| console.log(`Server running on port ${PORT}`) | |
| }) |