hotfix crunchyroll playback

This commit is contained in:
stratumadev 2025-08-21 22:02:44 +02:00
parent 3b81ef9977
commit 36cff8b496
4 changed files with 32 additions and 29 deletions

View file

@ -1,13 +1,13 @@
export enum CrunchyPlayStreams {
'chrome' = 'web/chrome',
'firefox' = 'web/firefox',
'safari' = 'web/safari',
'edge' = 'web/edge',
'fallback' = 'web/fallback',
'ps4' = 'console/ps4',
'ps5' = 'console/ps5',
'switch' = 'console/switch',
'xboxone' = 'console/xbox_one',
// 'chrome' = 'web/chrome',
// 'firefox' = 'web/firefox',
// 'safari' = 'web/safari',
// 'edge' = 'web/edge',
// 'fallback' = 'web/fallback',
// 'ps4' = 'console/ps4',
// 'ps5' = 'console/ps5',
// 'switch' = 'console/switch',
// 'xboxone' = 'console/xbox_one',
'vidaa' = 'tv/vidaa',
'samsungtv' = 'tv/samsung',
'lgtv' = 'tv/lg',

View file

@ -390,25 +390,25 @@ export default class Crunchy implements ServiceClass {
console.info('All required fonts downloaded!');
}
private async productionToken() {
const tokenReq = await this.req.getData(api.bundlejs);
// private async productionToken() {
// const tokenReq = await this.req.getData(api.bundlejs);
if (!tokenReq.ok || !tokenReq.res) {
console.error('Failed to get Production Token!');
return { isOk: false, reason: new Error('Failed to get Production Token') };
}
// if (!tokenReq.ok || !tokenReq.res) {
// console.error('Failed to get Production Token!');
// return { isOk: false, reason: new Error('Failed to get Production Token') };
// }
const rawjs = await tokenReq.res.text();
// const rawjs = await tokenReq.res.text();
const tokens = rawjs.match(/prod="([\w-]+:[\w-]+)"/);
// const tokens = rawjs.match(/prod="([\w-]+:[\w-]+)"/);
if (!tokens) {
console.error('Failed to find Production Token in js!');
return { isOk: false, reason: new Error('Failed to find Production Token in js') };
}
// if (!tokens) {
// console.error('Failed to find Production Token in js!');
// return { isOk: false, reason: new Error('Failed to find Production Token in js') };
// }
return Buffer.from(tokens[1], 'latin1').toString('base64');
}
// return Buffer.from(tokens[1], 'latin1').toString('base64');
// }
public async doAuth(data: AuthData): Promise<AuthResponse> {
const uuid = randomUUID();
@ -423,7 +423,7 @@ export default class Crunchy implements ServiceClass {
}).toString();
const authReqOpts: reqModule.Params = {
method: 'POST',
headers: {...api.crunchyAuthHeader, Authorization: `Basic ${await this.productionToken()}`},
headers: api.crunchyAuthHeader,
body: authData
};
const authReq = await this.req.getData(api.auth, authReqOpts);
@ -462,7 +462,7 @@ export default class Crunchy implements ServiceClass {
}).toString();
const authReqOpts: reqModule.Params = {
method: 'POST',
headers: {...api.crunchyAuthHeader, Authorization: `Basic ${await this.productionToken()}`},
headers: api.crunchyAuthHeader,
body: authData
};
const authReq = await this.req.getData(api.auth, authReqOpts);
@ -530,7 +530,7 @@ export default class Crunchy implements ServiceClass {
}).toString();
const authReqOpts: reqModule.Params = {
method: 'POST',
headers: {...api.crunchyAuthHeader, Authorization: `Basic ${await this.productionToken()}`, Cookie: `etp_rt=${refreshToken}`},
headers: {...api.crunchyAuthHeader, Cookie: `etp_rt=${refreshToken}`},
body: authData
};
const authReq = await this.req.getData(api.auth, authReqOpts);
@ -583,7 +583,7 @@ export default class Crunchy implements ServiceClass {
}).toString();
const authReqOpts: reqModule.Params = {
method: 'POST',
headers: {...api.crunchyAuthHeader, Authorization: `Basic ${await this.productionToken()}`},
headers: api.crunchyAuthHeader,
body: authData
};
const authReq = await this.req.getData(api.auth, authReqOpts);

View file

@ -11,6 +11,7 @@ export type APIType = {
// Crunchyroll Vilos bundle.js
bundlejs: string;
// Crunchyroll API
basic_auth_token: string;
auth: string;
profile: string;
search: string;
@ -47,6 +48,7 @@ const api: APIType = {
bundlejs: 'https://static.crunchyroll.com/vilos-v2/web/vilos/js/bundle.js',
//
// Crunchyroll API
basic_auth_token: 'Ym1icmt4eXgzZDd1NmpzZnlsYTQ6QUlONEQ1VkVfY3Awd1Z6Zk5vUDBZcUhVcllGcDloU2c=',
auth: `${domain.cr_www}/auth/v1/token`,
profile: `${domain.cr_www}/accounts/v1/me/profile`,
search: `${domain.cr_www}/content/v2/discover/search`,
@ -62,7 +64,7 @@ const api: APIType = {
cms_auth: `${domain.cr_www}/index/v2`,
//
// Crunchyroll Headers
crunchyDefUserAgent: 'Crunchyroll/4.83.0 (bundle_identifier:com.crunchyroll.iphone; build_number:4254815.324030705) iOS/19.0.0 Gravity/4.83.0',
crunchyDefUserAgent: 'Crunchyroll/ANDROIDTV/3.42.1_22267 (Android 16; en-US; sdk_gphone64_x86_64)',
crunchyDefHeader: {},
crunchyAuthHeader: {},
//
@ -92,6 +94,7 @@ api.crunchyDefHeader = {
// set header
api.crunchyAuthHeader = {
Authorization: `Basic ${api.basic_auth_token}`,
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
...api.crunchyDefHeader
};

View file

@ -359,7 +359,7 @@ const args: TAppArg<boolean|number|string|unknown[]>[] = [
describe: 'Select a specific Crunchyroll audio playback endpoint by device.',
choices: [...Object.keys(CrunchyPlayStreams), 'none'],
default: {
default: 'firefox'
default: 'android'
},
docDescribe: true,
usage: '${device}'