effective referer
This commit is contained in:
parent
10d5c46ec3
commit
fbc4d9bad9
4 changed files with 42 additions and 20 deletions
|
|
@ -13,15 +13,20 @@ export interface FetchSegmentResult {
|
|||
bytes: number;
|
||||
}
|
||||
|
||||
function gmFetchBuffer(url: string, referer?: string): Promise<FetchSegmentResult> {
|
||||
function gmFetchBuffer(url: string, referer?: string, origin?: string): Promise<FetchSegmentResult> {
|
||||
const fallbackReferer = document.location.href;
|
||||
const fallbackOrigin = new URL(document.location.href).origin;
|
||||
const effectiveReferer = referer || fallbackReferer;
|
||||
const effectiveOrigin = origin || (referer ? new URL(referer).origin : fallbackOrigin);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
(GM_xmlhttpRequest as any)({
|
||||
method: 'GET',
|
||||
url: url,
|
||||
responseType: 'arraybuffer',
|
||||
referer: referer || document.location.href,
|
||||
referer: effectiveReferer,
|
||||
headers: {
|
||||
'Origin': new URL(document.location.href).origin,
|
||||
'Origin': effectiveOrigin,
|
||||
},
|
||||
onload: (response: any) => {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
|
|
@ -41,11 +46,11 @@ function gmFetchBuffer(url: string, referer?: string): Promise<FetchSegmentResul
|
|||
});
|
||||
}
|
||||
|
||||
async function fetchWithRetry(url: string, referer?: string, maxRetries = 3): Promise<FetchSegmentResult> {
|
||||
async function fetchWithRetry(url: string, referer?: string, origin?: string, maxRetries = 3): Promise<FetchSegmentResult> {
|
||||
let lastError: Error | null = null;
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
return await gmFetchBuffer(url, referer);
|
||||
return await gmFetchBuffer(url, referer, origin);
|
||||
} catch (e) {
|
||||
lastError = e as Error;
|
||||
log.warn(`fetchWithRetry: attempt ${attempt}/${maxRetries} failed for ${url}: ${e}`);
|
||||
|
|
@ -60,6 +65,7 @@ async function fetchWithRetry(url: string, referer?: string, maxRetries = 3): Pr
|
|||
export async function fetchSegments(
|
||||
urls: string[],
|
||||
referer?: string,
|
||||
origin?: string,
|
||||
onProgress?: (progress: DownloadProgress) => void,
|
||||
concurrency = 5
|
||||
): Promise<FetchSegmentResult[]> {
|
||||
|
|
@ -79,7 +85,7 @@ export async function fetchSegments(
|
|||
while (queue.length > 0) {
|
||||
const idx = queue.shift()!;
|
||||
try {
|
||||
const result = await fetchWithRetry(urls[idx], referer);
|
||||
const result = await fetchWithRetry(urls[idx], referer, origin);
|
||||
results[idx] = result;
|
||||
bytesDownloaded += result.bytes;
|
||||
current++;
|
||||
|
|
|
|||
16
src/index.ts
16
src/index.ts
|
|
@ -89,7 +89,7 @@ async function startDownload(url: string): Promise<void> {
|
|||
|
||||
if (!parsed) {
|
||||
try {
|
||||
parsed = await parseM3U8(url, entry?.headers?.Referer);
|
||||
parsed = await parseM3U8(url, entry?.headers?.Referer, entry?.headers?.Origin);
|
||||
if (entry) entry.parsed = parsed;
|
||||
} catch (e) {
|
||||
log.error(`startDownload: parse failed for ${url}: ${e}`);
|
||||
|
|
@ -107,7 +107,7 @@ async function startDownload(url: string): Promise<void> {
|
|||
}
|
||||
targetUrl = selected;
|
||||
try {
|
||||
parsed = await parseM3U8(targetUrl, entry?.headers?.Referer);
|
||||
parsed = await parseM3U8(targetUrl, entry?.headers?.Referer, entry?.headers?.Origin);
|
||||
if (entry) entry.parsed = parsed;
|
||||
} catch (e) {
|
||||
log.error(`startDownload: parse selected playlist failed: ${e}`);
|
||||
|
|
@ -123,7 +123,8 @@ async function startDownload(url: string): Promise<void> {
|
|||
}
|
||||
|
||||
const segmentUrls = parsed.segments.map(s => s.uri);
|
||||
const referrer = entry?.headers?.Referer || document.location.href;
|
||||
const referrer = entry?.headers?.Referer;
|
||||
const requestOrigin = entry?.headers?.Origin;
|
||||
|
||||
resetProgress();
|
||||
|
||||
|
|
@ -131,6 +132,7 @@ async function startDownload(url: string): Promise<void> {
|
|||
const results = await fetchSegments(
|
||||
segmentUrls,
|
||||
referrer,
|
||||
requestOrigin,
|
||||
(progress: DownloadProgress) => {
|
||||
if (downloadAborted) return;
|
||||
showStatus(progress);
|
||||
|
|
@ -167,7 +169,7 @@ function onM3U8Detected(url: string, headers?: Record<string, string>): void {
|
|||
}
|
||||
|
||||
if (isTopFrame()) {
|
||||
parseM3U8(url, headers?.Referer).then(parsed => {
|
||||
parseM3U8(url, headers?.Referer, headers?.Origin).then(parsed => {
|
||||
detectedM3U8s.get(url)!.parsed = parsed;
|
||||
if (panel) {
|
||||
addStreamToUI(url, parsed);
|
||||
|
|
@ -191,7 +193,11 @@ if (typeof window === 'undefined') {
|
|||
window.addEventListener('message', (e: MessageEvent) => {
|
||||
if (e.data && typeof e.data === 'object' && e.data.__m3u8dl === true && e.data.url) {
|
||||
const referer = typeof e.data.referer === 'string' ? e.data.referer : '';
|
||||
onM3U8Detected(e.data.url as string, referer ? { Referer: referer } : undefined);
|
||||
const origin = typeof e.data.origin === 'string' ? e.data.origin : '';
|
||||
const headers: Record<string, string> = {};
|
||||
if (referer) headers['Referer'] = referer;
|
||||
if (origin) headers['Origin'] = origin;
|
||||
onM3U8Detected(e.data.url as string, Object.keys(headers).length ? headers : undefined);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
import { log } from '../logger';
|
||||
|
||||
export async function fetchKey(keyUri: string, referer?: string): Promise<Uint8Array> {
|
||||
export async function fetchKey(keyUri: string, referer?: string, origin?: string): Promise<Uint8Array> {
|
||||
log.info(`fetchKey: ${keyUri}`);
|
||||
|
||||
const fallbackReferer = document.location.href;
|
||||
const fallbackOrigin = new URL(document.location.href).origin;
|
||||
const effectiveReferer = referer || fallbackReferer;
|
||||
const effectiveOrigin = origin || (referer ? new URL(referer).origin : fallbackOrigin);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
(GM_xmlhttpRequest as any)({
|
||||
method: 'GET',
|
||||
url: keyUri,
|
||||
responseType: 'arraybuffer',
|
||||
referer: referer || document.location.href,
|
||||
referer: effectiveReferer,
|
||||
headers: {
|
||||
'Origin': new URL(document.location.href).origin,
|
||||
'Origin': effectiveOrigin,
|
||||
},
|
||||
onload: (response: any) => {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
|
|
|
|||
|
|
@ -28,15 +28,20 @@ export interface MasterPlaylistInfo {
|
|||
name?: string;
|
||||
}
|
||||
|
||||
function gmFetchText(url: string, referer?: string): Promise<string> {
|
||||
function gmFetchText(url: string, referer?: string, origin?: string): Promise<string> {
|
||||
const fallbackReferer = document.location.href;
|
||||
const fallbackOrigin = new URL(document.location.href).origin;
|
||||
const effectiveReferer = referer || fallbackReferer;
|
||||
const effectiveOrigin = origin || (referer ? new URL(referer).origin : fallbackOrigin);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
(GM_xmlhttpRequest as any)({
|
||||
method: 'GET',
|
||||
url: url,
|
||||
responseType: 'text',
|
||||
referer: referer || document.location.href,
|
||||
referer: effectiveReferer,
|
||||
headers: {
|
||||
'Origin': new URL(document.location.href).origin,
|
||||
'Origin': effectiveOrigin,
|
||||
},
|
||||
onload: (response: any) => {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
|
|
@ -52,10 +57,10 @@ function gmFetchText(url: string, referer?: string): Promise<string> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function parseM3U8(url: string, referer?: string): Promise<ParsedPlaylist> {
|
||||
export async function parseM3U8(url: string, referer?: string, origin?: string): Promise<ParsedPlaylist> {
|
||||
log.info(`parseM3U8: ${url}`);
|
||||
|
||||
const content = await gmFetchText(url, referer);
|
||||
const content = await gmFetchText(url, referer, origin);
|
||||
if (!content || !content.startsWith('#EXTM3U')) {
|
||||
throw new Error(`Invalid m3u8 content from ${url}`);
|
||||
}
|
||||
|
|
@ -106,7 +111,7 @@ export async function parseM3U8(url: string, referer?: string): Promise<ParsedPl
|
|||
let keyBytes = keyCache.get(keyUri);
|
||||
if (!keyBytes) {
|
||||
try {
|
||||
keyBytes = await fetchKey(keyUri, referer);
|
||||
keyBytes = await fetchKey(keyUri, referer, origin);
|
||||
keyCache.set(keyUri, keyBytes);
|
||||
} catch (e) {
|
||||
log.error(`parseM3U8: failed to fetch key ${keyUri}: ${e}`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue