Skip to content

Commit

Permalink
feat: extend music getInfo to allow MusicResponsiveListItem and Nav E…
Browse files Browse the repository at this point in the history
…ndpoints (#751)

* feat: extend music getInfo to allow MusicResponsiveListItem nav endpoints

* chore: remove debug statements from test

* chore: adapt test

* feat: add nav endpoints to music getInfo

---------

Co-authored-by: Luan <[email protected]>
  • Loading branch information
Duell10111 and LuanRT authored Sep 19, 2024
1 parent 2e61b99 commit 5db449c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/core/clients/Music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Message from '../../parser/classes/Message.js';
import MusicDescriptionShelf from '../../parser/classes/MusicDescriptionShelf.js';
import MusicQueue from '../../parser/classes/MusicQueue.js';
import MusicTwoRowItem from '../../parser/classes/MusicTwoRowItem.js';
import MusicResponsiveListItem from '../../parser/classes/MusicResponsiveListItem.js';
import NavigationEndpoint from '../../parser/classes/NavigationEndpoint.js';
import PlaylistPanel from '../../parser/classes/PlaylistPanel.js';
import SearchSuggestionsSection from '../../parser/classes/SearchSuggestionsSection.js';
import SectionList from '../../parser/classes/SectionList.js';
Expand Down Expand Up @@ -44,9 +46,13 @@ export default class Music {
* Retrieves track info. Passing a list item of type MusicTwoRowItem automatically starts a radio.
* @param target - Video id or a list item.
*/
getInfo(target: string | MusicTwoRowItem): Promise<TrackInfo> {
getInfo(target: string | MusicTwoRowItem | MusicResponsiveListItem | NavigationEndpoint): Promise<TrackInfo> {
if (target instanceof MusicTwoRowItem) {
return this.#fetchInfoFromListItem(target);
return this.#fetchInfoFromEndpoint(target.endpoint);
} else if (target instanceof MusicResponsiveListItem) {
return this.#fetchInfoFromEndpoint(target.overlay?.content?.endpoint ?? target.endpoint);
} else if (target instanceof NavigationEndpoint) {
return this.#fetchInfoFromEndpoint(target);
} else if (typeof target === 'string') {
return this.#fetchInfoFromVideoId(target);
}
Expand Down Expand Up @@ -75,14 +81,11 @@ export default class Music {
return new TrackInfo(response, this.#actions, cpn);
}

async #fetchInfoFromListItem(list_item: MusicTwoRowItem | undefined): Promise<TrackInfo> {
if (!list_item)
throw new InnertubeError('List item cannot be undefined');

if (!list_item.endpoint)
async #fetchInfoFromEndpoint(endpoint?: NavigationEndpoint): Promise<TrackInfo> {
if (!endpoint)
throw new Error('This item does not have an endpoint.');

const player_response = list_item.endpoint.call(this.#actions, {
const player_response = endpoint.call(this.#actions, {
client: 'YTMUSIC',
playbackContext: {
contentPlaybackContext: {
Expand All @@ -93,7 +96,7 @@ export default class Music {
}
});

const next_response = list_item.endpoint.call(this.#actions, {
const next_response = endpoint.call(this.#actions, {
client: 'YTMUSIC',
enablePersistentPlaylistPanel: true,
override_endpoint: '/next'
Expand Down
27 changes: 27 additions & 0 deletions test/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,33 @@ describe('YouTube.js Tests', () => {
// expect(info.basic_info.id).toBe('WSeNSzJ2-Jw');
// });

test('Innertube#music.getInfo.MusicResponsiveListItem', async () => {
const playlist = await innertube.music.getPlaylist('PLQxo8OvVvJ1WI_Bp67F2wdIl_R2Rc_1-u');
expect(playlist).toBeDefined();
expect(playlist.header).toBeDefined();
expect(playlist.contents).toBeDefined();
expect(playlist.contents?.length).toBeGreaterThan(0);

const info = await innertube.music.getInfo(playlist.contents!.first())
expect(info).toBeDefined();
});

test('Innertube#music.getInfo.NavEndpoint', async () => {
const playlist = await innertube.music.getPlaylist('PLQxo8OvVvJ1WI_Bp67F2wdIl_R2Rc_1-u');
expect(playlist).toBeDefined();
expect(playlist.header).toBeDefined();
expect(playlist.contents).toBeDefined();
expect(playlist.contents?.length).toBeGreaterThan(0);

const playlistPlayEndpoint = playlist.header!.as(YTNodes.MusicResponsiveHeader).buttons.firstOfType(YTNodes.MusicPlayButton)!.endpoint

const info = await innertube.music.getInfo(playlistPlayEndpoint)
expect(info).toBeDefined();

const upNext = await info.getUpNext();
expect(upNext.playlist_id).toBe("PLQxo8OvVvJ1WI_Bp67F2wdIl_R2Rc_1-u");
});

describe('Innertube#music.search', () => {
let search: YTMusic.Search;

Expand Down

0 comments on commit 5db449c

Please sign in to comment.