bye bye sei-helper

This commit is contained in:
stratumadev 2025-05-11 18:01:36 +02:00
parent 4d3c5e151c
commit 7dae72a38e
15 changed files with 2842 additions and 5219 deletions

View file

@ -1,14 +0,0 @@
declare module 'sei-helper' {
export async function question(qStr: string): Promise<string>;
export function cleanupFilename(str: string): string;
export const cookie: {
parse: (data: Record<string, string>) => Record<string, {
value: string;
expires: Date;
path: string;
domain: string;
secure: boolean;
}>
};
export function formatTime(time: number): string
}

6
adn.ts
View file

@ -7,7 +7,6 @@ import fs from 'fs-extra';
import crypto from 'crypto';
// Plugins
import shlp from 'sei-helper';
import m3u8 from 'm3u8-parsed';
// Modules
@ -24,6 +23,7 @@ import { downloaded } from './modules/module.downloadArchive';
import parseSelect from './modules/module.parseSelect';
import parseFileName, { Variable } from './modules/module.filename';
import { AvailableFilenameVars } from './modules/module.args';
import Helper from './modules/module.helper';
// Types
import { ServiceClass } from './@types/serviceClassInterface';
@ -91,8 +91,8 @@ export default class AnimationDigitalNetwork implements ServiceClass {
if (argv.auth) {
//Authenticate
await this.doAuth({
username: argv.username ?? await shlp.question('[Q] LOGIN/EMAIL'),
password: argv.password ?? await shlp.question('[Q] PASSWORD ')
username: argv.username ?? await Helper.question('[Q] LOGIN/EMAIL: '),
password: argv.password ?? await Helper.question('[Q] PASSWORD: ')
});
} else if (argv.search && argv.search.length > 2) {
//Search

13
ao.ts
View file

@ -5,9 +5,6 @@ import packageJson from './package.json';
import path from 'path';
import fs from 'fs-extra';
// Plugins
import shlp from 'sei-helper';
// Modules
import * as fontsData from './modules/module.fontsData';
import * as langsData from './modules/module.langsData';
@ -17,7 +14,6 @@ import * as reqModule from './modules/module.fetch';
import Merger, { Font, MergerInput, SubtitleInput } from './modules/module.merger';
import { canDecrypt, getKeysWVD, cdm, getKeysPRD } from './modules/cdm';
import streamdl, { M3U8Json } from './modules/hls-download';
import { exec } from './modules/sei-helper-fixes';
import { console } from './modules/log';
import { domain } from './modules/module.api-urls';
import { downloaded } from './modules/module.downloadArchive';
@ -25,6 +21,7 @@ import parseSelect from './modules/module.parseSelect';
import parseFileName, { Variable } from './modules/module.filename';
import { AvailableFilenameVars } from './modules/module.args';
import { parse } from './modules/module.transform-mpd';
import Helper from './modules/module.helper';
// Types
import { ServiceClass } from './@types/serviceClassInterface';
@ -103,8 +100,8 @@ export default class AnimeOnegai implements ServiceClass {
if (argv.auth) {
//Authenticate
await this.doAuth({
username: argv.username ?? await shlp.question('[Q] LOGIN/EMAIL'),
password: argv.password ?? await shlp.question('[Q] PASSWORD ')
username: argv.username ?? await Helper.question('[Q] LOGIN/EMAIL: '),
password: argv.password ?? await Helper.question('[Q] PASSWORD: ')
});
} else if (argv.search && argv.search.length > 2) {
//Search
@ -712,7 +709,7 @@ export default class AnimeOnegai implements ServiceClass {
if (videoDownloaded) {
console.info('Started decrypting video,', this.cfg.bin.shaka ? 'using shaka' : 'using mp4decrypt');
const decryptVideo = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
const decryptVideo = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
if (!decryptVideo.isOk) {
console.error(decryptVideo.err);
console.error(`Decryption failed with exit code ${decryptVideo.err.code}`);
@ -735,7 +732,7 @@ export default class AnimeOnegai implements ServiceClass {
if (audioDownloaded) {
console.info('Started decrypting audio,', this.cfg.bin.shaka ? 'using shaka' : 'using mp4decrypt');
const decryptAudio = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
const decryptAudio = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
if (!decryptAudio.isOk) {
console.error(decryptAudio.err);
console.error(`Decryption failed with exit code ${decryptAudio.err.code}`);

View file

@ -7,10 +7,9 @@ import packageJson from './package.json';
// plugins
import { console } from './modules/log';
import shlp from 'sei-helper';
import m3u8 from 'm3u8-parsed';
import streamdl, { M3U8Json } from './modules/hls-download';
import { exec } from './modules/sei-helper-fixes';
import Helper from './modules/module.helper';
// custom modules
import * as fontsData from './modules/module.fontsData';
@ -95,8 +94,8 @@ export default class Crunchy implements ServiceClass {
// select mode
if (argv.silentAuth && !argv.auth) {
await this.doAuth({
username: argv.username ?? await shlp.question('[Q] LOGIN/EMAIL'),
password: argv.password ?? await shlp.question('[Q] PASSWORD ')
username: argv.username ?? await Helper.question('[Q] LOGIN/EMAIL: '),
password: argv.password ?? await Helper.question('[Q] PASSWORD: ')
});
}
if(argv.dlFonts){
@ -104,8 +103,8 @@ export default class Crunchy implements ServiceClass {
}
else if(argv.auth){
await this.doAuth({
username: argv.username ?? await shlp.question('[Q] LOGIN/EMAIL'),
password: argv.password ?? await shlp.question('[Q] PASSWORD ')
username: argv.username ?? await Helper.question('[Q] LOGIN/EMAIL: '),
password: argv.password ?? await Helper.question('[Q] PASSWORD: ')
});
}
else if (argv.token) {
@ -612,7 +611,7 @@ export default class Crunchy implements ServiceClass {
// set object booleans
if(iMetadata.duration_ms){
oBooleans.push(shlp.formatTime(iMetadata.duration_ms/1000));
oBooleans.push(Helper.formatTime(iMetadata.duration_ms/1000));
}
if(iMetadata.is_simulcast) {
oBooleans.push('SIMULCAST');
@ -1888,7 +1887,7 @@ export default class Crunchy implements ServiceClass {
if (videoDownloaded) {
console.info('Started decrypting video,', this.cfg.bin.shaka ? 'using shaka' : 'using mp4decrypt');
const decryptVideo = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
const decryptVideo = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
if (!decryptVideo.isOk) {
console.error(decryptVideo.err);
console.error(`Decryption failed with exit code ${decryptVideo.err.code}`);
@ -1912,7 +1911,7 @@ export default class Crunchy implements ServiceClass {
if (audioDownloaded) {
console.info('Started decrypting audio,', this.cfg.bin.shaka ? 'using shaka' : 'using mp4decrypt');
const decryptAudio = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
const decryptAudio = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
if (!decryptAudio.isOk) {
console.error(decryptAudio.err);
console.error(`Decryption failed with exit code ${decryptAudio.err.code}`);

View file

@ -2,7 +2,6 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
export default tseslint.config(
eslint.configs.recommended,
@ -33,9 +32,6 @@ export default tseslint.config(
'always'
]
},
plugins: {
react
},
languageOptions: {
parserOptions: {
ecmaFeatures: {

View file

@ -7,7 +7,6 @@ import packageJson from './package.json';
// plugins
import { console } from './modules/log';
import shlp from 'sei-helper';
import streamdl, { M3U8Json } from './modules/hls-download';
// custom modules
@ -17,6 +16,7 @@ import * as yamlCfg from './modules/module.cfg-loader';
import * as yargs from './modules/module.app-args';
import Merger, { Font, MergerInput, SubtitleInput } from './modules/module.merger';
import vtt2ass from './modules/module.vtt2ass';
import Helper from './modules/module.helper';
// load req
import { domain, api } from './modules/module.api-urls';
@ -36,7 +36,6 @@ import { NewHidiveEpisode } from './@types/newHidiveEpisode';
import { NewHidivePlayback, Subtitle } from './@types/newHidivePlayback';
import { MPDParsed, parse } from './modules/module.transform-mpd';
import { canDecrypt, getKeysWVD, cdm, getKeysPRD } from './modules/cdm';
import { exec } from './modules/sei-helper-fixes';
import { KeyContainer } from './modules/widevine/license';
export default class Hidive implements ServiceClass {
@ -71,8 +70,8 @@ export default class Hidive implements ServiceClass {
if (argv.auth) {
//Authenticate
await this.doAuth({
username: argv.username ?? await shlp.question('[Q] LOGIN/EMAIL'),
password: argv.password ?? await shlp.question('[Q] PASSWORD ')
username: argv.username ?? await Helper.question('[Q] LOGIN/EMAIL: '),
password: argv.password ?? await Helper.question('[Q] PASSWORD: ')
});
} else if (argv.search && argv.search.length > 2){
await this.doSearch({ ...argv, search: argv.search as string });
@ -839,7 +838,7 @@ export default class Hidive implements ServiceClass {
}
console.info('Started decrypting video,', this.cfg.bin.shaka ? 'using shaka' : 'using mp4decrypt');
const decryptVideo = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
const decryptVideo = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandVideo);
if (!decryptVideo.isOk) {
console.error(decryptVideo.err);
console.error(`Decryption failed with exit code ${decryptVideo.err.code}`);
@ -925,7 +924,7 @@ export default class Hidive implements ServiceClass {
}
console.info('Started decrypting audio');
const decryptAudio = exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
const decryptAudio = Helper.exec(this.cfg.bin.shaka ? 'shaka-packager' : 'mp4decrypt', this.cfg.bin.shaka ? `"${this.cfg.bin.shaka}"` : `"${this.cfg.bin.mp4decrypt}"`, commandAudio);
if (!decryptAudio.isOk) {
console.error(decryptAudio.err);
console.error(`Decryption failed with exit code ${decryptAudio.err.code}`);

View file

@ -4,12 +4,10 @@ import fs from 'fs/promises';
import fsp from 'fs';
import url from 'url';
// extra
import shlp from 'sei-helper';
import { console } from './log';
import { ProgressData } from '../@types/messageHandler';
import { ofetch } from 'ofetch';
import Helper from './module.helper';
export type HLSCallback = (data: ProgressData) => unknown;
@ -131,7 +129,7 @@ class hlsDownload {
}
// ask before rewrite file
if (fsp.existsSync(`${fn}`) && !this.data.isResume) {
let rwts = this.data.override ?? (await shlp.question(`[Q] File «${fn}» already exists! Rewrite? ([y]es/[N]o/[c]ontinue)`));
let rwts = this.data.override ?? (await Helper.question(`[Q] File «${fn}» already exists! Rewrite? ([y]es/[N]o/[c]ontinue)`));
rwts = rwts || 'N';
if (['Y', 'y'].includes(rwts[0])) {
console.info(`Deleting «${fn}»...`);
@ -258,7 +256,7 @@ class hlsDownload {
})
);
console.info(
`${downloadedSeg} of ${totalSeg} parts downloaded [${data.percent}%] (${shlp.formatTime(parseInt((data.time / 1000).toFixed(0)))} | ${(
`${downloadedSeg} of ${totalSeg} parts downloaded [${data.percent}%] (${Helper.formatTime(parseInt((data.time / 1000).toFixed(0)))} | ${(
data.downloadSpeed / 1000000
).toPrecision(2)}Mb/s)`
);

View file

@ -2,13 +2,15 @@
import crypto from 'crypto';
import fs from 'fs';
import url from 'url';
import readline from 'readline/promises';
import { stdin as input, stdout as output } from 'process';
// extra
import shlp from 'sei-helper';
import got, { Response } from 'got';
import { console } from './log';
import { ProgressData } from '../@types/messageHandler';
import Helper from './module.helper';
// The following function should fix an issue with downloading. For more information see https://github.com/sindresorhus/got/issues/1489
const fixMiddleWare = (res: Response) => {
@ -155,7 +157,9 @@ class hlsDownload {
}
// ask before rewrite file
if (fs.existsSync(`${fn}`) && !this.data.isResume) {
let rwts = this.data.override ?? await shlp.question(`[Q] File «${fn}» already exists! Rewrite? ([y]es/[N]o/[c]ontinue)`);
const rl = readline.createInterface({ input, output });
let rwts = this.data.override ?? await rl.question(`[Q] File «${fn}» already exists! Rewrite? ([y]es/[N]o/[c]ontinue)`);
rl.close();
rwts = rwts || 'N';
if (['Y', 'y'].includes(rwts[0])) {
console.info(`Deleting «${fn}»...`);
@ -284,7 +288,7 @@ class hlsDownload {
completed: this.data.parts.completed,
total: totalSeg
}));
console.info(`${downloadedSeg} of ${totalSeg} parts downloaded [${data.percent}%] (${shlp.formatTime(parseInt((data.time / 1000).toFixed(0)))} | ${(data.downloadSpeed / 1000000).toPrecision(2)}Mb/s)`);
console.info(`${downloadedSeg} of ${totalSeg} parts downloaded [${data.percent}%] (${Helper.formatTime(parseInt((data.time / 1000).toFixed(0)))} | ${(data.downloadSpeed / 1000000).toPrecision(2)}Mb/s)`);
if (this.data.callback)
this.data.callback({ total: this.data.parts.total, cur: this.data.parts.completed, bytes: this.data.bytesDownloaded, percent: data.percent, time: data.time, downloadSpeed: data.downloadSpeed });
}

View file

@ -1,7 +1,7 @@
import * as shlp from 'sei-helper';
import path from 'path';
import { AvailableFilenameVars } from './module.args';
import { console } from './log';
import Helper from './module.helper';
export type Variable<T extends string = AvailableFilenameVars> = ({
type: 'number',
@ -38,11 +38,11 @@ const parseFileName = (input: string, variables: Variable[], numbers: number, ov
input = input.replace(type, replaceStr);
} else {
if (use.sanitize)
use.replaceWith = shlp.cleanupFilename(use.replaceWith);
use.replaceWith = Helper.cleanupFilename(use.replaceWith);
input = input.replace(type, use.replaceWith);
}
}
return input.split(path.sep).map(a => shlp.cleanupFilename(a));
return input.split(path.sep).map(a => Helper.cleanupFilename(a));
};
const parseOverride = (variables: Variable[], override: string[]): Variable<string>[] => {

77
modules/module.helper.ts Normal file
View file

@ -0,0 +1,77 @@
// Helper functions
import readline from 'readline/promises';
import { stdin as input, stdout as output } from 'process';
import childProcess from 'child_process';
import { console } from './log';
export default class Helper {
static async question(q: string) {
const rl = readline.createInterface({ input, output });
const a = await rl.question(q);
rl.close();
return a;
}
static formatTime(t: number) {
const days = Math.floor(t / 86400);
const hours = Math.floor((t % 86400) / 3600);
const minutes = Math.floor(((t % 86400) % 3600) / 60);
const seconds = t % 60;
const daysS = days > 0 ? `${days}d` : '';
const hoursS = daysS || hours ? `${daysS}${daysS && hours < 10 ? '0' : ''}${hours}h` : '';
const minutesS = minutes || hoursS ? `${hoursS}${hoursS && minutes < 10 ? '0' : ''}${minutes}m` : '';
const secondsS = `${minutesS}${minutesS && seconds < 10 ? '0' : ''}${seconds}s`;
return secondsS;
}
static cleanupFilename(n: string) {
/* eslint-disable no-extra-boolean-cast, no-useless-escape, no-control-regex */
const fixingChar = '_';
const illegalRe = /[\/\?<>\\:\*\|":]/g;
const controlRe = /[\x00-\x1f\x80-\x9f]/g;
const reservedRe = /^\.+$/;
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
const windowsTrailingRe = /[\. ]+$/;
return n
.replace(illegalRe, fixingChar)
.replace(controlRe, fixingChar)
.replace(reservedRe, fixingChar)
.replace(windowsReservedRe, fixingChar)
.replace(windowsTrailingRe, fixingChar);
}
static exec(
pname: string,
fpath: string,
pargs: string,
spc = false
):
| {
isOk: true;
}
| {
isOk: false;
err: Error & { code: number };
} {
pargs = pargs ? ' ' + pargs : '';
console.info(`\n> "${pname}"${pargs}${spc ? '\n' : ''}`);
try {
if (process.platform === 'win32') {
childProcess.execSync('& ' + fpath + pargs, { stdio: 'inherit', shell: 'powershell.exe', windowsHide: true });
} else {
childProcess.execSync(fpath + pargs, { stdio: 'inherit' });
}
return {
isOk: true
};
} catch (er) {
const err = er as Error & { status: number };
return {
isOk: false,
err: {
...err,
code: err.status
}
};
}
}
}

View file

@ -5,9 +5,9 @@ import path from 'path';
import fs from 'fs';
import { LanguageItem } from './module.langsData';
import { AvailableMuxer } from './module.args';
import { exec } from './sei-helper-fixes';
import { console } from './log';
import ffprobe from 'ffprobe';
import Helper from './module.helper';
export type MergerInput = {
path: string,
@ -402,7 +402,7 @@ class Merger {
return;
}
console.info(`[${type}] Started merging`);
const res = exec(type, `"${bin}"`, command);
const res = Helper.exec(type, `"${bin}"`, command);
if (!res.isOk && type === 'mkvmerge' && res.err.code === 1) {
console.info(`[${type}] Mkvmerge finished with at least one warning`);
} else if (!res.isOk) {

View file

@ -6,9 +6,9 @@ import packageJson from '../package.json';
import { CompilerOptions, transpileModule } from 'typescript';
import tsConfig from '../tsconfig.json';
import fsextra from 'fs-extra';
import seiHelper from 'sei-helper';
import { workingDir } from './module.cfg-loader';
import { console } from './log';
import Helper from './module.helper';
const updateFilePlace = path.join(workingDir, 'config', 'updates.json');
const updateIgnore = [
@ -95,7 +95,7 @@ export default async (force = false) => {
for (const a of changedFiles.filter((a) => a.status !== 'added')) {
if (!askBeforeUpdate.some((pattern) => matchString(pattern, a.filename))) continue;
const answer = await seiHelper.question(
const answer = await Helper.question(
`The developer decided that the file '${a.filename}' may contain information you changed yourself. Should they be overriden to be updated? [y/N]`
);
if (answer.toLowerCase() === 'y') remove.push(a.sha);

View file

@ -1,33 +0,0 @@
import childProcess from 'child_process';
import { console } from './log';
const exec = (pname: string, fpath: string, pargs: string, spc = false): {
isOk: true
} | {
isOk: false,
err: Error & { code: number }
} => {
pargs = pargs ? ' ' + pargs : '';
console.info(`\n> "${pname}"${pargs}${spc ? '\n' : ''}`);
try {
if (process.platform === 'win32') {
childProcess.execSync(('& ' + fpath + pargs), { stdio: 'inherit', 'shell': 'powershell.exe', 'windowsHide': true });
} else {
childProcess.execSync((fpath + pargs), { stdio: 'inherit' });
}
return {
isOk: true
};
} catch (er) {
const err = er as Error & { status: number };
return {
isOk: false,
err: {
...err,
code: err.status
}
};
}
};
export { exec };

View file

@ -51,7 +51,7 @@
"elliptic": "^6.6.1",
"esbuild": "^0.25.4",
"express": "^5.1.0",
"fast-xml-parser": "^5.2.2",
"fast-xml-parser": "^5.2.3",
"ffprobe": "^1.1.2",
"fs-extra": "^11.3.0",
"got": "11.8.6",
@ -65,8 +65,7 @@
"node-forge": "^1.3.1",
"ofetch": "^1.4.1",
"open": "^8.4.2",
"protobufjs": "^7.5.0",
"sei-helper": "^3.3.0",
"protobufjs": "^7.5.1",
"ws": "^8.18.2",
"yaml": "^2.7.1",
"yargs": "^17.7.2"
@ -74,20 +73,18 @@
"devDependencies": {
"@eslint/js": "^9.26.0",
"@types/bn.js": "^5.1.6",
"@types/cors": "^2.8.17",
"@types/cors": "^2.8.18",
"@types/elliptic": "^6.4.18",
"@types/express": "^5.0.1",
"@types/ffprobe": "^1.1.8",
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.15.14",
"@types/node": "^22.15.17",
"@types/node-forge": "^1.3.11",
"@types/ws": "^8.18.1",
"@types/yargs": "^17.0.33",
"@typescript-eslint/eslint-plugin": "^8.32.0",
"@typescript-eslint/parser": "^8.32.0",
"eslint": "^8.57.1",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "7.37.5",
"eslint": "^9.26.0",
"protoc": "^1.1.3",
"removeNPMAbsolutePaths": "^3.0.1",
"ts-node": "^10.9.2",

File diff suppressed because it is too large Load diff