Test + Style

This commit is contained in:
Izuco 2021-10-28 19:32:34 +02:00
parent 255574df1b
commit 2c07f51f54
No known key found for this signature in database
GPG key ID: 41DFCB1835A5695E
14 changed files with 1560 additions and 1494 deletions

2
.eslintignore Normal file
View file

@ -0,0 +1,2 @@
lib
/videos/*.ts

View file

@ -1,23 +0,0 @@
name: eslint
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm i
- run: npx eslint .

33
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: eslint
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14
uses: actions/setup-node@v2
with:
node-version: 14
cache: 'npm'
- run: npm i
- run: npx eslint .
test:
needs: eslint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14
uses: actions/setup-node@v2
with:
node-version: 14
cache: 'npm'
- run: npm i
- run: npm run test

39
@types/episode.d.ts vendored
View file

@ -59,20 +59,20 @@ export interface Value {
}
export enum Label {
Rating = "Rating",
RatingSystem = "Rating System",
ReleaseDate = "Release Date",
Synopsis = "Synopsis",
SynopsisType = "Synopsis Type",
Rating = 'Rating',
RatingSystem = 'Rating System',
ReleaseDate = 'Release Date',
Synopsis = 'Synopsis',
SynopsisType = 'Synopsis Type',
}
export enum MetaType {
Rating = "rating",
RatingSystemType = "RatingSystemType",
ReleaseDate = "release-date",
Synopsis = "synopsis",
Synopsistype = "synopsistype",
VideoRatingType = "VideoRatingType",
Rating = 'rating',
RatingSystemType = 'RatingSystemType',
ReleaseDate = 'release-date',
Synopsis = 'synopsis',
Synopsistype = 'synopsistype',
VideoRatingType = 'VideoRatingType',
}
export interface HistoricalSelections {
@ -87,8 +87,8 @@ export interface EpisodeDataIDS {
}
export enum TitleElement {
Empty = "",
English = "English",
Empty = '',
English = 'English',
}
export interface Media {
@ -194,8 +194,7 @@ export interface AvailIDS {
externalAlphaId: string;
}
export interface Next {
}
export type Next = Record<string, unknown>
export interface LanguageClass {
code: string;
@ -299,7 +298,7 @@ export interface CatalogParent {
}
export enum Source {
Dbb = "dbb",
Dbb = 'dbb',
}
export interface MetaItems {
@ -313,10 +312,10 @@ export interface Filters {
}
export interface Items {
"release-date": AnimationProductionStudio;
'release-date': AnimationProductionStudio;
rating: AnimationProductionStudio;
synopsis: AnimationProductionStudio;
"animation-production-studio": AnimationProductionStudio;
'animation-production-studio': AnimationProductionStudio;
}
export interface AnimationProductionStudio {
@ -366,8 +365,8 @@ export interface PreviousSeasonEpisode {
}
export enum Type {
Episode = "episode",
Ova = "ova",
Episode = 'episode',
Ova = 'ova',
}
export interface Quality {

View file

@ -2,7 +2,7 @@ declare module 'hls-download' {
export default class hlsDownload {
constructor(options: {
m3u8json: {
segments: {}[],
segments: Record<string, unknown>[],
mediaSequence?: number,
},
output?: string,

23
@types/items.d.ts vendored
View file

@ -39,8 +39,8 @@ export interface Item {
}
export enum ContentType {
Episode = "episode",
Ova = "ova",
Episode = 'episode',
Ova = 'ova',
}
export interface IDs {
@ -110,19 +110,18 @@ export interface MostRecentAvodIDS {
}
export enum Purchase {
AVOD = "A-VOD",
Dfov = "DFOV",
Est = "EST",
Svod = "SVOD",
AVOD = 'A-VOD',
Dfov = 'DFOV',
Est = 'EST',
Svod = 'SVOD',
}
export enum Version {
Simulcast = "Simulcast",
Uncut = "Uncut",
Simulcast = 'Simulcast',
Uncut = 'Uncut',
}
export interface MostRecentSvodJpnUs {
}
export type MostRecentSvodJpnUs = Record<string, any>
export interface QualityClass {
quality: QualityQuality;
@ -130,8 +129,8 @@ export interface QualityClass {
}
export enum QualityQuality {
HD = "HD",
SD = "SD",
HD = 'HD',
SD = 'SD',
}
export interface TitleImages {

View file

@ -32,17 +32,17 @@ declare module 'm3u8-parsed' {
uri: string,
timeline: number,
attributes: {
"CLOSED-CAPTIONS": string,
"AUDIO": string,
"FRAME-RATE": number,
"RESOLUTION": {
'CLOSED-CAPTIONS': string,
'AUDIO': string,
'FRAME-RATE': number,
'RESOLUTION': {
width: number,
height: number
},
"CODECS": string,
"AVERAGE-BANDWIDTH": string,
"BANDWIDTH": number
'CODECS': string,
'AVERAGE-BANDWIDTH': string,
'BANDWIDTH': number
}
}[],
}
};
}

182
funi.ts
View file

@ -22,11 +22,11 @@ import * as yamlCfg from './modules/module.cfg-loader';
import vttConvert from './modules/module.vttconvert';
// types
import { Item } from "./@types/items";
import { Item } from './@types/items';
// params
const cfg = yamlCfg.loadCfg();
let token = yamlCfg.loadFuniToken();
const token = yamlCfg.loadFuniToken();
// cli
const argv = appYargs.appArgv(cfg.cli);
@ -75,11 +75,11 @@ let title = '',
// auth
async function auth(){
let authOpts = {
const authOpts = {
user: await shlp.question('[Q] LOGIN/EMAIL'),
pass: await shlp.question('[Q] PASSWORD ')
};
let authData = await getData({
const authData = await getData({
baseUrl: api_host,
url: '/auth/login/',
auth: authOpts,
@ -102,8 +102,8 @@ async function auth(){
// search show
async function searchShow(){
let qs = {unique: true, limit: 100, q: argv.search, offset: 0 };
let searchData = await getData({
const qs = {unique: true, limit: 100, q: argv.search, offset: 0 };
const searchData = await getData({
baseUrl: api_host,
url: '/source/funimation/search/auto/',
querystring: qs,
@ -118,9 +118,9 @@ async function searchShow(){
return;
}
if(searchDataJSON.items && searchDataJSON.items.hits){
let shows = searchDataJSON.items.hits;
const shows = searchDataJSON.items.hits;
console.log('[INFO] Search Results:');
for(let ssn in shows){
for(const ssn in shows){
console.log(`[#${shows[ssn].id}] ${shows[ssn].title}` + (shows[ssn].tx_date?` (${shows[ssn].tx_date})`:''));
}
}
@ -130,7 +130,7 @@ async function searchShow(){
// get show
async function getShow(){
// show main data
let showData = await getData({
const showData = await getData({
baseUrl: api_host,
url: `/source/catalog/title/${argv.s}`,
token: token,
@ -151,7 +151,7 @@ async function getShow(){
const showDataItem = showDataJSON.items[0];
console.log('[#%s] %s (%s)',showDataItem.id,showDataItem.title,showDataItem.releaseYear);
// show episodes
let qs: {
const qs: {
limit: number,
sort: string,
sort_direction: string,
@ -159,7 +159,7 @@ async function getShow(){
language?: string
} = { limit: -1, sort: 'order', sort_direction: 'ASC', title_id: argv.s as number };
if(argv.alt){ qs.language = 'English'; }
let episodesData = await getData({
const episodesData = await getData({
baseUrl: api_host,
url: '/funimation/episodes/',
querystring: qs,
@ -170,14 +170,14 @@ async function getShow(){
if(!episodesData.ok || !episodesData.res){return;}
let epsDataArr: Item[] = JSON.parse(episodesData.res.body).items;
let epNumRegex = /^([A-Z0-9]*[A-Z])?(\d+)$/i;
let epSelEpsTxt = [], epSelList, typeIdLen = 0, epIdLen = 4;
const epNumRegex = /^([A-Z0-9]*[A-Z])?(\d+)$/i;
const epSelEpsTxt = []; let typeIdLen = 0, epIdLen = 4;
const parseEpStr = (epStr: string) => {
const match = epStr.match(epNumRegex);
if (!match) {
console.error('[ERROR] No match found')
return ['', '']
console.error('[ERROR] No match found');
return ['', ''];
}
if(match.length > 2){
const spliced = [...match].splice(1);
@ -204,14 +204,14 @@ async function getShow(){
return e;
});
epSelList = parseSelect(argv.e as string);
const epSelList = parseSelect(argv.e as string);
let fnSlug: {
const fnSlug: {
title: string,
episode: string
}[] = [], is_selected = false;
}[] = []; let is_selected = false;
let eps = epsDataArr;
const eps = epsDataArr;
epsDataArr.sort((a, b) => {
if (a.item.seasonOrder < b.item.seasonOrder && a.id.localeCompare(b.id) < 0) {
return -1;
@ -222,7 +222,7 @@ async function getShow(){
return 0;
});
for(let e in eps){
for(const e in eps){
eps[e].id_split[1] = parseInt(eps[e].id_split[1].toString()).toString().padStart(epIdLen, '0');
let epStrId = eps[e].id_split.join('');
// select
@ -236,13 +236,13 @@ async function getShow(){
is_selected = false;
}
// console vars
let tx_snum = eps[e].item.seasonNum=='1'?'':` S${eps[e].item.seasonNum}`;
let tx_type = eps[e].mediaCategory != 'episode' ? eps[e].mediaCategory : '';
let tx_enum = eps[e].item.episodeNum && eps[e].item.episodeNum !== '' ?
const tx_snum = eps[e].item.seasonNum=='1'?'':` S${eps[e].item.seasonNum}`;
const tx_type = eps[e].mediaCategory != 'episode' ? eps[e].mediaCategory : '';
const tx_enum = eps[e].item.episodeNum && eps[e].item.episodeNum !== '' ?
`#${(parseInt(eps[e].item.episodeNum) < 10 ? '0' : '')+eps[e].item.episodeNum}` : '#'+eps[e].item.episodeId;
let qua_str = eps[e].quality.height ? eps[e].quality.quality + eps[e].quality.height : 'UNK';
let aud_str = eps[e].audio.length > 0 ? `, ${eps[e].audio.join(', ')}` : '';
let rtm_str = eps[e].item.runtime !== '' ? eps[e].item.runtime : '??:??';
const qua_str = eps[e].quality.height ? eps[e].quality.quality + eps[e].quality.height : 'UNK';
const aud_str = eps[e].audio.length > 0 ? `, ${eps[e].audio.join(', ')}` : '';
const rtm_str = eps[e].item.runtime !== '' ? eps[e].item.runtime : '??:??';
// console string
eps[e].id_split[0] = eps[e].id_split[0].toString().padStart(typeIdLen, ' ');
epStrId = eps[e].id_split.join('');
@ -270,7 +270,7 @@ async function getEpisode(fnSlug: {
title: string,
episode: string
}) {
let episodeData = await getData({
const episodeData = await getData({
baseUrl: api_host,
url: `/source/catalog/episode/${fnSlug.title}/${fnSlug.episode}/`,
token: token,
@ -278,7 +278,7 @@ async function getEpisode(fnSlug: {
debug: argv.debug,
});
if(!episodeData.ok || !episodeData.res){return;}
let ep = JSON.parse(episodeData.res.body).items[0] as EpisodeData, streamIds = [];
const ep = JSON.parse(episodeData.res.body).items[0] as EpisodeData, streamIds = [];
// build fn
showTitle = ep.parent.title;
title = ep.title;
@ -289,7 +289,7 @@ async function getEpisode(fnSlug: {
fnEpNum = isNaN(parseInt(ep.number)) ? ep.number : parseInt(ep.number);
// is uncut
let uncut = {
const uncut = {
Japanese: false,
English: false
};
@ -306,7 +306,7 @@ async function getEpisode(fnSlug: {
console.log('[INFO] Available streams (Non-Encrypted):');
// map medias
let media = ep.media.map(function(m){
const media = ep.media.map(function(m){
if(m.mediaType == 'experience'){
if(m.version.match(/uncut/i) && m.language){
uncut[m.language] = true;
@ -334,28 +334,22 @@ async function getEpisode(fnSlug: {
// select
stDlPath = [];
for(let m of media){
for(const m of media){
let selected = false;
if(m.id > 0 && m.type == 'Non-Encrypted'){
let dub_type = m.language;
const dub_type = m.language;
if (!dub_type)
continue;
let localSubs: Subtitle[] = [];
let selUncut = !argv.simul && uncut[dub_type] && m.version?.match(/uncut/i)
const selUncut = !argv.simul && uncut[dub_type] && m.version?.match(/uncut/i)
? true
: (!uncut[dub_type] || argv.simul && m.version?.match(/simulcast/i) ? true : false);
for (let curDub of (argv.dub as appYargs.possibleDubs)) {
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))
});
if (!m.subtitles) {
console.log('[ERROR] Unable to find subs for episode ', m.id)
if (argv.debug)
console.log(m)
continue;
}
stDlPath.push(...m.subtitles);
localSubs = m.subtitles;
selected = true;
@ -367,7 +361,7 @@ async function getEpisode(fnSlug: {
}
}
let already: string[] = [];
const already: string[] = [];
stDlPath = stDlPath.filter(a => {
if (already.includes(a.language)) {
return false;
@ -382,8 +376,8 @@ async function getEpisode(fnSlug: {
}
else{
tsDlPath = [];
for (let streamId of streamIds) {
let streamData = await getData({
for (const streamId of streamIds) {
const streamData = await getData({
baseUrl: api_host,
url: `/source/catalog/video/${streamId.id}/signed`,
token: token,
@ -398,7 +392,7 @@ async function getEpisode(fnSlug: {
return;
}
else{
for(let u in streamDataRes.items){
for(const u in streamDataRes.items){
if(streamDataRes.items[u].videoType == 'm3u8'){
tsDlPath.push({
path: streamDataRes.items[u].src,
@ -432,18 +426,18 @@ function getSubsUrl(m: MediaChild[]) : Subtitle[] {
'ptBR': 'Portuguese (Brazil)'
};
let subLangAvailable = m.some(a => subLangs.some(subLang => a.ext == 'vtt' && a.language === subType[subLang]));
const subLangAvailable = m.some(a => subLangs.some(subLang => a.ext == 'vtt' && a.language === subType[subLang]));
if (!subLangAvailable) {
subLangs = [ 'enUS' ];
}
let found: Subtitle[] = [];
const found: Subtitle[] = [];
for(let i in m){
let fpp = m[i].filePath.split('.');
let fpe = fpp[fpp.length-1];
for (let lang of subLangs) {
for(const i in m){
const fpp = m[i].filePath.split('.');
const fpe = fpp[fpp.length-1];
for (const lang of subLangs) {
if(fpe == 'vtt' && m[i].language === subType[lang]) {
found.push({
path: m[i].filePath,
@ -462,26 +456,26 @@ async function downloadStreams(){
// req playlist
let purvideo: DownloadedFile[] = [];
let puraudio: DownloadedFile[] = [];
let audioAndVideo: DownloadedFile[] = [];
for (let streamPath of tsDlPath) {
let plQualityReq = await getData({
const purvideo: DownloadedFile[] = [];
const puraudio: DownloadedFile[] = [];
const audioAndVideo: DownloadedFile[] = [];
for (const streamPath of tsDlPath) {
const plQualityReq = await getData({
url: streamPath.path,
debug: argv.debug,
});
if(!plQualityReq.ok || !plQualityReq.res){return;}
let plQualityLinkList = m3u8(plQualityReq.res.body);
const plQualityLinkList = m3u8(plQualityReq.res.body);
let mainServersList = [
const mainServersList = [
'vmfst-api.prd.funimationsvc.com',
'd33et77evd9bgg.cloudfront.net',
'd132fumi6di1wa.cloudfront.net',
'funiprod.akamaized.net',
];
let plServerList: string[] = [],
const plServerList: string[] = [],
plStreams: Record<string|number, {
[key: string]: string
}> = {},
@ -489,8 +483,8 @@ async function downloadStreams(){
plLayersRes: Record<string|number, {
width: number,
height: number
}> = {},
plMaxLayer = 1,
}> = {};
let plMaxLayer = 1,
plNewIds = 1,
plAud: {
uri: string,
@ -499,11 +493,11 @@ async function downloadStreams(){
} = { uri: '', langStr: '', language: '' };
// new uris
let vplReg = /streaming_video_(\d+)_(\d+)_(\d+)_index\.m3u8/;
const vplReg = /streaming_video_(\d+)_(\d+)_(\d+)_index\.m3u8/;
if(plQualityLinkList.playlists[0].uri.match(vplReg)){
let audioKey = Object.keys(plQualityLinkList.mediaGroups.AUDIO).pop();
const audioKey = Object.keys(plQualityLinkList.mediaGroups.AUDIO).pop();
if (!audioKey)
return console.log('[ERROR] No audio key found')
return console.log('[ERROR] No audio key found');
if(plQualityLinkList.mediaGroups.AUDIO[audioKey]){
const audioDataParts = plQualityLinkList.mediaGroups.AUDIO[audioKey],
audioEl = Object.keys(audioDataParts);
@ -513,11 +507,11 @@ async function downloadStreams(){
plQualityLinkList.playlists.sort((a, b) => {
const aMatch = a.uri.match(vplReg), bMatch = b.uri.match(vplReg);
if (!aMatch || !bMatch) {
console.log('[ERROR] Unable to match')
console.log('[ERROR] Unable to match');
return 0;
}
let av = parseInt(aMatch[3]);
let bv = parseInt(bMatch[3]);
const av = parseInt(aMatch[3]);
const bv = parseInt(bMatch[3]);
if(av > bv){
return 1;
}
@ -528,7 +522,7 @@ async function downloadStreams(){
});
}
for(let s of plQualityLinkList.playlists){
for(const s of plQualityLinkList.playlists){
if(s.uri.match(/_Layer(\d+)\.m3u8/) || s.uri.match(vplReg)){
// set layer and max layer
let plLayerId: number|string = 0;
@ -541,8 +535,8 @@ async function downloadStreams(){
}
plMaxLayer = plMaxLayer < plLayerId ? plLayerId : plMaxLayer;
// set urls and servers
let plUrlDl = s.uri;
let plServer = new URL(plUrlDl).host;
const plUrlDl = s.uri;
const plServer = new URL(plUrlDl).host;
if(!plServerList.includes(plServer)){
plServerList.push(plServer);
}
@ -556,15 +550,15 @@ async function downloadStreams(){
plStreams[plServer][plLayerId] = plUrlDl;
}
// set plLayersStr
let plResolution = s.attributes.RESOLUTION;
const plResolution = s.attributes.RESOLUTION;
plLayersRes[plLayerId] = plResolution;
let plBandwidth = Math.round(s.attributes.BANDWIDTH/1024);
const plBandwidth = Math.round(s.attributes.BANDWIDTH/1024);
if(plLayerId<10){
plLayerId = plLayerId.toString().padStart(2,' ');
}
let qualityStrAdd = `${plLayerId}: ${plResolution.width}x${plResolution.height} (${plBandwidth}KiB/s)`;
let qualityStrRegx = new RegExp(qualityStrAdd.replace(/(:|\(|\)|\/)/g,'\\$1'),'m');
let qualityStrMatch = !plLayersStr.join('\r\n').match(qualityStrRegx);
const qualityStrAdd = `${plLayerId}: ${plResolution.width}x${plResolution.height} (${plBandwidth}KiB/s)`;
const qualityStrRegx = new RegExp(qualityStrAdd.replace(/(:|\(|\)|\/)/g,'\\$1'),'m');
const qualityStrMatch = !plLayersStr.join('\r\n').match(qualityStrRegx);
if(qualityStrMatch){
plLayersStr.push(qualityStrAdd);
}
@ -574,7 +568,7 @@ async function downloadStreams(){
}
}
for(let s of mainServersList){
for(const s of mainServersList){
if(plServerList.includes(s)){
plServerList.splice(plServerList.indexOf(s), 1);
plServerList.unshift(s);
@ -585,9 +579,9 @@ async function downloadStreams(){
argv.q = argv.q < 1 || argv.q > plMaxLayer ? plMaxLayer : argv.q;
let plSelectedServer = plServerList[argv.x-1];
let plSelectedList = plStreams[plSelectedServer];
let videoUrl = argv.x < plServerList.length+1 && plSelectedList[argv.q] ? plSelectedList[argv.q] : '';
const plSelectedServer = plServerList[argv.x-1];
const plSelectedList = plStreams[plSelectedServer];
const videoUrl = argv.x < plServerList.length+1 && plSelectedList[argv.q] ? plSelectedList[argv.q] : '';
plLayersStr.sort();
console.log(`[INFO] Servers available:\n\t${plServerList.join('\n\t')}`);
@ -623,15 +617,15 @@ async function downloadStreams(){
break video;
}
// download video
let reqVideo = await getData({
const reqVideo = await getData({
url: videoUrl,
debug: argv.debug,
});
if (!reqVideo.ok || !reqVideo.res) { break video; }
let chunkList = m3u8(reqVideo.res.body);
const chunkList = m3u8(reqVideo.res.body);
let tsFile = path.join(cfg.dir.content, ...fnOutput.slice(0, -1), `${fnOutput.slice(-1)}.video${(plAud.uri ? '' : '.' + streamPath.lang )}`);
const tsFile = path.join(cfg.dir.content, ...fnOutput.slice(0, -1), `${fnOutput.slice(-1)}.video${(plAud.uri ? '' : '.' + streamPath.lang )}`);
dlFailed = !await downloadFile(tsFile, chunkList);
if (!dlFailed) {
if (plAud.uri) {
@ -654,15 +648,15 @@ async function downloadStreams(){
// download audio
if (audioAndVideo.some(a => a.lang === plAud.language) || puraudio.some(a => a.lang === plAud.language))
break audio;
let reqAudio = await getData({
const reqAudio = await getData({
url: plAud.uri,
debug: argv.debug,
});
if (!reqAudio.ok || !reqAudio.res) { return; }
let chunkListA = m3u8(reqAudio.res.body);
const chunkListA = m3u8(reqAudio.res.body);
let tsFileA = path.join(cfg.dir.content, ...fnOutput.slice(0, -1), `${fnOutput.slice(-1)}.audio.${plAud.language}`);
const tsFileA = path.join(cfg.dir.content, ...fnOutput.slice(0, -1), `${fnOutput.slice(-1)}.audio.${plAud.language}`);
dlFailedA = !await downloadFile(tsFileA, chunkListA);
if (!dlFailedA)
@ -675,19 +669,19 @@ async function downloadStreams(){
}
// add subs
let subsExt = !argv.mp4 || argv.mp4 && argv.ass ? '.ass' : '.srt';
const subsExt = !argv.mp4 || argv.mp4 && argv.ass ? '.ass' : '.srt';
let addSubs = true;
// download subtitles
if(stDlPath.length > 0){
console.log('[INFO] Downloading subtitles...');
for (let subObject of stDlPath) {
let subsSrc = await getData({
for (const subObject of stDlPath) {
const subsSrc = await getData({
url: subObject.path,
debug: argv.debug,
});
if(subsSrc.ok && subsSrc.res){
let assData = vttConvert(subsSrc.res.body, (subsExt == '.srt' ? true : false), subObject.langName, argv.fontSize);
const assData = vttConvert(subsSrc.res.body, (subsExt == '.srt' ? true : false), subObject.langName, argv.fontSize);
subObject.file = path.join(cfg.dir.content, ...fnOutput.slice(0, -1), `${fnOutput.slice(-1)}.subtitle${subObject.ext}${subsExt}`);
fs.writeFileSync(subObject.file, assData);
}
@ -734,14 +728,14 @@ async function downloadStreams(){
subtitels: stDlPath as SubtitleInput[],
videoAndAudio: audioAndVideo,
simul: argv.simul
})
});
if(!argv.mp4 && mergerBin.MKVmerge){
let command = mergeInstance.MkvMerge();
const command = mergeInstance.MkvMerge();
shlp.exec('mkvmerge', `"${mergerBin.MKVmerge}"`, command);
}
else if(mergerBin.FFmpeg){
let command = mergeInstance.FFmpeg();
const command = mergeInstance.FFmpeg();
shlp.exec('ffmpeg',`"${mergerBin.FFmpeg}"`,command);
}
else{
@ -757,7 +751,7 @@ async function downloadStreams(){
}
async function downloadFile(filename: string, chunkList: {
segments: {}[],
segments: Record<string, unknown>[],
}) {
const downloadStatus = await new hlsDownload({
m3u8json: chunkList,
@ -782,7 +776,7 @@ function parseFileName(input: string, title: string, episode:number|string, show
break;
case 'episode': {
if (typeof episode === 'number') {
let len = episode.toFixed(0).toString().length;
const len = episode.toFixed(0).toString().length;
input = input.replace(vars[i], len < argv.numbers ? '0'.repeat(argv.numbers - len) + episode : episode.toString());
} else {
input = input.replace(vars[i], episode);
@ -793,7 +787,7 @@ function parseFileName(input: string, title: string, episode:number|string, show
input = input.replace(vars[i], showTitle);
break;
case 'season': {
let len = season.toFixed(0).toString().length;
const len = season.toFixed(0).toString().length;
input = input.replace(vars[i], len < argv.numbers ? '0'.repeat(argv.numbers - len) + season : season.toString());
break;
}

View file

@ -5,6 +5,7 @@ import fs from 'fs-extra';
import pkg from '../package.json';
import modulesCleanup from 'removeNPMAbsolutePaths';
import { exec } from 'pkg';
import { execSync } from 'child_process';
const buildsDir = './_builds';
const nodeVer = 'node14-';
@ -50,13 +51,13 @@ const nodeVer = 'node14-';
fs.copySync('./config/dir-path.yml', `${buildDir}/config/dir-path.yml`);
fs.copySync('./modules/cmd-here.bat', `${buildDir}/cmd-here.bat`);
fs.copySync('./modules/NotoSans-Regular.ttf', `${buildDir}/NotoSans-Regular.ttf`);
fs.copySync('./package.json', `${buildDir}/package.json`)
fs.copySync('./package.json', `${buildDir}/package.json`);
fs.copySync('./docs/', `${buildDir}/docs/`);
fs.copySync('./LICENSE.md', `${buildDir}/docs/LICENSE.md`);
if(fs.existsSync(`${buildsDir}/${buildFull}.7z`)){
fs.removeSync(`${buildsDir}/${buildFull}.7z`);
}
require('child_process').execSync(`7z a -t7z "${buildsDir}/${buildFull}.7z" "${buildDir}"`,{stdio:[0,1,2]});
execSync(`7z a -t7z "${buildsDir}/${buildFull}.7z" "${buildDir}"`,{stdio:[0,1,2]});
}());
function getTarget(bt: string) : string {

View file

@ -243,7 +243,7 @@ const appArgv = (cfg: {
argv.dub = dubLang;
if (argv.allSubs)
argv.subLang = subLang;
for (let key in argv) {
for (const key in argv) {
if (argv[key] instanceof Array && !(key === 'subLang' || key === 'dub')) {
argv[key] = (argv[key] as Array<unknown>).pop();
}

959
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "funimation-downloader-nx",
"short_name": "funi",
"version": "4.12.5",
"version": "5.0.0",
"description": "Download videos from Funimation via cli.",
"keywords": [
"download",
@ -57,6 +57,8 @@
"build-macos64": "cd lib && node modules/build macos64",
"eslint": "eslint *.js modules",
"eslint-fix": "eslint *.js modules --fix",
"test": "echo \"Error: no test specified\" && exit 1"
"pretest": "npm run tsc",
"test": "cd lib && node modules/build win64 && node modules/build linux64 && node modules/build macos64"
}
}

32
tsc.ts
View file

@ -1,7 +1,7 @@
import { exec } from "child_process";
import fs from "fs";
import path from "path";
import { removeSync, copyFileSync } from "fs-extra";
import { exec } from 'child_process';
import fs from 'fs';
import path from 'path';
import { removeSync, copyFileSync } from 'fs-extra';
const ignore = [
'.git',
@ -13,29 +13,29 @@ const ignore = [
(async () => {
removeSync('lib');
const tsc = exec('npx tsc');
tsc.stdout?.on("data", console.log);
tsc.stderr?.on("data", console.log);
tsc.stdout?.on('data', console.log);
tsc.stderr?.on('data', console.log);
tsc.on("close", () => {
tsc.on('close', () => {
const files = readDir(__dirname);
const filtered = files.filter(a => {
if (a.stats.isFile()) {
return a.path.split('.').pop() !== 'ts';
} else {
return true
return true;
}
})
});
filtered.forEach(item => {
const itemPath = path.join(__dirname, 'lib', item.path.replace(__dirname, ''));
if (item.stats.isDirectory()) {
if (!fs.existsSync(itemPath))
fs.mkdirSync(itemPath)
fs.mkdirSync(itemPath);
} else {
copyFileSync(item.path, itemPath)
copyFileSync(item.path, itemPath);
}
})
})
})()
});
});
})();
const readDir = (dir: string) : {
path: string,
@ -56,8 +56,8 @@ const readDir = (dir: string) : {
stats
});
if (stats.isDirectory()) {
items.push(...readDir(itemPath))
items.push(...readDir(itemPath));
}
}
return items;
}
};