added proxy support

This commit is contained in:
stratumadev 2025-10-10 15:57:57 +02:00
parent 6b3fd97f56
commit debc2876d6
12 changed files with 250 additions and 242 deletions

11
adn.ts
View file

@ -35,6 +35,7 @@ import { ADNVideo, ADNVideos } from './@types/adnVideos';
import { ADNPlayerConfig } from './@types/adnPlayerConfig';
import { ADNStreams } from './@types/adnStreams';
import { ADNSubtitles } from './@types/adnSubtitles';
import { FetchParams } from './modules/module.fetch';
export default class AnimationDigitalNetwork implements ServiceClass {
public cfg: yamlCfg.ConfigObject;
@ -58,7 +59,7 @@ export default class AnimationDigitalNetwork implements ServiceClass {
constructor(private debug = false) {
this.cfg = yamlCfg.loadCfg();
this.token = yamlCfg.loadADNToken();
this.req = new reqModule.Req(domain, debug, false, 'adn');
this.req = new reqModule.Req();
this.locale = 'fr';
}
@ -184,13 +185,14 @@ export default class AnimationDigitalNetwork implements ServiceClass {
password: data.password,
source: 'Web'
});
const authReqOpts: reqModule.Params = {
const authReqOpts: FetchParams = {
method: 'POST',
body: authData,
headers: {
'content-type': 'application/json',
'x-target-distribution': this.locale
}
},
useProxy: true
};
const authReq = await this.req.getData('https://gw.api.animationdigitalnetwork.com/authentication/login', authReqOpts);
if (!authReq.ok || !authReq.res) {
@ -212,7 +214,8 @@ export default class AnimationDigitalNetwork implements ServiceClass {
'content-type': 'application/json',
'x-target-distribution': this.locale
},
body: JSON.stringify({ refreshToken: this.token.refreshToken })
body: JSON.stringify({ refreshToken: this.token.refreshToken }),
useProxy: true
});
if (!authReq.ok || !authReq.res) {
console.error('Token refresh failed!');

View file

@ -41,6 +41,7 @@ import vtt2ass from './modules/module.vtt2ass';
import { CrunchyPlayStream } from './@types/crunchyPlayStreams';
import { CrunchyVideoPlayStreams, CrunchyAudioPlayStreams } from './@types/enums';
import { randomUUID } from 'node:crypto';
import { FetchParams } from './modules/module.fetch';
export type sxItem = {
language: langsData.LanguageItem;
@ -64,7 +65,7 @@ export default class Crunchy implements ServiceClass {
constructor(private debug = false) {
this.cfg = yamlCfg.loadCfg();
this.token = yamlCfg.loadCRToken();
this.req = new reqModule.Req(domain, debug, false, 'cr');
this.req = new reqModule.Req();
this.locale = 'en-US';
}
@ -193,8 +194,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
// seasons list
const seriesSeasonListReq = await this.req.getData(
@ -224,8 +224,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
// seasons list
let episodeList = { total: 0, data: [], meta: {} } as CrunchyEpisodeList;
@ -277,8 +276,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
const allShows: any[] = [];
@ -402,10 +400,11 @@ export default class Crunchy implements ServiceClass {
device_name: 'iPhone',
device_type: 'iPhone 13'
}).toString();
const authReqOpts: reqModule.Params = {
const authReqOpts: FetchParams = {
method: 'POST',
headers: { ...api.crunchyAuthHeader, 'ETP-Anonymous-ID': uuid },
body: authData
body: authData,
useProxy: true
};
const authReq = await this.req.getData(api.auth, authReqOpts);
if (!authReq.ok || !authReq.res) {
@ -441,10 +440,11 @@ export default class Crunchy implements ServiceClass {
device_name: 'iPhone',
device_type: 'iPhone 13'
}).toString();
const authReqOpts: reqModule.Params = {
const authReqOpts: FetchParams = {
method: 'POST',
headers: { ...api.crunchyAuthHeader, 'ETP-Anonymous-ID': uuid },
body: authData
body: authData,
useProxy: true
};
const authReq = await this.req.getData(api.auth, authReqOpts);
if (!authReq.ok || !authReq.res) {
@ -477,8 +477,7 @@ export default class Crunchy implements ServiceClass {
headers: {
...api.crunchyDefHeader,
Authorization: `Bearer ${this.token.access_token}`
},
useProxy: true
}
};
const profileReq = await this.req.getData(api.profile, profileReqOptions);
if (!profileReq.ok || !profileReq.res) {
@ -509,10 +508,11 @@ export default class Crunchy implements ServiceClass {
device_name: 'iPhone',
device_type: 'iPhone 13'
}).toString();
const authReqOpts: reqModule.Params = {
const authReqOpts: FetchParams = {
method: 'POST',
headers: { ...api.crunchyAuthHeader, 'ETP-Anonymous-ID': uuid, Cookie: `etp_rt=${refreshToken}` },
body: authData
body: authData,
useProxy: true
};
const authReq = await this.req.getData(api.auth, authReqOpts);
if (!authReq.ok || !authReq.res) {
@ -560,10 +560,11 @@ export default class Crunchy implements ServiceClass {
device_name: 'iPhone',
device_type: 'iPhone 13'
}).toString();
const authReqOpts: reqModule.Params = {
const authReqOpts: FetchParams = {
method: 'POST',
headers: { ...api.crunchyAuthHeader, 'ETP-Anonymous-ID': uuid },
body: authData
body: authData,
useProxy: true
};
const authReq = await this.req.getData(api.auth, authReqOpts);
if (!authReq.ok || !authReq.res) {
@ -613,8 +614,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
const cmsTokenReq = await this.req.getData(api.cms_auth, cmsTokenReqOpts);
if (!cmsTokenReq.ok || !cmsTokenReq.res) {
@ -666,8 +666,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
const searchStart = data.page ? (data.page - 1) * 5 : 0;
const searchParams = new URLSearchParams({
@ -929,8 +928,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
// reqs
if (!hideSeriesTitle) {
@ -974,8 +972,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
//Movie Listing
@ -1017,8 +1014,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
const newlyAddedParams = new URLSearchParams({
sort_by: 'newly_added',
@ -1070,8 +1066,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
//get show info
@ -1303,8 +1298,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
// reqs
@ -1317,8 +1311,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
const mvInfoReq = await this.req.getData(
@ -1545,7 +1538,7 @@ export default class Crunchy implements ServiceClass {
await this.refreshToken(true, true);
let currentVersion;
let isPrimary = mMeta.isSubbed;
const AuthHeaders: RequestInit = {
const AuthHeaders: FetchParams = {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
@ -3302,8 +3295,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
// seasons list
@ -3334,8 +3326,7 @@ export default class Crunchy implements ServiceClass {
headers: {
Authorization: `Bearer ${this.token.access_token}`,
...api.crunchyDefHeader
},
useProxy: true
}
};
//get show info

View file

@ -37,6 +37,7 @@ import { NewHidivePlayback, Subtitle } from './@types/newHidivePlayback';
import { MPDParsed, parse } from './modules/module.transform-mpd';
import { canDecrypt, getKeysWVD, cdm, getKeysPRD } from './modules/cdm';
import { KeyContainer } from './modules/widevine/license';
import { FetchParams } from './modules/module.fetch';
export default class Hidive implements ServiceClass {
public cfg: yamlCfg.ConfigObject;
@ -46,7 +47,7 @@ export default class Hidive implements ServiceClass {
constructor(private debug = false) {
this.cfg = yamlCfg.loadCfg();
this.token = yamlCfg.loadNewHDToken();
this.req = new reqModule.Req(domain, debug, false, 'hd');
this.req = new reqModule.Req();
}
public async cli() {
@ -127,7 +128,7 @@ export default class Hidive implements ServiceClass {
method: method as 'GET' | 'POST',
url: (api.hd_new_api + endpoint) as string,
body: body,
useProxy: true
useProxy: false
};
// get request type
const isGet = method == 'GET';
@ -139,8 +140,10 @@ export default class Hidive implements ServiceClass {
options.headers['Authorization'] = authHeader;
} else if (authType == 'auth') {
options.headers['Authorization'] = `Bearer ${this.token.authorisationToken}`;
options.useProxy = true;
} else if (authType == 'refresh') {
options.headers['Authorization'] = `Bearer ${this.token.refreshToken}`;
options.useProxy = true;
} else if (authType == 'both') {
options.headers['Authorization'] = `Mixed ${this.token.authorisationToken} ${this.token.refreshToken}`;
}
@ -148,10 +151,11 @@ export default class Hidive implements ServiceClass {
console.debug('[DEBUG] Request params:');
console.debug(options);
}
const apiReqOpts: reqModule.Params = {
const apiReqOpts: FetchParams = {
method: options.method,
headers: options.headers as Record<string, string>,
body: options.body as string
body: options.body as string,
useProxy: options.useProxy
};
let apiReq = await this.req.getData(options.url, apiReqOpts);
if (!apiReq.ok || !apiReq.res) {

View file

@ -6,7 +6,9 @@ import { Device } from './playready/device';
import Cdm from './playready/cdm';
import { PSSH } from './playready/pssh';
import { KeyContainer, Session } from './widevine/license';
import { ofetch } from 'ofetch';
import * as reqModule from './module.fetch';
const req = new reqModule.Req();
//read cdm files located in the same directory
let privateKey: Buffer = Buffer.from([]),
@ -97,45 +99,26 @@ export async function getKeysWVD(pssh: string | undefined, licenseServer: string
//Create a new widevine session
const session = new Session({ privateKey, identifierBlob }, psshBuffer);
//Generate license
const data = await ofetch(licenseServer, {
// Request License
const licReq = await req.getData(licenseServer, {
method: 'POST',
body: session.createLicenseRequest(),
headers: authData,
responseType: 'arrayBuffer'
}).catch((error) => {
if (error.status && error.statusText) {
console.error(`${error.name} ${error.status}: ${error.statusText}`);
} else {
console.error(`${error.name}: ${error.message}`);
}
if (!error.data) return;
const data = error.data instanceof ArrayBuffer ? new TextDecoder().decode(error.data) : error.data;
if (data) {
const docTitle = data.match(/<title>(.*)<\/title>/);
if (docTitle) {
console.error(docTitle[1]);
}
if (error.status && error.status != 404 && error.status != 403) {
console.error('Body:', data);
}
}
headers: authData
});
if (data) {
//Parse License and return keys
const text = new TextDecoder().decode(data);
try {
const json = JSON.parse(text);
return session.parseLicense(Buffer.from(json['license'], 'base64')) as KeyContainer[];
} catch {
return session.parseLicense(Buffer.from(new Uint8Array(data))) as KeyContainer[];
}
} else {
console.error('License request failed');
if (!licReq.ok || !licReq.res) {
console.error('License fetch Failed!');
return [];
}
const lic = await licReq.res.arrayBuffer();
const lictext = new TextDecoder().decode(lic);
try {
const json = JSON.parse(lictext);
return session.parseLicense(Buffer.from(json['license'], 'base64')) as KeyContainer[];
} catch {
return session.parseLicense(Buffer.from(new Uint8Array(lic))) as KeyContainer[];
}
}
export async function getKeysPRD(pssh: string | undefined, licenseServer: string, authData: Record<string, string>): Promise<KeyContainer[]> {
@ -146,45 +129,29 @@ export async function getKeysPRD(pssh: string | undefined, licenseServer: string
const session = prd_cdm.getLicenseChallenge(pssh_parsed.get_wrm_headers(true)[0]);
//Generate license
const data = await ofetch(licenseServer, {
const licReq = await req.getData(licenseServer, {
method: 'POST',
body: session,
headers: authData,
responseType: 'text'
}).catch((error) => {
if (error && error.status && error.statusText) {
console.error(`${error.name} ${error.status}: ${error.statusText}`);
} else {
console.error(`${error.name}: ${error.message}`);
}
if (!error.data) return;
const docTitle = error.data.match(/<title>(.*)<\/title>/);
if (docTitle) {
console.error(docTitle[1]);
}
if (error.status && error.status != 404 && error.status != 403) {
console.error('Body:', error.data);
}
headers: authData
});
if (data) {
//Parse License and return keys
try {
const keys = prd_cdm.parseLicense(data);
if (!licReq.ok || !licReq.res) {
console.error('License fetch Failed!');
return [];
}
return keys.map((k) => {
return {
kid: k.key_id,
key: k.key
};
});
} catch {
console.error('License parsing failed');
return [];
}
} else {
console.error('License request failed');
//Parse License and return keys
try {
const keys = prd_cdm.parseLicense(await licReq.res.text());
return keys.map((k) => {
return {
kid: k.key_id,
key: k.key
};
});
} catch {
console.error('License parsing failed');
return [];
}
}

View file

@ -6,8 +6,10 @@ import url from 'url';
import { console } from './log';
import { ProgressData } from '../@types/messageHandler';
import { ofetch } from 'ofetch';
import Helper from './module.helper';
import * as reqModule from './module.fetch';
const req = new reqModule.Req();
export type HLSCallback = (data: ProgressData) => unknown;
@ -343,6 +345,7 @@ class hlsDownload {
segOffset,
false
);
if (!part) throw Error();
// if (this.data.checkPartLength) {
// this.data.checkPartLength = false;
// console.warn(`Part ${segIndex + segOffset + 1}: can't check parts size!`);
@ -419,18 +422,20 @@ const extFn = {
const buffer = await fs.readFile(url.fileURLToPath(uri));
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
}
// do request
return await ofetch(uri, {
const partReq = await req.getData(uri, {
method: 'GET',
headers: headers,
responseType: 'arrayBuffer',
retry: 0,
async onRequestError({ error }) {
const partType = isKey ? 'Key' : 'Part';
const partIndx = partIndex + 1 + segOffset;
console.warn(`%s %s: ${error.message}`, partType, partIndx);
}
headers: headers
});
if (!partReq.res || !partReq.ok) {
const partType = isKey ? 'Key' : 'Part';
const partIndx = partIndex + 1 + segOffset;
console.warn(`%s %s: ${partReq.error?.res?.statusText}`, partType, partIndx);
return;
}
return await partReq.res.arrayBuffer();
}
};

View file

@ -8,7 +8,7 @@ import { console } from './log';
import { CrunchyVideoPlayStreams, CrunchyAudioPlayStreams } from '../@types/enums';
import pj from '../package.json';
let argvC: {
export let argvC: {
[x: string]: unknown;
ccTag: string;
defaultAudio: LanguageItem;
@ -96,6 +96,9 @@ let argvC: {
scaledBorderAndShadowFix: boolean;
scaledBorderAndShadow: 'yes' | 'no';
originalScriptFix: boolean;
// Proxy
proxy: string;
proxyAll: boolean;
};
export type ArgvType = typeof argvC;

View file

@ -1002,6 +1002,30 @@ const args: TAppArg<boolean | number | string | unknown[]>[] = [
default: {
default: 'cc'
}
},
{
name: 'proxy',
describe: 'Uses Proxy on geo-restricted or geo-defining endpoints (e.g. socks5://127.0.0.1:1080 or http://127.0.0.1:1080)',
docDescribe: true,
group: 'util',
service: ['all'],
type: 'string',
usage: '${proxy_url}',
default: {
default: ''
}
},
{
name: 'proxyAll',
describe: 'Proxies everything, not recommended. Proxy needs to be defined.',
docDescribe: true,
group: 'util',
service: ['all'],
type: 'boolean',
usage: '',
default: {
default: false
}
}
];

View file

@ -1,6 +1,11 @@
import * as yamlCfg from './module.cfg-loader';
import * as yargs from './module.app-args';
import { console } from './log';
import { connect } from 'puppeteer-real-browser';
import { argvC } from './module.app-args';
import { ProxyAgent, fetch, RequestInit } from 'undici';
export type FetchParams = Partial<RequestInit & CustomParams>;
export type Params = {
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
@ -10,6 +15,10 @@ export type Params = {
followRedirect?: 'follow' | 'error' | 'manual';
};
type CustomParams = {
useProxy: boolean;
};
type GetDataResponse = {
ok: boolean;
res?: Response;
@ -31,39 +40,19 @@ function hasDisplay(): boolean {
// req
export class Req {
private sessCfg: string;
private service: 'cr' | 'hd' | 'adn';
private session: Record<
string,
{
value: string;
expires: Date;
path: string;
domain: string;
secure: boolean;
'Max-Age'?: string;
}
> = {};
private cfgDir = yamlCfg.cfgDir;
private curl: boolean | string = false;
private debug: boolean;
public argv: typeof argvC;
constructor(
private domain: Record<string, unknown>,
private debug: boolean,
private nosess = false,
private type: 'cr' | 'hd' | 'adn'
) {
this.sessCfg = yamlCfg.sessCfgFile[type];
this.service = type;
constructor() {
const cfg = yamlCfg.loadCfg();
this.argv = yargs.appArgv(cfg.cli, process.env.isGUI ? true : false);
this.debug = this.argv.debug ?? false;
}
async getData(durl: string, params?: RequestInit): Promise<GetDataResponse> {
params = params || {};
// options
async getData(durl: string, params: Partial<RequestInit & CustomParams> = {}): Promise<GetDataResponse> {
const options: RequestInit = {
method: params.method ? params.method : 'GET'
};
// additional params
if (params.headers) {
options.headers = params.headers;
}
@ -73,14 +62,24 @@ export class Req {
if (typeof params.redirect == 'string') {
options.redirect = params.redirect;
}
// debug
// Proxy Handler
let dispatcher: ProxyAgent | undefined;
const validProxy = this.argv.proxy ? this.isValidProxyUrl(this.argv.proxy) : false;
if ((params.useProxy || this.argv.proxyAll) && this.argv.proxy && validProxy) {
dispatcher = new ProxyAgent(this.argv.proxy);
} else if ((params.useProxy || this.argv.proxyAll) && this.argv.proxy && !validProxy) {
console.warn('[Fetch] Provided invalid Proxy URL, not proxying traffic.');
}
// Debug
if (this.debug) {
console.debug('[DEBUG] FETCH OPTIONS:');
console.debug(options);
}
// try do request
try {
const res = await fetch(durl, options);
const res = await fetch(durl, { ...options, dispatcher: dispatcher });
if (!res.ok) {
console.error(`${res.status}: ${res.statusText}`);
const body = await res.text();
@ -122,7 +121,7 @@ export class Req {
}
return {
ok: res.ok,
res,
res: res as any,
headers: params.headers as Record<string, string>
};
} catch (_error) {
@ -149,33 +148,28 @@ export class Req {
};
}
}
}
export function buildProxy(proxyBaseUrl: string, proxyAuth: string) {
if (!proxyBaseUrl.match(/^(https?|socks4|socks5):/)) {
proxyBaseUrl = 'http://' + proxyBaseUrl;
}
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 (proxyAuth && typeof proxyAuth == 'string' && proxyAuth.match(':')) {
proxyCfg.username = proxyAuth.split(':')[0];
proxyCfg.password = proxyAuth.split(':')[1];
proxyStr += `${proxyCfg.username}:${proxyCfg.password}@`;
}
proxyStr += proxyCfg.hostname;
if (!proxyCfg.port && proxyCfg.protocol == 'http:') {
proxyStr += ':80';
} else if (!proxyCfg.port && proxyCfg.protocol == 'https:') {
proxyStr += ':443';
}
return proxyStr;
private isValidProxyUrl(proxyUrl: string): boolean {
try {
if (!proxyUrl.match(/^(https?|socks4|socks5):\/\//)) {
return false;
}
const url = new URL(proxyUrl);
if (!url.hostname) return false;
if (!['http:', 'https:', 'socks4:', 'socks5:'].includes(url.protocol)) {
return false;
}
if (url.port && (!/^\d+$/.test(url.port) || Number(url.port) < 1 || Number(url.port) > 65535)) {
return false;
}
return true;
} catch {
return false;
}
}
}

View file

@ -1,6 +1,10 @@
import { parse as mpdParse } from 'mpd-parser';
import { LanguageItem, findLang, languages } from './module.langsData';
import { console } from './log';
import * as reqModule from './module.fetch';
import { FetchParams } from './module.fetch';
const req = new reqModule.Req();
type Segment = {
uri: string;
@ -77,13 +81,15 @@ export async function parse(manifest: string, language?: LanguageItem, url?: str
if (!Object.prototype.hasOwnProperty.call(ret, host)) ret[host] = { audio: [], video: [] };
if (playlist.sidx && playlist.segments.length == 0) {
const options: RequestInit = {
const options: FetchParams = {
method: 'head'
};
const item = await fetch(playlist.sidx.uri, options);
if (!item.ok)
console.warn(`${item.status}: ${item.statusText}, Unable to fetch byteLength for audio stream ${Math.round(playlist.attributes.BANDWIDTH / 1024)}KiB/s`);
const byteLength = parseInt(item.headers.get('content-length') as string);
const itemReq = await req.getData(playlist.sidx.uri, options);
if (!itemReq.res || !itemReq.ok)
console.warn(
`${itemReq.error?.res?.status}: ${itemReq.error?.res?.statusText}, Unable to fetch byteLength for audio stream ${Math.round(playlist.attributes.BANDWIDTH / 1024)}KiB/s`
);
const byteLength = parseInt(itemReq.res?.headers?.get('content-length') as string);
let currentByte = playlist.sidx.map.byterange.length;
while (currentByte <= byteLength) {
playlist.segments.push({
@ -156,15 +162,15 @@ export async function parse(manifest: string, language?: LanguageItem, url?: str
if (!Object.prototype.hasOwnProperty.call(ret, host)) ret[host] = { audio: [], video: [] };
if (playlist.sidx && playlist.segments.length == 0) {
const options: RequestInit = {
const options: FetchParams = {
method: 'head'
};
const item = await fetch(playlist.sidx.uri, options);
if (!item.ok)
const itemReq = await req.getData(playlist.sidx.uri, options);
if (!itemReq.res || !itemReq.ok)
console.warn(
`${item.status}: ${item.statusText}, Unable to fetch byteLength for video stream ${playlist.attributes.RESOLUTION?.height}x${playlist.attributes.RESOLUTION?.width}@${Math.round(playlist.attributes.BANDWIDTH / 1024)}KiB/s`
`${itemReq.error?.res?.status}: ${itemReq.error?.res?.statusText}, Unable to fetch byteLength for video stream ${playlist.attributes.RESOLUTION?.height}x${playlist.attributes.RESOLUTION?.width}@${Math.round(playlist.attributes.BANDWIDTH / 1024)}KiB/s`
);
const byteLength = parseInt(item.headers.get('content-length') as string);
const byteLength = parseInt(itemReq.res?.headers?.get('content-length') as string);
let currentByte = playlist.sidx.map.byterange.length;
while (currentByte <= byteLength) {
playlist.segments.push({

View file

@ -9,8 +9,11 @@ import fsextra from 'fs-extra';
import { workingDir } from './module.cfg-loader';
import { console } from './log';
import Helper from './module.helper';
import * as reqModule from './module.fetch';
const updateFilePlace = path.join(workingDir, 'config', 'updates.json');
const req = new reqModule.Req();
const updateIgnore = [
'*.d.ts',
'.git',
@ -58,8 +61,13 @@ export default async (force = false) => {
}
}
console.info('Checking for updates...');
const tagRequest = await fetch('https://api.github.com/repos/anidl/multi-downloader-nx/tags');
const tags = JSON.parse(await tagRequest.text()) as GithubTag[];
const tagRequest = await req.getData('https://api.github.com/repos/anidl/multi-downloader-nx/tags');
if (!tagRequest.res || !tagRequest.ok) {
console.info('No new tags found');
return done();
}
const tags = JSON.parse((await tagRequest.res.text()) as string) as GithubTag[];
if (tags.length > 0) {
const newer = tags.filter((a) => {
@ -72,9 +80,13 @@ export default async (force = false) => {
return done();
}
const newest = newer.sort((a, b) => (a.name < b.name ? 1 : a.name > b.name ? -1 : 0))[0];
const compareRequest = await fetch(`https://api.github.com/repos/anidl/multi-downloader-nx/compare/${packageJson.version}...${newest.name}`);
const compareRequest = await req.getData(`https://api.github.com/repos/anidl/multi-downloader-nx/compare/${packageJson.version}...${newest.name}`);
if (!compareRequest.res || !compareRequest.ok) {
console.info('No new tags found');
return done();
}
const compareJSON = JSON.parse(await compareRequest.text()) as TagCompare;
const compareJSON = JSON.parse(await compareRequest.res.text()) as TagCompare;
console.info(`You are behind by ${compareJSON.ahead_by} releases!`);
const changedFiles = compareJSON.files
@ -109,7 +121,7 @@ export default async (force = false) => {
const isTSX = a.filename.endsWith('tsx');
const ret = {
path: a.filename.slice(0, isTSX ? -3 : -2) + `js${isTSX ? 'x' : ''}`,
content: transpileModule(await (await fetch(a.raw_url)).text(), {
content: transpileModule((await (await req.getData(a.raw_url)).res?.text()) ?? '', {
compilerOptions: tsConfig.compilerOptions as unknown as CompilerOptions
}).outputText,
type: a.status === 'modified' ? ApplyType.UPDATE : a.status === 'added' ? ApplyType.ADD : ApplyType.DELETE
@ -119,7 +131,7 @@ export default async (force = false) => {
} else {
const ret = {
path: a.filename,
content: await (await fetch(a.raw_url)).text(),
content: (await (await req.getData(a.raw_url)).res?.text()) ?? '',
type: a.status === 'modified' ? ApplyType.UPDATE : a.status === 'added' ? ApplyType.ADD : ApplyType.DELETE
};
console.info('✓ Got %s', ret.path);

View file

@ -59,10 +59,10 @@
"m3u8-parsed": "^2.0.0",
"mpd-parser": "^1.3.1",
"node-forge": "^1.3.1",
"ofetch": "^1.4.1",
"open": "^8.4.2",
"protobufjs": "^7.5.4",
"puppeteer-real-browser": "^1.4.4",
"undici": "^7.16.0",
"ws": "^8.18.3",
"yaml": "^2.8.1",
"yargs": "17.7.2"

View file

@ -65,9 +65,6 @@ importers:
node-forge:
specifier: ^1.3.1
version: 1.3.1
ofetch:
specifier: ^1.4.1
version: 1.4.1
open:
specifier: ^8.4.2
version: 8.4.2
@ -77,6 +74,9 @@ importers:
puppeteer-real-browser:
specifier: ^1.4.4
version: 1.4.4
undici:
specifier: ^7.16.0
version: 7.16.0
ws:
specifier: ^8.18.3
version: 8.18.3
@ -774,11 +774,16 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
bare-events@2.7.0:
resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==}
bare-events@2.8.0:
resolution: {integrity: sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA==}
peerDependencies:
bare-abort-controller: '*'
peerDependenciesMeta:
bare-abort-controller:
optional: true
bare-fs@4.4.7:
resolution: {integrity: sha512-huJQxUWc2d1T+6dxnC/FoYpBgEHzJp33mYZqFtQqTTPPyP9xPvmjC16VpR4wTte4ZKd5VxkFAcfDYi51iwWMcg==}
bare-fs@4.4.9:
resolution: {integrity: sha512-sh8UV8OvXBZa3Yg5rhF1LNH3U4DfHniexdqyUXelC1thQUxO9TCF37yvd1/7Ir+cgeSg/6YrXyH67xvRr7yaOg==}
engines: {bare: '>=1.16.0'}
peerDependencies:
bare-buffer: '*'
@ -991,9 +996,6 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
destr@2.0.5:
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@ -1570,9 +1572,6 @@ packages:
resolution: {integrity: sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==}
engines: {node: '>=10'}
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@ -1597,9 +1596,6 @@ packages:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
ofetch@1.4.1:
resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
@ -2020,15 +2016,16 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
ufo@1.6.1:
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
unbzip2-stream@1.4.3:
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
undici-types@7.14.0:
resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==}
undici@7.16.0:
resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==}
engines: {node: '>=20.18.1'}
universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
@ -2425,6 +2422,7 @@ snapshots:
unbzip2-stream: 1.4.3
yargs: 17.7.2
transitivePeerDependencies:
- bare-abort-controller
- bare-buffer
- react-native-b4a
- supports-color
@ -2665,6 +2663,7 @@ snapshots:
tar-fs: 3.1.1
yargs: 16.2.0
transitivePeerDependencies:
- bare-abort-controller
- bare-buffer
- encoding
- react-native-b4a
@ -2688,6 +2687,7 @@ snapshots:
tinyglobby: 0.2.15
unzipper: 0.12.3
transitivePeerDependencies:
- bare-abort-controller
- bare-buffer
- encoding
- react-native-b4a
@ -2746,16 +2746,17 @@ snapshots:
balanced-match@1.0.2: {}
bare-events@2.7.0: {}
bare-events@2.8.0: {}
bare-fs@4.4.7:
bare-fs@4.4.9:
dependencies:
bare-events: 2.7.0
bare-events: 2.8.0
bare-path: 3.0.0
bare-stream: 2.7.0(bare-events@2.7.0)
bare-stream: 2.7.0(bare-events@2.8.0)
bare-url: 2.2.2
fast-fifo: 1.3.2
transitivePeerDependencies:
- bare-abort-controller
- react-native-b4a
optional: true
@ -2767,12 +2768,13 @@ snapshots:
bare-os: 3.6.2
optional: true
bare-stream@2.7.0(bare-events@2.7.0):
bare-stream@2.7.0(bare-events@2.8.0):
dependencies:
streamx: 2.23.0
optionalDependencies:
bare-events: 2.7.0
bare-events: 2.8.0
transitivePeerDependencies:
- bare-abort-controller
- react-native-b4a
optional: true
@ -2957,8 +2959,6 @@ snapshots:
depd@2.0.0: {}
destr@2.0.5: {}
detect-libc@2.1.2: {}
devtools-protocol@0.0.1367902: {}
@ -3125,7 +3125,9 @@ snapshots:
events-universal@1.0.1:
dependencies:
bare-events: 2.7.0
bare-events: 2.8.0
transitivePeerDependencies:
- bare-abort-controller
expand-template@2.0.3: {}
@ -3596,8 +3598,6 @@ snapshots:
dependencies:
semver: 7.7.3
node-fetch-native@1.6.7: {}
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
@ -3610,12 +3610,6 @@ snapshots:
object-inspect@1.13.4: {}
ofetch@1.4.1:
dependencies:
destr: 2.0.5
node-fetch-native: 1.6.7
ufo: 1.6.1
on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
@ -3774,6 +3768,7 @@ snapshots:
xvfb: 0.4.0
transitivePeerDependencies:
- '@types/puppeteer'
- bare-abort-controller
- bare-buffer
- bufferutil
- puppeteer
@ -3829,6 +3824,7 @@ snapshots:
typed-query-selector: 2.12.0
ws: 8.18.3
transitivePeerDependencies:
- bare-abort-controller
- bare-buffer
- bufferutil
- react-native-b4a
@ -3987,6 +3983,7 @@ snapshots:
fast-fifo: 1.3.2
text-decoder: 1.2.3
transitivePeerDependencies:
- bare-abort-controller
- react-native-b4a
string-width@4.2.3:
@ -4031,9 +4028,10 @@ snapshots:
pump: 3.0.3
tar-stream: 3.1.7
optionalDependencies:
bare-fs: 4.4.7
bare-fs: 4.4.9
bare-path: 3.0.0
transitivePeerDependencies:
- bare-abort-controller
- bare-buffer
- react-native-b4a
@ -4051,6 +4049,7 @@ snapshots:
fast-fifo: 1.3.2
streamx: 2.23.0
transitivePeerDependencies:
- bare-abort-controller
- react-native-b4a
tar@7.5.1:
@ -4139,8 +4138,6 @@ snapshots:
typescript@5.9.3: {}
ufo@1.6.1: {}
unbzip2-stream@1.4.3:
dependencies:
buffer: 5.7.1
@ -4148,6 +4145,8 @@ snapshots:
undici-types@7.14.0: {}
undici@7.16.0: {}
universalify@0.1.2: {}
universalify@2.0.1: {}