How does anyone work with YouTube's internal API? Translated ytmusicapi's gethome() to JS, need to start refactoring the functions to produce lazuli media items.
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import { google } from 'googleapis'
|
||||
|
||||
export class Jellyfin {
|
||||
static audioPresets = (userId: string) => {
|
||||
return {
|
||||
@@ -123,81 +121,3 @@ export class Jellyfin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class YouTubeMusic {
|
||||
static baseHeaders = {
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0',
|
||||
accept: '*/*',
|
||||
'accept-encoding': 'gzip, deflate',
|
||||
'content-type': 'application/json',
|
||||
'content-encoding': 'gzip',
|
||||
origin: 'https://music.youtube.com',
|
||||
Cookie: 'SOCS=CAI;',
|
||||
}
|
||||
|
||||
static fetchServiceInfo = async (userId: string, accessToken: string): Promise<Connection<'youtube-music'>['service']> => {
|
||||
const youtube = google.youtube('v3')
|
||||
const userChannelResponse = await youtube.channels.list({ mine: true, part: ['snippet'], access_token: accessToken })
|
||||
const userChannel = userChannelResponse.data.items![0]
|
||||
|
||||
return {
|
||||
userId,
|
||||
username: userChannel.snippet?.title as string,
|
||||
profilePicture: userChannel.snippet?.thumbnails?.default?.url as string | undefined,
|
||||
}
|
||||
}
|
||||
|
||||
static getVisitorId = async (accessToken: string): Promise<string> => {
|
||||
const headers = Object.assign(this.baseHeaders, { authorization: `Bearer ${accessToken}`, 'X-Goog-Request-Time': `${Date.now()}` })
|
||||
const visitorIdResponse = await fetch('https://music.youtube.com', { headers })
|
||||
const visitorIdText = await visitorIdResponse.text()
|
||||
const regex = /ytcfg\.set\s*\(\s*({.+?})\s*\)\s*;/g
|
||||
const matches = []
|
||||
let match
|
||||
|
||||
while ((match = regex.exec(visitorIdText)) !== null) {
|
||||
const capturedGroup = match[1]
|
||||
matches.push(capturedGroup)
|
||||
}
|
||||
|
||||
let visitorId = ''
|
||||
if (matches.length > 0) {
|
||||
const ytcfg = JSON.parse(matches[0])
|
||||
visitorId = ytcfg.VISITOR_DATA
|
||||
}
|
||||
|
||||
return visitorId
|
||||
}
|
||||
|
||||
static getHome = async (accessToken: string) => {
|
||||
const headers = Object.assign(this.baseHeaders, { authorization: `Bearer ${accessToken}`, 'X-Goog-Request-Time': `${Date.now()}` })
|
||||
|
||||
function formatDate(): string {
|
||||
const currentDate = new Date()
|
||||
const year = currentDate.getUTCFullYear()
|
||||
const month = (currentDate.getUTCMonth() + 1).toString().padStart(2, '0') // Months are zero-based, so add 1
|
||||
const day = currentDate.getUTCDate().toString().padStart(2, '0')
|
||||
|
||||
return year + month + day
|
||||
}
|
||||
|
||||
const response = await fetch(`https://music.youtube.com/youtubei/v1/browse?alt=json`, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
browseId: 'FEmusic_home',
|
||||
context: {
|
||||
client: {
|
||||
clientName: 'WEB_REMIX',
|
||||
clientVersion: '1.' + formatDate() + '.01.00',
|
||||
hl: 'en',
|
||||
},
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
console.log(response.status)
|
||||
console.log(data.contents.singleColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[0].musicCarouselShelfRenderer.contents[0].musicTwoRowItemRenderer.title)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user