- admin config group "Bug reports": Gitea address, repository, token (secret),
and "Check the connection" — the repository must answer, take issues and
be PRIVATE (a report carries its reporter's log); checked on every send too
- POST /api/debug-sessions/{id}/issue sends the SAVED draft: create the issue,
upload each file on its own request (the measured API), then show the
screenshots inline; progress is kept in the draft, so a send that stops
half-way keeps its issue and the retry sends only what is missing; 5 new
issues an hour per user; audited as issue_create
- the composer: Create issue (only where a tracker is set up, naming the
repository), a partial-send banner with retry, and a Preview — the tracker's
own rendering in a sandboxed frame, or the zip's markdown without one
- the recorder's refusals answer in the localized family (debug_session_*,
screenshot_*, issue(s)_*), not bare codes the UI could only call generic
- a tracker refusal logs the status only: its message can quote the title back
314 lines
15 KiB
JSON
314 lines
15 KiB
JSON
{
|
||
"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",
|
||
"maintenance": "Maintenance",
|
||
"explore": "Channel explore",
|
||
"downloads": "Downloads",
|
||
"plex": "Plex",
|
||
"tmdb": "TMDB",
|
||
"audit": "Audit log",
|
||
"diagnostics": "Diagnostics",
|
||
"issues": "Bug reports"
|
||
},
|
||
"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. \"Website\" reads YouTube's own search endpoint and spends no API quota (recommended). \"Official API\" uses search.list (100 units/page) — switch to it if the website source 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."
|
||
},
|
||
"rss_fallback_hours": {
|
||
"label": "Feed fallback after (hours)",
|
||
"hint": "When a channel's RSS feed has not answered for this many hours, its newest uploads are read through the API instead (1 unit), at most once per this many hours. 0 turns it off."
|
||
},
|
||
"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."
|
||
},
|
||
"maintenance_revalidate_batch": {
|
||
"label": "Videos re-checked per run",
|
||
"hint": "How many least-recently-checked videos the maintenance job re-validates each run (1 API unit per 50 videos). Higher = a faster full cycle but more quota. Also adjustable on the Scheduler page."
|
||
},
|
||
"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_upload_max_bytes": {
|
||
"label": "Upload size cap per file (bytes)",
|
||
"hint": "Largest single file a user may upload to the download center. At least 1, so the cap is always on; the user's total storage is still bounded by their quota. Default 500 MiB."
|
||
},
|
||
"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."
|
||
},
|
||
"audit_retention_days": {
|
||
"label": "Retention (days)",
|
||
"hint": "How long admin audit-log entries are kept before the audit-log cleanup job prunes them. 0 = keep forever. Default 180."
|
||
},
|
||
"log_level": {
|
||
"label": "Log level",
|
||
"hint": "How much the server writes to its log. INFO is the normal setting; DEBUG and TRACE are for reproducing a problem and are far more detailed. Takes effect immediately, no restart."
|
||
},
|
||
"log_retention_days": {
|
||
"label": "Log retention (days)",
|
||
"hint": "How long stored log events are kept before the log cleanup job deletes them. They include account-linked request history, so there is no \"keep forever\". Default 7."
|
||
},
|
||
"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_overlay_map": {
|
||
"label": "Hungarian overlay map",
|
||
"hint": "Pairs a Hungarian Plex library with its English twin so titles show Hungarian metadata: comma-separated huSectionKey:enSectionKey pairs, e.g. 3:4,5:1. The Hungarian library isn't browsable on its own; its titles are matched to the English ones by id. Empty = no overlay."
|
||
},
|
||
"plex_max_transcodes": {
|
||
"label": "Max concurrent transcodes",
|
||
"hint": "Cap on simultaneous transcode sessions for non-H.264 files. Remux (stream-copy) sessions count only toward the overall session limit; direct-play files aren't limited."
|
||
},
|
||
"plex_max_sessions": {
|
||
"label": "Max concurrent playback sessions",
|
||
"hint": "Cap on all simultaneous playback sessions, remux (stream-copy) included — each one writes a full segmented copy of the film to the scratch volume. One account can hold at most two. Direct-play files aren't sessions and aren't limited."
|
||
},
|
||
"plex_transcode_hw": {
|
||
"label": "Hardware transcode",
|
||
"hint": "GPU (VAAPI) encoding policy. Auto uses the GPU when it is available and can decode the source, otherwise software; GPU forces it; Software never uses it."
|
||
},
|
||
"plex_transcode_preset": {
|
||
"label": "Software preset",
|
||
"hint": "libx264 preset for the software fallback, fastest first. 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."
|
||
},
|
||
"plex_audio_loudnorm": {
|
||
"label": "Normalize audio loudness",
|
||
"hint": "EBU R128 loudness normalization of the stereo downmix, for films whose dialogue is a whisper and whose action is deafening. Applies to remux/transcode playback only (a direct-played file is served untouched). Measured on a 5.1 film: −27.6 → −16.6 LUFS with the loud/quiet range narrowed — everything gets about 11 dB louder, so turn your volume down after switching it on. Takes effect on the next playback."
|
||
},
|
||
"tmdb_api_key": {
|
||
"label": "TMDB API key",
|
||
"hint": "Optional. A TMDB v3 API key for enriching Plex titles (keywords, crew, budget, TMDb score, recommendations, artwork). Used server-side only; the data is served from the app's own database. Empty = the enrichment job does nothing. Stored encrypted; write-only."
|
||
},
|
||
"tmdb_language": {
|
||
"label": "TMDB metadata language",
|
||
"hint": "Language of the data fetched from TMDB (keywords, overviews), as a TMDB locale code such as en-US or hu-HU. Default en-US."
|
||
},
|
||
"issues_gitea_url": {
|
||
"label": "Gitea address",
|
||
"hint": "The Gitea instance, e.g. https://git.example.com. Left empty, reports can only be downloaded as a zip."
|
||
},
|
||
"issues_gitea_repo": {
|
||
"label": "Repository",
|
||
"hint": "As owner/repository. It must be PRIVATE: a report carries its reporter's log, and nothing is sent to a public one."
|
||
},
|
||
"issues_gitea_token": {
|
||
"label": "Token",
|
||
"hint": "A Gitea access token with write:issue and read:repository. Stored encrypted; write-only."
|
||
}
|
||
},
|
||
"choices": {
|
||
"search_source": {
|
||
"scrape": "Website",
|
||
"api": "Official API"
|
||
},
|
||
"download_layout": {
|
||
"plex": "Plex",
|
||
"flat": "Flat"
|
||
},
|
||
"log_level": {
|
||
"TRACE": "TRACE",
|
||
"DEBUG": "DEBUG",
|
||
"INFO": "INFO",
|
||
"WARNING": "WARNING",
|
||
"ERROR": "ERROR"
|
||
},
|
||
"plex_transcode_hw": {
|
||
"auto": "Auto",
|
||
"on": "GPU",
|
||
"off": "Software"
|
||
},
|
||
"plex_transcode_preset": {
|
||
"ultrafast": "ultrafast",
|
||
"superfast": "superfast",
|
||
"veryfast": "veryfast",
|
||
"faster": "faster",
|
||
"fast": "fast",
|
||
"medium": "medium",
|
||
"slow": "slow",
|
||
"slower": "slower",
|
||
"veryslow": "veryslow"
|
||
}
|
||
},
|
||
"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.",
|
||
"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",
|
||
"emailOff": "Email sending is not configured — Siftlode silently skips every message: verification links, password resets and access-request notices. Fill in the fields above, then send a test.",
|
||
"issuesTest": "Check the connection",
|
||
"issuesTestHint": "Checks that the repository answers, is private and takes issues. Save your changes first.",
|
||
"issuesTestOk": "Works: {{repo}} (private)",
|
||
"issuesTestFailed": "The issue tracker check failed"
|
||
}
|