Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 710ce264f8 | |||
| ffd23120fa | |||
| c11708281e |
4 changed files with 19 additions and 16 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name M3U8 HLS Downloader
|
// @name M3U8 HLS Downloader
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 1.0.5
|
// @version 1.0.8
|
||||||
// @description 자동 탐지 및 다운로드: HLS(m3u8) 스트림의 세그먼트를 병합하여 단일 파일로 저장. 활성화된 동안 모든 트래픽을 모니터링하고 접근하기 때문에, 사용하지 않을때는 비활성화 필요.
|
// @description 자동 탐지 및 다운로드: HLS(m3u8) 스트림의 세그먼트를 병합하여 단일 파일로 저장. 활성화된 동안 모든 트래픽을 모니터링하고 접근하기 때문에, 사용하지 않을때는 비활성화 필요.
|
||||||
// @author kyush
|
// @author kyush
|
||||||
// @match *://*/*
|
// @match *://*/*
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "m3u8-monkey-script",
|
"name": "m3u8-monkey-script",
|
||||||
"version": "1.0.5",
|
"version": "1.0.8",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
29
src/index.ts
29
src/index.ts
|
|
@ -1,5 +1,5 @@
|
||||||
import { log } from './logger';
|
import { log } from './logger';
|
||||||
import { normalizeReferer } from './utils/uri';
|
import { normalizeReferer, resolveUri } from './utils/uri';
|
||||||
import { interceptXHR } from './detection/xhr-intercept';
|
import { interceptXHR } from './detection/xhr-intercept';
|
||||||
import { interceptFetch } from './detection/fetch-intercept';
|
import { interceptFetch } from './detection/fetch-intercept';
|
||||||
import { monitorDOM } from './detection/dom-monitor';
|
import { monitorDOM } from './detection/dom-monitor';
|
||||||
|
|
@ -252,13 +252,16 @@ async function downloadVttStream(url: string, entry: { url: string; type: 'vtt';
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStreamDetected(url: string, headers?: Record<string, string>): void {
|
function onStreamDetected(url: string, headers?: Record<string, string>): void {
|
||||||
if (detectedStreams.has(url)) return;
|
const base = headers?.Referer || location.href;
|
||||||
|
const resolvedUrl = resolveUri(base, url);
|
||||||
|
|
||||||
const type = isVttUrl(url) ? 'vtt' : 'm3u8';
|
if (detectedStreams.has(resolvedUrl)) return;
|
||||||
log.info(`onStreamDetected: ${url} type=${type} headers=${JSON.stringify(headers)}`);
|
|
||||||
detectedStreams.set(url, { url, type, headers });
|
|
||||||
|
|
||||||
notifyTopFrame(url, headers);
|
const type = isVttUrl(resolvedUrl) ? 'vtt' : 'm3u8';
|
||||||
|
log.info(`onStreamDetected: ${resolvedUrl} type=${type} headers=${JSON.stringify(headers)}`);
|
||||||
|
detectedStreams.set(resolvedUrl, { url: resolvedUrl, type, headers });
|
||||||
|
|
||||||
|
notifyTopFrame(resolvedUrl, headers);
|
||||||
|
|
||||||
if (isTopFrame() && !panel && type === 'm3u8') {
|
if (isTopFrame() && !panel && type === 'm3u8') {
|
||||||
panel = createPanel();
|
panel = createPanel();
|
||||||
|
|
@ -275,20 +278,20 @@ function onStreamDetected(url: string, headers?: Record<string, string>): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTopFrame() && panel) {
|
if (isTopFrame() && panel) {
|
||||||
addStreamToUI(url);
|
addStreamToUI(resolvedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTopFrame() && type === 'm3u8' && !detectedStreams.get(url)?.parsed) {
|
if (isTopFrame() && type === 'm3u8' && !detectedStreams.get(resolvedUrl)?.parsed) {
|
||||||
parseM3U8(url, headers?.Referer, headers?.Origin, false).then(parsed => {
|
parseM3U8(resolvedUrl, headers?.Referer, headers?.Origin, false).then(parsed => {
|
||||||
detectedStreams.get(url)!.parsed = parsed;
|
detectedStreams.get(resolvedUrl)!.parsed = parsed;
|
||||||
if (panel) {
|
if (panel) {
|
||||||
addStreamToUI(url, parsed);
|
addStreamToUI(resolvedUrl, parsed);
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
log.error(`onStreamDetected: pre-parse failed for ${url}: ${e}`);
|
log.error(`onStreamDetected: pre-parse failed for ${resolvedUrl}: ${e}`);
|
||||||
});
|
});
|
||||||
} else if (!isTopFrame() && type === 'm3u8') {
|
} else if (!isTopFrame() && type === 'm3u8') {
|
||||||
log.info(`onStreamDetected: iframe detected ${url}, skipping parse (top frame will handle)`);
|
log.info(`onStreamDetected: iframe detected ${resolvedUrl}, skipping parse (top frame will handle)`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export function guessFilename(url: string, mime?: string): string {
|
||||||
function extractTitleParts(): { name: string; volume: string } | null {
|
function extractTitleParts(): { name: string; volume: string } | null {
|
||||||
try {
|
try {
|
||||||
const title = document.title || '';
|
const title = document.title || '';
|
||||||
const match = title.match(/^(.+?)\s+😜\s+(\d+)\s+-\s+Anime\s+-\s+Linkkf/);
|
const match = title.match(/^(.+?)\s+😜\s+(\d+)\s+-\s+Ani\S+\s+-\s+Linkkf/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return { name: match[1].trim(), volume: match[2].trim() };
|
return { name: match[1].trim(), volume: match[2].trim() };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue