Download Archve

This commit is contained in:
Izuco 2021-11-21 14:53:14 +01:00
parent 9586b412a1
commit 8f6dcbed0f
No known key found for this signature in database
GPG key ID: 318460063D70949F
7 changed files with 266 additions and 51 deletions

3
.gitignore vendored
View file

@ -19,4 +19,5 @@ token.yml
lib
test.*
updates.json
cr_token.yml
cr_token.yml
archive.json

View file

@ -1,4 +1,6 @@
videoLayer: 7
videoLayer: 1
nServer: 1
mp4mux: false
noCleanUp: false
noCleanUp: false
partsize: 50
timeout: 30000

View file

@ -55,6 +55,7 @@ import { CrunchyEpMeta, CrunchyEpMetaMultiDub, ParseItem, SeriesSearch, SeriesSe
import { ObjectInfo } from './@types/objectInfo';
import parseFileName, { Variable } from './modules/module.filename';
import { PlaybackData } from './@types/playbackData';
import { downloaded } from './modules/module.downloadArchive';
const req = new reqModule.Req(domain, argv);
// select
@ -84,7 +85,7 @@ export default (async () => {
else if(argv.series && argv.series.match(/^[0-9A-Z]{9}$/)){
await refreshToken();
await getSeriesById();
await downloadFromSeriesID();
return await downloadFromSeriesID();
}
else if(argv['movie-listing'] && argv['movie-listing'].match(/^[0-9A-Z]{9}$/)){
await refreshToken();
@ -96,7 +97,7 @@ export default (async () => {
console.log('[INFO] One show can only be downloaded with one dub. Use --srz instead.');
}
argv.dubLang = argv.dubLang[0];
await getSeasonById();
return await getSeasonById();
}
else if(argv.e){
await refreshToken();
@ -719,10 +720,18 @@ async function getSeasonById(){
}
console.log();
let ok = true;
for(const media of selectedMedia){
await getMedia(media);
if (await getMedia(media) !== true) {
ok = false;
} else {
downloaded({
service: 'crunchy',
type: 's'
}, argv.s as string, [media.episodeNumber]);
}
}
return ok;
}
async function getObjectById(returnData?: boolean){
@ -1164,7 +1173,8 @@ async function getMedia(mMeta: CrunchyEpMeta){
else{
console.log();
}
return !dlFailed;
}
async function muxStreams(options: MergerOptions){
@ -1247,6 +1257,10 @@ const downloadFromSeriesID = async () => {
const res = await getMediaList(item);
if (!res)
return;
downloaded({
service: 'crunchy',
type: 'srz'
}, argv.series as string, [item.episodeNumber]);
muxStreams({
onlyAudio: [],
onlyVid: [],
@ -1262,6 +1276,7 @@ const downloadFromSeriesID = async () => {
fonts: Merger.makeFontsList(cfg.dir.fonts, appstore.sxList)
});
}
return true;
};
const itemSelectMultiDub = (eps: Record<string, {

60
funi.ts
View file

@ -26,7 +26,6 @@ const cfg = yamlCfg.loadCfg();
const token = yamlCfg.loadFuniToken();
// cli
const argv = appYargs.appArgv(cfg.cli);
// Import modules after argv has been exported
import getData from './modules/module.getdata.js';
import merger, { SubtitleInput } from './modules/module.merger';
@ -36,6 +35,7 @@ import { Subtitle } from './@types/subtitleObject';
import { StreamData } from './@types/streamData';
import { DownloadedFile } from './@types/downloadedFile';
import parseFileName, { Variable } from './modules/module.filename';
import { downloaded } from './modules/module.downloadArchive';
// check page
argv.p = 1;
@ -47,9 +47,9 @@ let title = '',
fnOutput: string[] = [],
season = 0,
tsDlPath: {
path: string,
lang: string,
}[] = [],
path: string,
lang: string
}[] = [],
stDlPath: Subtitle[] = [];
// main
@ -71,7 +71,7 @@ export default (async () => {
searchShow();
}
else if(argv.s && !isNaN(parseInt(argv.s)) && parseInt(argv.s) > 0){
getShow();
return getShow();
}
else{
appYargs.showHelp();
@ -134,7 +134,7 @@ async function searchShow(){
// get show
async function getShow(){
// show main data
let ok = true;
const showData = await getData({
baseUrl: api_host,
url: `/source/catalog/title/${argv.s}`,
@ -213,7 +213,8 @@ async function getShow(){
const fnSlug: {
title: string,
episode: string
episode: string,
episodeID: string
}[] = []; let is_selected = false;
const eps = epsDataArr;
@ -233,7 +234,7 @@ async function getShow(){
// select
is_selected = false;
if (argv.all || epSelList.isSelected(epStrId)) {
fnSlug.push({title:eps[e].item.titleSlug,episode:eps[e].item.episodeSlug});
fnSlug.push({title:eps[e].item.titleSlug,episode:eps[e].item.episodeSlug, episodeID:epStrId});
epSelEpsTxt.push(epStrId);
is_selected = true;
}
@ -265,15 +266,17 @@ async function getShow(){
else{
console.log('[INFO] Selected Episodes: %s\n',epSelEpsTxt.join(', '));
for(let fnEp=0;fnEp<fnSlug.length;fnEp++){
await getEpisode(fnSlug[fnEp]);
if (await getEpisode(fnSlug[fnEp]) !== true)
ok = false;
}
}
return ok;
}
async function getEpisode(fnSlug: {
title: string,
episode: string
title: string,
episode: string,
episodeID: string
}) {
const episodeData = await getData({
baseUrl: api_host,
@ -321,7 +324,7 @@ async function getEpisode(fnSlug: {
language: m.language,
version: m.version,
type: m.experienceType,
subtitles: getSubsUrl(m.mediaChildren),
subtitles: getSubsUrl(m.mediaChildren)
};
}
else{
@ -352,6 +355,7 @@ async function getEpisode(fnSlug: {
for (const curDub of (argv.dub as appYargs.possibleDubs)) {
if(dub_type == dubType[curDub] && selUncut){
streamIds.push({
id: m.id,
lang: merger.getLanguageCode(curDub, curDub.slice(0, -2))
});
@ -413,7 +417,7 @@ async function getEpisode(fnSlug: {
return;
}
else{
await downloadStreams();
return await downloadStreams(fnSlug.episodeID);
}
}
}
@ -457,7 +461,7 @@ function getSubsUrl(m: MediaChild[]) : Subtitle[] {
return found;
}
async function downloadStreams(){
async function downloadStreams(epsiodeID: string){
// req playlist
@ -713,7 +717,7 @@ async function downloadStreams(){
if (addSubs)
console.log('[INFO] Subtitles downloaded!');
}
if((puraudio.length < 1 && audioAndVideo.length < 1) || (purvideo.length < 1 && audioAndVideo.length < 1)){
console.log('\n[INFO] Unable to locate a video AND audio file\n');
return;
@ -721,6 +725,10 @@ async function downloadStreams(){
if(argv.skipmux){
console.log('[INFO] Skipping muxing...');
downloaded({
service: 'funi',
type: 's'
}, argv.s as string, [epsiodeID]);
return;
}
@ -759,14 +767,28 @@ async function downloadStreams(){
}
else{
console.log('\n[INFO] Done!\n');
return;
downloaded({
service: 'funi',
type: 's'
}, argv.s as string, [epsiodeID]);
return true;
}
if (argv.nocleanup) {
downloaded({
service: 'funi',
type: 's'
}, argv.s as string, [epsiodeID]);
return true;
}
if (argv.nocleanup)
return;
audioAndVideo.concat(puraudio).concat(purvideo).forEach(a => fs.unlinkSync(a.path));
stDlPath.forEach(subObject => subObject.file && fs.unlinkSync(subObject.file));
console.log('\n[INFO] Done!\n');
downloaded({
service: 'funi',
type: 's'
}, argv.s as string, [epsiodeID]);
return true;
}
async function downloadFile(filename: string, chunkList: {

View file

@ -1,5 +1,6 @@
import { appArgv } from './modules/module.app-args';
import { appArgv, overrideArguments } from './modules/module.app-args';
import * as yamlCfg from './modules/module.cfg-loader';
import { makeCommand, downloaded, addToArchive } from './modules/module.downloadArchive';
import update from './modules/module.updater';
@ -14,11 +15,43 @@ import update from './modules/module.updater';
console.log('[ERROR] --all and --but exclude each other!');
return;
}
if (argv.service === 'funi') {
(await import('./funi')).default();
} else if (argv.service === 'crunchy') {
(await import('./crunchy')).default();
}
if (argv.addArchive) {
if (argv.service === 'funi') {
if (argv.s === undefined)
return console.log('[ERROR] `-s` not found');
addToArchive({
service: 'funi',
type: 's'
}, argv.s);
console.log('[INFO] Added %s to the downloadArchive list', argv.s);
} else if (argv.service === 'crunchy') {
if (argv.s === undefined && argv.series === undefined)
return console.log('[ERROR] `-s` or `--srz` not found');
if (argv.s && argv.series)
return console.log('[ERROR] Both `-s` and `--srz` found');
addToArchive({
service: 'crunchy',
type: argv.s === undefined ? 'srz' : 's'
}, (argv.s === undefined ? argv.series : argv.s) as string);
console.log('[INFO] Added %s to the downloadArchive list', (argv.s === undefined ? argv.series : argv.s));
}
} else if (argv.downloadArchive) {
const ids = makeCommand(argv.service);
for (const id of ids) {
overrideArguments(cfg.cli, id);
/* Reimport module to override appArgv */
Object.keys(require.cache).forEach(key => {
if (key.endsWith('crunchy.js') || key.endsWith('funi.js'))
delete require.cache[key]
})
await (argv.service === 'funi' ? await import('./funi') : await import('./crunchy')).default();
}
} else {
if (argv.service === 'funi') {
(await import('./funi')).default();
} else if (argv.service === 'crunchy') {
(await import('./crunchy')).default();
}
}
})();

View file

@ -27,27 +27,58 @@ const availableFilenameVars: AvailableFilenameVars[] = [
];
export type possibleDubs = (
'enUS' | 'esLA' | 'ptBR' | 'zhMN' | 'jaJP'
)[];
'enUS' | 'esLA' | 'ptBR' | 'zhMN' | 'jaJP'
)[];
export type possibleSubs = (
'enUS' | 'esLA' | 'ptBR'
)[];
)[];
const subLang: possibleSubs = ['enUS', 'esLA', 'ptBR'];
const dubLang: possibleDubs = ['enUS', 'esLA', 'ptBR', 'zhMN', 'jaJP'];
let argvC: { [x: string]: unknown; but: boolean, auth: boolean | undefined; dlFonts: boolean | undefined; search: string | undefined; 'search-type': string; page: number | undefined; 'search-locale': string; new: boolean | undefined; 'movie-listing': string | undefined; series: string | undefined; s: string | undefined; e: string | undefined; q: number; x: number; kstream: number; partsize: number; hslang: string; subLang: string[]; dlsubs: string | string[]; novids: boolean | undefined; noaudio: boolean | undefined; nosubs: boolean | undefined; dub: possibleDubs; dubLang: string; all: boolean; fontSize: number; allSubs: boolean; allDubs: boolean; timeout: number; simul: boolean; mp4: boolean; skipmux: boolean | undefined; fileName: string; numbers: number; nosess: string; debug: boolean | undefined; nocleanup: boolean; help: boolean | undefined; service: 'funi' | 'crunchy'; update: boolean; fontName: string | undefined; _: (string | number)[]; $0: string; };
let argvC: { [x: string]: unknown; downloadArchive: boolean, addArchive: boolean, but: boolean, auth: boolean | undefined; dlFonts: boolean | undefined; search: string | undefined; 'search-type': string; page: number | undefined; 'search-locale': string; new: boolean | undefined; 'movie-listing': string | undefined; series: string | undefined; s: string | undefined; e: string | undefined; q: number; x: number; kstream: number; partsize: number; hslang: string; subLang: string[]; dlsubs: string | string[]; novids: boolean | undefined; noaudio: boolean | undefined; nosubs: boolean | undefined; dub: possibleDubs; dubLang: string; all: boolean; fontSize: number; allSubs: boolean; allDubs: boolean; timeout: number; simul: boolean; mp4: boolean; skipmux: boolean | undefined; fileName: string; numbers: number; nosess: string; debug: boolean | undefined; nocleanup: boolean; help: boolean | undefined; service: 'funi' | 'crunchy'; update: boolean; fontName: string | undefined; _: (string | number)[]; $0: string; };
export type ArgvType = typeof argvC;
const appArgv = (cfg: {
[key: string]: unknown
}) => {
if (argvC)
return argvC;
const argv = getArgv(cfg)
.parseSync();
argvC = argv;
return argv;
};
const overrideArguments = (cfg: { [key:string]: unknown }, override: Partial<typeof argvC>) => {
const argv = getArgv(cfg).middleware((ar) => {
for (const key of Object.keys(override)) {
ar[key] = override[key];
}
return ar;
}).parseSync();
argvC = argv;
};
const showHelp = yargs.showHelp;
export {
appArgv,
showHelp,
availableFilenameVars,
subLang,
dubLang,
overrideArguments
};
const getArgv = (cfg: { [key:string]: unknown }) => {
const parseDefault = <T = unknown>(key: string, _default: T) : T=> {
if (Object.prototype.hasOwnProperty.call(cfg, key)) {
return cfg[key] as T;
} else
return _default;
};
const argv = yargs.parserConfiguration({
'duplicate-arguments-array': false,
'camel-case-expansion': false,
@ -305,17 +336,19 @@ const appArgv = (cfg: {
type: 'boolean',
default: false
})
.parseSync();
argvC = argv;
.option('downloadArchive', {
group: groups.dl,
desc: 'Used to download all archived shows',
type: 'boolean',
default: false
})
.option('addArchive', {
group: groups.dl,
desc: 'Used to add the `-s` and `--srz` to downloadArchive',
type: 'boolean',
default: false
});
return argv;
};
const showHelp = yargs.showHelp;
export {
appArgv,
showHelp,
availableFilenameVars,
subLang,
dubLang
};

View file

@ -0,0 +1,109 @@
import * as path from 'path';
import * as fs from 'fs';
import { ArgvType } from './module.app-args';
const workingDir = (process as NodeJS.Process & {
pkg?: unknown
}).pkg ? path.dirname(process.execPath) : path.join(__dirname, '/..');
export const archiveFile = path.join(workingDir, 'config', 'archive.json');
export type ItemType = {
id: string,
already: string[]
}[]
export type DataType = {
funi: {
s: ItemType
},
crunchy: {
srz: ItemType,
s: ItemType
}
}
const addToArchive = (kind: {
service: 'funi',
type: 's'
} | {
service: 'crunchy',
type: 's'|'srz'
}, ID: string) => {
const data = loadData();
if (Object.prototype.hasOwnProperty.call(data, kind.service)) {
const items = kind.service === 'crunchy' ? data[kind.service][kind.type] : data[kind.service][kind.type];
items.push({
id: ID,
already: []
});
} else {
if (kind.service === 'funi') {
data['funi'] = {
s: [
{
id: ID,
already: []
}
]
};
} else {
data['crunchy'] = {
s: ([] as ItemType).concat(kind.type === 's' ? {
id: ID,
already: [] as string[]
} : []),
srz: ([] as ItemType).concat(kind.type === 'srz' ? {
id: ID,
already: [] as string[]
} : []),
};
}
}
fs.writeFileSync(archiveFile, JSON.stringify(data, null, 4));
};
const downloaded = (kind: {
service: 'funi',
type: 's'
} | {
service: 'crunchy',
type: 's'|'srz'
}, ID: string, episode: string[]) => {
const data = loadData();
if (!Object.prototype.hasOwnProperty.call(data, kind.service))
addToArchive(kind, ID);
(kind.service == 'crunchy' ? data[kind.service][kind.type] : data[kind.service][kind.type]).find(a => a.id === ID)?.already.push(...episode);
fs.writeFileSync(archiveFile, JSON.stringify(data, null, 4));
};
const makeCommand = (service: 'funi'|'crunchy') : Partial<ArgvType>[] => {
const data = loadData();
const ret: Partial<ArgvType>[] = [];
const kind = data[service];
for (const type of Object.keys(kind)) {
const item = kind[type as 's']; // 'srz' is also possible but will be ignored for the compiler
item.forEach(i => ret.push({
but: true,
all: false,
service,
e: i.already.join(','),
...(type === 's' ? {
s: i.id,
series: undefined
} : {
series: i.id,
s: undefined
})
}));
}
return ret;
};
const loadData = () : DataType => {
if (fs.existsSync(archiveFile))
return JSON.parse(fs.readFileSync(archiveFile).toString()) as DataType;
return {} as DataType;
};
export { addToArchive, downloaded, makeCommand };