Attempted fix at pornhub video
CI / test (pull_request) Failing after 10m39s

This commit is contained in:
kfj001 committed 2026-08-16 23:00:47 -07:00
1 parent b234c8dcae
commit 001cf146ee
10 files changed
+189 -217

No files matched your search

+93 -16
View File
@@ -829,29 +829,72 @@ function filterManifests(manifests) {
(u.includes('/playlist') && !u.endsWith('.ts'));
});
// If we have actual manifests, use them directly
if (actualManifests.length > 0) {
return actualManifests.map(m => ({ url: m.url }));
// Reject fake reconstructed manifest paths.
// Real manifests are under /hls/videos/{year}/{subdir}/{videoId}/...
// Fakes look like: phncdn.com/videos/{id}/playlist.m3u8 or .../master.m3u8 (no /hls/)
const valid = actualManifests.filter(m => {
const u = m.url.toLowerCase();
try {
const urlObj = new URL(u);
// phncdn URLs must have /hls/ in the path — fake reconstructed paths lack it
if (u.includes('phncdn') || u.includes('pornhubcdn')) {
if (!urlObj.pathname.includes('/hls/') && !u.includes('?h=')) {
return false; // Fake: phncdn URL without /hls/ or auth query param
}
}
} catch {}
return true;
});
// If we have actual (non-fake) manifests, use them directly
if (valid.length > 0) {
return valid.map(m => ({ url: m.url }));
}
// No .m3u8 found — interceptors only captured .ts segments.
// Reconstruct the manifest URL from segment URLs.
// Segment URLs look like: /hls/videos/{video-id}/seg-{n}-v{ver}-a{aud}.ts
// Manifest URL would be: /hls/videos/{video-id}/playlist.m3u8
// Reconstruct the parent manifest URL from segment paths.
// Segment: https://ev-h.phncdn.com/hls/videos/202008/01/338337051/720P_4000K_338337051.mp4/seg-1-v1-a1.ts?h=tmrD...&e=1786932752&f=1
// Manifest: https://ev-h.phncdn.com/hls/videos/202008/01/338337051/720P_4000K_338337051.mp4/master.m3u8?h=tmrD...&e=1786932752&f=1
//
// Auth tokens (h, e, f or validfrom, validto, hash) are extracted from segment query params
// and reapplied to the reconstructed manifest URL. This is critical because CDN domains
// require auth — a path-only URL will be rejected with 403.
const seen = new Set();
const reconstructed = [];
for (const m of manifests) {
const u = m.url.toLowerCase();
if (!u.includes('/hls/') || !u.endsWith('.ts')) continue;
if (!u.includes('/hls/videos/') || !/\/seg-\d+/.test(u)) continue;
try {
const url = new URL(m.url);
const pathParts = url.pathname.split('/');
// Find the /hls/videos/ segment and the video-id directory
const urlObj = new URL(m.url);
// Skip non-phncdn hosts — we only reconstruct for known video CDNs
const host = urlObj.host.toLowerCase();
if (!host.includes('phncdn')) continue;
const pathParts = urlObj.pathname.split('/');
// Find the /hls/ marker and extract: hls/videos/{year}/{subdir}/{videoId}/{variant}/...
const hlsIdx = pathParts.findIndex(p => p === 'hls');
if (hlsIdx === -1 || hlsIdx + 2 >= pathParts.length) continue;
// Build manifest URL: origin + /hls/videos/{video-id}/playlist.m3u8
const manifestPath = `${pathParts[hlsIdx]}/${pathParts[hlsIdx + 1]}/${pathParts[hlsIdx + 2]}/playlist.m3u8`;
const manifestUrl = `${url.protocol}//${url.host}${manifestPath}`;
if (hlsIdx === -1 || hlsIdx + 5 >= pathParts.length) continue;
// Reconstruct with BOTH "hls" prefix AND variant directory included:
// segment: /hls/videos/202008/01/338337051/720P_4000K_338337051.mp4/seg-1.ts
// manifest: /hls/videos/202008/01/338337051/720P_4000K_338337051.mp4/master.m3u8
const year = pathParts[hlsIdx + 2]; // e.g. 2020
const subDir = pathParts[hlsIdx + 3]; // e.g. 01
const videoId = pathParts[hlsIdx + 4]; // e.g. 338337051
const variant = pathParts[hlsIdx + 5]; // e.g. 720P_4000K_338337051.mp4
// Extract auth params from segment query string — different CDN variants use different keys:
// ev-h/validfrom/validto/hash vs hv-h/h/e/f
const authParts = [];
for (const [key, val] of urlObj.searchParams) {
if (['h', 'e', 'f', 'validfrom', 'validto', 'hash'].includes(key)) {
authParts.push(`${key}=${val}`);
}
}
const authStr = authParts.length > 0 ? '?' + authParts.join('&') : '';
// Build manifest URL: include hls prefix AND variant directory
const manifestUrl = `${urlObj.protocol}//${urlObj.host}/${pathParts[hlsIdx]}/${pathParts[hlsIdx + 1]}/${year}/${subDir}/${videoId}/${variant}/master.m3u8${authStr}`;
if (!seen.has(manifestUrl)) {
seen.add(manifestUrl);
reconstructed.push({ url: manifestUrl });
@@ -861,8 +904,30 @@ function filterManifests(manifests) {
return reconstructed;
}
/**
* Validate that a manifest URL uses a real phncdn.com path structure.
* Rejects fake paths like /videos/{id}/playlist.m3u8 — real manifests use
* /hls/videos/{year}/{subdir}/{videoId}/master.m3u8 or similar /hls/ paths.
*/
function isValidManifestUrl(url) {
if (!url || typeof url !== 'string') return false;
// Real phncdn HLS manifest: must contain /hls/videos/ with sufficient path depth
const hlsIdx = url.indexOf('/hls/videos/');
if (hlsIdx === -1) {
// Not phncdn — could be a different CDN, allow it
if (!url.includes('phncdn') && !url.includes('pornhubcdn')) return true;
// phncdn without /hls/ prefix is invalid for manifests
return false;
}
// Check there are at least {year}/{subdir}/{videoId} after /hls/videos/
const after = url.substring(hlsIdx + '/hls/videos/'.length);
if (after.indexOf('/') === -1) return false; // need at least one more segment
return true;
}
/**
* Build a normalized video entry from a scraped video object.
* Validates manifest URLs to prevent storing fake paths like /videos/{id}/playlist.m3u8.
* @param {{ src: string, poster: string|null, mediaType: string, hlsManifest: string|null }} video
* @param {string} tabTitle
* @param {string|null} posterFromContent - poster URL from content script (OG image, etc.)
@@ -875,7 +940,19 @@ function makeVideoEntry(video, tabTitle, posterFromContent) {
tab: tabTitle,
mediaType: video.mediaType || 'video',
};
if (video.hlsManifest) entry.hlsManifest = video.hlsManifest;
if (video.hlsManifest) {
// Reject fake phncdn manifest paths before storing
if (!isValidManifestUrl(video.hlsManifest)) {
console.warn('[goon] Rejecting fake manifest URL:', video.hlsManifest.substring(0, 120));
} else {
entry.hlsManifest = video.hlsManifest;
}
}
// Also validate src when it looks like a manifest URL (no hlsManifest set but src has .m3u8)
if (!entry.hlsManifest && entry.src?.includes('.m3u8') && !isValidManifestUrl(entry.src)) {
console.warn('[goon] Rejecting fake manifest URL from src:', entry.src.substring(0, 120));
// Don't treat it as HLS — leave mediaType as-is (likely 'video' or unset)
}
return entry;
}
@@ -930,7 +1007,7 @@ async function scanVideos(tabsToScan) {
// Step 1.6: Strategy 8 — Query phncdn.com requests and reconstruct manifest URLs.
// When the player uses in-memory dynamic HLS (zero .m3u8 network requests), we can
// still detect it by recognizing segment URL patterns from phncdn.com and deriving
// the parent manifest URL: /videos/{id}/playlist.m3u8
// the parent manifest URL: /hls/videos/{id}/master.m3u8
const phncdnPromises = tabsToScan.map(t => queryPhncdnRequests(t.id));
const phncdnResults = await Promise.all(phncdnPromises);
let totalPhncdnManifests = 0;