Files
siftlode/frontend/src/i18n/locales/en/scheduler.json
T
peter 27c2fcbd2e feat(scheduler): a channel's "get full history" backfill is a recorded run, and a row knows its last three runs
The one-channel deep backfill ran as a FastAPI BackgroundTask: what it fetched, what it spent and
how it failed reached only the log. It is now a one-shot run on the scheduler (`channel_backfill`,
trigger ad_hoc, actor = the user, target = the channel) with its quota tagged to the run. Its
per-channel exclusion with the scheduled backfill and the two-run cap are unchanged, and a run
they turn away says why in its result instead of returning nothing. A failure is no longer
swallowed: the run records it.

The scheduler snapshot carries each job's last three runs (one windowed query), so the page can
show an interrupted or skipped run instead of the latest outcome alone.
2026-10-18 01:05:24 +02:00

204 lines
11 KiB
JSON

{
"title": "Background scheduler",
"menu": "Scheduler actions",
"loading": "Loading scheduler…",
"running": "Running",
"paused": "Paused",
"notHere": "Not running in this instance",
"notHereNote": "The scheduler runs on the server. This instance shows the shared queue and quota, but live job activity appears only where the scheduler runs.",
"updating": "updating…",
"pause": "Pause",
"resume": "Resume",
"pauseHint": "Pause or resume all background sync for the whole app (every user).",
"toggleFailed": "Couldn't change the scheduler state",
"jobsTitle": "Jobs",
"queueTitle": "Work queued",
"quotaTitle": "Shared API quota",
"everyMin_one": "every {{count}} min",
"everyMin_other": "every {{count}} min",
"runningNow": "Running now…",
"lastRun": "Last run {{time}}",
"neverRun": "No run recorded yet",
"active": "active",
"nextRun": "next",
"quotaUsed": "{{used}} / {{budget}} units used today",
"quotaRemaining": "{{formatted}} left",
"quotaNote": "Shared YouTube Data API budget; resets at midnight US Pacific. Backfill yields to leave headroom for interactive use.",
"minutes": "min",
"range": "Must be between {{min}} and {{max}}",
"editInterval": "Click to change how often this runs",
"intervalFailed": "Couldn't change the interval",
"runNow": "Run now",
"runAll": "Start all now",
"runAllHint": "Run every job now, in addition to their schedules.",
"runAllPausedHint": "Resume the scheduler to run jobs (they're skipped while paused).",
"triggered": "Started {{job}}",
"triggeredAll_one": "Started {{count}} job",
"triggeredAll_other": "Started {{count}} jobs",
"phase": {
"recheck": "Re-checking flagged videos",
"revalidate": "Re-validating videos",
"enrich": "Enriching videos",
"backfill_recent": "Backfilling recent uploads",
"backfill_deep": "Backfilling full history",
"probe": "Classifying Shorts",
"rss_poll": "Checking for new uploads",
"subscriptions": "Syncing subscriptions",
"autotag": "Auto-tagging channels",
"playlist_sync": "Syncing playlists",
"working": "Working…"
},
"maintenance": {
"title": "Maintenance",
"batchLabel": "Videos re-checked per run",
"batchHint": "How many least-recently-checked videos the maintenance job re-validates each run. Higher = faster full cycle but more API quota (1 unit per 50 videos).",
"batchNote": "Default: {{default}}. ~233k videos ÷ this = days for a full re-check cycle."
},
"dot": {
"running": "running now",
"ok": "last run OK",
"idle": "idle (no run recorded yet)",
"error": "last run failed",
"skipped": "skipped (sync paused)"
},
"jobDesc": {
"rss_poll": "Checks each channel's RSS feed for new uploads (free, no quota). If it stops, new videos only appear later when a backfill pass catches them, so your Feed lags behind YouTube.",
"enrich": "Fetches video details (duration, views, live/Shorts flags) and re-checks live videos until they end. If it stops, videos stay without a duration/stats and ended livestreams stay stuck as “live”.",
"backfill": "Pulls in recent uploads, then the full back-catalogue for opted-in channels, within the shared quota. If it stops, older videos and full history don't fill in.",
"autotag": "Detects each channel's language/topics and applies automatic tags. If it stops, new channels get no auto tags, so language/topic filters miss them.",
"shorts": "Probes youtube.com/shorts to mark which videos are Shorts. If it stops, Shorts aren't separated from normal videos in the Feed.",
"subscriptions": "Re-imports every user's YouTube subscriptions. If it stops, channels subscribed to or dropped on YouTube aren't reflected here.",
"playlist_sync": "Mirrors each user's YouTube playlists into the app. If it stops, changes to your YouTube playlists don't show up locally.",
"maintenance": "Finds videos that can no longer be played (deleted, made private, abandoned premieres), hides them from the Feed and removes them after a grace period; re-checks the least-recently-checked videos. If it stops, dead videos linger in the catalogue.",
"explore_cleanup": "Removes channels you explored but never subscribed to (and their videos) after a grace period, so curiosity browsing doesn't pile up in the catalogue. If it stops, abandoned explored channels linger.",
"download_gc": "Deletes downloaded files past their retention window, reclaims space no one is holding anymore, and warns owners before a shared file or an API token expires. If it stops, old downloads pile up, disk space isn't freed, and a token runs out unannounced.",
"plex_sync": "Mirrors the enabled Plex libraries into the app's catalogue — the metadata behind Plex browsing, search, filters and the info pages (genres, cast, ratings, artwork). If it stops, newly added or changed Plex titles don't appear until the next sync.",
"plex_watch_sync": "Pulls recent Plex watch changes (finished episodes, resume positions) into Siftlode and re-pushes any local watch changes that didn't reach Plex. The cheap two-way keep-in-sync between full reconciles. If it stops, watched/resume made in the Plex app takes longer to show here.",
"plex_watch_reconcile": "A full watch-state reconcile that rescans every library — catches what the incremental pass can't, notably an episode un-marked as watched on the Plex side. Heavier, so it runs about once a day. If it stops, un-watches done in Plex aren't mirrored back.",
"audit_gc": "Prunes admin audit-log entries and YouTube quota history older than their retention windows (Configuration → Audit log, Quota). If it stops, both just keep growing — harmless but unbounded.",
"log_gc": "Deletes stored log events older than the retention window (Configuration → Diagnostics). Runs hourly so nothing outlives the promised limit by more than an hour.",
"tmdb_enrich": "Enriches the mirrored Plex catalogue from TMDB (keywords, crew, budget/revenue, TMDb score, recommendations, artwork), matched by each title's canonical id and served from the app's own database. Optional — a no-op until a TMDB API key is set. If it stops, new Plex titles just miss their TMDB extras until it runs again.",
"people_enrich": "Makes the people in the Plex library local: fetches each person's biography from TMDB and caches their portrait, resized through Plex, the most-credited people first. A person page and a cast strip then open from the app's own data. The TMDB half does nothing without a TMDB API key, the portrait half nothing without Plex. If it stops, a person page fetches its own bio when opened, a moment later."
},
"jobs": {
"rss_poll": "RSS poll (new uploads)",
"enrich": "Enrichment + live refresh",
"backfill": "Backfill (recent + full history)",
"autotag": "Auto-tagging",
"shorts": "Shorts classification",
"subscriptions": "Subscription sync from YouTube",
"playlist_sync": "Playlist sync from YouTube",
"maintenance": "Maintenance + validation",
"explore_cleanup": "Explored-channel cleanup",
"download_gc": "Download cleanup",
"plex_sync": "Plex library sync",
"plex_watch_sync": "Plex watch sync (incremental)",
"plex_watch_reconcile": "Plex watch reconcile (full)",
"tmdb_enrich": "TMDB enrichment (Plex)",
"audit_gc": "Audit-log and quota-history cleanup",
"log_gc": "Log cleanup",
"people_enrich": "People details and portraits (Plex)"
},
"queue": {
"recentPending": "Channels to sync",
"recentPendingHint": "Channels whose recent uploads haven't been fetched yet.",
"deepPending": "Full-history pending",
"deepPendingHint": "Channels opted into full-history backfill that aren't finished yet.",
"enrichPending": "Videos to enrich",
"enrichPendingHint": "Videos awaiting details (duration, stats, live/short classification).",
"shortsPending": "Shorts to classify",
"shortsPendingHint": "Enriched videos still awaiting the Shorts probe.",
"liveRefresh": "Live to refresh",
"liveRefreshHint": "Live/upcoming videos (and just-ended streams without a duration yet) re-checked until they settle."
},
"purgeDiscovery": "Purge discovery",
"purgeDiscoveryHint": "Delete all un-kept discovery content now (search results nobody watched/saved, and explored-but-unsubscribed channels) — ignoring the grace period.",
"purgeConfirmTitle": "Purge discovery content?",
"purgedDiscovery_one": "Deleted {{count}} discovery item",
"purgedDiscovery_other": "Deleted {{count}} discovery items",
"result": {
"new": "new videos",
"failed": "failed",
"fallback": "read through the API",
"channels_processed": "channels processed",
"videos_added": "videos added",
"reconciled_full": "fully reconciled",
"reason": "reason",
"channels_tagged": "channels tagged",
"orphan_tags_removed": "orphan tags removed",
"probed": "checked",
"shorts": "Shorts",
"users": "users",
"playlists_synced": "playlists synced",
"rechecked": "rechecked",
"recovered": "recovered",
"deleted": "deleted",
"notified": "notified",
"revalidated": "revalidated",
"flagged": "flagged",
"skipped": "skipped",
"expired": "expired",
"videos_deleted": "videos deleted",
"channels_deleted": "channels deleted",
"search_videos_deleted": "search results deleted",
"warned": "warned",
"evicted": "evicted",
"reaped": "cleaned up",
"swept": "swept",
"tokens_warned": "tokens warned",
"libraries": "libraries",
"movies": "movies",
"shows": "shows",
"seasons": "seasons",
"episodes": "episodes",
"collections": "collections",
"overlaid": "HU overlay",
"pruned": "pruned",
"people_enriched": "people enriched",
"media_probed": "media probed",
"people_pruned": "people pruned",
"error": "error",
"links": "links",
"watched": "watched",
"in_progress": "in progress",
"repushed": "re-sent",
"movie_probes": "movie probes",
"applied": "applied",
"cleared": "cleared",
"scanned": "scanned",
"enriched": "enriched",
"countries_coded": "countries coded",
"sessions_closed": "sessions closed",
"sessions_reaped": "sessions cleaned up",
"quota_reaped": "quota history cleaned up",
"recent": "recent",
"deep": "deep",
"bios": "biographies",
"portraits": "portraits",
"cached": "cached"
},
"skip": {
"disabled": "disabled",
"PlexserverURLortokenisnotconfigured": "Plex server URL or token is not configured",
"tmdbapikeynotset": "TMDB API key not set",
"noserviceuser": "no service user",
"syncpaused": "sync paused",
"lowquota": "low quota",
"noreadscope": "no YouTube read access",
"busy": "another sync is running",
"channelbusy": "this channel is already being backfilled",
"atcapacity": "two full-history backfills are already running — the scheduler finishes this one",
"nothingtodo": "nothing left to fetch"
},
"failure": {
"rss_all_failed_one": "The RSS feed did not answer for the one channel, {{channel}}: {{cause}}. Read through the API instead: {{read}}.",
"rss_all_failed_other": "The RSS feed answered for none of the {{total}} channels — the first: {{channel}}, {{cause}}. Read through the API instead: {{read}}."
},
"rssCause": {
"http": "HTTP {{status}}",
"transport": "unreachable",
"apply": "could not be saved",
"error": "unexpected error"
}
}