Skip to content

Job Dashboard

The dashboard is a live view of every download, not a page you reload. Job state is pushed to the browser over Server-Sent Events.

Live updates

Two SSE endpoints exist:

Endpoint Scope
GET /events Every job — powers the dashboard list
GET /api/jobs/{job_id}/events One job — powers the job detail page
Property Value
Keep-alive interval 5 s
Per-client queue 32 events
Max concurrent connections 200
Rate limit 30/minute per client

The event broker is process-local

Subscribers only receive events published by the same Python process. This is why WORKERS must stay at 1; with a second Gunicorn worker, clients would subscribe to a process that never sees their job. See Resources & Workers.

If a client's queue overflows — a browser tab suspended in the background, for instance — the connection is dropped rather than allowed to grow unbounded. The page reconnects and re-reads the current state from GET /api/jobs.

Job statuses

Status Terminal Meaning
queued Waiting for a worker slot
processing Metadata extraction and format selection
downloading yt-dlp is fetching
transcoding ffmpeg is converting
analysis BPM detection running; the file is already downloadable
analysis_done Finished, with analysis
done Finished, no analysis
error Failed — the message is shown and a retry is offered
cancelled Cancelled by the user

done and analysis_done both count as completed. analysis additionally counts as downloadable, so an audio file can be fetched while its tempo analysis is still running.

A completed video whose file is VP9 or AV1 (see Video Codecs & Output Format) carries a Limited playback marker in the job list and the details dialog — it will not open on Safari, iOS, or most TVs.

Job actions

Action Availability
Download Any downloadable status (automatic when Start Download after Processing is on)
Open job page Any job
Cancel While in flight
Retry After error
Trim Audio jobs, downloadable — Audio Trimming
Stems Audio jobs, Lalal.ai connected — Stem Separation
Share Completed jobs — Share Links

There is no per-job delete action. Jobs are removed either by retention sweeping expired jobs — row, files and share links together, so they leave this list as well — or by Settings → System → Remove all jobs, which clears every job at once (see Bulk cleanup below).

Hiding jobs from the history

Settings → General → Retention → Enable Job History decides whether a new job is listed in the dashboard. A job submitted while it is off still runs and is counted in the statistics, but is left out of the list. The choice is stored per job at submission, so flipping the setting later never changes jobs that already exist. The Show Job History toggle on the dashboard is unrelated: it only collapses the list in your browser. See Application Settings.

Starting the download automatically

Settings → General → Retention → Start Download after Processing is on by default. Once a newly submitted job becomes downloadable, the browser starts the file download on its own — no extra click on Download needed. The job still appears in the job history exactly as before; only the extra click is skipped. Turning it off restores the previous behavior: the job waits in the list until you download it yourself. Like Enable Job History, this only applies to jobs submitted after the change. See Application Settings.

Phones and tablets

On touch devices up to iPad Pro 12.9" in landscape, the job list switches from a table to compact cards.

A Current job card above the list keeps the download you just started visible even while Show Job History is off. It holds one job at a time, is cleared by a page reload, and hands the job back to the list once the screen is wide enough for the table.

Track length

duration_seconds is filled twice. At submit time it comes from the source's own metadata, so a job shows its length while it is still queued or downloading. When the download finishes, ffprobe measures the actual file and replaces the value — a probe that comes back empty leaves the source value in place rather than blanking it.

It is rendered as M:SS, or H:MM:SS from an hour up, in the job list (desktop media column and mobile card), the detail dialog, and on the job page. Jobs whose length is unknown show an en dash.

The job page

GET /job/{job_id} renders a detail view with:

  • The player (in-browser playback of the downloaded file)
  • The waveform for audio jobs, with drag-to-select trimming
  • Detected BPM and beat confidence, when analysis has run
  • Job metadata: source URL, platform, type, quality, duration, file size, timestamps

Statistics

GET /api/stats returns aggregate counters for the dashboard — totals by status, bytes downloaded, and the like. The result is cached briefly so a busy dashboard does not re-aggregate the database on every event.

GET /api/stats/bpm-clusters buckets every detected tempo into 5-BPM groups, sorted by count, for the tempo distribution chart.

Settings → System → Reset statistics (POST /api/stats/reset) stamps a reset marker rather than deleting rows, so counters restart without losing job history.

Bulk cleanup

Settings → System → Remove all jobs (POST /api/jobs/remove-all, 2/minute) deletes every job row and its on-disk artifacts in one step.

There is no undo

Removing all jobs deletes the downloaded media as well. Any share links pointing at those jobs stop working immediately.

For automatic cleanup by age, use retention instead — see Storage & Retention.

Recovery after a restart

Jobs that were processing, downloading, or transcoding when the process stopped cannot be resumed — the subprocess is gone. At startup they are marked cancelled with the message "Cancelled because the application restarted during processing", so they end up in a terminal state you can retry from instead of being stuck in flight forever.