mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-01-11 20:10:20 +00:00
reverted crunchyroll to legacy api
This commit is contained in:
parent
ea53e9071f
commit
160c8a1cb4
2 changed files with 75 additions and 35 deletions
58
crunchy.ts
58
crunchy.ts
|
|
@ -390,15 +390,20 @@ export default class Crunchy implements ServiceClass {
|
|||
// }
|
||||
|
||||
public async doAuth(data: AuthData): Promise<AuthResponse> {
|
||||
const basic = atob(api.basic_auth_token);
|
||||
const client = basic.split(':');
|
||||
|
||||
const uuid = randomUUID();
|
||||
const authData = new URLSearchParams({
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
grant_type: 'password',
|
||||
scope: 'offline_access',
|
||||
client_id: client[0],
|
||||
client_secret: client[1],
|
||||
device_id: uuid,
|
||||
device_name: 'iPhone',
|
||||
device_type: 'iPhone 13'
|
||||
device_name: 'emu64xa',
|
||||
device_type: 'ANDROIDTV'
|
||||
}).toString();
|
||||
const authReqOpts: FetchParams = {
|
||||
method: 'POST',
|
||||
|
|
@ -411,6 +416,7 @@ export default class Crunchy implements ServiceClass {
|
|||
console.error('Authentication failed!');
|
||||
return { isOk: false, reason: new Error('Authentication failed') };
|
||||
}
|
||||
|
||||
// To prevent any Cloudflare errors in the future
|
||||
if (authReq.res.headers.get('Set-Cookie')) {
|
||||
api.crunchyDefHeader['Cookie'] = authReq.res.headers.get('Set-Cookie') as string;
|
||||
|
|
@ -422,6 +428,7 @@ export default class Crunchy implements ServiceClass {
|
|||
api.crunchyDefHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
api.crunchyAuthHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
}
|
||||
|
||||
this.token = await authReq.res.json();
|
||||
this.token.device_id = uuid;
|
||||
this.token.expires = new Date(Date.now() + this.token.expires_in * 1000);
|
||||
|
|
@ -432,13 +439,18 @@ export default class Crunchy implements ServiceClass {
|
|||
}
|
||||
|
||||
public async doAnonymousAuth() {
|
||||
const basic = atob(api.basic_auth_token);
|
||||
const client = basic.split(':');
|
||||
|
||||
const uuid = randomUUID();
|
||||
const authData = new URLSearchParams({
|
||||
grant_type: 'client_id',
|
||||
scope: 'offline_access',
|
||||
client_id: client[0],
|
||||
client_secret: client[1],
|
||||
device_id: uuid,
|
||||
device_name: 'iPhone',
|
||||
device_type: 'iPhone 13'
|
||||
device_name: 'emu64xa',
|
||||
device_type: 'ANDROIDTV'
|
||||
}).toString();
|
||||
const authReqOpts: FetchParams = {
|
||||
method: 'POST',
|
||||
|
|
@ -462,6 +474,7 @@ export default class Crunchy implements ServiceClass {
|
|||
api.crunchyDefHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
api.crunchyAuthHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
}
|
||||
|
||||
this.token = await authReq.res.json();
|
||||
this.token.device_id = uuid;
|
||||
this.token.expires = new Date(Date.now() + this.token.expires_in * 1000);
|
||||
|
|
@ -473,6 +486,7 @@ export default class Crunchy implements ServiceClass {
|
|||
console.error('No access token!');
|
||||
return false;
|
||||
}
|
||||
|
||||
const profileReqOptions = {
|
||||
headers: {
|
||||
...api.crunchyDefHeader,
|
||||
|
|
@ -498,15 +512,20 @@ export default class Crunchy implements ServiceClass {
|
|||
}
|
||||
|
||||
public async loginWithToken(refreshToken: string) {
|
||||
const basic = atob(api.basic_auth_token);
|
||||
const client = basic.split(':');
|
||||
|
||||
const uuid = randomUUID();
|
||||
const authData = new URLSearchParams({
|
||||
refresh_token: this.token.refresh_token,
|
||||
grant_type: 'refresh_token',
|
||||
//'grant_type': 'etp_rt_cookie',
|
||||
scope: 'offline_access',
|
||||
client_id: client[0],
|
||||
client_secret: client[1],
|
||||
device_id: uuid,
|
||||
device_name: 'iPhone',
|
||||
device_type: 'iPhone 13'
|
||||
device_name: 'emu64xa',
|
||||
device_type: 'ANDROIDTV'
|
||||
}).toString();
|
||||
const authReqOpts: FetchParams = {
|
||||
method: 'POST',
|
||||
|
|
@ -533,6 +552,7 @@ export default class Crunchy implements ServiceClass {
|
|||
api.crunchyDefHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
api.crunchyAuthHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
}
|
||||
|
||||
this.token = await authReq.res.json();
|
||||
this.token.device_id = uuid;
|
||||
this.token.expires = new Date(Date.now() + this.token.expires_in * 1000);
|
||||
|
|
@ -552,17 +572,24 @@ export default class Crunchy implements ServiceClass {
|
|||
} else {
|
||||
//console.info('[WARN] The token has expired compleatly. I will try to refresh the token anyway, but you might have to reauth.');
|
||||
}
|
||||
|
||||
const basic = atob(api.basic_auth_token);
|
||||
const client = basic.split(':');
|
||||
|
||||
const uuid = this.token.device_id || randomUUID();
|
||||
const authData = new URLSearchParams({
|
||||
refresh_token: this.token.refresh_token,
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: this.token.refresh_token,
|
||||
scope: 'offline_access',
|
||||
client_id: client[0],
|
||||
client_secret: client[1],
|
||||
device_id: uuid,
|
||||
device_name: 'iPhone',
|
||||
device_type: 'iPhone 13'
|
||||
device_name: 'emu64xa',
|
||||
device_type: 'ANDROIDTV'
|
||||
}).toString();
|
||||
const authReqOpts: FetchParams = {
|
||||
method: 'POST',
|
||||
headers: { ...api.crunchyAuthHeader, 'ETP-Anonymous-ID': uuid },
|
||||
headers: { ...api.crunchyAuthHeader },
|
||||
body: authData,
|
||||
useProxy: true
|
||||
};
|
||||
|
|
@ -585,6 +612,7 @@ export default class Crunchy implements ServiceClass {
|
|||
api.crunchyDefHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
api.crunchyAuthHeader['User-Agent'] = authReq.headers['User-Agent'];
|
||||
}
|
||||
|
||||
this.token = await authReq.res.json();
|
||||
this.token.device_id = uuid;
|
||||
this.token.expires = new Date(Date.now() + this.token.expires_in * 1000);
|
||||
|
|
@ -1719,7 +1747,7 @@ export default class Crunchy implements ServiceClass {
|
|||
const me = await this.req.getData(api.me, AuthHeaders);
|
||||
if (me.ok && me.res) {
|
||||
const data_me = await me.res.json();
|
||||
const benefits = await this.req.getData(`https://www.crunchyroll.com/subs/v1/subscriptions/${data_me.external_id}/benefits`, AuthHeaders);
|
||||
const benefits = await this.req.getData(`https://beta-api.crunchyroll.com/subs/v1/subscriptions/${data_me.external_id}/benefits`, AuthHeaders);
|
||||
if (benefits.ok && benefits.res) {
|
||||
const data_benefits = (await benefits.res.json()) as { items: { benefit: string }[] };
|
||||
if (data_benefits?.items && !data_benefits.items.find((i) => i.benefit === 'offline_viewing')) {
|
||||
|
|
@ -1763,14 +1791,14 @@ export default class Crunchy implements ServiceClass {
|
|||
if (activeStreamsReq.ok && activeStreamsReq.res) {
|
||||
const data = await activeStreamsReq.res.json();
|
||||
for (const s of data.items) {
|
||||
await this.req.getData(`https://www.crunchyroll.com/playback/v1/token/${s.contentId}/${s.token}`, { ...{ method: 'DELETE' }, ...AuthHeaders });
|
||||
await this.req.getData(`https://cr-play-service.prd.crunchyrollsvc.com/v1/token/${s.contentId}/${s.token}`, { ...{ method: 'DELETE' }, ...AuthHeaders });
|
||||
}
|
||||
console.warn(`Killed ${data.items?.length ?? 0} Sessions`);
|
||||
}
|
||||
}
|
||||
|
||||
const videoPlaybackReq = await this.req.getData(
|
||||
`https://www.crunchyroll.com/playback/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyVideoPlayStreams['androidtv']}/play?queue=0`,
|
||||
`https://cr-play-service.prd.crunchyrollsvc.com/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyVideoPlayStreams['androidtv']}/play?queue=0`,
|
||||
AuthHeaders
|
||||
);
|
||||
if (!videoPlaybackReq.ok || !videoPlaybackReq.res) {
|
||||
|
|
@ -1787,7 +1815,7 @@ export default class Crunchy implements ServiceClass {
|
|||
}
|
||||
if (isDLVideoBypass) {
|
||||
const videoDLReq = await this.req.getData(
|
||||
`https://www.crunchyroll.com/playback/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyVideoPlayStreams[options.vstream]}/download`,
|
||||
`https://cr-play-service.prd.crunchyrollsvc.com/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyVideoPlayStreams[options.vstream]}/download`,
|
||||
AuthHeaders
|
||||
);
|
||||
if (videoDLReq.ok && videoDLReq.res) {
|
||||
|
|
@ -1824,7 +1852,7 @@ export default class Crunchy implements ServiceClass {
|
|||
|
||||
if (!options.cstream && options.vstream !== options.astream && videoStream) {
|
||||
const audioPlaybackReq = await this.req.getData(
|
||||
`https://www.crunchyroll.com/playback/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyAudioPlayStreams[options.astream]}/${isDLAudioBypass ? 'download' : 'play?queue=1'}`,
|
||||
`https://cr-play-service.prd.crunchyrollsvc.com/v3/${currentVersion ? currentVersion.guid : currentMediaId}/${CrunchyAudioPlayStreams[options.astream]}/${isDLAudioBypass ? 'download' : 'play?queue=1'}`,
|
||||
AuthHeaders
|
||||
);
|
||||
if (!audioPlaybackReq.ok || !audioPlaybackReq.res) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// api domains
|
||||
const domain = {
|
||||
cr_www: 'https://www.crunchyroll.com',
|
||||
cr_api: 'https://api.crunchyroll.com',
|
||||
cr_api: 'https://beta-api.crunchyroll.com',
|
||||
cr_playback: 'https://cr-play-service.prd.crunchyrollsvc.com',
|
||||
cr_license: 'https://cr-license-proxy.prd.crunchyrollsvc.com',
|
||||
hd_www: 'https://www.hidive.com',
|
||||
hd_api: 'https://api.hidive.com',
|
||||
hd_new: 'https://dce-frontoffice.imggaming.com'
|
||||
|
|
@ -28,8 +30,9 @@ export type APIType = {
|
|||
cms_auth: string;
|
||||
// Crunchyroll Headers
|
||||
crunchyDefUserAgent: string;
|
||||
crunchyDefHeader: Record<string, string>;
|
||||
crunchyDefHeader: Record<string, any>;
|
||||
crunchyAuthHeader: Record<string, string>;
|
||||
crunchyAuthRefreshHeader: Record<string, string>;
|
||||
// Hidive
|
||||
hd_apikey: string;
|
||||
hd_devName: string;
|
||||
|
|
@ -50,27 +53,28 @@ const api: APIType = {
|
|||
bundlejs: 'https://static.crunchyroll.com/vilos-v2/web/vilos/js/bundle.js',
|
||||
//
|
||||
// Crunchyroll API
|
||||
basic_auth_token: 'bGtlc2k3c25zeTlvb2ptaTJyOWg6LWFHRFhGRk5UbHVaTUxZWEVSbmdOWW5FanZnSDVvZHY=',
|
||||
auth: `${domain.cr_www}/auth/v1/token`,
|
||||
me: `${domain.cr_www}/accounts/v1/me`,
|
||||
profile: `${domain.cr_www}/accounts/v1/me/profile`,
|
||||
search: `${domain.cr_www}/content/v2/discover/search`,
|
||||
content_cms: `${domain.cr_www}/content/v2/cms`,
|
||||
content_music: `${domain.cr_www}/content/v2/music`,
|
||||
browse: `${domain.cr_www}/content/v1/browse`,
|
||||
browse_all_series: `${domain.cr_www}/content/v2/discover/browse`,
|
||||
streaming_sessions: `${domain.cr_www}/playback/v1/sessions/streaming`,
|
||||
drm_widevine: `${domain.cr_www}/license/v1/license/widevine`,
|
||||
drm_playready: `${domain.cr_www}/license/v1/license/playReady`,
|
||||
basic_auth_token: 'bmR0aTZicXlqcm9wNXZnZjF0dnU6elpIcS00SEJJVDlDb2FMcnBPREJjRVRCTUNHai1QNlg=',
|
||||
auth: `${domain.cr_api}/auth/v1/token`,
|
||||
me: `${domain.cr_api}/accounts/v1/me`,
|
||||
profile: `${domain.cr_api}/accounts/v1/me/profile`,
|
||||
search: `${domain.cr_api}/content/v2/discover/search`,
|
||||
content_cms: `${domain.cr_api}/content/v2/cms`,
|
||||
content_music: `${domain.cr_api}/content/v2/music`,
|
||||
browse: `${domain.cr_api}/content/v1/browse`,
|
||||
browse_all_series: `${domain.cr_api}/content/v2/discover/browse`,
|
||||
streaming_sessions: `${domain.cr_playback}/v1/sessions/streaming`,
|
||||
drm_widevine: `https://cr-license-proxy.prd.crunchyrollsvc.com/v1/license/widevine`,
|
||||
drm_playready: `https://cr-license-proxy.prd.crunchyrollsvc.com/v1/license/playReady`,
|
||||
//
|
||||
// Crunchyroll Bucket
|
||||
cms_bucket: `${domain.cr_www}/cms/v2`,
|
||||
cms_auth: `${domain.cr_www}/index/v2`,
|
||||
cms_bucket: `${domain.cr_api}/cms/v2`,
|
||||
cms_auth: `${domain.cr_api}/index/v2`,
|
||||
//
|
||||
// Crunchyroll Headers
|
||||
crunchyDefUserAgent: 'Crunchyroll/ANDROIDTV/3.49.1_22281 (Android 12; en-US; SHIELD Android TV Build/SR1A.211012.001)',
|
||||
crunchyDefUserAgent: 'Crunchyroll/ANDROIDTV/3.50.0_22282 (Android 16; en-US; sdk_gphone64_x86_64)',
|
||||
crunchyDefHeader: {},
|
||||
crunchyAuthHeader: {},
|
||||
crunchyAuthRefreshHeader: {},
|
||||
//
|
||||
//
|
||||
// Hidive
|
||||
|
|
@ -89,7 +93,6 @@ const api: APIType = {
|
|||
|
||||
api.crunchyDefHeader = {
|
||||
'User-Agent': api.crunchyDefUserAgent,
|
||||
Accept: '*/*',
|
||||
'Accept-Encoding': 'gzip',
|
||||
Connection: 'Keep-Alive',
|
||||
Host: 'www.crunchyroll.com'
|
||||
|
|
@ -97,10 +100,19 @@ api.crunchyDefHeader = {
|
|||
|
||||
// set header
|
||||
api.crunchyAuthHeader = {
|
||||
Authorization: `Basic ${api.basic_auth_token}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
||||
Accept: 'application/json',
|
||||
'Accept-Charset': 'UTF-8',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Request-Type': 'SignIn',
|
||||
...api.crunchyDefHeader
|
||||
};
|
||||
|
||||
// set header
|
||||
api.crunchyAuthRefreshHeader = {
|
||||
Accept: 'application/json',
|
||||
'Accept-Charset': 'UTF-8',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
...api.crunchyDefHeader
|
||||
};
|
||||
|
||||
export { domain, api };
|
||||
|
|
|
|||
Loading…
Reference in a new issue