Skip to content

Commit

Permalink
Merge branch 'main' into add-video-history-removal
Browse files Browse the repository at this point in the history
  • Loading branch information
dnicolson committed Aug 1, 2024
2 parents dfbd0a0 + 4f5635a commit f80ba60
Show file tree
Hide file tree
Showing 65 changed files with 574 additions and 616 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Changelog

## [10.3.0](https://github.com/LuanRT/YouTube.js/compare/v10.2.0...v10.3.0) (2024-08-01)


### Features

* **parser:** Add `EomSettingsDisclaimer` node ([#703](https://github.com/LuanRT/YouTube.js/issues/703)) ([a9bf225](https://github.com/LuanRT/YouTube.js/commit/a9bf225a62108e47a50316235a83a814c682d745))
* **PlaylistManager:** Add ability to remove videos by set ID ([#715](https://github.com/LuanRT/YouTube.js/issues/715)) ([d85fbc5](https://github.com/LuanRT/YouTube.js/commit/d85fbc56cf0fd7367b182ae36e65c1701bc5e62d))


### Bug Fixes

* **HTTPClient:** Adjust more context fields for the iOS client ([#705](https://github.com/LuanRT/YouTube.js/issues/705)) ([3153375](https://github.com/LuanRT/YouTube.js/commit/3153375bcaa6c03afba9da8474e6a9d37471ed29))

## [10.2.0](https://github.com/LuanRT/YouTube.js/compare/v10.1.0...v10.2.0) (2024-07-25)


### Features

* **Format:** Add `is_secondary` for detecting secondary audio tracks ([#697](https://github.com/LuanRT/YouTube.js/issues/697)) ([a352dde](https://github.com/LuanRT/YouTube.js/commit/a352ddeb9db001e99f49025048ad0942d84f1b3e))
* **parser:** add classdata to unhandled parse errors ([#691](https://github.com/LuanRT/YouTube.js/issues/691)) ([090539b](https://github.com/LuanRT/YouTube.js/commit/090539b28f9bc3387d01e37325ba5741b33b1765))
* **proto:** Add `comment_id` to commentSectionParams ([#693](https://github.com/LuanRT/YouTube.js/issues/693)) ([a5f6209](https://github.com/LuanRT/YouTube.js/commit/a5f62093a18705fc822abd86beaa81788b6535ce))


### Bug Fixes

* **parser:** ignore MiniGameCardView node ([#692](https://github.com/LuanRT/YouTube.js/issues/692)) ([6d0bc89](https://github.com/LuanRT/YouTube.js/commit/6d0bc89be18f27a8ce74517f5cab5020d6790328))
* **parser:** ThumbnailView background color ([#686](https://github.com/LuanRT/YouTube.js/issues/686)) ([0f8f92a](https://github.com/LuanRT/YouTube.js/commit/0f8f92a28a5b6143e890626b22ce570730a0cf09))
* **Player:** Bump cache version ([#702](https://github.com/LuanRT/YouTube.js/issues/702)) ([6765f4e](https://github.com/LuanRT/YouTube.js/commit/6765f4e0d791c657fc7411e9cdd2c0f9284e9982))
* **Player:** Fix extracting the n-token decipher algorithm again ([#701](https://github.com/LuanRT/YouTube.js/issues/701)) ([3048f70](https://github.com/LuanRT/YouTube.js/commit/3048f70f60756884bd7b591d770f7b6343cfa259))

## [10.1.0](https://github.com/LuanRT/YouTube.js/compare/v10.0.0...v10.1.0) (2024-07-10)


Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "youtubei.js",
"version": "10.1.0",
"version": "10.3.0",
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).",
"type": "module",
"types": "./dist/src/platform/lib.d.ts",
Expand Down Expand Up @@ -103,7 +103,7 @@
},
"license": "MIT",
"dependencies": {
"jintr": "^2.0.0",
"jintr": "^2.1.1",
"tslib": "^2.5.0",
"undici": "^5.19.1"
},
Expand Down
112 changes: 26 additions & 86 deletions src/Innertube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ import {
VideoInfo
} from './parser/youtube/index.js';

import { VideoInfo as ShortsVideoInfo } from './parser/ytshorts/index.js';
import { ShortFormVideoInfo } from './parser/ytshorts/index.js';

import NavigationEndpoint from './parser/classes/NavigationEndpoint.js';

import * as Proto from './proto/index.js';
import * as Constants from './utils/Constants.js';
import { InnertubeError, generateRandomString, throwIfMissing } from './utils/Utils.js';


import type { ApiResponse } from './core/Actions.js';
import type { INextRequest } from './types/index.js';
import type { IBrowseResponse, IParsedResponse } from './parser/types/index.js';
Expand Down Expand Up @@ -71,13 +70,8 @@ export default class Innertube {
return new Innertube(await Session.create(config));
}

/**
* Retrieves video info.
* @param target - The video id or `NavigationEndpoint`.
* @param client - The client to use.
*/
async getInfo(target: string | NavigationEndpoint, client?: InnerTubeClient): Promise<VideoInfo> {
throwIfMissing({ target });
throwIfMissing({ target: target });

let next_payload: INextRequest;

Expand All @@ -93,7 +87,7 @@ export default class Innertube {
video_id: target
});
} else {
throw new InnertubeError('Invalid target, expected either a video id or a valid NavigationEndpoint', target);
throw new InnertubeError('Invalid target. Expected a video id or NavigationEndpoint.', target);
}

if (!next_payload.videoId)
Expand All @@ -115,11 +109,6 @@ export default class Innertube {
return new VideoInfo(response, this.actions, cpn);
}

/**
* Retrieves basic video info.
* @param video_id - The video id.
* @param client - The client to use.
*/
async getBasicInfo(video_id: string, client?: InnerTubeClient): Promise<VideoInfo> {
throwIfMissing({ video_id });

Expand All @@ -136,37 +125,26 @@ export default class Innertube {
return new VideoInfo([ response ], this.actions, cpn);
}

/**
* Retrieves shorts info.
* @param short_id - The short id.
* @param client - The client to use.
*/
async getShortsWatchItem(short_id: string, client?: InnerTubeClient): Promise<ShortsVideoInfo> {
throwIfMissing({ short_id });
async getShortsVideoInfo(video_id: string, client?: InnerTubeClient): Promise<ShortFormVideoInfo> {
throwIfMissing({ video_id });

const watchResponse = this.actions.execute(
Reel.WatchEndpoint.PATH, Reel.WatchEndpoint.build({
short_id: short_id,
client: client
})
const watch_response = this.actions.execute(
Reel.ReelItemWatchEndpoint.PATH, Reel.ReelItemWatchEndpoint.build({ video_id, client })
);

const sequenceResponse = this.actions.execute(
Reel.WatchSequenceEndpoint.PATH, Reel.WatchSequenceEndpoint.build({
sequenceParams: Proto.encodeReelSequence(short_id)
const sequence_response = this.actions.execute(
Reel.ReelWatchSequenceEndpoint.PATH, Reel.ReelWatchSequenceEndpoint.build({
sequence_params: Proto.encodeReelSequence(video_id)
})
);

const response = await Promise.all([ watchResponse, sequenceResponse ]);
const response = await Promise.all([ watch_response, sequence_response ]);

const cpn = generateRandomString(16);

return new ShortsVideoInfo(response, this.actions);
return new ShortFormVideoInfo([ response[0] ], this.actions, cpn, response[1]);
}

/**
* Searches a given query.
* @param query - The search query.
* @param filters - Search filters.
*/
async search(query: string, filters: SearchFilters = {}): Promise<Search> {
throwIfMissing({ query });

Expand All @@ -179,10 +157,6 @@ export default class Innertube {
return new Search(this.actions, response);
}

/**
* Retrieves search suggestions for a given query.
* @param query - The search query.
*/
async getSearchSuggestions(query: string): Promise<string[]> {
throwIfMissing({ query });

Expand All @@ -204,11 +178,6 @@ export default class Innertube {
return suggestions;
}

/**
* Retrieves comments for a video.
* @param video_id - The video id.
* @param sort_by - Sorting options.
*/
async getComments(video_id: string, sort_by?: 'TOP_COMMENTS' | 'NEWEST_FIRST'): Promise<Comments> {
throwIfMissing({ video_id });

Expand All @@ -223,9 +192,6 @@ export default class Innertube {
return new Comments(this.actions, response.data);
}

/**
* Retrieves YouTube's home feed (aka recommendations).
*/
async getHomeFeed(): Promise<HomeFeed> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FEwhat_to_watch' })
Expand All @@ -241,61 +207,41 @@ export default class Innertube {
return new Guide(response.data);
}

/**
* Returns the account's library.
*/
async getLibrary(): Promise<Library> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FElibrary' })
);
return new Library(this.actions, response);
}

/**
* Retrieves watch history.
* Which can also be achieved with {@link getLibrary}.
*/
async getHistory(): Promise<History> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FEhistory' })
);
return new History(this.actions, response);
}

/**
* Retrieves Trending content.
*/
async getTrending(): Promise<TabbedFeed<IBrowseResponse>> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, { ...BrowseEndpoint.build({ browse_id: 'FEtrending' }), parse: true }
);
return new TabbedFeed(this.actions, response);
}

/**
* Retrieves Subscriptions feed.
*/
async getSubscriptionsFeed(): Promise<Feed<IBrowseResponse>> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, { ...BrowseEndpoint.build({ browse_id: 'FEsubscriptions' }), parse: true }
);
return new Feed(this.actions, response);
}

/**
* Retrieves Channels feed.
*/
async getChannelsFeed(): Promise<Feed<IBrowseResponse>> {
const response = await this.actions.execute(
BrowseEndpoint.PATH, { ...BrowseEndpoint.build({ browse_id: 'FEchannels' }), parse: true }
);
return new Feed(this.actions, response);
}

/**
* Retrieves contents for a given channel.
* @param id - Channel id
*/
async getChannel(id: string): Promise<Channel> {
throwIfMissing({ id });
const response = await this.actions.execute(
Expand All @@ -304,9 +250,6 @@ export default class Innertube {
return new Channel(this.actions, response);
}

/**
* Retrieves notifications.
*/
async getNotifications(): Promise<NotificationsMenu> {
const response = await this.actions.execute(
GetNotificationMenuEndpoint.PATH, GetNotificationMenuEndpoint.build({
Expand All @@ -316,17 +259,14 @@ export default class Innertube {
return new NotificationsMenu(this.actions, response);
}

/**
* Retrieves unseen notifications count.
*/
async getUnseenNotificationsCount(): Promise<number> {
const response = await this.actions.execute(Notification.GetUnseenCountEndpoint.PATH);
// TODO: properly parse this
// FIXME: properly parse this.
return response.data?.unseenCount || response.data?.actions?.[0].updateNotificationsUnseenCountAction?.unseenCount || 0;
}

/**
* Retrieves playlists.
* Retrieves the user's playlists.
*/
async getPlaylists(): Promise<Feed<IBrowseResponse>> {
const response = await this.actions.execute(
Expand All @@ -335,10 +275,6 @@ export default class Innertube {
return new Feed(this.actions, response);
}

/**
* Retrieves playlist contents.
* @param id - Playlist id
*/
async getPlaylist(id: string): Promise<Playlist> {
throwIfMissing({ id });

Expand All @@ -353,10 +289,6 @@ export default class Innertube {
return new Playlist(this.actions, response);
}

/**
* Retrieves a given hashtag's page.
* @param hashtag - The hashtag to fetch.
*/
async getHashtag(hashtag: string): Promise<HashtagFeed> {
throwIfMissing({ hashtag });

Expand All @@ -380,11 +312,15 @@ export default class Innertube {
*/
async getStreamingData(video_id: string, options: FormatOptions = {}): Promise<Format> {
const info = await this.getBasicInfo(video_id);
return info.chooseFormat(options);

const format = info.chooseFormat(options);
format.url = format.decipher(this.#session.player);

return format;
}

/**
* Downloads a given video. If you only need the direct download link see {@link getStreamingData}.
* Downloads a given video. If all you need the direct download link, see {@link getStreamingData}.
* If you wish to retrieve the video info too, have a look at {@link getBasicInfo} or {@link getInfo}.
* @param video_id - The video id.
* @param options - Download options.
Expand All @@ -402,6 +338,10 @@ export default class Innertube {
const response = await this.actions.execute(
ResolveURLEndpoint.PATH, { ...ResolveURLEndpoint.build({ url }), parse: true }
);

if (!response.endpoint)
throw new InnertubeError('Failed to resolve URL. Expected a NavigationEndpoint but got undefined', response);

return response.endpoint;
}

Expand Down
Loading

0 comments on commit f80ba60

Please sign in to comment.