This commit is contained in:
parent
b56be38431
commit
a8f025e1b5
5 changed files with 48 additions and 18 deletions
|
|
@ -1,8 +1,8 @@
|
|||
// ==UserScript==
|
||||
// @name M3U8 HLS Downloader
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.0.4
|
||||
// @description 자동 탐지 및 다운로드: HLS(m3u8) 스트림의 세그먼트를 병합하여 단일 파일로 저장
|
||||
// @version 1.0.5
|
||||
// @description 자동 탐지 및 다운로드: HLS(m3u8) 스트림의 세그먼트를 병합하여 단일 파일로 저장. 활성화된 동안 모든 트래픽을 모니터링하고 접근하기 때문에, 사용하지 않을때는 비활성화 필요.
|
||||
// @author kyush
|
||||
// @match *://*/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "m3u8-monkey-script",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -278,8 +278,8 @@ function onStreamDetected(url: string, headers?: Record<string, string>): void {
|
|||
addStreamToUI(url);
|
||||
}
|
||||
|
||||
if (isTopFrame() && type === 'm3u8') {
|
||||
parseM3U8(url, headers?.Referer, headers?.Origin).then(parsed => {
|
||||
if (isTopFrame() && type === 'm3u8' && !detectedStreams.get(url)?.parsed) {
|
||||
parseM3U8(url, headers?.Referer, headers?.Origin, false).then(parsed => {
|
||||
detectedStreams.get(url)!.parsed = parsed;
|
||||
if (panel) {
|
||||
addStreamToUI(url, parsed);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,24 @@
|
|||
export const log = (() => {
|
||||
let targetConsole: Console;
|
||||
let prefix: string;
|
||||
|
||||
try {
|
||||
const uW = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : null) as any;
|
||||
targetConsole = uW && uW.console ? uW.console : console;
|
||||
} catch {
|
||||
targetConsole = console;
|
||||
// Collect all reachable consoles: page, unsafeWindow, top, parent, native
|
||||
const consoles: Console[] = [];
|
||||
const seen = new Set<any>();
|
||||
|
||||
function addConsole(c: any) {
|
||||
if (c && c.log && consoles.length < 5 && !seen.has(c)) {
|
||||
seen.add(c);
|
||||
consoles.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
try { addConsole(console); } catch { /* ignore */ }
|
||||
try { addConsole((typeof unsafeWindow !== 'undefined' ? unsafeWindow : null)?.console); } catch { /* ignore */ }
|
||||
try { addConsole(window.top?.console); } catch { /* ignore */ }
|
||||
try { addConsole(window.parent?.console); } catch { /* ignore */ }
|
||||
|
||||
if (consoles.length === 0) {
|
||||
try { addConsole(console); } catch { /* ignore */ }
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -16,9 +28,24 @@ export const log = (() => {
|
|||
prefix = '[M3U8-DL]';
|
||||
}
|
||||
|
||||
function formatMsg(level: string, ...args: unknown[]): string {
|
||||
return `${prefix} [${level}] ${args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')}`;
|
||||
}
|
||||
|
||||
function teeLog(level: string, method: string, ...args: unknown[]) {
|
||||
const msg = formatMsg(level, ...args);
|
||||
for (const c of consoles) {
|
||||
try {
|
||||
if (c[method]) {
|
||||
(c[method] as any)(msg);
|
||||
}
|
||||
} catch { /* console may be broken */ }
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
info: (...args: unknown[]) => targetConsole.log(`${prefix} [INFO]`, ...args),
|
||||
warn: (...args: unknown[]) => targetConsole.warn(`${prefix} [WARN]`, ...args),
|
||||
error: (...args: unknown[]) => targetConsole.error(`${prefix} [ERROR]`, ...args),
|
||||
info: (...args: unknown[]) => teeLog('INFO', 'log', ...args),
|
||||
warn: (...args: unknown[]) => teeLog('WARN', 'warn', ...args),
|
||||
error: (...args: unknown[]) => teeLog('ERROR', 'error', ...args),
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export async function parseM3U8(
|
|||
}
|
||||
|
||||
const segments = manifest.segments || [];
|
||||
const keyCache = new Map<string, Uint8Array>();
|
||||
const keyCache = new Map<string, Uint8Array | undefined>();
|
||||
const resolvedSegments: SegmentInfo[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
|
|
@ -122,13 +122,16 @@ export async function parseM3U8(
|
|||
|
||||
let keyBytes: Uint8Array | null = null;
|
||||
if (fetchKeys) {
|
||||
keyBytes = keyCache.get(keyUri);
|
||||
if (!keyBytes) {
|
||||
const cached = keyCache.get(keyUri);
|
||||
if (cached !== undefined) {
|
||||
keyBytes = cached;
|
||||
} else {
|
||||
try {
|
||||
keyBytes = await fetchKey(keyUri, referer, origin);
|
||||
keyCache.set(keyUri, keyBytes);
|
||||
} catch (e) {
|
||||
log.error(`parseM3U8: failed to fetch key ${keyUri}: ${e}`);
|
||||
log.warn(`parseM3U8: failed to fetch key ${keyUri}: ${e}`);
|
||||
keyCache.set(keyUri, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue