From c230c6b7d74801aa9e4a6c2c206bc80b6a894863 Mon Sep 17 00:00:00 2001 From: Shaku-Med Date: Fri, 19 Jun 2026 00:14:34 -0400 Subject: [PATCH] feat: make hover thumbnails optional (--no-thumbnails) Thumbnails stay on by default. --no-thumbnails skips building the preview sprite, so the server does no extra work and the rest of the player still works. The frontend already shows no preview when the sprite is unavailable. --- README.md | 3 +++ stream_server.py | 10 ++++++++++ test/test_scrub.py | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/README.md b/README.md index e37f2a7..2b0bd41 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,9 @@ video the first time you hover, in a single quick ffmpeg pass, and keeps it in memory so nothing is written to disk. If you already have your own sprite, point the `/scrub` route at it instead. +Hover previews are on by default. If you would rather not build them at all, start +the server with `--no-thumbnails` and the rest of the player keeps working. + ### 4. Run directly in Terminal (Standalone) If you prefer to bypass the web interface, you can render the video directly inside an ANSI-supported terminal (zero-flicker, true color): ```bash diff --git a/stream_server.py b/stream_server.py index 83d7a23..0ddb5c3 100644 --- a/stream_server.py +++ b/stream_server.py @@ -310,6 +310,9 @@ async def scrub_meta(v: int | None = None): loop) the first time it's asked for, then reuses it from memory.""" from fastapi import Response import json as _json + # Thumbnails are on by default; --no-thumbnails turns the whole thing off. + if not getattr(app.state, "thumbnails", True): + return Response(content='{"available": false}', media_type="application/json") video_path = _scrub_video_path(v) if not video_path or not os.path.exists(video_path): return Response(content='{"available": false}', media_type="application/json") @@ -757,6 +760,12 @@ if __name__ == "__main__": help="Adaptive-codec colour fidelity (lossless = bit-exact; lower = " "smaller stream via lossy temporal delta). Chars always exact." ) + playback.add_argument( + "--no-thumbnails", + action="store_true", default=False, + help="Turn off the hover thumbnails on the seek bar (skips building the " + "preview sprite). The rest of the player still works." + ) # ── Server ── srv = parser.add_argument_group('\033[33mServer\033[0m') @@ -784,6 +793,7 @@ if __name__ == "__main__": app.state.loop = args.loop app.state.tolerance = {"lossless": 0, "high": 4, "balanced": 8, "low": 16}[args.quality] app.state.debug = args.debug + app.state.thumbnails = not args.no_thumbnails global_default_cols = args.cols if args.cols is not None else (450 if args.pixel else 200) app.state.cols = global_default_cols app.state.rows = args.rows diff --git a/test/test_scrub.py b/test/test_scrub.py index 345b1a3..b2851dd 100644 --- a/test/test_scrub.py +++ b/test/test_scrub.py @@ -78,6 +78,14 @@ class ScrubTests(unittest.TestCase): finally: ss.app.state.queue = [_entry(self.video)] + def test_thumbnails_can_be_disabled(self): + ss.app.state.thumbnails = False + try: + body = json.loads(asyncio.run(ss.scrub_meta(0)).body) + self.assertFalse(body["available"]) + finally: + ss.app.state.thumbnails = True + def test_sprite_404_before_it_is_built(self): from fastapi import HTTPException ss._scrub_cache.clear()