feat(supjav): resolve voe hoster to direct stream instead of WebView
Some checks failed
Backend tests / test (push) Has been cancelled
Some checks failed
Backend tests / test (push) Has been cancelled
supjav is an embed-aggregator (voe/streamtape/turbovid/fc2stream). It was playing through the WebView fallback because none of its hosters had a native phone-side resolver wired into the scene player. voe.sx does have one (voeResolver.ts, already used for movies) — it just was not wired for scenes. - PlayerScreen: wire isVoeUrl/resolveVoePage into the hoster routing (like dood/filemoon), so a voe embed resolves on the phone to a direct m3u8 (token bound to the phone /16, plays direct, no WebView, no proxy). - supjav extractor: return voe first (sorted by URL), and stop putting the raw hostname in `quality` (the digit in "fc2stream" was parsed as quality 2 and won _pick_best) — use a clean digit-free server label instead. - SceneDetailScreen: for hoster-only scenes, open the first embed (the extractor puts the natively-resolvable one first) rather than _pick_best's choice. Verified: supjav's voe embed resolves to a real HLS manifest (200, application/vnd.apple.mpegurl, #EXTM3U). WebView stays only as last-resort fallback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
39374c0e49
commit
7e2807b42e
4 changed files with 31 additions and 2 deletions
|
|
@ -98,15 +98,23 @@ def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | Non
|
|||
continue
|
||||
seen.add(hoster)
|
||||
host = hoster.split("/")[2] if "://" in hoster else hoster
|
||||
# Label serwera bez cyfr (host "fc2stream.tv" psułby _quality_to_int → "2" jako
|
||||
# jakość → zły `best`). Zostawiamy skróconą, bezcyfrową nazwę do pickera.
|
||||
label = re.sub(r"\.[a-z]+$", "", host.split(".")[0]) if host else None
|
||||
label = re.sub(r"\d+", "", label).upper() if label else None
|
||||
out.append(
|
||||
StreamSource(
|
||||
link=hoster,
|
||||
type="hoster",
|
||||
quality=host,
|
||||
quality=label or None,
|
||||
referer="https://supjav.com/",
|
||||
)
|
||||
)
|
||||
if not out:
|
||||
log.info("supjav: żaden data-link nie rozwiązał się na hoster (%s)", page_url)
|
||||
return None
|
||||
# voe.sx PIERWSZY (sort po URL, niezależnie od label) — telefon resolwuje go do
|
||||
# bezpośredniego m3u8 (voeResolver.ts, phone-IP-bound → gra direct, zero WebView).
|
||||
# Reszta (turbovid/fc2stream/streamtape) bez phone-side resolvera → WebView, więc niżej.
|
||||
out.sort(key=lambda s: 0 if "//voe." in s.link or ".voe." in s.link else 1)
|
||||
return out
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-07-11',
|
||||
date: 'July 2026',
|
||||
items: [
|
||||
'JAV and other voe-hosted videos now play directly in the built-in player instead of falling back to the web view, faster start and smoother playback.',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-07-10b',
|
||||
date: 'July 2026',
|
||||
|
|
|
|||
|
|
@ -1389,6 +1389,7 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) {
|
|||
const { isDoodStream, resolveDoodStream } = await import('../lib/doodstream');
|
||||
const { isPackerHoster, resolvePackerHoster } = await import('../lib/packerHoster');
|
||||
const { isFilemoonHoster, resolveFilemoonHoster } = await import('../lib/filemoonHoster');
|
||||
const { isVoeUrl, resolveVoePage } = await import('../lib/voeResolver');
|
||||
|
||||
let result: { url?: string; headers?: Record<string, string>; error?: string } | null = null;
|
||||
if (isDoodStream(url)) {
|
||||
|
|
@ -1400,6 +1401,15 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) {
|
|||
} else if (isFilemoonHoster(url)) {
|
||||
setResolveStatus('pending');
|
||||
result = await resolveFilemoonHoster(url, source);
|
||||
} else if (isVoeUrl(url)) {
|
||||
// voe.sx (supjav i inne): resolwujemy NA TELEFONIE do direct m3u8 (token bound
|
||||
// do /16 telefonu → gra direct, zero WebView/proxy). Pusto → WebView fallback.
|
||||
setResolveStatus('pending');
|
||||
const voeLinks = await resolveVoePage(url);
|
||||
const best = voeLinks[0];
|
||||
if (best) {
|
||||
result = { url: best.direct_url || best.stream_url, headers: best.headers };
|
||||
}
|
||||
}
|
||||
|
||||
setResolveAttempted(true);
|
||||
|
|
|
|||
|
|
@ -665,7 +665,11 @@ function PlaybackButton({
|
|||
// Player JS hostera może też ujawnić finalny m3u8 — auto-extract w PlayerScreen
|
||||
// pokaże banner "Otwórz w native playerze".
|
||||
if (directLinks.length === 0) {
|
||||
const target = res.best?.embed_url || embedLinks[0].embed_url!;
|
||||
// Preferuj PIERWSZY embed z listy (ekstraktor sortuje resolvowalne natywnie
|
||||
// hostery na przód, np. supjav → voe.sx pierwszy → Player resolwuje go do direct
|
||||
// m3u8 zamiast WebView). res.best bywa gorszy (multi-hoster: _pick_best nie wie
|
||||
// który jest phone-resolvowalny). Pozostałe hostery są w quality-pickerze.
|
||||
const target = embedLinks[0]?.embed_url || res.best?.embed_url!;
|
||||
let refererHost: string | undefined;
|
||||
try {
|
||||
refererHost = new URL(source.page_url).hostname;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue