Compare commits

...

7 Commits

Author SHA1 Message Date
github-actions[bot]
bff4210349 chore(main): release 6.3.0 (#495)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-08-31 20:41:06 -03:00
absidue
91de6e5c0e feat(ChannelMetadata): Add music_artist_name (#497) 2023-08-31 20:29:58 -03:00
absidue
c26972c42a fix(CompactMovie): Add missing import and remove unnecessary console.log (#496) 2023-08-31 20:28:25 -03:00
Jeremy Banks
8bc2aaa358 feat(Session): Add on_behalf_of_user session option. (#494)
This specifies which channel to use if multiple are associated with the logged-in account.
2023-08-31 08:20:37 -03:00
github-actions[bot]
2e5f076fd7 chore(main): release 6.2.0 (#491)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-08-29 14:25:32 -03:00
absidue
0412fa05ff fix(Format): Fix is_original always being true (#492) 2023-08-29 14:23:08 -03:00
Luan
10c15bfb9f feat(Session): Add fallback for session data retrieval (#490)
* feat(Session): Add fallback for session data retrieval

Should have added this when we first implemented session data retrieval to be honest. It makes a request to YouTube's service worker and the data there can change or the request can just fail.

* chore: lint
2023-08-28 07:18:27 -03:00
7 changed files with 57 additions and 11 deletions

View File

@@ -1,5 +1,30 @@
# Changelog
## [6.3.0](https://github.com/LuanRT/YouTube.js/compare/v6.2.0...v6.3.0) (2023-08-31)
### Features
* **ChannelMetadata:** Add `music_artist_name` ([#497](https://github.com/LuanRT/YouTube.js/issues/497)) ([91de6e5](https://github.com/LuanRT/YouTube.js/commit/91de6e5c0e5b27e6d12ce5db2f500c5ff78b9830))
* **Session:** Add on_behalf_of_user session option. ([#494](https://github.com/LuanRT/YouTube.js/issues/494)) ([8bc2aaa](https://github.com/LuanRT/YouTube.js/commit/8bc2aaa3587fcf79f69eedbc2bf422a4c6fa7eb1))
### Bug Fixes
* **CompactMovie:** Add missing import and remove unnecessary console.log ([#496](https://github.com/LuanRT/YouTube.js/issues/496)) ([c26972c](https://github.com/LuanRT/YouTube.js/commit/c26972c42a6368822ac254c00f1bbee5a1542486))
## [6.2.0](https://github.com/LuanRT/YouTube.js/compare/v6.1.0...v6.2.0) (2023-08-29)
### Features
* **Session:** Add fallback for session data retrieval ([#490](https://github.com/LuanRT/YouTube.js/issues/490)) ([10c15bf](https://github.com/LuanRT/YouTube.js/commit/10c15bfb9f131a2acea2f26ff3328993d8d8f4aa))
### Bug Fixes
* **Format:** Fix `is_original` always being `true` ([#492](https://github.com/LuanRT/YouTube.js/issues/492)) ([0412fa0](https://github.com/LuanRT/YouTube.js/commit/0412fa05ff1f00960b398c2f18d5ce39ce0cb864))
## [6.1.0](https://github.com/LuanRT/YouTube.js/compare/v6.0.2...v6.1.0) (2023-08-27)

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "youtubei.js",
"version": "6.1.0",
"version": "6.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "youtubei.js",
"version": "6.1.0",
"version": "6.3.0",
"funding": [
"https://github.com/sponsors/LuanRT"
],

View File

@@ -1,6 +1,6 @@
{
"name": "youtubei.js",
"version": "6.1.0",
"version": "6.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",

View File

@@ -63,6 +63,7 @@ export interface Context {
user: {
enableSafetyMode: boolean;
lockedSafetyMode: boolean;
onBehalfOfUser?: string;
};
thirdParty?: {
embedUrl: string;
@@ -84,6 +85,10 @@ export interface SessionOptions {
* Only works if you are signed in with cookies.
*/
account_index?: number;
/**
* Specify the Page ID of the YouTube profile/channel to use, if the logged-in account has multiple profiles.
*/
on_behalf_of_user?: string;
/**
* Specifies whether to retrieve the JS player. Disabling this will make session creation faster.
* **NOTE:** Deciphering formats is not possible without the JS player.
@@ -193,7 +198,8 @@ export default class Session extends EventEmitterLike {
options.device_category,
options.client_type,
options.timezone,
options.fetch
options.fetch,
options.on_behalf_of_user
);
return new Session(
@@ -213,14 +219,22 @@ export default class Session extends EventEmitterLike {
device_category: DeviceCategory = 'desktop',
client_name: ClientType = ClientType.WEB,
tz: string = Intl.DateTimeFormat().resolvedOptions().timeZone,
fetch: FetchFunction = Platform.shim.fetch
fetch: FetchFunction = Platform.shim.fetch,
on_behalf_of_user?: string
) {
let session_data: SessionData;
const session_args = { lang, location, time_zone: tz, device_category, client_name, enable_safety_mode, visitor_data, on_behalf_of_user };
if (generate_session_locally) {
session_data = this.#generateSessionData({ lang, location, time_zone: tz, device_category, client_name, enable_safety_mode, visitor_data });
session_data = this.#generateSessionData(session_args);
} else {
session_data = await this.#retrieveSessionData({ lang, location, time_zone: tz, device_category, client_name, enable_safety_mode, visitor_data }, fetch);
try {
// This can fail if the data changes or the request is blocked for some reason.
session_data = await this.#retrieveSessionData(session_args, fetch);
} catch (err) {
session_data = this.#generateSessionData(session_args);
}
}
return { ...session_data, account_index };
@@ -234,6 +248,7 @@ export default class Session extends EventEmitterLike {
client_name: string;
enable_safety_mode: boolean;
visitor_data: string;
on_behalf_of_user?: string;
}, fetch: FetchFunction = Platform.shim.fetch): Promise<SessionData> {
const url = new URL('/sw.js_data', Constants.URLS.YT_BASE);
@@ -293,7 +308,8 @@ export default class Session extends EventEmitterLike {
},
user: {
enableSafetyMode: options.enable_safety_mode,
lockedSafetyMode: false
lockedSafetyMode: false,
onBehalfOfUser: options.on_behalf_of_user
}
};
@@ -308,6 +324,7 @@ export default class Session extends EventEmitterLike {
client_name: string;
enable_safety_mode: boolean;
visitor_data: string;
on_behalf_of_user?: string;
}): SessionData {
let visitor_id = generateRandomString(11);
@@ -340,7 +357,8 @@ export default class Session extends EventEmitterLike {
},
user: {
enableSafetyMode: options.enable_safety_mode,
lockedSafetyMode: false
lockedSafetyMode: false,
onBehalfOfUser: options.on_behalf_of_user
}
};

View File

@@ -14,6 +14,7 @@ export default class ChannelMetadata extends YTNode {
is_family_safe: boolean;
keywords: string[];
avatar: Thumbnail[];
music_artist_name?: string;
available_countries: string[];
android_deep_link: string;
android_appindexing_link: string;
@@ -30,6 +31,8 @@ export default class ChannelMetadata extends YTNode {
this.is_family_safe = data.isFamilySafe;
this.keywords = data.keywords;
this.avatar = Thumbnail.fromResponse(data.avatar);
// Can be an empty string sometimes, so we need the extra length check
this.music_artist_name = typeof data.musicArtistName === 'string' && data.musicArtistName.length > 0 ? data.musicArtistName : undefined;
this.available_countries = data.availableCountryCodes;
this.android_deep_link = data.androidDeepLink;
this.android_appindexing_link = data.androidAppindexingLink;

View File

@@ -3,6 +3,7 @@ import type { RawNode } from '../index.js';
import Parser from '../index.js';
import Author from './misc/Author.js';
import NavigationEndpoint from './NavigationEndpoint.js';
import Text from './misc/Text.js';
import Thumbnail from './misc/Thumbnail.js';
import Menu from './menus/Menu.js';
import { timeToSeconds } from '../../utils/Utils.js';
@@ -29,7 +30,6 @@ export default class CompactMovie extends YTNode {
constructor(data: RawNode) {
super();
console.log(data);
const overlay_time_status = data.thumbnailOverlays
.find((overlay: RawNode) => overlay.thumbnailOverlayTimeStatusRenderer)
?.thumbnailOverlayTimeStatusRenderer.text || 'N/A';

View File

@@ -104,7 +104,7 @@ export default class Format {
this.language = xtags?.find((x: string) => x.startsWith('lang='))?.split('=')[1] || null;
this.is_dubbed = audio_content === 'dubbed';
this.is_descriptive = audio_content === 'descriptive';
this.is_original = audio_content === 'original' || !this.is_dubbed || !this.is_descriptive;
this.is_original = audio_content === 'original' || (!this.is_dubbed && !this.is_descriptive);
if (Reflect.has(data, 'audioTrack')) {
this.audio_track = {