YoutubeStreamAPI / index.ts
quanvndzai's picture
init
f78a86d
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}`)
})