innertube.js
Version:
A lightweight library to interact with YouTube API using InnerTube.
162 lines (141 loc) • 4.29 kB
JavaScript
const REFERER_YOUTUBE = 'https://www.youtube.com/';
const USER_AGENT_ANDROID = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36';
class InnerTube {
constructor(options = {}) {
// Default to Android client
this.baseUrl = 'https://youtubei.googleapis.com/youtubei/v1/';
this.context = {
clientName: 'ANDROID',
clientVersion: '19.17.34',
clientId: 3,
apiKey: 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w',
userAgent: USER_AGENT_ANDROID,
referer: REFERER_YOUTUBE,
...options
};
}
getHeaders() {
return {
'X-Goog-Api-Format-Version': '1',
'X-YouTube-Client-Name': this.context.clientId.toString(),
'X-YouTube-Client-Version': this.context.clientVersion,
'User-Agent': this.context.userAgent || USER_AGENT_ANDROID,
'Referer': this.context.referer || REFERER_YOUTUBE,
'Content-Type': 'application/json'
};
}
getContextPayload() {
return {
context: {
client: {
clientName: this.context.clientName,
clientVersion: this.context.clientVersion
}
}
};
}
async makeRequest(endpoint, payload) {
try {
const url = new URL(endpoint, this.baseUrl);
url.searchParams.set('key', this.context.apiKey);
const response = await fetch(url, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
throw this.handleError(error);
}
}
handleError(error) {
return new Error(`YouTube API Error: ${error.message}`);
}
async config() {
const payload = this.getContextPayload();
return this.makeRequest('config', payload);
}
async guide() {
const payload = this.getContextPayload();
return this.makeRequest('guide', payload);
}
async player(options) {
const payload = {
...this.getContextPayload(),
videoId: options.videoId
};
return this.makeRequest('player', payload);
}
async browse(options = {}) {
const payload = {
...this.getContextPayload(),
browseId: options.browseId,
params: options.params,
continuation: options.continuation
};
return this.makeRequest('browse', payload);
}
async search(options = {}) {
const payload = {
...this.getContextPayload(),
query: options.query || '',
params: options.params,
continuation: options.continuation
};
return this.makeRequest('search', payload);
}
async next(options = {}) {
const payload = {
...this.getContextPayload(),
params: options.params,
playlistId: options.playlistId,
videoId: options.videoId,
playlistIndex: options.index,
continuation: options.continuation
};
return this.makeRequest('next', payload);
}
async getTranscript(options) {
const payload = {
...this.getContextPayload(),
params: options.params
};
return this.makeRequest('get_transcript', payload);
}
async musicGetSearchSuggestions(options = {}) {
const payload = {
...this.getContextPayload(),
input: options.input || ''
};
return this.makeRequest('music/get_search_suggestions', payload);
}
async musicGetQueue(options = {}) {
const payload = {
...this.getContextPayload(),
playlistId: options.playlistId,
videoIds: options.videoIds || []
};
return this.makeRequest('music/get_queue', payload);
}
}
// Example usage
async function example() {
const yt = new InnerTube();
try {
// Player example
const playerInfo = await yt.player({ videoId: 'dQw4w9WgXcQ' });
console.log('Player Info:', playerInfo);
// Search example
const searchResults = await yt.search({ query: 'JavaScript tutorials' });
console.log('Search Results:', searchResults);
// Browse example
const browseResults = await yt.browse({ browseId: 'FEwhat_to_watch' });
console.log('Browse Results:', browseResults);
} catch (error) {
console.error(error);
}
}
module.exports = InnerTube;