f1-stream: drop demo + landing-page extractors, add fetch-proxy injection
Per user feedback: the demo Big Buck Bunny / Apple test streams aren't useful in an F1-streams app. Removed DemoExtractor entirely. Tightened the discord-extractor path filter from "any stream-shaped path" to "direct embed/player path only" — the previous filter still let sportsurge `/event/...` landing pages through, which the verifier mistook for playable because they render player-class divs without a real player. Embed proxy now also rewrites window.fetch + XMLHttpRequest.open inside the upstream HTML so that cross-origin XHRs (e.g. the hmembeds `/sec/<JWT>` token-binding endpoint) go through our /embed-asset relay. This avoids the CORS reject that fired when the player JS tried to call hghndasw.gbgdhdffhf.shop/sec/... from an `f1.viktorbarzin.me` origin. The verifier now requires a `<video>` element to mark embed streams playable (not just a player-class div). Curated streams bypass the verifier — hmembeds aggressively detects headless Chromium (devtool trap, console-clear timing, automation flags) and won't progress past JW Player init in our pod, but the user's real browser should clear those checks. We can't honestly headless-verify hmembeds, so we trust the curator instead of falsely rejecting them. Image: viktorbarzin/f1-stream:v6.1.1
This commit is contained in:
parent
f90d79ed4e
commit
574cdf08d2
5 changed files with 87 additions and 27 deletions
|
|
@ -162,12 +162,9 @@ _EMBED_POLL_JS = """
|
|||
sources: v.querySelectorAll('source').length,
|
||||
};
|
||||
}
|
||||
const player_divs = document.querySelectorAll(
|
||||
'[id*="player" i], [class*="player" i], [class*="jwplayer" i], [id*="video" i], [class*="video-js" i]'
|
||||
);
|
||||
return {has_video: false, has_player_div: player_divs.length > 0};
|
||||
return {has_video: false};
|
||||
} catch (e) {
|
||||
return {has_video: false, has_player_div: false, err: String(e)};
|
||||
return {has_video: false, err: String(e)};
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
|
@ -271,12 +268,14 @@ async def _verify_embed(page, proxied_url: str, deadline: float) -> PlaybackVerd
|
|||
)
|
||||
|
||||
# Track the best state seen across all polls. Some embeds load a player
|
||||
# div briefly then anti-bot JS tears the DOM down (hmembeds redirects
|
||||
# to google.com if its devtool-detection trips). We accept any positive
|
||||
# briefly then anti-bot JS tears the DOM down (hmembeds redirects to
|
||||
# google.com if its devtool-detection trips). We accept any positive
|
||||
# signal observed during the window, even if it's gone by timeout.
|
||||
#
|
||||
# We require an actual <video> element — a "player container div"
|
||||
# is too weak (sportsurge has player-class divs but no real player).
|
||||
seen_video_wired = False
|
||||
seen_video_tag = False
|
||||
seen_player_div = False
|
||||
last_err = ""
|
||||
|
||||
while time.monotonic() < deadline:
|
||||
|
|
@ -295,8 +294,6 @@ async def _verify_embed(page, proxied_url: str, deadline: float) -> PlaybackVerd
|
|||
is_playable=True, signal="video.wired",
|
||||
elapsed_ms=int((time.monotonic() - start) * 1000),
|
||||
)
|
||||
if r.get("has_player_div"):
|
||||
seen_player_div = True
|
||||
last_err = r.get("err", "")
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
|
|
@ -306,11 +303,8 @@ async def _verify_embed(page, proxied_url: str, deadline: float) -> PlaybackVerd
|
|||
if seen_video_tag:
|
||||
return PlaybackVerdict(is_playable=True, signal="video.tag_only",
|
||||
elapsed_ms=int((time.monotonic() - start) * 1000))
|
||||
if seen_player_div:
|
||||
return PlaybackVerdict(is_playable=True, signal="player_div",
|
||||
elapsed_ms=int((time.monotonic() - start) * 1000))
|
||||
|
||||
err = "no <video> or player container found"
|
||||
err = "no <video> element rendered"
|
||||
if last_err:
|
||||
err += f"; last_err: {last_err}"
|
||||
return PlaybackVerdict(is_playable=False, error=err,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue