Skip to content

Detect external CLI runs in Web UI operation banner#130

Merged
StudioNirin merged 10 commits into
StudioNirin:mainfrom
Brandon-Haney:pr/external-cli-detection
Apr 7, 2026
Merged

Detect external CLI runs in Web UI operation banner#130
StudioNirin merged 10 commits into
StudioNirin:mainfrom
Brandon-Haney:pr/external-cli-detection

Conversation

@Brandon-Haney

@Brandon-Haney Brandon-Haney commented Apr 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add unified activity writer (core/activity.py) so CLI and Web UI share activity tracking
  • Detect external CLI runs in the operation banner with live log tailing
  • Add completion banner and lifecycle tracking for external CLI runs
  • Add Stop button for external CLI runs via SIGTERM
  • Add active file tracking in banner during external CLI runs
  • Fix external log parser losing state on large verbose logs
  • Add should_stop checks inside media processing loops for faster shutdown
  • Guard SIGTERM handler to main thread only

Relates to #127

Test plan

  • Start a CLI run externally while Web UI is open — banner should detect and display it
  • Verify live log tailing shows progress in the banner pill
  • Verify Stop button sends SIGTERM and CLI run stops gracefully
  • Verify completion banner appears when external CLI run finishes
  • Verify active file tracking shows current file being processed
  • Run with --verbose to generate large logs — parser should not lose state

@StudioNirin

Copy link
Copy Markdown
Owner

@Brandon-Haney
All of these prs seem to say theyre out of date with the main branch, have I merged one in the wrong sequence or something?

I'm having to do this from mobile so ill give you a change to reply before I go through and do more checks in case ive mucked something up.

Extract activity recording (FileActivity, load/save, run summary) from
web/services/operation_runner.py into core/activity.py so CLI-triggered
runs are visible in the Web UI dashboard. FileMover gains an optional
file_activity_callback for per-file recording during CLI runs.
When PlexCache is triggered via docker exec or cron, the web UI banner
now detects the running process via plexcache.lock and tails the shared
log file to show live progress. Displays a purple CLI badge, phase info,
file counts, and ETA — same detail as web-triggered runs. Idle banner
poll reduced from 30s to 10s for faster detection.
Log files use plexcache_log_latest.log symlink, not plexcache.log.
This was preventing log parsing for external CLI run detection.
Track external CLI process lifecycle so the banner shows a completion
pill with file counts and duration when the CLI run finishes. Completion
banner auto-dismisses after 60 seconds or on manual dismiss. Shows CLI
badge in completed state. Also fixes dismiss to clear external state.
- Parse error messages from log (up to 10, shown in completion detail)
- Detect dry run mode from log header (DRY RUN / --dry-run)
- Add user lookups from OnDeck/Watchlist trackers for cached files
- Apply dry run prefix to phase display during external runs
CLI process registers a SIGTERM handler that calls request_stop() for
graceful shutdown (finishes current file, then exits). The web banner's
Stop button sends SIGTERM to the external PID read from plexcache.lock.
Same behavior as web-triggered stop — no data loss.
FileMover now logs [Copying] before each file copy starts. The external
log parser tracks [Copying] entries minus completed [Cached]/[Restored]
to derive currently-active files. Tier 3 detail now shows COPYING rows
for external CLI runs, matching web-triggered run behavior.
The parser read the last 200KB of the log file, but verbose runs easily
exceed 600KB. Once the file outgrew the read window, the run header
fell outside and the parser returned default Starting/0s state. Now
reads backwards in 256KB chunks to find the header, then reads forward
from there. Works for any log size with minimal I/O per poll.
Stop requests during _process_media() and _process_watchlist() were
ignored until the entire phase completed because checks only existed
between sections, not inside the per-item loops. Now bails within one
iteration of OnDeck tracker, watchlist local, and watchlist RSS loops.
signal.signal() raises ValueError when called from a background
thread. Skip registration when run from web UI's OperationRunner
thread — the web UI uses request_stop() directly instead.
@Brandon-Haney
Brandon-Haney force-pushed the pr/external-cli-detection branch from e608e8d to 3b217d6 Compare April 7, 2026 14:32
@Brandon-Haney

Brandon-Haney commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

@Brandon-Haney All of these prs seem to say theyre out of date with the main branch, have I merged one in the wrong sequence or something?

I'm having to do this from mobile so ill give you a change to reply before I go through and do more checks in case ive mucked something up.

@StudioNirin
I just needed to sync them up with the changes, give it a shot now. Merge in this order, #129, #130, #131.

@StudioNirin
StudioNirin merged commit 2a0c646 into StudioNirin:main Apr 7, 2026
2 checks passed
@Brandon-Haney
Brandon-Haney deleted the pr/external-cli-detection branch April 7, 2026 19:42
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