UNPKG

@imput/youtubei.js

Version:

A JavaScript client for YouTube's private API, known as InnerTube. Fork of youtubei.js

115 lines 5.56 kB
import { Constants } from '../../utils/index.js'; import { InnertubeError } from '../../utils/Utils.js'; import { MediaInfo } from '../../core/mixins/index.js'; import Tab from '../classes/Tab.js'; import AutomixPreviewVideo from '../classes/AutomixPreviewVideo.js'; import Message from '../classes/Message.js'; import MusicDescriptionShelf from '../classes/MusicDescriptionShelf.js'; import PlayerOverlay from '../classes/PlayerOverlay.js'; import PlaylistPanel from '../classes/PlaylistPanel.js'; import SectionList from '../classes/SectionList.js'; import WatchNextTabbedResults from '../classes/WatchNextTabbedResults.js'; import NavigationEndpoint from '../classes/NavigationEndpoint.js'; import { PlaylistPanelContinuation } from '../continuations.js'; class TrackInfo extends MediaInfo { constructor(data, actions, cpn) { super(data, actions, cpn); const next = this.page[1]; if (next) { const tabbed_results = next.contents_memo?.getType(WatchNextTabbedResults)?.[0]; this.tabs = tabbed_results?.tabs.as(Tab); this.current_video_endpoint = next.current_video_endpoint; // TODO: update PlayerOverlay, YTMusic's is a little bit different. this.player_overlays = next.player_overlays?.item().as(PlayerOverlay); } } /** * Retrieves contents of the given tab. */ async getTab(title_or_page_type) { if (!this.tabs) throw new InnertubeError('Could not find any tab'); const target_tab = this.tabs.get({ title: title_or_page_type }) || this.tabs.find((tab) => tab.endpoint.payload.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType === title_or_page_type) || this.tabs?.[0]; if (!target_tab) throw new InnertubeError(`Tab "${title_or_page_type}" not found`, { available_tabs: this.available_tabs }); if (target_tab.content) return target_tab.content; const page = await target_tab.endpoint.call(this.actions, { client: 'YTMUSIC', parse: true }); if (page.contents?.item().type === 'Message') return page.contents.item().as(Message); if (!page.contents) throw new InnertubeError('Page contents was empty', page); return page.contents.item().as(SectionList).contents; } /** * Retrieves up next. */ async getUpNext(automix = true) { const music_queue = await this.getTab('Up next'); if (!music_queue || !music_queue.content) throw new InnertubeError('Music queue was empty, the video id is probably invalid.', music_queue); const playlist_panel = music_queue.content.as(PlaylistPanel); if (!playlist_panel.playlist_id && automix) { const automix_preview_video = playlist_panel.contents.firstOfType(AutomixPreviewVideo); if (!automix_preview_video) throw new InnertubeError('Automix item not found'); const page = await automix_preview_video.playlist_video?.endpoint.call(this.actions, { videoId: this.basic_info.id, client: 'YTMUSIC', parse: true }); if (!page || !page.contents_memo) throw new InnertubeError('Could not fetch automix'); return page.contents_memo.getType(PlaylistPanel)?.[0]; } return playlist_panel; } /** * Retrieves up next continuation relative to current TrackInfo. */ async getUpNextContinuation(playlistPanel) { if (!this.current_video_endpoint) throw new InnertubeError('Current Video Endpoint was not defined.', this.current_video_endpoint); if (playlistPanel instanceof PlaylistPanel && playlistPanel.playlist_id !== this.current_video_endpoint.payload.playlistId) { throw new InnertubeError('PlaylistId from TrackInfo does not match with PlaylistPanel'); } const watch_next_endpoint = new NavigationEndpoint({ watchNextEndpoint: { ...this.current_video_endpoint.payload, continuation: playlistPanel.continuation } }); const response = await watch_next_endpoint.call(this.actions, { ...this.current_video_endpoint.payload, continuation: playlistPanel.continuation, client: 'YTMUSIC', parse: true }); const playlistCont = response.continuation_contents?.as(PlaylistPanelContinuation); if (!playlistCont) throw new InnertubeError('No PlaylistPanel Continuation available.', response); return playlistCont; } /** * Retrieves related content. */ async getRelated() { return await this.getTab('MUSIC_PAGE_TYPE_TRACK_RELATED'); } /** * Retrieves lyrics. */ async getLyrics() { const tab = await this.getTab('MUSIC_PAGE_TYPE_TRACK_LYRICS'); return tab.firstOfType(MusicDescriptionShelf); } /** * Adds the song to the watch history. */ async addToWatchHistory() { return super.addToWatchHistory(Constants.CLIENTS.YTMUSIC.NAME, Constants.CLIENTS.YTMUSIC.VERSION, 'https://music.'); } /** * Updates the watch time of the song. */ async updateWatchTime(startTime) { return super.updateWatchTime(startTime, Constants.CLIENTS.YTMUSIC.NAME, Constants.CLIENTS.YTMUSIC.VERSION, 'https://music.'); } get available_tabs() { return this.tabs ? this.tabs.map((tab) => tab.title) : []; } } export default TrackInfo; //# sourceMappingURL=TrackInfo.js.map