Files
siftlode/frontend/src/i18n/locales/en/config.json
T
peter ce96032edb feat(plex): transcode resource discipline + admin knobs (E6 S1c)
The software-fallback re-encode now runs deprioritized and admin-configurable.
The SW transcode ffmpeg child is niced (preexec_fn → os.nice, applied per-child
because the Popen lives in the long-lived API process, which must NOT itself be
niced — unlike the download worker's whole-process _deprioritize) so a CPU-bound
re-encode can't starve request handling or playback; the VAAPI path needs none of
it.

New sysconfig knobs (plex group, rendered on the admin Configuration page, i18n
HU/EN): plex_transcode_hw (auto/on/off, layered onto _want_hw), plex_transcode_
preset, plex_transcode_crf, plex_transcode_max_height (software-only downscale-to
cap; the GPU path encodes at source resolution). plex_max_transcodes stays the
concurrency cap (comment corrected — the fallback is shipped, not "later").

pytest extends the command-builder + _want_hw coverage (preset/crf/max_height
plumbing, the on/off/auto policy). Browser-UAT'd: max_height=240 drops the live
resolution to 330x240; the SW ffmpeg child runs at nice 10 (ppid=api process).
2026-08-30 01:22:30 +02:00

221 lines
10 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"intro": "Operational settings stored in the database — these override the file/env defaults and take effect without a redeploy. Leave a field empty (or reset it) to fall back to the default.",
"loading": "Loading configuration…",
"groups": {
"access": "Access",
"email": "Email / SMTP",
"youtube": "YouTube API",
"google": "Google sign-in",
"quota": "Quota",
"backfill": "Backfill",
"shorts": "Shorts probe",
"batch": "Batch sizes",
"explore": "Channel explore",
"downloads": "Downloads",
"plex": "Plex",
"audit": "Audit log"
},
"fields": {
"smtp_host": {
"label": "SMTP host",
"hint": "e.g. smtp.gmail.com"
},
"smtp_port": {
"label": "SMTP port",
"hint": "Usually 587 (STARTTLS)."
},
"smtp_user": {
"label": "SMTP username",
"hint": "The sending account / login."
},
"smtp_from": {
"label": "From address",
"hint": "e.g. Siftlode <addr@gmail.com>. Defaults to the username."
},
"smtp_password": {
"label": "SMTP password",
"hint": "App password. Stored encrypted; write-only — it's never shown back."
},
"quota_daily_budget": {
"label": "Daily quota budget",
"hint": "Total YouTube Data API units to spend per day (free tier is 10,000). Default 9000 leaves headroom."
},
"backfill_quota_reserve": {
"label": "Backfill quota reserve",
"hint": "Units kept in reserve so scheduled backfill never starves interactive syncs / enrichment."
},
"search_daily_limit_per_user": {
"label": "Live search — daily limit per user",
"hint": "Max live YouTube searches per user per day. With the API source each search costs 100 units (so the shared budget affords only ~80-90/day total); with the scrape source it's a pure anti-abuse limit. Set 0 to disable live search."
},
"search_source": {
"label": "Live search source",
"hint": "Where live YouTube search results come from. \"scrape\" uses YouTube's internal endpoint and spends no API quota (recommended). \"api\" uses the official search.list (100 units/page). Switch to \"api\" if scraping ever breaks or is blocked."
},
"backfill_recent_max_videos": {
"label": "Recent backfill — max videos",
"hint": "Newest videos fetched per channel on the first pass."
},
"backfill_recent_max_days": {
"label": "Recent backfill — max age (days)",
"hint": "How far back the first pass reaches per channel."
},
"shorts_probe_max_seconds": {
"label": "Shorts probe — max duration (s)",
"hint": "Only videos at or below this length are probed as possible Shorts."
},
"shorts_probe_batch": {
"label": "Shorts probe — batch size",
"hint": "How many videos to classify per run."
},
"enrich_batch_size": {
"label": "Enrichment batch size",
"hint": "videos.list ids per call (YouTube caps this at 50)."
},
"autotag_title_sample": {
"label": "Auto-tag title sample",
"hint": "Recent video titles sampled per channel for language detection."
},
"youtube_api_key": {
"label": "YouTube API key",
"hint": "Optional. Used for public reads (channels/videos) so shared backfill doesn't depend on a user's OAuth. Stored encrypted; write-only."
},
"youtube_api_proxy": {
"label": "YouTube API egress proxy",
"hint": "Optional. HTTP(S) proxy URL for outbound YouTube API calls — route them through a fixed-IP host so an IP-restricted key keeps working from a dynamic-IP server. Leave empty for direct."
},
"google_client_id": {
"label": "Google client ID",
"hint": "OAuth 2.0 client ID for Sign in with Google. Stored encrypted; write-only. Leave both Google fields empty to disable Google sign-in (email+password still works)."
},
"google_client_secret": {
"label": "Google client secret",
"hint": "OAuth 2.0 client secret. Stored encrypted; write-only."
},
"allow_registration": {
"label": "Allow registration",
"hint": "When on, anyone can submit an email+password registration. They still need to verify their email and be approved by an admin before they can sign in."
},
"explore_grace_days": {
"label": "Explore — grace period (days)",
"hint": "How long an explored-but-unsubscribed channel (and its ephemeral videos) is kept before the cleanup job removes it. Subscribing keeps it permanently."
},
"search_grace_days": {
"label": "Search results — grace period (days)",
"hint": "How long an un-kept live-search result video (nobody watched / saved / subscribed to) is kept before the discovery-cleanup job removes it."
},
"download_total_max_bytes": {
"label": "Total cache cap (bytes)",
"hint": "Max total size across all users' downloads. 0 = unlimited (disk is the limit); when exceeded, the GC evicts the least-recently-used files."
},
"download_default_max_bytes": {
"label": "Default per-user quota (bytes)",
"hint": "How much storage a user may hold before new downloads are blocked. A per-user override takes precedence. Default 5 GiB."
},
"download_default_max_concurrent": {
"label": "Default concurrent downloads / user",
"hint": "How many downloads one user may run at the same time."
},
"download_default_max_jobs": {
"label": "Default job limit / user",
"hint": "Max number of downloads a user may keep in their library."
},
"download_retention_days": {
"label": "Retention (days)",
"hint": "A download expires this many days after its last access; the cleanup job then removes it (once nothing references it) after the grace window."
},
"download_gc_grace_days": {
"label": "Cleanup grace (days)",
"hint": "Extra days an expired download is kept before it's deleted."
},
"download_layout": {
"label": "On-disk layout",
"hint": "\"plex\" = a Channel/Season YYYY/… tree with .nfo + poster (Plex-indexable); \"flat\" = a single folder."
},
"download_worker_concurrency": {
"label": "Worker concurrency",
"hint": "How many downloads the worker processes in parallel."
},
"sponsorblock_default": {
"label": "SponsorBlock by default",
"hint": "Enable SponsorBlock (skip sponsor segments) for newly created custom download profiles."
},
"plex_enabled": {
"label": "Enable Plex",
"hint": "Expose the Plex library as a feed source with a rich player. Requires the Plex server to be reachable from this host and its media on a local mount (see the path map)."
},
"plex_server_url": {
"label": "Plex server URL",
"hint": "Base URL reachable from this host, e.g. http://192.168.1.100:32400."
},
"plex_server_token": {
"label": "Plex server token",
"hint": "The server admin X-Plex-Token. Used server-side only (metadata + images); never sent to the browser. Stored encrypted; write-only."
},
"plex_path_map": {
"label": "Media path map",
"hint": "Maps Plex's on-disk paths to this host's local mount so Siftlode can play the physical file. Newline/comma-separated plexPrefix=localPrefix pairs, e.g. /data=/plex-media. Empty = identical on both sides."
},
"plex_libraries": {
"label": "Exposed libraries",
"hint": "Comma-separated Plex section keys to expose. Empty = all sections. Use the library picker below after testing the connection."
},
"plex_sync_interval_min": {
"label": "Sync interval (minutes)",
"hint": "How often the catalog sync job mirrors Plex metadata."
},
"plex_max_transcodes": {
"label": "Max concurrent transcodes",
"hint": "Cap on simultaneous transcode sessions for non-H.264 files. Direct-play and remux (stream-copy) files aren't limited."
},
"plex_transcode_hw": {
"label": "Hardware transcode",
"hint": "GPU (VAAPI) encoding policy: auto (GPU when available and the source is decodable, else software), on (force GPU), off (always software)."
},
"plex_transcode_preset": {
"label": "Software preset",
"hint": "libx264 preset for the software fallback (e.g. veryfast, faster, medium). Slower presets shrink the stream but cost more CPU. Ignored on the GPU path."
},
"plex_transcode_crf": {
"label": "Software quality (CRF)",
"hint": "libx264 CRF for the software fallback (0–51; lower = better quality, larger). 20 is a good default. Ignored on the GPU path."
},
"plex_transcode_max_height": {
"label": "Software max height",
"hint": "Cap the software transcode's output height in pixels (e.g. 1080; 0 = keep source) so a tall source stays affordable to re-encode. The GPU path keeps source resolution."
}
},
"save": "Save",
"saving": "Saving…",
"saved": "Saved",
"saveFailed": "Couldn't save",
"unsaved": "Unsaved changes",
"discard": "Discard",
"willReset": "will reset to default on save",
"reset": "Reset",
"resetHint": "Remove this override and fall back to the file/env default.",
"resetDone": "Reset to default",
"usingDefault": "using default",
"overridden": "overridden in DB",
"secretSet": "•••••••• stored",
"secretEnv": "using env value",
"secretUnset": "not set",
"secretsDisabled": "Set TOKEN_ENCRYPTION_KEY to store secrets in the database.",
"testEmail": "Send test email",
"testEmailHint": "Send a test email to your own address using the settings above, to confirm they work.",
"testSent": "Test email sent to {{to}}",
"testFailed": "Test email failed — check the settings",
"plexTest": "Test connection",
"plexTestHint": "Verify the Plex server URL + token and load the library list. Save any edits first.",
"plexTestDirty": "Save your changes before testing the connection.",
"plexTestOk": "Connected to {{name}}",
"plexTestFailed": "Plex connection failed — check the URL and token",
"plexConnected": "Connected to {{name}} {{version}}",
"plexMediaOk": "Media mount OK — a sample file was found on disk.",
"plexMediaMissing": "Media not readable at {{path}} — check that the Plex media is bind-mounted into the container and that the path map is correct. Playback will fail until this is fixed.",
"plexPickLibraries": "Libraries to expose:",
"plexPickHint": "Unchecking all is the same as exposing every library. Remember to Save.",
"plexMovies": "Movies",
"plexShows": "TV Shows"
}