Twitch-VOD-Manager/src/renderer-locale-en.ts
xRangerDE 3f04b42b02 feat: auto-resume queue toggle + already-downloaded VOD indicator
Two real UX wins.

1. Auto-resume queue on startup. New checkbox in Settings -> Download
   ("Queue beim Start automatisch fortsetzen"). When enabled and the
   persisted queue has pending items, processQueue() fires ~5 seconds
   after did-finish-load — long enough for the user to see the queue
   and pause if they did not actually want this. Default off so the
   existing behaviour (explicit Start click) is preserved on upgrade.
   The Settings auto-save fingerprint includes the new flag and
   syncSettingsFormFromConfig restores it. Tooltip explains the
   timing on hover.

2. Already-downloaded indicator on VOD cards. Config gains
   downloaded_vod_ids: string[] (bounded to 4096 latest entries).
   Every successful queue-item download appends its parsed VOD ID
   (or every component ID for merge groups). On the VOD grid each
   card whose vod.id is in the set gets a small green checkmark
   badge in the top-right plus a slightly dimmed thumbnail, with a
   localized "Already downloaded" / "Bereits heruntergeladen"
   tooltip. The lookup builds a Set once per render so it stays
   O(1) per card. The renderer refreshes its local config copy on
   every "newly completed" queue update so the badge appears live
   without waiting for a settings save.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:16:21 +02:00

291 lines
12 KiB
TypeScript

const UI_TEXT_EN = {
appName: 'Twitch VOD Manager',
static: {
navVods: 'Twitch VODs',
navClips: 'Twitch Clips',
navCutter: 'Video Cutter',
navMerge: 'Merge Videos',
navSettings: 'Settings',
queueTitle: 'Queue',
retryFailed: 'Retry',
retryFailedHint: 'Retry failed downloads only',
healthUnknown: 'System: Unknown',
healthGood: 'System: Stable',
healthWarn: 'System: Warning',
healthBad: 'System: Problem',
clearQueue: 'Clear',
refresh: 'Refresh',
streamerPlaceholder: 'Add streamer...',
clipsHeading: 'Twitch Clip Download',
clipsInfoTitle: 'Info',
clipsInfoText: 'Supported formats:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips are saved in your download folder under "Clips/StreamerName/".',
cutterSelectTitle: 'Select video',
cutterBrowse: 'Browse',
mergeTitle: 'Merge videos',
mergeDesc: 'Select multiple videos to merge into one file. You can change the order before merging.',
mergeAdd: '+ Add videos',
designTitle: 'Design',
themeLabel: 'Theme',
themeLight: 'Light',
languageLabel: 'Language',
languageDe: 'German',
languageEn: 'English',
apiTitle: 'Twitch API',
clientIdLabel: 'Client ID',
clientSecretLabel: 'Client Secret',
saveSettings: 'Save & Connect',
downloadSettingsTitle: 'Download Settings',
storageLabel: 'Storage Path',
openFolder: 'Open',
modeLabel: 'Download Mode',
modeFull: 'Full VOD',
modeParts: 'Split into parts',
partMinutesLabel: 'Part Length (Minutes)',
parallelDownloadsLabel: 'Parallel Downloads',
parallelDownloads1: '1 (Default)',
parallelDownloads2: '2 (Parallel)',
performanceModeLabel: 'Performance Profile',
performanceModeStability: 'Max Stability',
performanceModeBalanced: 'Balanced',
performanceModeSpeed: 'Max Speed',
smartSchedulerLabel: 'Enable smart queue scheduler',
smartSchedulerHint: 'Prefers shorter VODs and older queue entries first so the queue throughput stays steady. Disable to drain in strict insertion order.',
streamerInvalid: 'Invalid Twitch username (4-25 chars, letters/digits/underscore).',
apiHelpIntro: 'You need a Client ID and Client Secret from Twitch.',
apiHelpLinkText: 'dev.twitch.tv/console/apps',
openDebugLogFile: 'Open log file',
duplicatePreventionLabel: 'Prevent duplicate queue entries',
persistQueueLabel: 'Keep queue between app restarts',
autoResumeQueueLabel: 'Auto-resume the queue on startup',
autoResumeQueueHint: 'When enabled and the persisted queue has pending entries, downloads kick off ~5 seconds after the window opens. Disable to require an explicit Start click.',
metadataCacheMinutesLabel: 'Metadata Cache (Minutes)',
filenameTemplatesTitle: 'Filename Templates',
vodTemplateLabel: 'VOD Template',
partsTemplateLabel: 'VOD Part Template',
defaultClipTemplateLabel: 'Clip Template',
filenameTemplateHint: 'Placeholders: {title} {id} {channel} {date} {part} {part_padded} {trim_start} {trim_end} {trim_length} {date_custom="yyyy-MM-dd"}',
vodTemplatePlaceholder: '{title}.mp4',
partsTemplatePlaceholder: '{date}_Part{part_padded}.mp4',
defaultClipTemplatePlaceholder: '{date}_{part}.mp4',
templateLintOk: 'Template check: OK',
templateLintWarn: 'Unknown placeholder(s)',
templateGuideButton: 'Template Guide',
templateGuideTitle: 'Filename Template Guide',
templateGuideIntro: 'Use placeholders for filenames and test your pattern with a live preview.',
templateGuideTemplateLabel: 'Template',
templateGuideOutputLabel: 'Live preview',
templateGuideVarsTitle: 'Available placeholders',
templateGuideVarCol: 'Placeholder',
templateGuideDescCol: 'Description',
templateGuideExampleCol: 'Example',
templateGuideUseVod: 'Use VOD template',
templateGuideUseParts: 'Use part template',
templateGuideUseClip: 'Use clip template',
templateGuideClose: 'Close',
templateGuideContextVod: 'Context: Sample full VOD download',
templateGuideContextParts: 'Context: Sample split VOD part',
templateGuideContextClip: 'Context: Sample clip trim',
templateGuideContextClipLive: 'Context: Current clip dialog selection',
runtimeMetricsTitle: 'Runtime Metrics',
runtimeMetricsRefresh: 'Refresh',
runtimeMetricsExport: 'Export JSON',
runtimeMetricsAutoRefresh: 'Auto refresh',
runtimeMetricsLoading: 'Loading metrics...',
runtimeMetricsError: 'Could not load runtime metrics.',
runtimeMetricsExportDone: 'Runtime metrics exported successfully.',
runtimeMetricsExportCancelled: 'Runtime metrics export cancelled.',
runtimeMetricsExportFailed: 'Runtime metrics export failed.',
runtimeMetricQueue: 'Queue',
runtimeMetricMode: 'Mode',
runtimeMetricRetries: 'Retries',
runtimeMetricIntegrity: 'Integrity failures',
runtimeMetricCache: 'Cache',
runtimeMetricBandwidth: 'Bandwidth',
runtimeMetricDownloads: 'Downloads',
runtimeMetricActive: 'Active item',
runtimeMetricLastError: 'Last error class',
runtimeMetricUpdated: 'Updated',
updateTitle: 'Updates',
checkUpdates: 'Check for updates',
preflightTitle: 'System Check',
preflightRun: 'Run check',
preflightFix: 'Auto-fix tools',
preflightEmpty: 'No checks run yet.',
preflightChecking: 'Checking...',
preflightFixing: 'Fixing...',
preflightReady: 'Everything is ready.',
preflightInternet: 'Internet',
preflightStreamlink: 'Streamlink',
preflightFfmpeg: 'FFmpeg',
preflightFfprobe: 'FFprobe',
preflightPath: 'Download path',
debugLogTitle: 'Live Debug Log',
refreshLog: 'Refresh',
autoRefresh: 'Auto refresh',
notConnected: 'Not connected'
},
status: {
noLogin: 'No login (public mode)',
connecting: 'Connecting...',
connected: 'Connected',
connectFailedPublic: 'Connection failed - public mode active'
},
tabs: {
vods: 'VODs',
clips: 'Clips',
cutter: 'Video Cutter',
merge: 'Merge Videos',
settings: 'Settings'
},
queue: {
empty: 'No downloads in queue',
start: 'Start',
stop: 'Pause',
resume: 'Resume',
statusDone: 'Completed',
statusFailed: 'Failed',
statusRunning: 'Running',
statusPaused: 'Paused',
statusWaiting: 'Waiting',
progressError: 'Error',
progressReady: 'Ready',
progressLoading: 'Loading...',
readyToDownload: 'Ready to download',
started: 'Download started',
done: 'Done',
failed: 'Download failed',
speed: 'Speed',
eta: 'ETA',
part: 'Part',
emptyAlert: 'Queue is empty. Add a VOD or clip first.',
duplicateSkipped: 'This item is already active in the queue.',
openFile: 'Open file',
showInFolder: 'Show in folder',
openFileFailed: 'Could not open the file (it may have been moved or deleted).',
outputFilesLabel: '{count} output files',
retryItem: 'Retry this item',
statusBarSummary: '{downloading} dl, {pending} queued'
},
vods: {
noneTitle: 'No VODs',
noneText: 'Select a streamer from the list.',
loading: 'Loading VODs...',
notFound: 'Streamer not found',
noResultsTitle: 'No VODs found',
noResultsText: 'This streamer has no VODs.',
untitled: 'Untitled VOD',
views: 'views',
addQueue: '+ Queue',
trimButton: 'Trim VOD',
filterPlaceholder: 'Filter by title... (Ctrl+F)',
filterClearTitle: 'Clear filter (Esc)',
filterNoMatchTitle: 'No matches',
filterNoMatchText: 'No VODs match the current filter.',
filterMatchCount: '{shown} of {total} VODs',
sortLabel: 'Sort:',
sortDateDesc: 'Newest first',
sortDateAsc: 'Oldest first',
sortViewsDesc: 'Most viewed',
sortDurationDesc: 'Longest first',
sortDurationAsc: 'Shortest first',
bulkSelectedCount: '{count} selected',
bulkAddToQueue: '+ Queue',
bulkAdding: 'Adding...',
bulkClear: 'Clear',
bulkAddedToQueue: 'Added {count} VODs to the queue.',
bulkAddSkipped: 'No VODs were added (already in queue or invalid).',
alreadyDownloaded: 'Already downloaded'
},
clips: {
dialogTitle: 'Trim VOD',
dialogStart: 'Start:',
dialogStartTime: 'Start time (HH:MM:SS):',
dialogEnd: 'End:',
dialogEndTime: 'End time (HH:MM:SS):',
dialogDuration: 'Duration: ',
dialogPartLabel: 'Start part number (optional, for continuation):',
dialogPartHint: 'Leave empty = part 1',
dialogFormatLabel: 'Filename format:',
dialogConfirm: 'Add to queue',
invalidDuration: 'Invalid!',
endBeforeStart: 'End time must be greater than start time!',
outOfRange: 'Time is outside VOD range!',
enterUrl: 'Please enter a URL',
loadingButton: 'Loading...',
loadingStatus: 'Downloading...',
downloadButton: 'Download clip',
success: 'Download successful!',
errorPrefix: 'Error: ',
unknownError: 'Unknown error',
formatSimple: '(default)',
formatTimestamp: '(with timestamp)',
formatParts: '(parts naming)',
formatTemplate: '(custom template)',
templateEmpty: 'Template cannot be empty in custom template mode.',
templatePlaceholder: '{date}_{part}.mp4',
templateHelp: 'Placeholders: {title} {id} {channel} {date} {part} {part_padded} {trim_start} {trim_end} {trim_length} {date_custom="yyyy-MM-dd"}'
},
cutter: {
videoInfoFailed: 'Could not read video info. Is FFprobe installed?',
previewLoading: 'Loading preview...',
previewUnavailable: 'Preview unavailable',
cutting: 'Cutting...',
cut: 'Cut',
cutSuccess: 'Video cut successfully!',
cutFailed: 'Failed to cut video.',
infoDuration: 'Duration',
infoResolution: 'Resolution',
infoFps: 'FPS',
infoSelection: 'Selection',
startLabel: 'Start:',
endLabel: 'End:'
},
merge: {
empty: 'No videos selected',
merging: 'Merging...',
merge: 'Merge',
success: 'Videos merged successfully!',
failed: 'Failed to merge videos.'
},
mergeGroup: {
btn: 'Merge & Split',
phaseDownloading: 'Downloading VOD',
phaseMerging: 'Merging...',
phaseSplitting: 'Splitting Part',
phaseCleanup: 'Cleaning up...',
needMinTwo: 'Select at least 2 VODs',
titleTwo: 'Merge: {title1} + {title2}',
titleMany: 'Merge: {title1} + {count} more',
metaLabel: '{count} VODs',
},
updates: {
bannerDefault: 'New version available!',
latest: 'You are on the latest version!',
checking: 'Checking for updates...',
checkInProgress: 'Update check is already running.',
readyToInstall: 'Update is ready to install.',
checkFailed: 'Update check failed.',
downloading: 'Downloading...',
downloadInProgress: 'Update download is already running.',
downloadFailed: 'Update download failed.',
available: 'available!',
downloadNow: 'Download now',
downloadLabel: 'Download',
ready: 'ready to install!',
installNow: 'Install now & restart',
modalAvailableTitle: 'Update available',
modalAvailableMessage: 'Version {version} is available. Download it now?',
modalReadyTitle: 'Update ready',
modalReadyMessage: 'Version {version} has been downloaded. Install and restart now?',
modalDismiss: 'No',
modalDownloadConfirm: 'Yes, download',
modalInstallConfirm: 'Yes, install',
modalSkipVersion: 'Skip this version',
changelogLabel: 'Changelog',
showChangelog: 'Show changelog',
hideChangelog: 'Hide changelog',
noChangelog: 'No changelog available.',
releasedLabel: 'Release'
}
} as const;