mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-03-11 17:45:30 +00:00
100%
This commit is contained in:
parent
8b557abdf1
commit
3c599cd48e
20 changed files with 1646 additions and 1714 deletions
|
|
@ -1,2 +1,3 @@
|
|||
lib
|
||||
/videos/*.ts
|
||||
/videos/*.ts
|
||||
crunchy
|
||||
45
@types/crunchyEpisodeList.d.ts
vendored
45
@types/crunchyEpisodeList.d.ts
vendored
|
|
@ -2,21 +2,18 @@ export interface CrunchyEpisodeList {
|
|||
__class__: string;
|
||||
__href__: string;
|
||||
__resource_key__: string;
|
||||
__links__: Actions;
|
||||
__actions__: Actions;
|
||||
__links__: unknown;
|
||||
__actions__: unknown;
|
||||
total: number;
|
||||
items: Item[];
|
||||
}
|
||||
|
||||
export interface Actions {
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
__class__: Class;
|
||||
__href__: string;
|
||||
__resource_key__: string;
|
||||
__links__: Links;
|
||||
__actions__: Actions;
|
||||
__actions__: unknown;
|
||||
id: string;
|
||||
channel_id: ChannelID;
|
||||
series_id: string;
|
||||
|
|
@ -64,15 +61,15 @@ export interface Item {
|
|||
}
|
||||
|
||||
export enum Class {
|
||||
Episode = "episode",
|
||||
Episode = 'episode',
|
||||
}
|
||||
|
||||
export interface Links {
|
||||
ads: Ads;
|
||||
"episode/channel": Ads;
|
||||
"episode/next_episode"?: Ads;
|
||||
"episode/season": Ads;
|
||||
"episode/series": Ads;
|
||||
'episode/channel': Ads;
|
||||
'episode/next_episode'?: Ads;
|
||||
'episode/season': Ads;
|
||||
'episode/series': Ads;
|
||||
streams?: Ads;
|
||||
}
|
||||
|
||||
|
|
@ -86,12 +83,12 @@ export interface AdBreak {
|
|||
}
|
||||
|
||||
export enum AdBreakType {
|
||||
Midroll = "midroll",
|
||||
Preroll = "preroll",
|
||||
Midroll = 'midroll',
|
||||
Preroll = 'preroll',
|
||||
}
|
||||
|
||||
export enum ChannelID {
|
||||
Crunchyroll = "crunchyroll",
|
||||
Crunchyroll = 'crunchyroll',
|
||||
}
|
||||
|
||||
export interface Images {
|
||||
|
|
@ -106,17 +103,17 @@ export interface Thumbnail {
|
|||
}
|
||||
|
||||
export enum ThumbnailType {
|
||||
Thumbnail = "thumbnail",
|
||||
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",
|
||||
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',
|
||||
}
|
||||
|
|
|
|||
34
@types/crunchySearch.d.ts
vendored
34
@types/crunchySearch.d.ts
vendored
|
|
@ -5,13 +5,11 @@ export interface CrunchySearch {
|
|||
__href__: string;
|
||||
__resource_key__: string;
|
||||
__links__: CrunchySearchLinks;
|
||||
__actions__: Actions;
|
||||
__actions__: unknown;
|
||||
total: number;
|
||||
items: CrunchySearchItem[];
|
||||
}
|
||||
|
||||
export interface Actions {
|
||||
}
|
||||
|
||||
export interface CrunchySearchLinks {
|
||||
continuation?: Continuation;
|
||||
|
|
@ -26,14 +24,14 @@ export interface CrunchySearchItem {
|
|||
__href__: string;
|
||||
__resource_key__: string;
|
||||
__links__: CrunchySearchLinks;
|
||||
__actions__: Actions;
|
||||
__actions__: unknown;
|
||||
type: string;
|
||||
total: number;
|
||||
items: ItemItem[];
|
||||
}
|
||||
|
||||
export interface ItemItem {
|
||||
__actions__: Actions;
|
||||
__actions__: unknown;
|
||||
__class__: Class;
|
||||
__href__: string;
|
||||
__links__: PurpleLinks;
|
||||
|
|
@ -69,19 +67,19 @@ export interface ItemItem {
|
|||
}
|
||||
|
||||
export enum Class {
|
||||
Panel = "panel",
|
||||
Panel = 'panel',
|
||||
}
|
||||
|
||||
export interface PurpleLinks {
|
||||
resource: Continuation;
|
||||
"resource/channel": Continuation;
|
||||
"episode/season"?: Continuation;
|
||||
"episode/series"?: Continuation;
|
||||
'resource/channel': Continuation;
|
||||
'episode/season'?: Continuation;
|
||||
'episode/series'?: Continuation;
|
||||
streams?: Continuation;
|
||||
}
|
||||
|
||||
export enum ChannelID {
|
||||
Crunchyroll = "crunchyroll",
|
||||
Crunchyroll = 'crunchyroll',
|
||||
}
|
||||
|
||||
export interface EpisodeMetadata {
|
||||
|
|
@ -119,14 +117,14 @@ export interface AdBreak {
|
|||
}
|
||||
|
||||
export enum AdBreakType {
|
||||
Midroll = "midroll",
|
||||
Preroll = "preroll",
|
||||
Midroll = 'midroll',
|
||||
Preroll = 'preroll',
|
||||
}
|
||||
|
||||
export enum TenantCategory {
|
||||
Action = "Action",
|
||||
Drama = "Drama",
|
||||
SciFi = "Sci-Fi",
|
||||
Action = 'Action',
|
||||
Drama = 'Drama',
|
||||
SciFi = 'Sci-Fi',
|
||||
}
|
||||
|
||||
export interface Images {
|
||||
|
|
@ -143,9 +141,9 @@ export interface PosterTall {
|
|||
}
|
||||
|
||||
export enum PosterTallType {
|
||||
PosterTall = "poster_tall",
|
||||
PosterWide = "poster_wide",
|
||||
Thumbnail = "thumbnail",
|
||||
PosterTall = 'poster_tall',
|
||||
PosterWide = 'poster_wide',
|
||||
Thumbnail = 'thumbnail',
|
||||
}
|
||||
|
||||
export interface SearchMetadata {
|
||||
|
|
|
|||
16
@types/objectInfo.d.ts
vendored
16
@types/objectInfo.d.ts
vendored
|
|
@ -4,20 +4,16 @@ export interface ObjectInfo {
|
|||
__class__: string;
|
||||
__href__: string;
|
||||
__resource_key__: string;
|
||||
__links__: Actions;
|
||||
__actions__: Actions;
|
||||
__links__: unknown;
|
||||
__actions__: unknown;
|
||||
total: number;
|
||||
items: Item[];
|
||||
}
|
||||
|
||||
export interface Actions {
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
__class__: string;
|
||||
__href__: string;
|
||||
__links__: Links;
|
||||
__actions__: Actions;
|
||||
__actions__: unknown;
|
||||
id: string;
|
||||
external_id: string;
|
||||
channel_id: string;
|
||||
|
|
@ -43,10 +39,10 @@ export interface Item {
|
|||
}
|
||||
|
||||
export interface Links {
|
||||
"episode/season": EpisodeSeason;
|
||||
"episode/series": EpisodeSeason;
|
||||
'episode/season': EpisodeSeason;
|
||||
'episode/series': EpisodeSeason;
|
||||
resource: EpisodeSeason;
|
||||
"resource/channel": EpisodeSeason;
|
||||
'resource/channel': EpisodeSeason;
|
||||
streams: EpisodeSeason;
|
||||
}
|
||||
|
||||
|
|
|
|||
2
@types/playbackData.d.ts
vendored
2
@types/playbackData.d.ts
vendored
|
|
@ -24,7 +24,7 @@ export interface Stream {
|
|||
|
||||
|
||||
export enum Vcodec {
|
||||
H264 = "h264",
|
||||
H264 = 'h264',
|
||||
}
|
||||
|
||||
export interface Subtitle {
|
||||
|
|
|
|||
2
@types/sei-helper.d.ts
vendored
2
@types/sei-helper.d.ts
vendored
|
|
@ -10,6 +10,6 @@ declare module 'sei-helper' {
|
|||
domain: string;
|
||||
secure: boolean;
|
||||
}>
|
||||
}
|
||||
};
|
||||
export function formatTime(time: number): string
|
||||
}
|
||||
1263
crunchy-beta.ts
1263
crunchy-beta.ts
File diff suppressed because it is too large
Load diff
1189
crunchy.ts
Normal file
1189
crunchy.ts
Normal file
File diff suppressed because it is too large
Load diff
11
index.ts
11
index.ts
|
|
@ -1,7 +1,8 @@
|
|||
import { appArgv } from "./modules/module.app-args";
|
||||
import { appArgv } from './modules/module.app-args';
|
||||
import * as yamlCfg from './modules/module.cfg-loader';
|
||||
|
||||
import funimation from './funi'
|
||||
import funimation from './funi';
|
||||
import crunchy from './crunchy';
|
||||
|
||||
(async () => {
|
||||
const cfg = yamlCfg.loadCfg();
|
||||
|
|
@ -9,9 +10,9 @@ import funimation from './funi'
|
|||
const argv = appArgv(cfg.cli);
|
||||
|
||||
if (argv.service === 'funi') {
|
||||
await funimation()
|
||||
await funimation();
|
||||
} else if (argv.service === 'crunchy') {
|
||||
|
||||
await crunchy();
|
||||
}
|
||||
|
||||
})()
|
||||
})();
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Headers } from "got/dist/source";
|
||||
import { Headers } from 'got/dist/source';
|
||||
|
||||
// api domains
|
||||
const domain = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import yargs from 'yargs';
|
||||
import * as langsData from "./module.langsData";
|
||||
import * as langsData from './module.langsData';
|
||||
|
||||
yargs(process.argv.slice(2));
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ const groups = {
|
|||
'fileName': 'Filename Template:',
|
||||
'debug': 'Debug:',
|
||||
'util': 'Utilities:'
|
||||
}
|
||||
};
|
||||
|
||||
export type AvailableFilenameVars = 'title' | 'episode' | 'showTitle' | 'season' | 'width' | 'height' | 'service'
|
||||
|
||||
|
|
@ -46,240 +46,247 @@ const appArgv = (cfg: {
|
|||
};
|
||||
|
||||
const argv = yargs.parserConfiguration({
|
||||
"duplicate-arguments-array": false,
|
||||
"camel-case-expansion": false
|
||||
'duplicate-arguments-array': false,
|
||||
'camel-case-expansion': false
|
||||
})
|
||||
.wrap(yargs.terminalWidth())
|
||||
.usage('Usage: $0 [options]')
|
||||
.help(false).version(false)
|
||||
.option('auth', {
|
||||
group: groups.auth,
|
||||
describe: 'Enter authentication mode',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('dlFonts', {
|
||||
group: groups.fonts,
|
||||
describe: 'Download all required fonts for mkv muxing',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('search', {
|
||||
group: groups.search,
|
||||
alias: 'f',
|
||||
describe: 'Search for an anime',
|
||||
type: 'string'
|
||||
})
|
||||
.option('search-type', {
|
||||
group: groups.search,
|
||||
describe: 'Search type used for crunchyroll',
|
||||
choices: [ '', 'top_results', 'series', 'movie_listing', 'episode' ],
|
||||
default: '',
|
||||
type: 'string',
|
||||
})
|
||||
.option('page', {
|
||||
group: groups.search,
|
||||
alias: 'p',
|
||||
describe: 'Page number for search results',
|
||||
type: 'number',
|
||||
})
|
||||
.option('search-locale', {
|
||||
group: groups.search,
|
||||
describe: 'Search locale used for crunchyroll',
|
||||
choices: langsData.searchLocales,
|
||||
default: '',
|
||||
type: 'string',
|
||||
})
|
||||
.option('new', {
|
||||
group: groups.dl,
|
||||
describe: 'Get last updated series list from crunchyroll',
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('movie-listing', {
|
||||
group: groups.dl,
|
||||
alias: 'flm',
|
||||
describe: 'Get video list by Movie Listing ID',
|
||||
type: 'string',
|
||||
})
|
||||
.option('series', {
|
||||
group: groups.dl,
|
||||
alias: 'srz',
|
||||
describe: 'Get season list by Series ID',
|
||||
type: 'string',
|
||||
})
|
||||
.option('s', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the season ID',
|
||||
type: 'string'
|
||||
})
|
||||
.option('e', {
|
||||
group: groups.dl,
|
||||
alias: 'episode',
|
||||
describe: 'Sets the Episode Number/IDs (comma-separated, hyphen-sequence)',
|
||||
type: 'string',
|
||||
})
|
||||
.option('q', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the quality layer. Use 0 to get the best quality.',
|
||||
default: parseDefault<number>('videoLayer', 7),
|
||||
type: 'number'
|
||||
})
|
||||
.option('x', {
|
||||
group: groups.dl,
|
||||
alias: 'server',
|
||||
describe: 'Select server',
|
||||
choices: [1, 2, 3, 4],
|
||||
default: parseDefault<number>('nServer', 1),
|
||||
type: 'number',
|
||||
})
|
||||
.option('kstream', {
|
||||
group: groups.dl,
|
||||
alias: 'k',
|
||||
describe: 'Select specific stream for crunchyroll',
|
||||
choices: [1, 2, 3, 4, 5, 6, 7],
|
||||
default: parseDefault<number>('kStream', 1),
|
||||
type: 'number',
|
||||
})
|
||||
.option('partsize', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the amount of parts that should be downloaded in paralell',
|
||||
type: 'number',
|
||||
default: parseDefault<number>('partsize', 10)
|
||||
})
|
||||
.option('hslang', {
|
||||
group: groups.dl,
|
||||
describe: 'Download video with specific hardsubs',
|
||||
choices: langsData.subtitleLanguagesFilter.slice(1),
|
||||
default: parseDefault<string>('hsLang', 'none'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('subLang', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the subtitles to download (Funi only)',
|
||||
choices: subLang,
|
||||
default: parseDefault<string[]>('subLang', []),
|
||||
type: 'array'
|
||||
})
|
||||
.option('novids', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading videos',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('noaudio', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading audio',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('nosubs', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading subtitles',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('dub', {
|
||||
group: groups.dl,
|
||||
describe: 'Set languages to download (funi only)',
|
||||
choices: dubLang,
|
||||
default: parseDefault<possibleDubs>('dub', ['enUS']),
|
||||
type: 'array'
|
||||
})
|
||||
.option('dubLang', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the language to download (Crunchy only)',
|
||||
choices: langsData.dubLanguageCodes,
|
||||
default: parseDefault('dubLanguage', langsData.dubLanguageCodes.slice(-1)[0]),
|
||||
type: 'string',
|
||||
})
|
||||
.option('all', {
|
||||
group: groups.dl,
|
||||
describe: 'Used to download all episodes from the show (Funi only)',
|
||||
type: 'boolean',
|
||||
default: parseDefault<boolean>('all', false)
|
||||
})
|
||||
.option('fontSize', {
|
||||
group: groups.dl,
|
||||
describe: 'Used to set the fontsize of the subtitles',
|
||||
default: parseDefault<number>('fontSize', 55),
|
||||
type: 'number'
|
||||
})
|
||||
.option('allSubs', {
|
||||
group: groups.dl,
|
||||
describe: 'If set to true, all available subs will get downloaded (Funi only)',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('allDubs', {
|
||||
group: groups.dl,
|
||||
describe: 'If set to true, all available dubs will get downloaded (Funi only)',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('timeout', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the timeout of all download reqests. Set in millisecods',
|
||||
type: 'number',
|
||||
default: parseDefault('timeout', 60 * 1000)
|
||||
})
|
||||
.option('simul', {
|
||||
group: groups.dl,
|
||||
describe: 'Force downloading simulcast ver. instead of uncut ver. (if uncut ver. available) (Funi only)',
|
||||
default: parseDefault<boolean>('forceSimul', false),
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('mp4', {
|
||||
group: groups.mux,
|
||||
describe: 'Mux video into mp4',
|
||||
default: parseDefault<boolean>('mp4mux', false),
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('skipmux', {
|
||||
group: groups.mux,
|
||||
describe: 'Skip muxing video and subtitles',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('fileName', {
|
||||
group: groups.fileName,
|
||||
describe: `Set the filename template. Use \${variable_name} to insert variables.\nYou may use ${availableFilenameVars
|
||||
.map(a => `'${a}'`).join(', ')} as variables.`,
|
||||
type: 'string',
|
||||
default: parseDefault<string>('fileName', '[${service}] ${showTitle} - ${episode} [${height}p]')
|
||||
})
|
||||
.option('numbers', {
|
||||
group: groups.fileName,
|
||||
describe: `Set how long a number in the title should be at least.\n${[[3, 5, '005'], [2, 1, '01'], [1, 20, '20']]
|
||||
.map(val => `Set in config: ${val[0]}; Episode number: ${val[1]}; Output: ${val[2]}`).join('\n')}`,
|
||||
type: 'number',
|
||||
default: parseDefault<number>('numbers', 2)
|
||||
})
|
||||
.option('nosess', {
|
||||
group: groups.debug,
|
||||
type: 'boolean',
|
||||
default: 'Reset session cookie for testing purposes'
|
||||
})
|
||||
.option('debug', {
|
||||
group: groups.debug,
|
||||
describe: 'Debug mode (tokens may be revield in the console output)',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('nocleanup', {
|
||||
group: groups.util,
|
||||
describe: 'Don\'t delete subtitles and videos after muxing',
|
||||
default: parseDefault<boolean>('noCleanUp', false),
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('help', {
|
||||
alias: 'h',
|
||||
group: 'Help:',
|
||||
describe: 'Show this help',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('service', {
|
||||
group: groups.util,
|
||||
describe: 'Set the service to use',
|
||||
choices: ['funi', 'crunchy'],
|
||||
demandOption: true,
|
||||
default: parseDefault<'crunchy'|'funi'|undefined>('service', undefined)
|
||||
})
|
||||
.parseSync();
|
||||
.wrap(yargs.terminalWidth())
|
||||
.usage('Usage: $0 [options]')
|
||||
.help(false).version(false)
|
||||
.option('auth', {
|
||||
group: groups.auth,
|
||||
describe: 'Enter authentication mode',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('dlFonts', {
|
||||
group: groups.fonts,
|
||||
describe: 'Download all required fonts for mkv muxing',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('search', {
|
||||
group: groups.search,
|
||||
alias: 'f',
|
||||
describe: 'Search for an anime',
|
||||
type: 'string'
|
||||
})
|
||||
.option('search-type', {
|
||||
group: groups.search,
|
||||
describe: 'Search type used for crunchyroll',
|
||||
choices: [ '', 'top_results', 'series', 'movie_listing', 'episode' ],
|
||||
default: '',
|
||||
type: 'string',
|
||||
})
|
||||
.option('page', {
|
||||
group: groups.search,
|
||||
alias: 'p',
|
||||
describe: 'Page number for search results',
|
||||
type: 'number',
|
||||
})
|
||||
.option('search-locale', {
|
||||
group: groups.search,
|
||||
describe: 'Search locale used for crunchyroll',
|
||||
choices: langsData.searchLocales,
|
||||
default: '',
|
||||
type: 'string',
|
||||
})
|
||||
.option('new', {
|
||||
group: groups.dl,
|
||||
describe: 'Get last updated series list from crunchyroll',
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('movie-listing', {
|
||||
group: groups.dl,
|
||||
alias: 'flm',
|
||||
describe: 'Get video list by Movie Listing ID',
|
||||
type: 'string',
|
||||
})
|
||||
.option('series', {
|
||||
group: groups.dl,
|
||||
alias: 'srz',
|
||||
describe: 'Get season list by Series ID',
|
||||
type: 'string',
|
||||
})
|
||||
.option('s', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the season ID',
|
||||
type: 'string'
|
||||
})
|
||||
.option('e', {
|
||||
group: groups.dl,
|
||||
alias: 'episode',
|
||||
describe: 'Sets the Episode Number/IDs (comma-separated, hyphen-sequence)',
|
||||
type: 'string',
|
||||
})
|
||||
.option('q', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the quality layer. Use 0 to get the best quality.',
|
||||
default: parseDefault<number>('videoLayer', 7),
|
||||
type: 'number'
|
||||
})
|
||||
.option('x', {
|
||||
group: groups.dl,
|
||||
alias: 'server',
|
||||
describe: 'Select server',
|
||||
choices: [1, 2, 3, 4],
|
||||
default: parseDefault<number>('nServer', 1),
|
||||
type: 'number',
|
||||
})
|
||||
.option('kstream', {
|
||||
group: groups.dl,
|
||||
alias: 'k',
|
||||
describe: 'Select specific stream for crunchyroll',
|
||||
choices: [1, 2, 3, 4, 5, 6, 7],
|
||||
default: parseDefault<number>('kStream', 1),
|
||||
type: 'number',
|
||||
})
|
||||
.option('partsize', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the amount of parts that should be downloaded in paralell',
|
||||
type: 'number',
|
||||
default: parseDefault<number>('partsize', 10)
|
||||
})
|
||||
.option('hslang', {
|
||||
group: groups.dl,
|
||||
describe: 'Download video with specific hardsubs',
|
||||
choices: langsData.subtitleLanguagesFilter.slice(1),
|
||||
default: parseDefault<string>('hsLang', 'none'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('subLang', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the subtitles to download (Funi only)',
|
||||
choices: subLang,
|
||||
default: parseDefault<string[]>('subLang', []),
|
||||
type: 'array'
|
||||
})
|
||||
.option('dlsubs', {
|
||||
group: groups.dl,
|
||||
describe: 'Download subtitles by language tag (space-separated) (crunchy only)',
|
||||
choices: langsData.subtitleLanguagesFilter,
|
||||
default: parseDefault<string|string[]>('dlSubs', 'all'),
|
||||
type: 'array',
|
||||
})
|
||||
.option('novids', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading videos',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('noaudio', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading audio',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('nosubs', {
|
||||
group: groups.dl,
|
||||
describe: 'Skip downloading subtitles',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('dub', {
|
||||
group: groups.dl,
|
||||
describe: 'Set languages to download (funi only)',
|
||||
choices: dubLang,
|
||||
default: parseDefault<possibleDubs>('dub', ['enUS']),
|
||||
type: 'array'
|
||||
})
|
||||
.option('dubLang', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the language to download (Crunchy only)',
|
||||
choices: langsData.dubLanguageCodes,
|
||||
default: parseDefault('dubLanguage', langsData.dubLanguageCodes.slice(-1)[0]),
|
||||
type: 'string',
|
||||
})
|
||||
.option('all', {
|
||||
group: groups.dl,
|
||||
describe: 'Used to download all episodes from the show (Funi only)',
|
||||
type: 'boolean',
|
||||
default: parseDefault<boolean>('all', false)
|
||||
})
|
||||
.option('fontSize', {
|
||||
group: groups.dl,
|
||||
describe: 'Used to set the fontsize of the subtitles',
|
||||
default: parseDefault<number>('fontSize', 55),
|
||||
type: 'number'
|
||||
})
|
||||
.option('allSubs', {
|
||||
group: groups.dl,
|
||||
describe: 'If set to true, all available subs will get downloaded (Funi only)',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('allDubs', {
|
||||
group: groups.dl,
|
||||
describe: 'If set to true, all available dubs will get downloaded (Funi only)',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('timeout', {
|
||||
group: groups.dl,
|
||||
describe: 'Set the timeout of all download reqests. Set in millisecods',
|
||||
type: 'number',
|
||||
default: parseDefault('timeout', 60 * 1000)
|
||||
})
|
||||
.option('simul', {
|
||||
group: groups.dl,
|
||||
describe: 'Force downloading simulcast ver. instead of uncut ver. (if uncut ver. available) (Funi only)',
|
||||
default: parseDefault<boolean>('forceSimul', false),
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('mp4', {
|
||||
group: groups.mux,
|
||||
describe: 'Mux video into mp4',
|
||||
default: parseDefault<boolean>('mp4mux', false),
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('skipmux', {
|
||||
group: groups.mux,
|
||||
describe: 'Skip muxing video and subtitles',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('fileName', {
|
||||
group: groups.fileName,
|
||||
describe: `Set the filename template. Use \${variable_name} to insert variables.\nYou may use ${availableFilenameVars
|
||||
.map(a => `'${a}'`).join(', ')} as variables.`,
|
||||
type: 'string',
|
||||
default: parseDefault<string>('fileName', '[${service}] ${showTitle} - ${episode} [${height}p]')
|
||||
})
|
||||
.option('numbers', {
|
||||
group: groups.fileName,
|
||||
describe: `Set how long a number in the title should be at least.\n${[[3, 5, '005'], [2, 1, '01'], [1, 20, '20']]
|
||||
.map(val => `Set in config: ${val[0]}; Episode number: ${val[1]}; Output: ${val[2]}`).join('\n')}`,
|
||||
type: 'number',
|
||||
default: parseDefault<number>('numbers', 2)
|
||||
})
|
||||
.option('nosess', {
|
||||
group: groups.debug,
|
||||
type: 'boolean',
|
||||
default: 'Reset session cookie for testing purposes'
|
||||
})
|
||||
.option('debug', {
|
||||
group: groups.debug,
|
||||
describe: 'Debug mode (tokens may be revield in the console output)',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('nocleanup', {
|
||||
group: groups.util,
|
||||
describe: 'Don\'t delete subtitles and videos after muxing',
|
||||
default: parseDefault<boolean>('noCleanUp', false),
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('help', {
|
||||
alias: 'h',
|
||||
group: 'Help:',
|
||||
describe: 'Show this help',
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('service', {
|
||||
group: groups.util,
|
||||
describe: 'Set the service to use',
|
||||
choices: ['funi', 'crunchy'],
|
||||
demandOption: true,
|
||||
default: parseDefault<'crunchy'|'funi'|undefined>('service', undefined)
|
||||
})
|
||||
.parseSync();
|
||||
return argv;
|
||||
}
|
||||
};
|
||||
|
||||
const showHelp = yargs.showHelp;
|
||||
|
||||
|
|
@ -289,4 +296,4 @@ export {
|
|||
availableFilenameVars,
|
||||
subLang,
|
||||
dubLang
|
||||
}
|
||||
};
|
||||
|
|
@ -171,7 +171,7 @@ const loadFuniToken = () => {
|
|||
}>(tokenFile.funi, true);
|
||||
let token: false|string = false;
|
||||
if (loadedToken && loadedToken.token)
|
||||
token = loadedToken.token;
|
||||
token = loadedToken.token;
|
||||
// info if token not set
|
||||
if(!token){
|
||||
console.log('[INFO] Token not set!\n');
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export type Res = {
|
|||
// req
|
||||
const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache: string) => {
|
||||
|
||||
let curlOpt = [
|
||||
const curlOpt = [
|
||||
`"${curlBin}"`,
|
||||
`"${url}"`,
|
||||
];
|
||||
|
|
@ -35,8 +35,8 @@ const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache
|
|||
options = options || {};
|
||||
|
||||
if(options.headers && Object.keys(options.headers).length > 0){
|
||||
for(let h of Object.keys(options.headers)){
|
||||
let hC = options.headers[h];
|
||||
for(const h of Object.keys(options.headers)){
|
||||
const hC = options.headers[h];
|
||||
curlOpt.push('-H', `"${h}: ${hC}"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache
|
|||
fs.unlinkSync(bodyFile);
|
||||
fs.unlinkSync(errFile);
|
||||
|
||||
let res: Res = {
|
||||
const res: Res = {
|
||||
httpVersion: '',
|
||||
statusCode: '',
|
||||
statusMessage: '',
|
||||
|
|
@ -113,20 +113,20 @@ const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache
|
|||
body: rawBody.toString(),
|
||||
};
|
||||
|
||||
let headersCont = rawHeaders.replace(/\r/g, '').split('\n');
|
||||
const headersCont = rawHeaders.replace(/\r/g, '').split('\n');
|
||||
|
||||
for(let h of headersCont){
|
||||
for(const h of headersCont){
|
||||
if( h == '' ){ continue; }
|
||||
if(!h.match(':')){
|
||||
let statusRes = h.split(' ');
|
||||
const statusRes = h.split(' ');
|
||||
res.httpVersion = statusRes[0].split('/')[1];
|
||||
res.statusCode = statusRes[1];
|
||||
res.statusMessage = statusRes.slice(2).join(' ');
|
||||
}
|
||||
else{
|
||||
let resHeader = h.split(': ');
|
||||
let resHeadName = resHeader[0].toLowerCase();
|
||||
let resHeadCont = resHeader.slice(1).join(': ');
|
||||
const resHeader = h.split(': ');
|
||||
const resHeadName = resHeader[0].toLowerCase();
|
||||
const resHeadCont = resHeader.slice(1).join(': ');
|
||||
if(resHeadName == 'set-cookie'){
|
||||
if(!Object.prototype.hasOwnProperty.call(res.headers, resHeadName)){
|
||||
res.headers[resHeadName] = [];
|
||||
|
|
@ -140,7 +140,7 @@ const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache
|
|||
}
|
||||
|
||||
if(!res.statusCode.match(/^(2|3)\d\d$/)){
|
||||
let httpStatusMessage = res.statusMessage ? ` (${res.statusMessage})` : '';
|
||||
const httpStatusMessage = res.statusMessage ? ` (${res.statusMessage})` : '';
|
||||
throw {
|
||||
name: 'HTTPError',
|
||||
message: `Response code ${res.statusCode}${httpStatusMessage}`,
|
||||
|
|
@ -154,7 +154,7 @@ const curlReq = async (curlBin: string, url: string, options: CurlOptions, cache
|
|||
|
||||
function uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ const betaEpRegex = new RegExp (/^[0-9A-Z]{9}$/);
|
|||
const epLtReg = new RegExp (/(?:E|S|M)/);
|
||||
|
||||
class doFilter {
|
||||
constructor(){}
|
||||
ifMaxEp(type: keyof typeof epNumLen, num: number){
|
||||
const maxEp = Math.pow(10, epNumLen[type]) - 1;
|
||||
return num > maxEp ? true : false;
|
||||
|
|
@ -40,7 +39,7 @@ class doFilter {
|
|||
eRange[0] = this.ifMaxEp(epLetter, eRange[0]) ? this.powNum(epLetter) - 1 : eRange[0];
|
||||
eRange[1] = eRange[1].toString().match(/^\d+$/) ? parseInt(eRange[1] as string) : 0;
|
||||
eRange[1] = this.ifMaxEp(epLetter, eRange[1]) ? this.powNum(epLetter) - 1 : eRange[1];
|
||||
console.log(eRange)
|
||||
console.log(eRange);
|
||||
// check if correct range
|
||||
if (eRange[0] > eRange[1]){
|
||||
const parsedEl = [
|
||||
|
|
@ -76,7 +75,7 @@ class doFilter {
|
|||
return '';
|
||||
});
|
||||
// end
|
||||
const filteredArr1 = [...new Set(filteredArr.concat(inputEpsRange))]
|
||||
const filteredArr1 = [...new Set(filteredArr.concat(inputEpsRange))];
|
||||
const filteredArr2 = filteredArr1.indexOf('') > -1 ? filteredArr1.slice(1) : filteredArr1;
|
||||
return filteredArr2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as shlp from "sei-helper";
|
||||
import path from "path";
|
||||
import { AvailableFilenameVars } from "./module.app-args";
|
||||
import * as shlp from 'sei-helper';
|
||||
import path from 'path';
|
||||
import { AvailableFilenameVars } from './module.app-args';
|
||||
|
||||
|
||||
export type Variable = ({
|
||||
|
|
@ -23,7 +23,7 @@ const parseFileName = (input: string, variables: Variable[], numbers: number): s
|
|||
const varName = type.slice(2, -1);
|
||||
const use = variables.find(a => a.name === varName);
|
||||
if (use === undefined) {
|
||||
console.log(`[ERROR] Found variable '${type}' in fileName but no values was internally found!`)
|
||||
console.log(`[ERROR] Found variable '${type}' in fileName but no values was internally found!`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -32,10 +32,10 @@ const parseFileName = (input: string, variables: Variable[], numbers: number): s
|
|||
const replaceStr = len < numbers ? '0'.repeat(numbers - len) + use.replaceWith : use.replaceWith.toFixed(0);
|
||||
input = input.replace(type, replaceStr);
|
||||
} else {
|
||||
input = input.replace(type, use.replaceWith)
|
||||
input = input.replace(type, use.replaceWith);
|
||||
}
|
||||
}
|
||||
return input.split(path.sep).map(a => shlp.cleanupFilename(a));
|
||||
}
|
||||
};
|
||||
|
||||
export default parseFileName;
|
||||
|
|
@ -67,11 +67,11 @@ const fonts = {
|
|||
|
||||
// collect styles from ass string
|
||||
function assFonts(ass: string){
|
||||
let strings = ass.replace(/\r/g,'').split('\n');
|
||||
let styles = [];
|
||||
for(let s of strings){
|
||||
const strings = ass.replace(/\r/g,'').split('\n');
|
||||
const styles = [];
|
||||
for(const s of strings){
|
||||
if(s.match(/^Style: /)){
|
||||
let addStyle = s.split(',');
|
||||
const addStyle = s.split(',');
|
||||
styles.push(addStyle[1]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const languages: LanguageItem[] = [
|
|||
|
||||
// add en language names
|
||||
(() =>{
|
||||
for(let languageIndex in languages){
|
||||
for(const languageIndex in languages){
|
||||
if(!languages[languageIndex].language){
|
||||
languages[languageIndex].language = languages[languageIndex].name;
|
||||
}
|
||||
|
|
@ -99,16 +99,18 @@ const parseSubtitlesArray = (tags: string[]) => {
|
|||
};
|
||||
|
||||
// sort subtitles
|
||||
const sortSubtitles = (data: Partial<LanguageItem>[], sortkey: keyof LanguageItem = 'locale') => {
|
||||
const sortSubtitles = <T extends {
|
||||
[key: string]: unknown
|
||||
} = Record<string, string>> (data: T[], sortkey?: keyof T) : T[] => {
|
||||
const idx: Record<string, number> = {};
|
||||
sortkey = sortkey || 'locale';
|
||||
const key = sortkey || 'locale' as keyof T;
|
||||
const tags = [...new Set(Object.values(languages).map(e => e.locale))];
|
||||
for(const l of tags){
|
||||
idx[l] = Object.keys(idx).length + 1;
|
||||
}
|
||||
data.sort((a, b) => {
|
||||
const ia = idx[a[sortkey] as string] ? idx[a[sortkey] as string] : 50;
|
||||
const ib = idx[b[sortkey] as string] ? idx[b[sortkey] as string] : 50;
|
||||
const ia = idx[a[key] as string] ? idx[a[key] as string] : 50;
|
||||
const ib = idx[b[key] as string] ? idx[b[key] as string] : 50;
|
||||
return ia - ib;
|
||||
});
|
||||
return data;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
import * as iso639 from 'iso-639';
|
||||
import { fonts, fontMime } from "./module.fontsData";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { fonts, fontMime } from './module.fontsData';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { LanguageItem } from './module.langsData';
|
||||
|
||||
export type MergerInput = {
|
||||
path: string,
|
||||
lang: string,
|
||||
lookup?: false,
|
||||
}
|
||||
|
||||
export type SubtitleInput = {
|
||||
language: string,
|
||||
file: string,
|
||||
fonts?: ParsedFont[]
|
||||
title?: string
|
||||
lookup?: false,
|
||||
}
|
||||
|
||||
export type Font = keyof typeof fonts;
|
||||
|
|
@ -30,6 +32,7 @@ export type MergerOptions = {
|
|||
subtitels: SubtitleInput[],
|
||||
output: string,
|
||||
simul?: boolean,
|
||||
fonts?: ParsedFont[]
|
||||
}
|
||||
|
||||
class Merger {
|
||||
|
|
@ -131,7 +134,7 @@ class Merger {
|
|||
'--video-tracks 0',
|
||||
'--no-audio'
|
||||
);
|
||||
const trackName = this.subDict[vid.lang] + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
const trackName = (vid.lookup === false ? vid.lang : this.subDict[vid.lang]) + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
args.push('--track-name', `0:"${trackName}"`);
|
||||
args.push(`--language 0:${Merger.getLanguageCode(vid.lang, vid.lang)}`);
|
||||
hasVideo = true;
|
||||
|
|
@ -145,7 +148,7 @@ class Merger {
|
|||
'--video-tracks 0',
|
||||
'--audio-tracks 1'
|
||||
);
|
||||
const trackName = this.subDict[vid.lang] + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
const trackName = (vid.lookup === false ? vid.lang : this.subDict[vid.lang]) + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
args.push('--track-name', `0:"${trackName}"`);
|
||||
args.push('--track-name', `1:"${trackName}"`);
|
||||
args.push(`--language 1:${Merger.getLanguageCode(vid.lang, vid.lang)}`);
|
||||
|
|
@ -155,7 +158,7 @@ class Merger {
|
|||
'--no-video',
|
||||
'--audio-tracks 1'
|
||||
);
|
||||
const trackName = this.subDict[vid.lang] + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
const trackName = (vid.lookup === false ? vid.lang : this.subDict[vid.lang]) + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
args.push('--track-name', `1:"${trackName}"`);
|
||||
args.push(`--language 1:${Merger.getLanguageCode(vid.lang, vid.lang)}`);
|
||||
}
|
||||
|
|
@ -163,7 +166,7 @@ class Merger {
|
|||
}
|
||||
|
||||
for (const aud of this.options.onlyAudio) {
|
||||
const trackName = this.subDict[aud.lang] + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
const trackName = (aud.lookup === false ? aud.lang : this.subDict[aud.lang]) + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
args.push('--track-name', `0:"${trackName}"`);
|
||||
args.push(`--language 0:${Merger.getLanguageCode(aud.lang, aud.lang)}`);
|
||||
args.push(
|
||||
|
|
@ -175,26 +178,27 @@ class Merger {
|
|||
|
||||
if (this.options.subtitels.length > 0) {
|
||||
for (const subObj of this.options.subtitels) {
|
||||
const trackName = this.subDict[subObj.language] + (this.options.simul ? ' [Simulcast]' : ' [Uncut]');
|
||||
args.push('--track-name', `0:"${trackName}"`);
|
||||
args.push('--language', `0:${Merger.getLanguageCode(subObj.language)}`);
|
||||
args.push('--track-name', (subObj.title !== undefined ? `0:"${subObj.title}"` : `0:"${subObj.lookup === false ? subObj.language : Merger.getLanguageCode(subObj.language)}"`));
|
||||
args.push('--language', `0:"${subObj.lookup === false ? subObj.language : Merger.getLanguageCode(subObj.language)}"`);
|
||||
args.push(`"${subObj.file}"`);
|
||||
if (subObj.fonts && subObj.fonts.length > 0) {
|
||||
for (const f of subObj.fonts) {
|
||||
args.push('--attachment-name', f.name);
|
||||
args.push('--attachment-mime-type', f.mime);
|
||||
args.push('--attach-file', f.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
args.push(
|
||||
'--no-subtitles',
|
||||
);
|
||||
}
|
||||
if (this.options.fonts && this.options.fonts.length > 0) {
|
||||
for (const f of this.options.fonts) {
|
||||
args.push('--attachment-name', f.name);
|
||||
args.push('--attachment-mime-type', f.mime);
|
||||
args.push('--attach-file', f.path);
|
||||
}
|
||||
} else {
|
||||
args.push(
|
||||
'--no-attachments'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return args.join(' ');
|
||||
};
|
||||
|
||||
|
|
@ -225,7 +229,7 @@ class Merger {
|
|||
language: LanguageItem,
|
||||
fonts: Font[]
|
||||
}[]) : ParsedFont[] {
|
||||
let fontsNameList: Font[] = [], fontsList = [], subsList = [], isNstr = true;
|
||||
let fontsNameList: Font[] = []; const fontsList = [], subsList = []; let isNstr = true;
|
||||
for(const s of subs){
|
||||
fontsNameList.push(...s.fonts);
|
||||
subsList.push(s.language.locale);
|
||||
|
|
@ -253,7 +257,12 @@ class Merger {
|
|||
}
|
||||
}
|
||||
return fontsList;
|
||||
};
|
||||
}
|
||||
|
||||
public cleanUp() {
|
||||
this.options.onlyAudio.concat(this.options.onlyVid).concat(this.options.videoAndAudio).forEach(a => fs.unlinkSync(a.path));
|
||||
this.options.subtitels.forEach(a => fs.unlinkSync(a.file));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import shlp from 'sei-helper';
|
||||
import got, { Headers, Method, Options, ReadError, Response } from 'got';
|
||||
import cookieFile from './module.cookieFile';
|
||||
|
|
@ -44,7 +41,7 @@ class Req {
|
|||
async getData<T = string> (durl: string, params?: Params) {
|
||||
params = params || {};
|
||||
// options
|
||||
let options: Options & {
|
||||
const options: Options & {
|
||||
minVersion?: string,
|
||||
maxVersion?: string
|
||||
curlDebug?: boolean
|
||||
|
|
@ -83,7 +80,6 @@ class Req {
|
|||
}
|
||||
}*/
|
||||
// if auth
|
||||
let cookie = [];
|
||||
const loc = new URL(durl);
|
||||
// avoid cloudflare protection
|
||||
if(loc.origin == this.domain.www){
|
||||
|
|
@ -124,7 +120,7 @@ class Req {
|
|||
name: string
|
||||
} & ReadError & {
|
||||
res: Response<unknown>
|
||||
}
|
||||
};
|
||||
if(error.response && error.response.statusCode && error.response.statusMessage){
|
||||
console.log(`[ERROR] ${error.name} ${error.response.statusCode}: ${error.response.statusMessage}`);
|
||||
}
|
||||
|
|
@ -140,122 +136,122 @@ class Req {
|
|||
}
|
||||
if(error.res && error.res.body && error.response.statusCode
|
||||
&& error.response.statusCode != 404 && error.response.statusCode != 403){
|
||||
console.log('[ERROR] Body:', error.res.body);
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
error,
|
||||
};
|
||||
console.log('[ERROR] Body:', error.res.body);
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
setNewCookie(setCookie: Record<string, string>, isAuth: boolean, fileData?: string){
|
||||
const cookieUpdated = []; let lastExp = 0;
|
||||
console.trace('Type of setCookie:', typeof setCookie, setCookie);
|
||||
const parsedCookie = fileData ? cookieFile(fileData) : shlp.cookie.parse(setCookie);
|
||||
for(const cookieName of Object.keys(parsedCookie)){
|
||||
if(parsedCookie[cookieName] && parsedCookie[cookieName].value && parsedCookie[cookieName].value == 'deleted'){
|
||||
delete parsedCookie[cookieName];
|
||||
}
|
||||
}
|
||||
setNewCookie(setCookie: Record<string, string>, isAuth: boolean, fileData?: string){
|
||||
let cookieUpdated = [], lastExp = 0;
|
||||
console.trace('Type of setCookie:', typeof setCookie, setCookie)
|
||||
const parsedCookie = fileData ? cookieFile(fileData) : shlp.cookie.parse(setCookie);
|
||||
for(let cookieName of Object.keys(parsedCookie)){
|
||||
if(parsedCookie[cookieName] && parsedCookie[cookieName].value && parsedCookie[cookieName].value == 'deleted'){
|
||||
delete parsedCookie[cookieName];
|
||||
}
|
||||
for(const uCookie of usefulCookies.auth){
|
||||
const cookieForceExp = 60*60*24*7;
|
||||
const cookieExpCur = this.session[uCookie] ? this.session[uCookie] : { expires: 0 };
|
||||
const cookieExp = new Date(cookieExpCur.expires).getTime() - cookieForceExp;
|
||||
if(cookieExp > lastExp){
|
||||
lastExp = cookieExp;
|
||||
}
|
||||
for(let uCookie of usefulCookies.auth){
|
||||
const cookieForceExp = 60*60*24*7;
|
||||
const cookieExpCur = this.session[uCookie] ? this.session[uCookie] : { expires: 0 };
|
||||
const cookieExp = new Date(cookieExpCur.expires).getTime() - cookieForceExp;
|
||||
if(cookieExp > lastExp){
|
||||
lastExp = cookieExp;
|
||||
}
|
||||
}
|
||||
for(const uCookie of usefulCookies.auth){
|
||||
if(!parsedCookie[uCookie]){
|
||||
continue;
|
||||
}
|
||||
for(let uCookie of usefulCookies.auth){
|
||||
if(!parsedCookie[uCookie]){
|
||||
continue;
|
||||
}
|
||||
if(isAuth || parsedCookie[uCookie] && Date.now() > lastExp){
|
||||
this.session[uCookie] = parsedCookie[uCookie];
|
||||
cookieUpdated.push(uCookie);
|
||||
}
|
||||
if(isAuth || parsedCookie[uCookie] && Date.now() > lastExp){
|
||||
this.session[uCookie] = parsedCookie[uCookie];
|
||||
cookieUpdated.push(uCookie);
|
||||
}
|
||||
for(let uCookie of usefulCookies.sess){
|
||||
if(!parsedCookie[uCookie]){
|
||||
continue;
|
||||
}
|
||||
if(
|
||||
isAuth
|
||||
}
|
||||
for(const uCookie of usefulCookies.sess){
|
||||
if(!parsedCookie[uCookie]){
|
||||
continue;
|
||||
}
|
||||
if(
|
||||
isAuth
|
||||
|| this.argv.nosess && parsedCookie[uCookie]
|
||||
|| parsedCookie[uCookie] && !this.checkSessId(this.session[uCookie])
|
||||
){
|
||||
const sessionExp = 60*60;
|
||||
this.session[uCookie] = parsedCookie[uCookie];
|
||||
this.session[uCookie].expires = new Date(Date.now() + sessionExp*1000);
|
||||
this.session[uCookie]['Max-Age'] = sessionExp.toString();
|
||||
cookieUpdated.push(uCookie);
|
||||
}
|
||||
}
|
||||
if(cookieUpdated.length > 0){
|
||||
if(this.argv.debug){
|
||||
console.log('[SAVING FILE]',`${this.sessCfg}.yml`);
|
||||
}
|
||||
yamlCfg.saveCRSession(this.session);
|
||||
console.log(`[INFO] Cookies were updated! (${cookieUpdated.join(', ')})\n`);
|
||||
}
|
||||
){
|
||||
const sessionExp = 60*60;
|
||||
this.session[uCookie] = parsedCookie[uCookie];
|
||||
this.session[uCookie].expires = new Date(Date.now() + sessionExp*1000);
|
||||
this.session[uCookie]['Max-Age'] = sessionExp.toString();
|
||||
cookieUpdated.push(uCookie);
|
||||
}
|
||||
checkCookieVal(chcookie: Record<string, string>){
|
||||
return chcookie
|
||||
}
|
||||
if(cookieUpdated.length > 0){
|
||||
if(this.argv.debug){
|
||||
console.log('[SAVING FILE]',`${this.sessCfg}.yml`);
|
||||
}
|
||||
yamlCfg.saveCRSession(this.session);
|
||||
console.log(`[INFO] Cookies were updated! (${cookieUpdated.join(', ')})\n`);
|
||||
}
|
||||
}
|
||||
checkCookieVal(chcookie: Record<string, string>){
|
||||
return chcookie
|
||||
&& chcookie.toString() == '[object Object]'
|
||||
&& typeof chcookie.value == 'string'
|
||||
? true : false;
|
||||
}
|
||||
checkSessId(session_id: Record<string, unknown>){
|
||||
if(session_id && typeof session_id.expires == 'string'){
|
||||
session_id.expires = new Date(session_id.expires);
|
||||
}
|
||||
return session_id
|
||||
? true : false;
|
||||
}
|
||||
checkSessId(session_id: Record<string, unknown>){
|
||||
if(session_id && typeof session_id.expires == 'string'){
|
||||
session_id.expires = new Date(session_id.expires);
|
||||
}
|
||||
return session_id
|
||||
&& session_id.toString() == '[object Object]'
|
||||
&& typeof session_id.expires == 'object'
|
||||
&& Date.now() < new Date(session_id.expires as any).getTime()
|
||||
&& typeof session_id.value == 'string'
|
||||
? true : false;
|
||||
}
|
||||
uuidv4(){
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
};
|
||||
? true : false;
|
||||
}
|
||||
uuidv4(){
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildProxy(proxyBaseUrl: string, proxyAuth: string){
|
||||
if(!proxyBaseUrl.match(/^(https?|socks4|socks5):/)){
|
||||
proxyBaseUrl = 'http://' + proxyBaseUrl;
|
||||
}
|
||||
function buildProxy(proxyBaseUrl: string, proxyAuth: string){
|
||||
if(!proxyBaseUrl.match(/^(https?|socks4|socks5):/)){
|
||||
proxyBaseUrl = 'http://' + proxyBaseUrl;
|
||||
}
|
||||
|
||||
let proxyCfg = new URL(proxyBaseUrl);
|
||||
let proxyStr = `${proxyCfg.protocol}//`;
|
||||
const proxyCfg = new URL(proxyBaseUrl);
|
||||
let proxyStr = `${proxyCfg.protocol}//`;
|
||||
|
||||
if(typeof proxyCfg.hostname != 'string' || proxyCfg.hostname == ''){
|
||||
throw new Error('[ERROR] Hostname and port required for proxy!');
|
||||
}
|
||||
if(typeof proxyCfg.hostname != 'string' || proxyCfg.hostname == ''){
|
||||
throw new Error('[ERROR] Hostname and port required for proxy!');
|
||||
}
|
||||
|
||||
if(proxyAuth && typeof proxyAuth == 'string' && proxyAuth.match(':')){
|
||||
proxyCfg.username = proxyAuth.split(':')[0];
|
||||
proxyCfg.password = proxyAuth.split(':')[1];
|
||||
proxyStr += `${proxyCfg.username}:${proxyCfg.password}@`;
|
||||
}
|
||||
if(proxyAuth && typeof proxyAuth == 'string' && proxyAuth.match(':')){
|
||||
proxyCfg.username = proxyAuth.split(':')[0];
|
||||
proxyCfg.password = proxyAuth.split(':')[1];
|
||||
proxyStr += `${proxyCfg.username}:${proxyCfg.password}@`;
|
||||
}
|
||||
|
||||
proxyStr += proxyCfg.hostname;
|
||||
proxyStr += proxyCfg.hostname;
|
||||
|
||||
if(!proxyCfg.port && proxyCfg.protocol == 'http:'){
|
||||
proxyStr += ':80';
|
||||
}
|
||||
else if(!proxyCfg.port && proxyCfg.protocol == 'https:'){
|
||||
proxyStr += ':443';
|
||||
}
|
||||
if(!proxyCfg.port && proxyCfg.protocol == 'http:'){
|
||||
proxyStr += ':80';
|
||||
}
|
||||
else if(!proxyCfg.port && proxyCfg.protocol == 'https:'){
|
||||
proxyStr += ':443';
|
||||
}
|
||||
|
||||
return proxyStr;
|
||||
}
|
||||
return proxyStr;
|
||||
}
|
||||
|
||||
export {
|
||||
buildProxy,
|
||||
usefulCookies,
|
||||
Req,
|
||||
};
|
||||
export {
|
||||
buildProxy,
|
||||
usefulCookies,
|
||||
Req,
|
||||
};
|
||||
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"url": "https://github.com/izu-co/funimation-downloader-nx/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "funi.js",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"form-data": "^4.0.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue