Update Crunchy to new API

This commit is contained in:
AnimeDL 2023-01-22 21:37:53 -08:00
parent 614c382402
commit 64a69d953e
10 changed files with 813 additions and 554 deletions

View file

@ -1,90 +1,87 @@
export interface CrunchyEpisodeList {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: unknown;
__actions__: unknown;
total: number;
items: Item[];
total: number;
data: CrunchyEpisode[];
meta: Meta;
}
export interface Item {
__class__: Class;
__href__: string;
__resource_key__: string;
__links__: Links;
__actions__: unknown;
id: string;
channel_id: ChannelID;
series_id: string;
series_title: string;
series_slug_title: string;
season_id: string;
season_title: string;
season_slug_title: string;
season_number: number;
episode: string;
episode_number: number | null;
sequence_number: number;
production_episode_id: string;
title: string;
slug_title: string;
description: string;
next_episode_id?: string;
next_episode_title?: string;
hd_flag: boolean;
is_mature: boolean;
mature_blocked: boolean;
episode_air_date: string;
is_subbed: boolean;
is_dubbed: boolean;
is_clip: boolean;
seo_title: string;
seo_description: string;
season_tags: string[];
available_offline: boolean;
media_type: Class;
slug: string;
images: Images;
duration_ms: number;
ad_breaks: AdBreak[];
is_premium_only: boolean;
listing_id: string;
subtitle_locales: SubtitleLocale[];
playback?: string;
availability_notes: string;
available_date?: string;
export interface CrunchyEpisode {
next_episode_id: string;
series_id: string;
season_number: number;
next_episode_title: string;
availability_notes: string;
duration_ms: number;
series_slug_title: string;
series_title: string;
is_dubbed: boolean;
versions: Version[] | null;
identifier: string;
sequence_number: number;
eligible_region: Record<unknown>;
availability_starts: Date;
images: Images;
season_id: string;
seo_title: string;
is_premium_only: boolean;
extended_maturity_rating: Record<unknown>;
title: string;
production_episode_id: string;
premium_available_date: Date;
season_title: string;
seo_description: string;
audio_locale: Locale;
id: string;
media_type: MediaType;
availability_ends: Date;
free_available_date: Date;
playback: string;
channel_id: ChannelID;
episode: string;
is_mature: boolean;
listing_id: string;
episode_air_date: Date;
slug: string;
available_date: null;
subtitle_locales: Locale[];
slug_title: string;
available_offline: boolean;
description: string;
is_subbed: boolean;
premium_date: null;
upload_date: Date;
season_slug_title: string;
closed_captions_available: boolean;
episode_number: number;
season_tags: any[];
maturity_ratings: MaturityRating[];
streams_link: string;
mature_blocked: boolean;
is_clip: boolean;
hd_flag: boolean;
hide_season_title?: boolean;
hide_season_number?: boolean;
isSelected?: boolean;
seq_id: string;
}
export enum Class {
Episode = 'episode',
}
export interface Links {
ads: Ads;
'episode/channel': Ads;
'episode/next_episode'?: Ads;
'episode/season': Ads;
'episode/series': Ads;
streams?: Ads;
}
export interface Ads {
href: string;
}
export interface AdBreak {
type: AdBreakType;
offset_ms: number;
}
export enum AdBreakType {
Midroll = 'midroll',
Preroll = 'preroll',
export enum Locale {
enUS = 'en-US',
esLA = 'es-LA',
es419 = 'es-419',
esES = 'es-ES',
ptBR = 'pt-BR',
ptBR = 'pt-BR',
frFR = 'fr-FR',
deDE = 'de-DE',
arME = 'ar-ME',
arSA = 'ar-SA',
itIT = 'it-IT',
ruRU = 'ru-RU',
trTR = 'tr-TR',
hiIN = 'hi-IN',
zhCN = 'zh-CN',
koKR = 'ko-KR',
jaJP = 'ja-JP',
}
export enum ChannelID {
@ -92,28 +89,44 @@ export enum ChannelID {
}
export interface Images {
thumbnail: Array<Thumbnail[]>;
poster_tall?: Array<Image[]>;
poster_wide?: Array<Image[]>;
promo_image?: Array<Image[]>;
thumbnail?: Array<Image[]>;
}
export interface Thumbnail {
width: number;
export interface Image {
height: number;
type: ThumbnailType;
source: string;
type: ImageType;
width: number;
}
export enum ThumbnailType {
export enum ImageType {
PosterTall = 'poster_tall',
PosterWide = 'poster_wide',
PromoImage = 'promo_image',
Thumbnail = 'thumbnail',
}
export enum SubtitleLocale {
ArSA = 'ar-SA',
DeDE = 'de-DE',
EnUS = 'en-US',
Es419 = 'es-419',
EsES = 'es-ES',
FrFR = 'fr-FR',
ItIT = 'it-IT',
PtBR = 'pt-BR',
RuRU = 'ru-RU',
export enum MaturityRating {
Tv14 = 'TV-14',
}
export enum MediaType {
Episode = 'episode',
}
export interface Version {
audio_locale: Locale;
guid: string;
is_premium_only: boolean;
media_guid: string;
original: boolean;
season_guid: string;
variant: string;
}
export interface Meta {
versions_considered: boolean;
}

View file

@ -1,81 +1,37 @@
// Generated by https://quicktype.io
export interface CrunchySearch {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: CrunchySearchLinks;
__actions__: unknown;
total: number;
items: CrunchySearchItem[];
total: number;
data: CrunchySearchData[];
meta: Record<string, unknown>;
}
export interface CrunchySearchLinks {
continuation?: Continuation;
}
export interface Continuation {
href: string;
export interface CrunchySearchData {
type: string;
count: number;
items: CrunchySearchItem[];
}
export interface CrunchySearchItem {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: CrunchySearchLinks;
__actions__: unknown;
type: string;
total: number;
items: ItemItem[];
}
export interface ItemItem {
__actions__: unknown;
__class__: Class;
__href__: string;
__links__: PurpleLinks;
channel_id: ChannelID;
description: string;
external_id: string;
id: string;
images: Images;
linked_resource_key: string;
new: boolean;
new_content: boolean;
promo_description: string;
promo_title: string;
search_metadata: SearchMetadata;
series_metadata?: SeriesMetadata;
slug: string;
slug_title: string;
title: string;
type: ItemType;
episode_metadata?: EpisodeMetadata;
playback?: string;
isSelected?: boolean;
season_number?: string;
is_premium_only?: boolean;
hide_metadata?: boolean;
seq_id?: string;
f_num?: string;
s_num?: string;
ep_num?: string;
last_public?: string;
subtitle_locales?: string[];
availability_notes?: string
}
export enum Class {
Panel = 'panel',
}
export interface PurpleLinks {
resource: Continuation;
'resource/channel': Continuation;
'episode/season'?: Continuation;
'episode/series'?: Continuation;
streams?: Continuation;
title: string;
images: Images;
series_metadata?: SeriesMetadata;
promo_description: string;
external_id: string;
slug: string;
new: boolean;
slug_title: string;
channel_id: ChannelID;
description: string;
linked_resource_key: string;
type: ItemType;
id: string;
promo_title: string;
search_metadata: SearchMetadata;
movie_listing_metadata?: MovieListingMetadata;
playback?: string;
streams_link?: string;
episode_metadata?: EpisodeMetadata;
}
export enum ChannelID {
@ -83,83 +39,146 @@ export enum ChannelID {
}
export interface EpisodeMetadata {
ad_breaks: AdBreak[];
availability_notes: string;
available_offline: boolean;
duration_ms: number;
episode: string;
episode_air_date: string;
episode_number: number;
is_clip: boolean;
is_dubbed: boolean;
is_mature: boolean;
is_premium_only: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
season_id: string;
season_number: number;
season_slug_title: string;
season_title: string;
sequence_number: number;
series_id: string;
series_slug_title: string;
series_title: string;
subtitle_locales: string[];
tenant_categories?: TenantCategory[];
available_date?: string;
free_available_date?: string;
audio_locale: Locale;
availability_ends: Date;
availability_notes: string;
availability_starts: Date;
available_date: null;
available_offline: boolean;
closed_captions_available: boolean;
duration_ms: number;
eligible_region: string[];
episode: string;
episode_air_date: Date;
episode_number: number;
extended_maturity_rating: Record<unknown>;
free_available_date: Date;
identifier: string;
is_clip: boolean;
is_dubbed: boolean;
is_mature: boolean;
is_premium_only: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: MaturityRating[];
premium_available_date: Date;
premium_date: null;
season_id: string;
season_number: number;
season_slug_title: string;
season_title: string;
sequence_number: number;
series_id: string;
series_slug_title: string;
series_title: string;
subtitle_locales: Locale[];
upload_date: Date;
versions: Version[] | null;
tenant_categories?: string[];
}
export interface AdBreak {
offset_ms: number;
type: AdBreakType;
export enum Locale {
enUS = 'en-US',
esLA = 'es-LA',
es419 = 'es-419',
esES = 'es-ES',
ptBR = 'pt-BR',
ptBR = 'pt-BR',
frFR = 'fr-FR',
deDE = 'de-DE',
arME = 'ar-ME',
arSA = 'ar-SA',
itIT = 'it-IT',
ruRU = 'ru-RU',
trTR = 'tr-TR',
hiIN = 'hi-IN',
zhCN = 'zh-CN',
koKR = 'ko-KR',
jaJP = 'ja-JP',
}
export enum AdBreakType {
Midroll = 'midroll',
Preroll = 'preroll',
export enum MaturityRating {
Tv14 = 'TV-14',
TvMa = 'TV-MA',
}
export enum TenantCategory {
Action = 'Action',
Drama = 'Drama',
SciFi = 'Sci-Fi',
export interface Version {
audio_locale: Locale;
guid: string;
is_premium_only: boolean;
media_guid: string;
original: boolean;
season_guid: string;
variant: string;
}
export interface Images {
poster_tall?: Array<PosterTall[]>;
poster_wide?: Array<PosterTall[]>;
thumbnail?: Array<PosterTall[]>;
poster_tall?: Array<Image[]>;
poster_wide?: Array<Image[]>;
promo_image?: Array<Image[]>;
thumbnail?: Array<Image[]>;
}
export interface PosterTall {
export interface Image {
height: number;
source: string;
type: PosterTallType;
type: ImageType;
width: number;
}
export enum PosterTallType {
export enum ImageType {
PosterTall = 'poster_tall',
PosterWide = 'poster_wide',
PromoImage = 'promo_image',
Thumbnail = 'thumbnail',
}
export interface MovieListingMetadata {
availability_notes: string;
available_date: null;
available_offline: boolean;
duration_ms: number;
extended_description: string;
extended_maturity_rating: Record<unknown>;
first_movie_id: string;
free_available_date: Date;
is_dubbed: boolean;
is_mature: boolean;
is_premium_only: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
movie_release_year: number;
premium_available_date: Date;
premium_date: null;
subtitle_locales: any[];
tenant_categories: string[];
}
export interface SearchMetadata {
score: number;
}
export interface SeriesMetadata {
availability_notes: string;
episode_count: number;
extended_description: string;
is_dubbed: boolean;
is_mature: boolean;
is_simulcast: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
season_count: number;
tenant_categories: TenantCategory[];
audio_locales: Locale[];
availability_notes: string;
episode_count: number;
extended_description: string;
extended_maturity_rating: Record<unknown>;
is_dubbed: boolean;
is_mature: boolean;
is_simulcast: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: MaturityRating[];
season_count: number;
series_launch_year: number;
subtitle_locales: Locale[];
tenant_categories?: string[];
}
export enum ItemType {
Episode = 'episode',
MovieListing = 'movie_listing',
Series = 'series',
}

View file

@ -56,8 +56,7 @@ export type CrunchyEpMeta = {
mediaId: string,
lang?: LanguageItem,
playback?: string,
streams?: string,
videoStreams?: string
versions?: EpisodeVersion[] | null
}[],
seasonTitle: string,
episodeNumber: string,
@ -66,7 +65,7 @@ export type CrunchyEpMeta = {
season: number,
showID: string,
e: string,
image: string
image: string,
}
export type DownloadedMedia = {
@ -95,52 +94,85 @@ export type ParseItem = {
ep_num?: string
last_public?: string,
subtitle_locales?: string[],
availability_notes?: string
availability_notes?: string,
identifier?: string,
versions?: Version[] | null,
}
export interface SeriesSearch {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: Actions;
__actions__: Actions;
total: number;
items: SeriesSearchItem[];
total: number;
data: SeriesSearchItem[];
meta: Meta;
}
export interface SeriesSearchItem {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: Links;
__actions__: string[];
id: string;
channel_id: string;
title: string;
slug_title: string;
series_id: string;
season_number: number;
is_complete: boolean;
description: string;
keywords: any[];
season_tags: string[];
images: Actions;
is_mature: boolean;
mature_blocked: boolean;
is_subbed: boolean;
is_dubbed: boolean;
is_simulcast: boolean;
seo_title: string;
seo_description: string;
availability_notes: string;
description: string;
seo_description: string;
number_of_episodes: number;
is_dubbed: boolean;
identifier: string;
channel_id: string;
slug_title: string;
season_sequence_number: number;
season_tags: string[];
extended_maturity_rating: Record<unknown>;
is_mature: boolean;
audio_locale: string;
season_number: number;
images: Record<unknown>;
mature_blocked: boolean;
versions: Version[];
title: string;
is_subbed: boolean;
id: string;
audio_locales: string[];
subtitle_locales: string[];
availability_notes: string;
series_id: string;
season_display_number: string;
is_complete: boolean;
keywords: any[];
maturity_ratings: string[];
is_simulcast: boolean;
seo_title: string;
}
export interface Version {
audio_locale: Locale;
guid: string;
original: boolean;
variant: string;
}
export interface Links {
'season/channel': Season;
'season/episodes': Season;
'season/series': Season;
export interface EpisodeVersion {
audio_locale: Locale;
guid: string;
is_premium_only: boolean;
media_guid: string;
original: boolean;
season_guid: string;
variant: string;
}
export interface Season {
href: string;
export enum Locale {
enUS = 'en-US',
esLA = 'es-LA',
es419 = 'es-419',
esES = 'es-ES',
ptBR = 'pt-BR',
ptBR = 'pt-BR',
frFR = 'fr-FR',
deDE = 'de-DE',
arME = 'ar-ME',
arSA = 'ar-SA',
itIT = 'it-IT',
ruRU = 'ru-RU',
trTR = 'tr-TR',
hiIN = 'hi-IN',
zhCN = 'zh-CN',
koKR = 'ko-KR',
jaJP = 'ja-JP',
}
export interface Meta {
versions_considered: boolean;
}

238
@types/objectInfo.d.ts vendored
View file

@ -1,93 +1,181 @@
// Generated by https://quicktype.io
export interface ObjectInfo {
__class__: string;
__href__: string;
__resource_key__: string;
__links__: unknown;
__actions__: unknown;
total: number;
items: Item[];
}
export interface Item {
__class__: string;
__href__: string;
__links__: Links;
__actions__: unknown;
id: string;
external_id: string;
channel_id: string;
title: string;
description: string;
promo_title: string;
promo_description: string;
type: string;
slug: string;
slug_title: string;
images: Images;
episode_metadata: EpisodeMetadata;
playback: string;
linked_resource_key: string;
type: string;
s_num?: string;
f_num?: string;
movie_metadata?: {
movie_listing_id: string;
movie_listing_title: string
};
isSelected?: boolean
total: number;
data: CrunchyObject[];
meta: Record<unknown>;
}
export interface Links {
'episode/season': EpisodeSeason;
'episode/series': EpisodeSeason;
resource: EpisodeSeason;
'resource/channel': EpisodeSeason;
streams: EpisodeSeason;
}
export interface EpisodeSeason {
href: string;
export interface CrunchyObject {
channel_id: string;
slug: string;
images: Images;
linked_resource_key: string;
description: string;
promo_description: string;
external_id: string;
title: string;
series_metadata?: SeriesMetadata;
id: string;
slug_title: string;
type: string;
promo_title: string;
movie_listing_metadata?: MovieListingMetadata;
playback?: string;
episode_metadata?: EpisodeMetadata;
streams_link?: string;
season_metadata?: SeasonMetadata;
isSelected?: boolean;
f_num: string;
s_num: string;
}
export interface EpisodeMetadata {
series_id: string;
series_title: string;
series_slug_title: string;
season_id: string;
season_title: string;
season_slug_title: string;
season_number: number;
episode_number: number;
episode: string;
sequence_number: number;
duration_ms: number;
ad_breaks: AdBreak[];
episode_air_date: string;
is_premium_only: boolean;
is_mature: boolean;
mature_blocked: boolean;
is_subbed: boolean;
is_dubbed: boolean;
is_clip: boolean;
available_offline: boolean;
maturity_ratings: string[];
subtitle_locales: string[];
availability_notes: string;
audio_locale: Locale;
availability_ends: Date;
availability_notes: string;
availability_starts: Date;
available_date: null;
available_offline: boolean;
closed_captions_available: boolean;
duration_ms: number;
eligible_region: string;
episode: string;
episode_air_date: Date;
episode_number: number;
extended_maturity_rating: Record<unknown>;
free_available_date: Date;
identifier: string;
is_clip: boolean;
is_dubbed: boolean;
is_mature: boolean;
is_premium_only: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
premium_available_date: Date;
premium_date: null;
season_id: string;
season_number: number;
season_slug_title: string;
season_title: string;
sequence_number: number;
series_id: string;
series_slug_title: string;
series_title: string;
subtitle_locales: Locale[];
tenant_categories?: string[];
upload_date: Date;
versions: EpisodeMetadataVersion[];
}
export interface AdBreak {
type: string;
offset_ms: number;
export interface EpisodeMetadataVersion {
audio_locale: Locale;
guid: string;
is_premium_only: boolean;
media_guid: string;
original: boolean;
season_guid: string;
variant: string;
}
export interface Images {
thumbnail: Array<Thumbnail[]>;
poster_tall?: Array<Image[]>;
poster_wide?: Array<Image[]>;
promo_image?: Array<Image[]>;
thumbnail?: Array<Image[]>;
}
export interface Thumbnail {
width: number;
export interface Image {
height: number;
type: string;
source: string;
type: ImageType;
width: number;
}
export enum ImageType {
PosterTall = 'poster_tall',
PosterWide = 'poster_wide',
PromoImage = 'promo_image',
Thumbnail = 'thumbnail',
}
export interface MovieListingMetadata {
availability_notes: string;
available_date: null;
available_offline: boolean;
duration_ms: number;
extended_description: string;
extended_maturity_rating: Record<unknown>;
first_movie_id: string;
free_available_date: Date;
is_dubbed: boolean;
is_mature: boolean;
is_premium_only: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
movie_release_year: number;
premium_available_date: Date;
premium_date: null;
subtitle_locales: Locale[];
tenant_categories: string[];
}
export interface SeasonMetadata {
audio_locale: Locale;
audio_locales: Locale[];
extended_maturity_rating: Record<unknown>;
identifier: string;
is_mature: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
season_display_number: string;
season_sequence_number: number;
subtitle_locales: Locale[];
versions: SeasonMetadataVersion[];
}
export interface SeasonMetadataVersion {
audio_locale: Locale;
guid: string;
original: boolean;
variant: string;
}
export interface SeriesMetadata {
audio_locales: Locale[];
availability_notes: string;
episode_count: number;
extended_description: string;
extended_maturity_rating: Record<unknown>;
is_dubbed: boolean;
is_mature: boolean;
is_simulcast: boolean;
is_subbed: boolean;
mature_blocked: boolean;
maturity_ratings: string[];
season_count: number;
series_launch_year: number;
subtitle_locales: Locale[];
tenant_categories?: string[];
}
export enum Locale {
enUS = 'en-US',
esLA = 'es-LA',
es419 = 'es-419',
esES = 'es-ES',
ptBR = 'pt-BR',
ptBR = 'pt-BR',
frFR = 'fr-FR',
deDE = 'de-DE',
arME = 'ar-ME',
arSA = 'ar-SA',
itIT = 'it-IT',
ruRU = 'ru-RU',
trTR = 'tr-TR',
hiIN = 'hi-IN',
zhCN = 'zh-CN',
koKR = 'ko-KR',
jaJP = 'ja-JP',
}

View file

@ -1,34 +1,120 @@
// Generated by https://quicktype.io
export interface PlaybackData {
audio_locale: string;
subtitles: { [key: string]: Subtitle };
streams: { [key: string]: { [key: string]: Stream } };
QoS: QoS;
total: number;
data: { [key: string]: { [key: string]: StreamDetails } };
meta: Meta;
}
export interface QoS {
region: string;
cloudFrontRequestId: string;
lambdaRunTime: number;
export interface StreamList {
download_hls: Streams;
drm_adaptive_hls: Streams;
multitrack_adaptive_hls_v2: Streams;
vo_adaptive_hls: Streams;
vo_drm_adaptive_hls: Streams;
adaptive_hls: Streams;
drm_download_dash: Streams;
drm_download_hls: Streams;
drm_multitrack_adaptive_hls_v2: Streams;
vo_drm_adaptive_dash: Streams;
adaptive_dash: Streams;
urls: Streams;
vo_adaptive_dash: Streams;
download_dash: Streams;
drm_adaptive_dash: Streams;
}
export interface Stream {
hardsub_locale: string;
export interface Streams {
'': StreamDetails;
'en-US'?: StreamDetails;
'es-LA'?: StreamDetails;
'es-419'?: StreamDetails;
'es-ES'?: StreamDetails;
'pt-BR'?: StreamDetails;
'pt-BR'?: StreamDetails;
'fr-FR'?: StreamDetails;
'de-DE'?: StreamDetails;
'ar-ME'?: StreamDetails;
'ar-SA'?: StreamDetails;
'it-IT'?: StreamDetails;
'ru-RU'?: StreamDetails;
'tr-TR'?: StreamDetails;
'hi-IN'?: StreamDetails;
'zh-CN'?: StreamDetails;
'ko-KR'?: StreamDetails;
'ja-JP'?: StreamDetails;
}
export interface StreamDetails {
hardsub_locale: Locale;
url: string;
vcodec: Vcodec;
hardsub_lang?: string;
audio_lang?: string;
type?: string;
}
export enum Vcodec {
H264 = 'h264',
export interface Meta {
media_id: string;
subtitles: Subtitles;
bifs: string[];
versions: Version[];
audio_locale: Locale;
closed_captions: Record<unknown>;
captions: Record<unknown>;
}
export interface Subtitle {
export interface Subtitles {
'': SubtitleInfo;
'en-US'?: SubtitleInfo;
'es-LA'?: SubtitleInfo;
'es-419'?: SubtitleInfo;
'es-ES'?: SubtitleInfo;
'pt-BR'?: SubtitleInfo;
'pt-BR'?: SubtitleInfo;
'fr-FR'?: SubtitleInfo;
'de-DE'?: SubtitleInfo;
'ar-ME'?: SubtitleInfo;
'ar-SA'?: SubtitleInfo;
'it-IT'?: SubtitleInfo;
'ru-RU'?: SubtitleInfo;
'tr-TR'?: SubtitleInfo;
'hi-IN'?: SubtitleInfo;
'zh-CN'?: SubtitleInfo;
'ko-KR'?: SubtitleInfo;
'ja-JP'?: SubtitleInfo;
}
export interface SubtitleInfo {
format: string;
locale: Locale;
url: string;
format: string;
}
export interface Version {
audio_locale: Locale;
guid: string;
is_premium_only: boolean;
media_guid: string;
original: boolean;
season_guid: string;
variant: string;
}
export enum Locale {
default = '',
enUS = 'en-US',
esLA = 'es-LA',
es419 = 'es-419',
esES = 'es-ES',
ptBR = 'pt-BR',
ptBR = 'pt-BR',
frFR = 'fr-FR',
deDE = 'de-DE',
arME = 'ar-ME',
arSA = 'ar-SA',
itIT = 'it-IT',
ruRU = 'ru-RU',
trTR = 'tr-TR',
hiIN = 'hi-IN',
zhCN = 'zh-CN',
koKR = 'ko-KR',
jaJP = 'ja-JP',
}

View file

@ -30,7 +30,7 @@ export type sxItem = {
import { domain, api } from './modules/module.api-urls';
import * as reqModule from './modules/module.req';
import { CrunchySearch } from './@types/crunchySearch';
import { CrunchyEpisodeList, Item } from './@types/crunchyEpisodeList';
import { CrunchyEpisodeList, CrunchyEpisode } from './@types/crunchyEpisodeList';
import { CrunchyDownloadOptions, CrunchyEpMeta, CrunchyMuxOptions, CurnchyMultiDownload, DownloadedMedia, ParseItem, SeriesSearch, SeriesSearchItem } from './@types/crunchyTypes';
import { ObjectInfo } from './@types/objectInfo';
import parseFileName, { Variable } from './modules/module.filename';
@ -340,6 +340,7 @@ export default class Crunchy implements ServiceClass {
},
useProxy: true
};
const searchStart = data.page ? (data.page-1)*5 : 0;
const searchParams = new URLSearchParams({
q: data.search,
n: '5',
@ -347,7 +348,7 @@ export default class Crunchy implements ServiceClass {
type: data['search-type'] ?? getDefault('search-type', this.cfg.cli),
locale: data['search-locale'] ?? getDefault('search-locale', this.cfg.cli),
}).toString();
const searchReq = await this.req.getData(`${api.beta_search}?${searchParams}`, searchReqOpts);
const searchReq = await this.req.getData(`${api.search}?${searchParams}`, searchReqOpts);
if(!searchReq.ok || ! searchReq.res){
console.log('[ERROR] Search FAILED!');
return { isOk: false, reason: new Error('Search failed. No more information provided') };
@ -364,17 +365,16 @@ export default class Crunchy implements ServiceClass {
'movie_listing': 'Found movie lists',
'episode': 'Found episodes'
};
for(const search_item of searchResults.items){
for(const search_item of searchResults.data){
console.log('[INFO] %s:', searchTypesInfo[search_item.type as keyof typeof searchTypesInfo]);
// calculate pages
const itemPad = parseInt(new URL(search_item.__href__, domain.api_beta).searchParams.get('start') || '');
const pageCur = itemPad > 0 ? Math.ceil(itemPad/5) + 1 : 1;
const pageMax = Math.ceil(search_item.total/5);
const pageCur = searchStart > 0 ? Math.ceil(searchStart/5) + 1 : 1;
const pageMax = Math.ceil(search_item.count/5);
// pages per category
if(search_item.total < 1){
if(search_item.count < 1){
console.log(' [INFO] Nothing Found...');
}
if(search_item.total > 0){
if(search_item.count > 0){
if(pageCur > pageMax){
console.log(' [INFO] Last page is %s...', pageMax);
continue;
@ -382,10 +382,10 @@ export default class Crunchy implements ServiceClass {
for(const item of search_item.items){
await this.logObject(item);
}
console.log(` [INFO] Total results: ${search_item.total} (Page: ${pageCur}/${pageMax})`);
console.log(` [INFO] Total results: ${search_item.count} (Page: ${pageCur}/${pageMax})`);
}
}
const toSend = searchResults.items.filter(a => a.type === 'series' || a.type === 'movie_listing');
const toSend = searchResults.data.filter(a => a.type === 'series' || a.type === 'movie_listing');
return { isOk: true, value: toSend.map(a => {
return a.items.map((a): SearchResponseItem => {
const images = (a.images.poster_tall ?? [[ { source: '/notFound.png' } ]])[0];
@ -426,23 +426,39 @@ export default class Crunchy implements ServiceClass {
tMetadata = item.type + '_metadata',
iMetadata = (Object.prototype.hasOwnProperty.call(item, tMetadata) ? item[tMetadata as keyof ParseItem] : item) as Record<string, any>,
iTitle = [ item.title ];
// set object booleans
let iType = item.type;
const audio_languages = [];
// set object booleans
if(iMetadata.duration_ms){
oBooleans.push(shlp.formatTime(iMetadata.duration_ms/1000));
}
if(iMetadata.is_simulcast){
if(iMetadata.is_simulcast) {
oBooleans.push('SIMULCAST');
}
if(iMetadata.is_mature){
if(iMetadata.is_mature) {
oBooleans.push('MATURE');
}
if(iMetadata.is_subbed){
oBooleans.push('SUB');
if (item.versions) {
for(const version of item.versions) {
audio_languages.push(version.audio_locale);
if (version.original) {
oBooleans.push('SUB');
} else {
if (!oBooleans.includes('DUB')) {
oBooleans.push('DUB');
}
}
}
} else {
if(iMetadata.is_subbed){
oBooleans.push('SUB');
}
if(iMetadata.is_dubbed){
oBooleans.push('DUB');
}
}
if(iMetadata.is_dubbed){
oBooleans.push('DUB');
}
if(item.playback && item.type != 'movie_listing'){
if(item.playback && item.type != 'movie_listing') {
oBooleans.push('STREAM');
}
// set object metadata
@ -474,7 +490,25 @@ export default class Crunchy implements ServiceClass {
const showObjectBooleans = oBooleans.length > 0 && !iMetadata.hide_metadata ? true : false;
// make obj ids
const objects_ids = [];
objects_ids.push(oTypes[item.type as keyof typeof oTypes] + ':' + item.id);
if (!iType) {
if (item.identifier !== '') {
const iTypeCheck = item.identifier?.split('|');
if (iTypeCheck) {
if (iTypeCheck[1] == 'M') {
iType = 'movie';
} else if (!iTypeCheck[2]) {
iType = 'season';
} else {
iType = 'episode';
}
} else {
iType = 'series';
}
} else {
iType = 'movie_listing';
}
}
objects_ids.push(oTypes[iType as keyof typeof oTypes] + ':' + item.id);
if(item.seq_id){
objects_ids.unshift(item.seq_id);
}
@ -490,6 +524,7 @@ export default class Crunchy implements ServiceClass {
if(item.ep_num){
objects_ids.push(item.ep_num);
}
// show entry
console.log(
'%s%s[%s] %s%s%s',
@ -507,6 +542,13 @@ export default class Crunchy implements ServiceClass {
if(item.subtitle_locales){
iMetadata.subtitle_locales = item.subtitle_locales;
}
if (item.versions && audio_languages.length > 0) {
console.log(
'%s- Versions: %s',
''.padStart(pad + 2, ' '),
langsData.parseSubtitlesArray(audio_languages)
);
}
if(iMetadata.subtitle_locales && iMetadata.subtitle_locales.length > 0){
console.log(
'%s- Subtitles: %s',
@ -541,41 +583,24 @@ export default class Crunchy implements ServiceClass {
return;
}
// opts
const seriesReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/series/',
id,
'?',
new URLSearchParams({
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const seriesSeasonListReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/seasons?',
new URLSearchParams({
'series_id': id,
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
// reqs
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
// reqs
if(!hideSeriesTitle){
const seriesReq = await this.req.getData(seriesReqOpts);
const seriesReq = await this.req.getData(`${api.cms}/series/${id}?preferred_audio_language=ja-JP`, AuthHeaders);
if(!seriesReq.ok || !seriesReq.res){
console.log('[ERROR] Series Request FAILED!');
return;
}
const seriesData = JSON.parse(seriesReq.res.body);
await this.logObject(seriesData, pad, false);
await this.logObject(seriesData.data[0], pad, false);
}
// seasons list
const seriesSeasonListReq = await this.req.getData(seriesSeasonListReqOpts);
const seriesSeasonListReq = await this.req.getData(`${api.cms}/series/${id}/seasons?preferred_audio_language=ja-JP`, AuthHeaders);
if(!seriesSeasonListReq.ok || !seriesSeasonListReq.res){
console.log('[ERROR] Series Request FAILED!');
return;
@ -586,7 +611,7 @@ export default class Crunchy implements ServiceClass {
console.log('[INFO] Series is empty!');
return;
}
for(const item of seasonsList.items){
for(const item of seasonsList.data){
await this.logObject(item, pad+2);
}
}
@ -661,38 +686,26 @@ export default class Crunchy implements ServiceClass {
console.log('[ERROR] Authentication required!');
return { isOk: false, reason: new Error('Authentication required') };
}
const showInfoReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/seasons/',
id,
'?',
new URLSearchParams({
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const showInfoReq = await this.req.getData(showInfoReqOpts);
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
//get show info
const showInfoReq = await this.req.getData(`${api.cms}/seasons/${id}?preferred_audio_language=ja-JP`, AuthHeaders);
if(!showInfoReq.ok || !showInfoReq.res){
console.log('[ERROR] Show Request FAILED!');
return { isOk: false, reason: new Error('Show request failed. No more information provided.') };
}
const showInfo = JSON.parse(showInfoReq.res.body);
this.logObject(showInfo, 0);
const reqEpsListOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/episodes?',
new URLSearchParams({
'season_id': id,
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const reqEpsList = await this.req.getData(reqEpsListOpts);
//get episode info
const reqEpsList = await this.req.getData(`${api.cms}/seasons/${id}/episodes?preferred_audio_language=ja-JP`, AuthHeaders);
if(!reqEpsList.ok || !reqEpsList.res){
console.log('[ERROR] Episode List Request FAILED!');
return { isOk: false, reason: new Error('Episode List request failed. No more information provided.') };
@ -713,7 +726,7 @@ export default class Crunchy implements ServiceClass {
const doEpsFilter = parseSelect(e as string);
const selectedMedia: CrunchyEpMeta[] = [];
episodeList.items.forEach((item) => {
episodeList.data.forEach((item) => {
item.hide_season_title = true;
if(item.season_title == '' && item.series_title != ''){
item.season_title = item.series_title;
@ -743,7 +756,9 @@ export default class Crunchy implements ServiceClass {
const epMeta: CrunchyEpMeta = {
data: [
{
mediaId: item.id
mediaId: item.id,
versions: null,
lang: langsData.languages.find(a => a.code == yargs.appArgv(this.cfg.cli).dubLang[0])
}
],
seasonTitle: item.season_title,
@ -756,10 +771,10 @@ export default class Crunchy implements ServiceClass {
image: images[Math.floor(images.length / 2)].source
};
if(item.playback){
epMeta.data[0].playback = item.playback;
epMeta.data[0].playback = item.streams_link;
}
if(item.__links__.streams?.href){
epMeta.data[0].streams = item.__links__.streams.href;
if (item.versions) {
epMeta.data[0].versions = item.versions;
}
// find episode numbers
if((but && item.playback && !doEpsFilter.isSelected([selEpId, item.id])) || (all && item.playback) || (!but && doEpsFilter.isSelected([selEpId, item.id]) && !item.isSelected && item.playback)){
@ -807,22 +822,18 @@ export default class Crunchy implements ServiceClass {
return;
}
// node crunchy-beta -e G6497Z43Y,GRZXCMN1W,G62PEZ2E6,G25FVGDEK,GZ7UVPVX5
// node index.js --service crunchy -e G6497Z43Y,GRZXCMN1W,G62PEZ2E6,G25FVGDEK,GZ7UVPVX5
console.log('[INFO] Requested object ID: %s', doEpsFilter.values.join(', '));
const objectReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/objects/',
doEpsFilter.values.join(','),
'?',
new URLSearchParams({
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const objectReq = await this.req.getData(objectReqOpts);
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
// reqs
const objectReq = await this.req.getData(`${api.cms}/objects/${doEpsFilter.values.join(',')}?preferred_audio_language=ja-JP`, AuthHeaders);
if(!objectReq.ok || !objectReq.res){
console.log('[ERROR] Objects Request FAILED!');
if(objectReq.error && objectReq.error.res && objectReq.error.res.body){
@ -841,44 +852,43 @@ export default class Crunchy implements ServiceClass {
const selectedMedia = [];
for(const item of objectInfo.items){
for(const item of objectInfo.data){
if(item.type != 'episode' && item.type != 'movie'){
await this.logObject(item, 2, true, false);
continue;
}
const epMeta: Partial<CrunchyEpMeta> = {};
switch (item.type) {
case 'episode':
epMeta.data = [];
if (item.episode_metadata) {
item.s_num = 'S:' + item.episode_metadata.season_id;
epMeta.data = [
{
mediaId: 'E:'+ item.id
mediaId: 'E:'+ item.id,
versions: item.episode_metadata.versions
}
];
epMeta.seasonTitle = item.episode_metadata.season_title;
epMeta.episodeNumber = item.episode_metadata.episode;
epMeta.episodeTitle = item.title;
break;
case 'movie':
item.f_num = 'F:' + item.movie_metadata?.movie_listing_id;
} else if (item.movie_listing_metadata) {
item.f_num = 'F:' + item.id;
epMeta.data = [
{
mediaId: 'M:'+ item.id
}
];
epMeta.seasonTitle = item.movie_metadata?.movie_listing_title;
epMeta.seasonTitle = item.title;
epMeta.episodeNumber = 'Movie';
epMeta.episodeTitle = item.title;
break;
}
if(item.__links__.streams.href){
epMeta.data[0].streams = item.__links__.streams.href;
if(item.playback) {
epMeta.data[0].playback = item.streams_link;
selectedMedia.push(epMeta);
item.isSelected = true;
}
await this.logObject(item, 2);
}
console.log();
return selectedMedia;
}
@ -910,31 +920,30 @@ export default class Crunchy implements ServiceClass {
let dlFailed = false;
let dlVideoOnce = false; // Variable to save if best selected video quality was downloaded
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
for (const mMeta of medias.data) {
if(mMeta.streams) {
mMeta.videoStreams = [
domain.api_beta,
mMeta.streams,
'?',
new URLSearchParams({
streams: 'all',
textType: 'all',
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
// console.log(mMeta.vstreams);
mMeta.playback = mMeta.videoStreams;
console.log(`[INFO] Requesting: [${mMeta.mediaId}] ${mediaName}`);
//Get Media GUID
let mediaId = mMeta.mediaId;
if (mMeta.versions && mMeta.lang) {
mediaId = mMeta.versions.find(a => a.audio_locale == mMeta.lang?.cr_locale)?.media_guid as string;
}
console.log(`[INFO] Requesting: [${mMeta.mediaId}] ${mediaName}`);
const playbackReq = await this.req.getData(mMeta.playback as string);
let playbackReq = await this.req.getData(`${api.cms}/videos/${mediaId}/streams`, AuthHeaders);
if(!playbackReq.ok || !playbackReq.res){
console.log('[ERROR] Request Stream URLs FAILED!');
return undefined;
console.log('[ERROR] Request Stream URLs FAILED! Attempting fallback');
playbackReq = await this.req.getData(`${domain.api_beta}${mMeta.playback}`, AuthHeaders);
if(!playbackReq.ok || !playbackReq.res){
console.log('[ERROR] Fallback Request Stream URLs FAILED!');
return undefined;
}
}
const pbData = JSON.parse(playbackReq.res.body) as PlaybackData;
@ -956,10 +965,10 @@ export default class Crunchy implements ServiceClass {
let streams = [];
let hsLangs: string[] = [];
const pbStreams = pbData.streams;
const pbStreams = pbData.data[0];
for(const s of Object.keys(pbStreams)){
if(s.match(/hls/) && !s.match(/drm/) && !s.match(/trailer/)){
if(s.match(/hls/) && !s.match(/drm/) && !s.match(/trailer/)) {
const pb = Object.values(pbStreams[s]).map(v => {
v.hardsub_lang = v.hardsub_locale
? langsData.fixAndFindCrLC(v.hardsub_locale).locale
@ -980,8 +989,8 @@ export default class Crunchy implements ServiceClass {
console.log('[WARN] No full streams found!');
return undefined;
}
const audDub = langsData.findLang(langsData.fixLanguageTag(pbData.audio_locale) || '').code;
const audDub = langsData.findLang(langsData.fixLanguageTag(pbData.meta.audio_locale as string) || '').code;
hsLangs = langsData.sortTags(hsLangs);
streams = streams.map((s) => {
@ -990,6 +999,13 @@ export default class Crunchy implements ServiceClass {
s.type = `${s.format}/${s.audio_lang}/${s.hardsub_lang}`;
return s;
});
streams = streams.sort((a, b) => {
if (a.type < b.type) {
return -1;
}
return 0;
});
if(options.hslang != 'none'){
if(hsLangs.indexOf(options.hslang) > -1){
@ -1224,8 +1240,8 @@ export default class Crunchy implements ServiceClass {
}
if(!options.skipsubs && options.dlsubs.indexOf('none') == -1){
if(pbData.subtitles && Object.values(pbData.subtitles).length > 0){
const subsData = Object.values(pbData.subtitles);
if(pbData.meta.subtitles && Object.values(pbData.meta.subtitles).length > 0){
const subsData = Object.values(pbData.meta.subtitles);
const subsDataMapped = subsData.map((s) => {
const subLang = langsData.fixAndFindCrLC(s.locale);
return {
@ -1342,31 +1358,37 @@ export default class Crunchy implements ServiceClass {
}
public async listSeriesID(id: string): Promise<{ list: Episode[], data: Record<string, {
items: Item[];
items: CrunchyEpisode[];
langs: langsData.LanguageItem[];
}>}> {
await this.refreshToken();
let serieshasversions = true;
const parsed = await this.parseSeriesById(id);
if (!parsed)
return { data: {}, list: [] };
const result = this.parseSeriesResult(parsed);
const episodes : Record<string, {
items: Item[],
items: CrunchyEpisode[],
langs: langsData.LanguageItem[]
}> = {};
for(const season of Object.keys(result) as unknown as number[]) {
for (const key of Object.keys(result[season])) {
const s = result[season][key];
(await this.getSeasonDataById(s))?.items.forEach(a => {
if (Object.prototype.hasOwnProperty.call(episodes, `S${a.season_number}E${a.episode_number || a.episode}`)) {
const item = episodes[`S${a.season_number}E${a.episode_number || a.episode}`];
item.items.push(a);
item.langs.push(langsData.languages.find(a => a.code == key) as langsData.LanguageItem);
(await this.getSeasonDataById(s))?.data?.forEach(episode => {
//TODO: fix this
const item = episodes[`S${episode.season_number}E${episode.episode_number || episode.episode}`] = {
items: [] as CrunchyEpisode[],
langs: [] as langsData.LanguageItem[]
};
if (episode.versions) {
for (const version of episode.versions) {
item.items.push(episode);
item.langs.push(langsData.languages.find(a => a.cr_locale == version.audio_locale) as langsData.LanguageItem);
}
} else {
episodes[`S${a.season_number}E${a.episode_number || a.episode}`] = {
items: [a],
langs: [langsData.languages.find(a => a.code == key) as langsData.LanguageItem]
};
serieshasversions = false;
item.items.push(episode);
item.langs.push(langsData.languages.find(a => a.cr_locale == episode.audio_locale) as langsData.LanguageItem);
}
});
}
@ -1397,6 +1419,10 @@ export default class Crunchy implements ServiceClass {
}).join(', ')
}]`);
}
if (!serieshasversions) {
console.log('[WARN] Couldn\'t find versions on some episodes, fell back to old method.');
}
return { data: episodes, list: Object.entries(episodes).map(([key, value]) => {
const images = (value.items[0].images.thumbnail ?? [[ { source: '/notFound.png' } ]])[0];
@ -1434,7 +1460,7 @@ export default class Crunchy implements ServiceClass {
}
public itemSelectMultiDub (eps: Record<string, {
items: Item[],
items: CrunchyEpisode[],
langs: langsData.LanguageItem[]
}>, dubLang: string[], but?: boolean, all?: boolean, e?: string, ) {
const doEpsFilter = parseSelect(e as string);
@ -1461,7 +1487,8 @@ export default class Crunchy implements ServiceClass {
const epMeta: CrunchyEpMeta = {
data: [
{
mediaId: item.id
mediaId: item.id,
versions: item.versions
}
],
seasonTitle: itemE.items.find(a => !a.season_title.match(/\(\w+ Dub\)/))?.season_title ?? itemE.items[0].season_title.replace(/\(\w+ Dub\)/g, '').trimEnd(),
@ -1471,16 +1498,13 @@ export default class Crunchy implements ServiceClass {
season: item.season_number,
showID: item.series_id,
e: epNum,
image: images[Math.floor(images.length / 2)].source
image: images[Math.floor(images.length / 2)].source,
};
if(item.playback){
epMeta.data[0].playback = item.playback;
}
if(item.__links__.streams?.href){
epMeta.data[0].streams = item.__links__.streams.href;
epMeta.data[0].playback = item.streams_link;
}
// find episode numbers
if((item.playback || item.__links__.streams?.href) && ((but && !doEpsFilter.isSelected([epNum, item.id])) || (all || (doEpsFilter.isSelected([epNum, item.id])) && !but))) {
if(item.playback && ((but && !doEpsFilter.isSelected([epNum, item.id])) || (all || (doEpsFilter.isSelected([epNum, item.id])) && !but))) {
if (Object.prototype.hasOwnProperty.call(ret, key)) {
const epMe = ret[key];
epMe.data.push({
@ -1503,17 +1527,29 @@ export default class Crunchy implements ServiceClass {
public parseSeriesResult (seasonsList: SeriesSearch) : Record<number, Record<string, SeriesSearchItem>> {
const ret: Record<number, Record<string, SeriesSearchItem>> = {};
for (const item of seasonsList.items) {
for (const item of seasonsList.data) {
for (const lang of langsData.languages) {
if (!Object.prototype.hasOwnProperty.call(ret, item.season_number))
ret[item.season_number] = {};
const season_number = item.season_number;
//TODO: Implement below code for missing episodes when seasons are the same
/*
let season_number = item.season_number;
const seasondetails = item.identifier.split('|')[1];
//check if episode has no versions and is a cour/movie
if (item.versions && (seasondetails.match('C') || seasondetails.match('M'))) {
//if above conditions are true, make sure all seasons are unique
while (Object.prototype.hasOwnProperty.call(ret, season_number) ? Object.keys(ret[season_number]).length !== 0 : false) {
season_number++;
}
}
*/
if (!Object.prototype.hasOwnProperty.call(ret, season_number))
ret[season_number] = {};
if (item.title.includes(`(${lang.name} Dub)`) || item.title.includes(`(${lang.name})`)) {
ret[item.season_number][lang.code] = item;
ret[season_number][lang.code] = item;
} else if (item.is_subbed && !item.is_dubbed && lang.code == 'jpn') {
ret[item.season_number][lang.code] = item;
ret[season_number][lang.code] = item;
} else if (item.is_dubbed && lang.code === 'eng' && !langsData.languages.some(a => item.title.includes(`(${a.name})`) || item.title.includes(`(${a.name} Dub)`))) { // Dubbed with no more infos will be treated as eng dubs
ret[item.season_number][lang.code] = item;
ret[season_number][lang.code] = item;
}
}
}
@ -1525,19 +1561,16 @@ export default class Crunchy implements ServiceClass {
console.log('[ERROR] Authentication required!');
return;
}
const seriesSeasonListReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/seasons?',
new URLSearchParams({
'series_id': id,
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
// seasons list
const seriesSeasonListReq = await this.req.getData(seriesSeasonListReqOpts);
const seriesSeasonListReq = await this.req.getData(`${api.cms}/series/${id}/seasons?preferred_audio_language=ja-JP`, AuthHeaders);
if(!seriesSeasonListReq.ok || !seriesSeasonListReq.res){
console.log('[ERROR] Series Request FAILED!');
return;
@ -1556,20 +1589,16 @@ export default class Crunchy implements ServiceClass {
console.log('[ERROR] Authentication required!');
return;
}
const showInfoReqOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/seasons/',
item.id,
'?',
new URLSearchParams({
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const showInfoReq = await this.req.getData(showInfoReqOpts);
const AuthHeaders = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
},
useProxy: true
};
//get show info
const showInfoReq = await this.req.getData(`${api.cms}/seasons/${item.id}?preferred_audio_language=ja-JP`, AuthHeaders);
if(!showInfoReq.ok || !showInfoReq.res){
console.log('[ERROR] Show Request FAILED!');
return;
@ -1577,18 +1606,8 @@ export default class Crunchy implements ServiceClass {
const showInfo = JSON.parse(showInfoReq.res.body);
if (log)
this.logObject(showInfo, 0);
const reqEpsListOpts = [
api.beta_cms,
this.cmsToken.cms.bucket,
'/episodes?',
new URLSearchParams({
'season_id': item.id as string,
'Policy': this.cmsToken.cms.policy,
'Signature': this.cmsToken.cms.signature,
'Key-Pair-Id': this.cmsToken.cms.key_pair_id,
}),
].join('');
const reqEpsList = await this.req.getData(reqEpsListOpts);
//get episode info
const reqEpsList = await this.req.getData(`${api.cms}/seasons/${item.id}/episodes?preferred_audio_language=ja-JP`, AuthHeaders);
if(!reqEpsList.ok || !reqEpsList.res){
console.log('[ERROR] Episode List Request FAILED!');
return;

View file

@ -27,7 +27,8 @@ export type APIType = {
beta_authBasicMob: string
beta_profile: string
beta_cmsToken: string
beta_search: string
search: string
cms: string
beta_browse: string
beta_cms: string,
beta_authHeader: Headers,
@ -55,7 +56,8 @@ const api: APIType = {
beta_authBasicMob: 'Basic YTZ5eGxvYW04c2VqaThsZDhldnc6aFQ3d2FjWHhNaURJcDhSNE9kekJybWVoQUtLTEVKUEE=',
beta_profile: `${domain.api_beta}/accounts/v1/me/profile`,
beta_cmsToken: `${domain.api_beta}/index/v2`,
beta_search: `${domain.api_beta}/content/v1/search`,
search: `${domain.api_beta}/content/v2/discover/search`,
cms: `${domain.api_beta}/content/v2/cms`,
beta_browse: `${domain.api_beta}/content/v1/browse`,
beta_cms: `${domain.api_beta}/cms/v2`,
beta_authHeader: {},

View file

@ -212,7 +212,7 @@ const args: TAppArg<boolean|number|string|unknown[]>[] = [
describe: 'Select specific stream',
choices: [1, 2, 3, 4, 5, 6, 7],
default: {
default: 2
default: 1
},
docDescribe: true,
service: 'crunchy',

View file

@ -2,7 +2,7 @@ import shlp from 'sei-helper';
import got, { Headers, Method, Options, ReadError, Response } from 'got';
import cookieFile from './module.cookieFile';
import * as yamlCfg from './module.cfg-loader';
import curlReq from './module.curl-req';
//import curlReq from './module.curl-req';
export type Params = {
method?: Method,
@ -86,7 +86,7 @@ class Req {
}
// try do request
try {
const res = await got(durl.toString(), options) as unknown as Response<T>;
const res = await got(loc, options) as unknown as Response<T>;
return {
ok: true,
res

View file

@ -1,7 +1,7 @@
{
"name": "multi-downloader-nx",
"short_name": "aniDL",
"version": "3.2.0",
"version": "3.3.0",
"description": "Download videos from Funimation or Crunchyroll via cli",
"keywords": [
"download",