mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 21:07:03 +01:00
review.py held three separable concerns. Two move out:
_render.py emptiness, status_line, filename_line, title_line, render --
pure state-to-text, no toolkit and no transitions
_undo.py can_undo, on_undo, forget_last -- correcting the tally and
putting the on-screen video back at the front of the queue
review.py keeps the state transitions and re-exports all eight names through
__all__, so ui.py and test_review.py reach them at review.* exactly as before;
verified by resolving every name in __all__.
Both new modules reference SessionState under TYPE_CHECKING only, so there is
no runtime cycle. Also inlined _worker_message, a single-caller passthrough
that just returned event.message.
review.py 330 -> 196, _render.py 107, _undo.py 74.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
108 lines
3.0 KiB
Python
108 lines
3.0 KiB
Python
"""Turning reviewer state into the text and commands the window applies.
|
|
|
|
Split out of :mod:`python_pkg.wsg_grabber.review` to keep that module under the
|
|
250-line cap. Everything here is a pure function of :class:`SessionState`: no
|
|
toolkit, no I/O, no state transitions -- those stay in ``review``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from python_pkg.wsg_grabber.models import Emptiness, ReviewCommand
|
|
|
|
if TYPE_CHECKING:
|
|
from python_pkg.wsg_grabber.review import SessionState
|
|
|
|
_BYTES_PER_MIB = 1024 * 1024
|
|
|
|
|
|
def emptiness(state: SessionState) -> Emptiness:
|
|
"""Explain why there is nothing to show, if that is the case.
|
|
|
|
Args:
|
|
state: Current state.
|
|
|
|
Returns:
|
|
Emptiness: Whether the queue is merely waiting or genuinely exhausted.
|
|
"""
|
|
if state.current is not None:
|
|
return Emptiness.NOT_EMPTY
|
|
return Emptiness.EXHAUSTED if state.scan_complete else Emptiness.WAITING
|
|
|
|
|
|
def status_line(state: SessionState) -> str:
|
|
"""Build the text under the video.
|
|
|
|
Args:
|
|
state: Current state.
|
|
|
|
Returns:
|
|
str: One line summarising progress.
|
|
"""
|
|
if state.error is not None:
|
|
return f"downloader stopped: {state.error}"
|
|
counts = (
|
|
f"kept {state.kept} · passed {state.passed} · "
|
|
f"queued {len(state.pending)} · downloaded {state.downloaded}"
|
|
)
|
|
if state.indexed:
|
|
counts = f"{counts}/{state.indexed}"
|
|
undo = f" · u undoes ({state.undoable})" if state.undoable else ""
|
|
mood = {
|
|
Emptiness.NOT_EMPTY: "",
|
|
Emptiness.WAITING: " · waiting for downloads…",
|
|
Emptiness.EXHAUSTED: " · all caught up",
|
|
}[emptiness(state)]
|
|
return f"{counts}{mood}{undo}"
|
|
|
|
|
|
def filename_line(state: SessionState) -> str:
|
|
"""Describe the video currently on screen.
|
|
|
|
Args:
|
|
state: Current state.
|
|
|
|
Returns:
|
|
str: Original filename with size and dimensions, or a placeholder.
|
|
"""
|
|
item = state.current
|
|
if item is None:
|
|
return "—"
|
|
size = item.fsize / _BYTES_PER_MIB
|
|
return f"{item.orig_name} · {item.width}x{item.height} · {size:.1f} MiB"
|
|
|
|
|
|
def title_line(state: SessionState) -> str:
|
|
"""Build the window title.
|
|
|
|
Args:
|
|
state: Current state.
|
|
|
|
Returns:
|
|
str: Title including the running verdict tally.
|
|
"""
|
|
return f"/wsg/ — kept {state.kept}, passed {state.passed}"
|
|
|
|
|
|
def render(state: SessionState) -> ReviewCommand:
|
|
"""Turn the state into instructions the window applies verbatim.
|
|
|
|
Args:
|
|
state: Current state.
|
|
|
|
Returns:
|
|
ReviewCommand: Everything the GUI should show or do.
|
|
"""
|
|
item = state.current
|
|
return ReviewCommand(
|
|
play=None if item is None else item.path,
|
|
stop=item is None,
|
|
status=status_line(state),
|
|
title=title_line(state),
|
|
filename=filename_line(state),
|
|
verdicts_enabled=item is not None and not state.quitting,
|
|
undo_enabled=state.undoable > 0 and not state.quitting,
|
|
quit_app=state.quitting,
|
|
)
|