Visitar URL original
Feat/api phase e by wisdom-technologies-bit · Pull Request #1997 · pystardust/ani-cli · GitHub
Skip to content

Feat/api phase e - #1997

Closed
wisdom-technologies-bit wants to merge 4 commits into
pystardust:masterfrom
wisdom-technologies-bit:feat/api-phase-e
Closed

wisdom-technologies-bit wants to merge 4 commits into
pystardust:masterfrom
wisdom-technologies-bit:feat/api-phase-e

Conversation

@wisdom-technologies-bit

Copy link
Copy Markdown

Pull Request Template

Contributing guidelines · CI workflows

Type of change

  • Bug fix
  • Feature
  • Documentation update

Description

ramble here

Which flags, players or platforms does this affect?

Use the fixes keyword to link an issue if this directly resolves one.

Fixes #xyz

Verification

Explain briefly how we can verify your results.
Specific anime are the most valuable for bug fixes.
Quick example invocation is most valuable for features.
No need to restate documentation updates

e.g. ./ani-cli -d -q 720 cyberpunk 2 -e 1 && mpv cyber*

(prepend the ./ since during development, we work within the repo)

Checklist

  • any anime playing
  • bumped version

  • next, prev, replay and select work
  • -c history and continue work
  • -d downloads work
  • -e (select episode) aka -r (range selection) works
  • -S select index works
  • -q quality works
  • -s syncplay works
  • -v vlc works
  • --dub and regular (sub) mode both work
  • --nextep-countdown countdown to next ep works

  • -h help info is up to date
  • Readme is up to date
  • Man page is up to date

Additional Testcases

(these don't block a merge)

  • --skip ani-skip works
  • --no-detach no detach works
  • --exit-after-play auto exit after playing works

Copy Pasta

./ani-cli -V
./ani-cli -S 1 -e 1 -d flcl
./ani-cli -S 1 -e 1 -q worst -v flcl
./ani-cli -c -s --dub

Solas (agent) added 4 commits November 12, 2026 21:24
Some CDNs serve HLS segments with a non-standard extension (e.g.
seg_00000.ts.jpg). libavformat >= 5.1 rejects those segments by default
(extension_picky defaults to true), so the HLS demuxer fails and mpv
falls back to opening each segment as separate media, which loses the
timeline and seeking.

Pass --demuxer-lavf-o=extension_picky=0 to the mpv-family player paths
(mpv, flatpak mpv, android_mpv config, syncplay) only. VLC, iina, the
generic fallback and the download path are unchanged.
Phase A-C of the approved architecture.

- adapters: metadata (hianime) and stream (zokoanime) behind protocols, so a
  provider swap is one class, not a rewrite
- extraction ported from the proven shell implementation; real captured
  responses committed as fixtures; parity harness in tests/test_live.py
- stream resolution proves delivery by probing the first media segment:
  playlist 200 alone is never reported as playable
- edge-cached 403 detection (cf-cache-status/age on a 403), per-object denylist
  so broken segments are not retried blindly, ordered alternatives, and no
  pointless re-extraction when the master URL is unchanged
- auth refuses all non-loopback traffic when no API keys are configured
- signed short-lived tokens + host allowlist for the playlist/subtitle proxies
  (browsers cannot set Referer, which the master playlist requires)
- Redis cache with an in-process fallback; server-side downloads explicitly off
Circuit breaker per provider (closed/open/half-open, shared through cache),
in-process single-flight so N concurrent identical requests cause one upstream
extraction, and an escalating cached-403 denylist (30m, 1h, 2h, 4h) whose base
window is set from the measured 20-40 minute recovery rather than a guess.

Observability: dependency-free Prometheus registry at /metrics plus JSON
structured logging with request ids, stage and latency. Prober worker
(python -m ani_api.workers.lifetime_prober) maintains the 2h/6h/24h URL lifetime
curve as measurements; /v1/admin/lifetime reports 'pending' until real samples
land, and /v1/admin/providers exposes breaker state.

Security: API-key auth with rotation, structural test that every /v1 route
requires access, rate limiting, forwarded-header spoofing defence, SSRF host
allowlist, signed short-lived proxy tokens, query validation.

Tests: 25 offline (unit + security + structural) and 9 live. Simulated
failure-injection tests are labelled as such and are never used as evidence of
live resolution.
Adds workers/checkpoints.py: probes only the ORIGINAL extracted URL for each
target (master -> first variant -> first segment), never re-extracting or
substituting a fresh URL, so each checkpoint describes the same object captured
at t+0.

Recording: extraction timestamp, elapsed minutes, provider/anime/episode/audio,
playlist/variant/segment status, ranged byte count, age, cf-cache-status and
cache-control, playback_validated flag, and an outcome that names cached_403
separately from blocked_403 and expired_or_denied.

Idempotent by construction: one state entry per (target, checkpoint), written to
disk before the next probe, so restarts and overlapping runs cannot duplicate a
checkpoint or re-fire requests. State writes are atomic; a corrupt state file is
preserved as .corrupt instead of being lost. Transient failures retry with 2/5/10s
backoff, definitive HTTP answers are recorded at once. Sub and dub are separate
targets so successes do not leak between audio variants.

9 new tests: due-time maths at the exact boundary, ordering, no-substitution,
dedupe across re-runs and simulated restart, corrupt-state recovery, transient
retry, and cached-403 classification.
@port19x

port19x commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

no

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants