Completes the two-way watch-state sync with two scheduler jobs: - plex_watch_sync (default 30m): pull recent Plex-side changes (watch history + on-deck, filtered to the owner account) into Siftlode under last-write-wins (_pull_apply + a _same_state ping-pong guard + skew tolerance), then re-push any still-unsynced local states. - plex_watch_reconcile (default daily): full section rescan; uses synced_to_plex to settle what the incremental feed can't — notably propagating a Plex-side un-watch (clear a previously-mirrored row Plex no longer has) — while re-pushing never-synced local states and never touching hidden (Siftlode-only) rows. Union-preserving. PlexClient gains accounts/watch_history/on_deck; _scan_plex_states is factored out and shared with the one-time import. Owner accountID is resolved once and cached on the link. Both jobs are registered in the scheduler (pause-skip, activity tracking, run-now, admin-tunable intervals) with trilingual (HU/EN/DE) labels + descriptions. New config default plex_watch_reconcile_interval_min. Verified live against the real Plex server: read feeds, last-write-wins, dirty re-push, the incremental job end-to-end, and a full reconcile that cleared exactly the one un-watched item with zero collateral across 17976 scanned.
107 lines
6.8 KiB
JSON
107 lines
6.8 KiB
JSON
{
|
|
"title": "Background scheduler",
|
|
"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": "every {{count}} min",
|
|
"runningNow": "Running now…",
|
|
"lastRun": "Last run {{time}}",
|
|
"neverRun": "Hasn't run yet this session",
|
|
"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",
|
|
"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 (not run yet this session)",
|
|
"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 expires. If it stops, old downloads pile up and disk space isn't freed.",
|
|
"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."
|
|
},
|
|
"jobs": {
|
|
"rss_poll": "RSS poll (new uploads)",
|
|
"enrich": "Enrichment + live refresh",
|
|
"backfill": "Backfill (recent + full history)",
|
|
"autotag": "Auto-tagging",
|
|
"shorts": "Shorts classification",
|
|
"subscriptions": "Subscription resync",
|
|
"playlist_sync": "YouTube playlist sync",
|
|
"maintenance": "Maintenance + validation",
|
|
"demo_reset": "Demo account reset",
|
|
"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)"
|
|
},
|
|
"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": "Remove all un-kept discovery content now (search results nobody watched/saved, and explored-but-unsubscribed channels) — ignoring the grace period.",
|
|
"purgedDiscovery": "Removed {{count}} discovery items"
|
|
}
|