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
|
continue
|
||||||
seen.add(hoster)
|
seen.add(hoster)
|
||||||
host = hoster.split("/")[2] if "://" in hoster else 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(
|
out.append(
|
||||||
StreamSource(
|
StreamSource(
|
||||||
link=hoster,
|
link=hoster,
|
||||||
type="hoster",
|
type="hoster",
|
||||||
quality=host,
|
quality=label or None,
|
||||||
referer="https://supjav.com/",
|
referer="https://supjav.com/",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if not out:
|
if not out:
|
||||||
log.info("supjav: żaden data-link nie rozwiązał się na hoster (%s)", page_url)
|
log.info("supjav: żaden data-link nie rozwiązał się na hoster (%s)", page_url)
|
||||||
return None
|
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
|
return out
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@ export type ChangelogEntry = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CHANGELOG: 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',
|
id: '2026-07-10b',
|
||||||
date: 'July 2026',
|
date: 'July 2026',
|
||||||
|
|
|
||||||
|
|
@ -1389,6 +1389,7 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) {
|
||||||
const { isDoodStream, resolveDoodStream } = await import('../lib/doodstream');
|
const { isDoodStream, resolveDoodStream } = await import('../lib/doodstream');
|
||||||
const { isPackerHoster, resolvePackerHoster } = await import('../lib/packerHoster');
|
const { isPackerHoster, resolvePackerHoster } = await import('../lib/packerHoster');
|
||||||
const { isFilemoonHoster, resolveFilemoonHoster } = await import('../lib/filemoonHoster');
|
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;
|
let result: { url?: string; headers?: Record<string, string>; error?: string } | null = null;
|
||||||
if (isDoodStream(url)) {
|
if (isDoodStream(url)) {
|
||||||
|
|
@ -1400,6 +1401,15 @@ function EmbedWebViewPlayer({ params }: { params: RouteParams }) {
|
||||||
} else if (isFilemoonHoster(url)) {
|
} else if (isFilemoonHoster(url)) {
|
||||||
setResolveStatus('pending');
|
setResolveStatus('pending');
|
||||||
result = await resolveFilemoonHoster(url, source);
|
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);
|
setResolveAttempted(true);
|
||||||
|
|
|
||||||
|
|
@ -665,7 +665,11 @@ function PlaybackButton({
|
||||||
// Player JS hostera może też ujawnić finalny m3u8 — auto-extract w PlayerScreen
|
// Player JS hostera może też ujawnić finalny m3u8 — auto-extract w PlayerScreen
|
||||||
// pokaże banner "Otwórz w native playerze".
|
// pokaże banner "Otwórz w native playerze".
|
||||||
if (directLinks.length === 0) {
|
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;
|
let refererHost: string | undefined;
|
||||||
try {
|
try {
|
||||||
refererHost = new URL(source.page_url).hostname;
|
refererHost = new URL(source.page_url).hostname;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue