In-flight live recordings now show a small coloured dot before the title indicating whether bytes are still flowing. The health state is derived from byte-progress liveness: each time the byte counter advances, we stamp lastBytesAdvancedAt; if more than 30s pass without an advance we flip the badge to amber to tell the user the streamlink subprocess has gone quiet (dropped segments, network blip, or the stream just ended). Until the first segment arrives we report "unknown" so we don't claim health prematurely on a streamlink that's still negotiating playlists. Critical wrinkle: streamlink emits progress events on byte boundaries, so a hung process emits NO events at all. A pure event-driven badge would never update from "ok" to "stale" — it'd stay frozen at the last known good state. To avoid that, downloadLiveStream now runs a 10s health-tick interval that re-emits the most recent progress event with a fresh health computation. The interval is killed in a finally block so process termination doesn't leak it. DownloadProgress + QueueItem in both src/types.ts and the renderer declaration shadow get the new optional recordingHealth field. The renderer queue handler copies it onto the item; the queue render function shows a coloured dot before the title for in-flight live items only (status === 'downloading' && isLive). Three states: green pulsing (ok), amber flashing (stale), grey static (unknown). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
413 lines
22 KiB
TypeScript
413 lines
22 KiB
TypeScript
const UI_TEXT_DE = {
|
|
appName: 'Twitch VOD Manager',
|
|
static: {
|
|
navVods: 'Twitch VODs',
|
|
navClips: 'Twitch Clips',
|
|
navCutter: 'Video schneiden',
|
|
navMerge: 'Videos zusammenfugen',
|
|
navSettings: 'Einstellungen',
|
|
queueTitle: 'Warteschlange',
|
|
retryFailed: 'Wiederholen',
|
|
retryFailedHint: 'Nur fehlgeschlagene Downloads erneut starten',
|
|
healthUnknown: 'System: Unbekannt',
|
|
healthGood: 'System: Stabil',
|
|
healthWarn: 'System: Warnung',
|
|
healthBad: 'System: Problem',
|
|
clearQueue: 'Leeren',
|
|
refresh: 'Aktualisieren',
|
|
streamerPlaceholder: 'Streamer hinzufugen...',
|
|
clipsHeading: 'Twitch Clip-Download',
|
|
clipsInfoTitle: 'Info',
|
|
clipsInfoText: 'Unterstutzte Formate:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips werden im Download-Ordner unter "Clips/StreamerName/" gespeichert.',
|
|
cutterSelectTitle: 'Video auswahlen',
|
|
cutterBrowse: 'Durchsuchen',
|
|
mergeTitle: 'Videos zusammenfugen',
|
|
mergeDesc: 'Wahle mehrere Videos aus, um sie zu einem Video zusammenzufugen. Die Reihenfolge kann geandert werden.',
|
|
mergeAdd: '+ Videos hinzufugen',
|
|
designTitle: 'Design',
|
|
themeLabel: 'Theme',
|
|
themeLight: 'Hell',
|
|
languageLabel: 'Sprache',
|
|
languageDe: 'Deutsch',
|
|
languageEn: 'Englisch',
|
|
apiTitle: 'Twitch API',
|
|
clientIdLabel: 'Client ID',
|
|
clientSecretLabel: 'Client Secret',
|
|
saveSettings: 'Speichern & Verbinden',
|
|
downloadSettingsTitle: 'Download-Einstellungen',
|
|
storageLabel: 'Speicherort',
|
|
openFolder: 'Offnen',
|
|
modeLabel: 'Download-Modus',
|
|
modeFull: 'Ganzes VOD',
|
|
modeParts: 'In Teile splitten',
|
|
partMinutesLabel: 'Teil-Lange (Minuten)',
|
|
parallelDownloadsLabel: 'Parallele Downloads',
|
|
parallelDownloads1: '1 (Standard)',
|
|
parallelDownloads2: '2 (Parallel)',
|
|
performanceModeLabel: 'Performance-Profil',
|
|
performanceModeStability: 'Max Stabilitat',
|
|
performanceModeBalanced: 'Ausgewogen',
|
|
performanceModeSpeed: 'Max Geschwindigkeit',
|
|
smartSchedulerLabel: 'Smart Queue Scheduler aktivieren',
|
|
smartSchedulerHint: 'Bevorzugt kuerzere VODs und aeltere Queue-Eintraege zuerst, damit der Durchsatz gleichmaessig bleibt. Deaktivieren = strikte Einfuegereihenfolge.',
|
|
streamerInvalid: 'Twitch-Username ungueltig (4-25 Zeichen, Buchstaben/Zahlen/Unterstrich).',
|
|
apiHelpIntro: 'Du brauchst eine Client-ID und ein Client-Secret von Twitch.',
|
|
apiHelpLinkText: 'dev.twitch.tv/console/apps',
|
|
openDebugLogFile: 'Log-Datei oeffnen',
|
|
storageCardTitle: 'Speicher',
|
|
storageCardIntro: 'Disk-Verbrauch pro Streamer im aktuellen Download-Ordner. Live-Aufnahmen werden separat ausgewiesen.',
|
|
storageRefresh: 'Aktualisieren',
|
|
storageEmpty: 'Download-Ordner ist leer oder nicht lesbar.',
|
|
storageScanning: 'Scanne...',
|
|
storageSummary: 'Gesamt: {files} Dateien, {size} — Freier Speicher: {free}',
|
|
storageColumnFolder: 'Ordner',
|
|
storageColumnFiles: 'Dateien',
|
|
storageColumnTotal: 'Gesamt',
|
|
storageColumnLive: 'Live',
|
|
storageColumnChat: 'Chat',
|
|
storageOpen: 'Oeffnen',
|
|
storageOtherFolders: 'Andere Ordner im Download-Pfad',
|
|
cleanupTitle: 'Auto-Cleanup',
|
|
cleanupIntro: 'Aufnahmen aelter als X Tage in einen Archiv-Ordner verschieben oder loeschen. Sidecar-Chat-Dateien (.chat.json/.chat.jsonl) werden mit der Aufnahme bewegt.',
|
|
cleanupEnabledLabel: 'Auto-Cleanup aktivieren',
|
|
cleanupDaysLabel: 'Tage-Schwelle',
|
|
cleanupTargetLabel: 'Bereich',
|
|
cleanupTargetLive: 'Nur Live-Aufnahmen',
|
|
cleanupTargetAll: 'Alle Aufnahmen',
|
|
cleanupActionLabel: 'Aktion',
|
|
cleanupActionArchive: 'In Archiv verschieben',
|
|
cleanupActionDelete: 'Loeschen',
|
|
cleanupDryRun: 'Vorschau',
|
|
cleanupRunNow: 'Jetzt ausfuehren',
|
|
cleanupReportPreview: 'Wuerde {count} Dateien betreffen (~{size}). Es wurden keine Dateien verschoben oder geloescht.',
|
|
cleanupReportDone: '{count} Dateien verarbeitet, ~{size} frei.{failed}',
|
|
cleanupReportFailedSuffix: ' {failed} fehlgeschlagen.',
|
|
cleanupReportEmpty: 'Keine Aufnahmen aelter als {days} Tage gefunden.',
|
|
discordCardTitle: 'Discord-Webhook',
|
|
discordCardIntro: 'Sende Benachrichtigungen an einen Discord-Channel via Webhook - nuetzlich fuer Multi-Device-Setups oder eine dedizierte Archiv-Maschine.',
|
|
discordWebhookUrlLabel: 'Webhook-URL',
|
|
discordNotifyLiveStartLabel: 'Bei Live-Aufnahme-Start benachrichtigen',
|
|
discordNotifyLiveEndLabel: 'Bei Live-Aufnahme-Ende benachrichtigen',
|
|
discordNotifyVodAutoQueuedLabel: 'Bei automatisch eingereihten VODs benachrichtigen',
|
|
autoVodCardTitle: 'Auto-VOD-Download',
|
|
autoVodCardIntro: 'Streamer mit aktiviertem VOD-Toggle werden in dem hier festgelegten Intervall auf neue Twitch-VODs geprueft. Neue VODs innerhalb des Alters-Fensters werden automatisch zur Download-Queue hinzugefuegt.',
|
|
autoVodPollMinutesLabel: 'Poll-Intervall (Minuten)',
|
|
autoVodMaxAgeHoursLabel: 'Max. Alter (Stunden)',
|
|
discordNotifyVodCompleteLabel: 'Bei abgeschlossenem VOD-Download benachrichtigen',
|
|
backupCardTitle: 'Sicherung & Wartung',
|
|
backupCardIntro: 'Konfiguration sichern, auf einem anderen Geraet wiederherstellen oder die Liste der bereits heruntergeladenen VODs zuruecksetzen.',
|
|
exportConfig: 'Konfiguration exportieren',
|
|
importConfig: 'Konfiguration importieren',
|
|
resetDownloadedIds: 'Downloaded-VODs zuruecksetzen',
|
|
configExported: 'Konfiguration exportiert.',
|
|
configExportFailed: 'Export der Konfiguration fehlgeschlagen.',
|
|
configImported: 'Konfiguration importiert. Einige Aenderungen erfordern evtl. einen Neustart.',
|
|
configImportFailed: 'Import der Konfiguration fehlgeschlagen.',
|
|
resetDownloadedConfirm: 'Liste der heruntergeladenen VODs zuruecksetzen? Karten verlieren das gruene Haekchen, es werden aber keine Dateien geloescht.',
|
|
resetDownloadedDone: '{count} Eintraege aus der Downloaded-Liste entfernt.',
|
|
duplicatePreventionLabel: 'Duplikate in Queue verhindern',
|
|
persistQueueLabel: 'Queue zwischen App-Starts speichern',
|
|
autoResumeQueueLabel: 'Queue beim Start automatisch fortsetzen',
|
|
autoResumeQueueHint: 'Wenn aktiv und die gespeicherte Queue noch ausstehende Eintraege hat, starten Downloads ~5 Sekunden nach dem Fensteroeffnen. Deaktivieren = Start-Klick noetig.',
|
|
notifyEachCompletionLabel: 'Benachrichtigung bei jedem fertigen Download',
|
|
notifyEachCompletionHint: 'Standardmaessig aus — bei langen Queues wuerde das System-Notifications-Panel sonst zugespammt. Die Queue-End-Zusammenfassung erscheint trotzdem.',
|
|
streamlinkDisableAdsLabel: 'Twitch-Ads beim Download ueberspringen',
|
|
streamlinkDisableAdsHint: 'Gibt --twitch-disable-ads an streamlink weiter, damit Mid-Roll-Ads nicht ins VOD eingebettet werden. Empfohlen aktiv lassen.',
|
|
downloadChatReplayLabel: 'Chat-Replay parallel zum VOD speichern (.chat.json)',
|
|
downloadChatReplayHint: 'Nach erfolgreichem VOD-Download wird der oeffentliche Chat-Replay via Twitch GQL geholt und als JSON neben dem Video gespeichert. Twitch behaelt Chat-Replays nur solange wie das VOD selbst.',
|
|
captureLiveChatLabel: 'Live-Chat waehrend der Aufnahme mitschneiden (.chat.jsonl)',
|
|
captureLiveChatHint: 'Oeffnet waehrend einer Live-Aufnahme eine anonyme IRC-Verbindung zum Twitch-Chat und schreibt jede Nachricht in eine .chat.jsonl-Datei neben dem Video (JSON Lines, eine Nachricht pro Zeile, damit ein Mid-Stream-Abbruch frueheren Inhalt nicht korrumpiert).',
|
|
logStreamEventsLabel: 'Stream-Events bei Live-Aufnahmen mitloggen (.events.jsonl)',
|
|
logStreamEventsHint: 'Pollt den Streamer einmal pro Minute und schreibt Title-/Game-Wechsel in eine .events.jsonl-Datei neben dem Video. Hilfreich beim Suchen in langen archivierten Streams ("wann hat er auf CS:GO gewechselt?"). Sehr guenstig — ein zusaetzlicher Helix/GQL-Call pro Minute pro aktiver Aufnahme.',
|
|
streamlinkQualityLabel: 'Stream-Qualitaet',
|
|
streamlinkQualityHint: 'Streamlink versucht erst diese Qualitaet; falls das VOD sie nicht anbietet, faellt es auf "best" zurueck.',
|
|
streamlinkQualityBest: 'Best (Standard)',
|
|
streamlinkQualitySource: 'Source (Original)',
|
|
streamlinkQualityAudio: 'Nur Audio',
|
|
downloadPathNotWritable: 'Download-Ordner ist nicht beschreibbar. Waehle einen anderen Ordner oder pruefe die Schreibrechte.',
|
|
streamerSectionTitle: 'Streamer',
|
|
streamerListFilterPlaceholder: 'Filtern...',
|
|
streamerBulkRemoveTitle: 'Alle entfernen (oder gefilterte)',
|
|
streamerBulkRemoveAll: 'Alle {count} Streamer aus der Liste entfernen?',
|
|
streamerBulkRemoveFiltered: 'Die {count} passenden Streamer aus der Liste entfernen?',
|
|
cutterDropHint: 'Video-Datei hierher ziehen zum Laden.',
|
|
metadataCacheMinutesLabel: 'Metadata-Cache (Minuten)',
|
|
filenameTemplatesTitle: 'Dateinamen-Templates',
|
|
vodTemplateLabel: 'VOD-Template',
|
|
partsTemplateLabel: 'VOD-Teile-Template',
|
|
defaultClipTemplateLabel: 'Clip-Template',
|
|
filenameTemplateHint: 'Platzhalter: {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: 'Unbekannte Platzhalter',
|
|
templateGuideButton: 'Template Guide',
|
|
templateGuideTitle: 'Dateinamen-Template Guide',
|
|
templateGuideIntro: 'Nutze Platzhalter fur Dateinamen und teste dein Muster mit einer Live-Vorschau.',
|
|
templateGuideTemplateLabel: 'Template',
|
|
templateGuideOutputLabel: 'Live-Vorschau',
|
|
templateGuideVarsTitle: 'Verfugbare Platzhalter',
|
|
templateGuideVarCol: 'Platzhalter',
|
|
templateGuideDescCol: 'Beschreibung',
|
|
templateGuideExampleCol: 'Beispiel',
|
|
templateGuideUseVod: 'VOD-Template nutzen',
|
|
templateGuideUseParts: 'Teile-Template nutzen',
|
|
templateGuideUseClip: 'Clip-Template nutzen',
|
|
templateGuideClose: 'Schliessen',
|
|
templateGuideContextVod: 'Kontext: Beispiel fur kompletten VOD-Download',
|
|
templateGuideContextParts: 'Kontext: Beispiel fur VOD-Teil',
|
|
templateGuideContextClip: 'Kontext: Beispiel fur Clip-Zuschnitt',
|
|
templateGuideContextClipLive: 'Kontext: Aktuelle Auswahl im Clip-Dialog',
|
|
runtimeMetricsTitle: 'Runtime Metrics',
|
|
runtimeMetricsRefresh: 'Aktualisieren',
|
|
runtimeMetricsExport: 'Export JSON',
|
|
runtimeMetricsAutoRefresh: 'Auto-Refresh',
|
|
runtimeMetricsLoading: 'Metriken werden geladen...',
|
|
runtimeMetricsError: 'Runtime-Metriken konnten nicht geladen werden.',
|
|
runtimeMetricsExportDone: 'Runtime-Metriken wurden exportiert.',
|
|
runtimeMetricsExportCancelled: 'Export der Runtime-Metriken abgebrochen.',
|
|
runtimeMetricsExportFailed: 'Export der Runtime-Metriken fehlgeschlagen.',
|
|
runtimeMetricQueue: 'Queue',
|
|
runtimeMetricMode: 'Modus',
|
|
runtimeMetricRetries: 'Retries',
|
|
runtimeMetricIntegrity: 'Integritatsfehler',
|
|
runtimeMetricCache: 'Cache',
|
|
runtimeMetricBandwidth: 'Bandbreite',
|
|
runtimeMetricDownloads: 'Downloads',
|
|
runtimeMetricActive: 'Aktiver Job',
|
|
runtimeMetricLastError: 'Letzte Fehlerklasse',
|
|
runtimeMetricUpdated: 'Aktualisiert',
|
|
updateTitle: 'Updates',
|
|
checkUpdates: 'Nach Updates suchen',
|
|
preflightTitle: 'System-Check',
|
|
preflightRun: 'Check ausfuhren',
|
|
preflightFix: 'Auto-Fix Tools',
|
|
preflightEmpty: 'Noch kein Check ausgefuhrt.',
|
|
preflightChecking: 'Prufe...',
|
|
preflightFixing: 'Fixe...',
|
|
preflightReady: 'Alles bereit.',
|
|
preflightInternet: 'Internet',
|
|
preflightStreamlink: 'Streamlink',
|
|
preflightFfmpeg: 'FFmpeg',
|
|
preflightFfprobe: 'FFprobe',
|
|
preflightPath: 'Download-Pfad',
|
|
debugLogTitle: 'Live Debug-Log',
|
|
refreshLog: 'Aktualisieren',
|
|
autoRefresh: 'Auto-Refresh',
|
|
notConnected: 'Nicht verbunden'
|
|
},
|
|
status: {
|
|
noLogin: 'Ohne Login (Public Modus)',
|
|
connecting: 'Verbinde...',
|
|
connected: 'Verbunden',
|
|
connectFailedPublic: 'Verbindung fehlgeschlagen - Public Modus aktiv'
|
|
},
|
|
tabs: {
|
|
vods: 'VODs',
|
|
clips: 'Clips',
|
|
cutter: 'Video schneiden',
|
|
merge: 'Videos zusammenfugen',
|
|
settings: 'Einstellungen'
|
|
},
|
|
queue: {
|
|
empty: 'Keine Downloads in der Warteschlange',
|
|
start: 'Start',
|
|
stop: 'Pausieren',
|
|
resume: 'Fortsetzen',
|
|
statusDone: 'Abgeschlossen',
|
|
statusFailed: 'Fehlgeschlagen',
|
|
statusRunning: 'Laeuft',
|
|
statusPaused: 'Pausiert',
|
|
statusWaiting: 'Wartet',
|
|
progressError: 'Fehler',
|
|
progressReady: 'Bereit',
|
|
progressLoading: 'Lade...',
|
|
readyToDownload: 'Bereit zum Download',
|
|
started: 'Download gestartet',
|
|
done: 'Fertig',
|
|
failed: 'Download fehlgeschlagen',
|
|
speed: 'Geschwindigkeit',
|
|
eta: 'Restzeit',
|
|
part: 'Teil',
|
|
emptyAlert: 'Die Warteschlange ist leer. Fuge zuerst ein VOD oder einen Clip hinzu.',
|
|
duplicateSkipped: 'Dieser Eintrag ist bereits aktiv in der Warteschlange.',
|
|
openFile: 'Datei oeffnen',
|
|
showInFolder: 'Im Ordner zeigen',
|
|
openFileFailed: 'Datei konnte nicht geoeffnet werden (evtl. verschoben oder geloescht).',
|
|
outputFilesLabel: '{count} Ausgabedateien',
|
|
retryItem: 'Diesen Eintrag erneut versuchen',
|
|
viewChat: 'Chat ansehen',
|
|
viewChatLoading: 'Lade Chat...',
|
|
viewChatFailed: 'Chat-Datei konnte nicht gelesen werden',
|
|
viewChatCount: '{count} Nachrichten',
|
|
viewChatTruncatedSuffix: ' (gekuerzt)',
|
|
viewEvents: 'Events ansehen',
|
|
viewEventsCount: '{count} Events',
|
|
viewEventsEmpty: 'Keine Events aufgezeichnet.',
|
|
eventStartedAs: 'Gestartet als',
|
|
eventEndedAfter: 'Beendet nach',
|
|
eventTitleFromTo: 'Titel: {from} -> {to}',
|
|
eventGameFromTo: 'Game: {from} -> {to}',
|
|
statusBarSummary: '{downloading} aktiv, {pending} wartet',
|
|
ctxMoveTop: 'Nach oben verschieben',
|
|
ctxMoveBottom: 'Nach unten verschieben',
|
|
ctxCopyUrl: 'URL kopieren',
|
|
ctxOpenOnTwitch: 'Auf Twitch oeffnen',
|
|
ctxRemove: 'Aus Queue entfernen',
|
|
ctxCopiedUrl: 'URL in Zwischenablage kopiert.',
|
|
liveRecordingTitle: 'Live-Aufnahme - laeuft bis der Stream endet',
|
|
recordingHealth: {
|
|
ok: 'Gesund - Bytes fliessen',
|
|
stale: 'Stillstand - keine Bytes mehr (Netz-Hickser oder Stream endet)',
|
|
unknown: 'Warte auf ersten Segment'
|
|
}
|
|
},
|
|
streamers: {
|
|
recordLiveTitle: 'Diesen Streamer live aufnehmen (laeuft bis der Stream endet)',
|
|
liveRecordingStarted: 'Live-Aufnahme fuer {streamer} gestartet.',
|
|
liveRecordingOffline: '{streamer} ist gerade offline.',
|
|
liveRecordingAlreadyActive: 'Aufnahme von {streamer} laeuft bereits.',
|
|
liveRecordingFailed: 'Live-Aufnahme konnte nicht gestartet werden',
|
|
autoRecordTitle: 'Auto-Aufnahme: wenn dieser Streamer live geht, nimmt die App automatisch auf',
|
|
autoRecordEnabled: 'Auto-Aufnahme aktiviert fuer {streamer}. Live-Status wird geprueft...',
|
|
autoRecordDisabled: 'Auto-Aufnahme fuer {streamer} deaktiviert.',
|
|
autoVodTitle: 'Neue VODs (kuerzlich veroeffentlicht) automatisch herunterladen',
|
|
autoVodEnabled: 'Auto-VOD aktiviert fuer {streamer}. Neue VODs werden automatisch geladen.',
|
|
autoVodDisabled: 'Auto-VOD fuer {streamer} deaktiviert.'
|
|
},
|
|
vods: {
|
|
noneTitle: 'Keine VODs',
|
|
noneText: 'Wahle einen Streamer aus der Liste.',
|
|
loading: 'Lade VODs...',
|
|
notFound: 'Streamer nicht gefunden',
|
|
noResultsTitle: 'Keine VODs gefunden',
|
|
noResultsText: 'Dieser Streamer hat keine VODs.',
|
|
untitled: 'Unbenanntes VOD',
|
|
views: 'Aufrufe',
|
|
addQueue: '+ Warteschlange',
|
|
trimButton: 'VOD zuschneiden',
|
|
filterPlaceholder: 'Nach Titel filtern... (Strg+F)',
|
|
filterClearTitle: 'Filter loeschen (Esc)',
|
|
filterNoMatchTitle: 'Keine Treffer',
|
|
filterNoMatchText: 'Keine VODs entsprechen dem aktuellen Filter.',
|
|
filterMatchCount: '{shown} von {total} VODs',
|
|
sortLabel: 'Sortierung:',
|
|
sortDateDesc: 'Neueste zuerst',
|
|
sortDateAsc: 'Aelteste zuerst',
|
|
sortViewsDesc: 'Meiste Aufrufe',
|
|
sortDurationDesc: 'Laengste zuerst',
|
|
sortDurationAsc: 'Kuerzeste zuerst',
|
|
bulkSelectedCount: '{count} ausgewaehlt',
|
|
bulkAddToQueue: '+ Warteschlange',
|
|
bulkAdding: 'Fuege hinzu...',
|
|
bulkClear: 'Loeschen',
|
|
bulkAddedToQueue: '{count} VODs zur Warteschlange hinzugefuegt.',
|
|
bulkAddSkipped: 'Keine VODs hinzugefuegt (bereits in Queue oder ungueltig).',
|
|
bulkMarkDownloaded: 'Als heruntergeladen markieren',
|
|
bulkUnmark: 'Markierung entfernen',
|
|
bulkMarkedDownloaded: '{count} VODs als heruntergeladen markiert.',
|
|
bulkUnmarkedDownloaded: 'Markierung von {count} VODs entfernt.',
|
|
alreadyDownloaded: 'Bereits heruntergeladen',
|
|
hideDownloaded: 'Bereits geladene ausblenden',
|
|
hideDownloadedTitle: 'VODs ausblenden, die als bereits heruntergeladen markiert sind',
|
|
openOnTwitch: 'Auf Twitch oeffnen',
|
|
ctxOpenOnTwitch: 'Auf Twitch oeffnen',
|
|
ctxCopyUrl: 'VOD-URL kopieren',
|
|
ctxCopiedUrl: 'URL in Zwischenablage kopiert.',
|
|
ctxMarkDownloaded: 'Als heruntergeladen markieren',
|
|
ctxUnmarkDownloaded: 'Markierung entfernen'
|
|
},
|
|
clips: {
|
|
dialogTitle: 'VOD zuschneiden',
|
|
dialogStart: 'Start:',
|
|
dialogStartTime: 'Startzeit (HH:MM:SS):',
|
|
dialogEnd: 'Ende:',
|
|
dialogEndTime: 'Endzeit (HH:MM:SS):',
|
|
dialogDuration: 'Dauer: ',
|
|
dialogPartLabel: 'Start Part-Nummer (optional, fur Fortsetzung):',
|
|
dialogPartHint: 'Leer lassen = Teil 1',
|
|
dialogFormatLabel: 'Dateinamen-Format:',
|
|
dialogConfirm: 'Zur Queue hinzufuegen',
|
|
invalidDuration: 'Ungultig!',
|
|
endBeforeStart: 'Endzeit muss grosser als Startzeit sein!',
|
|
outOfRange: 'Zeit ausserhalb des VOD-Bereichs!',
|
|
enterUrl: 'Bitte URL eingeben',
|
|
loadingButton: 'Lade...',
|
|
loadingStatus: 'Download laeuft...',
|
|
downloadButton: 'Clip herunterladen',
|
|
success: 'Download erfolgreich!',
|
|
errorPrefix: 'Fehler: ',
|
|
unknownError: 'Unbekannter Fehler',
|
|
formatSimple: '(Standard)',
|
|
formatTimestamp: '(mit Zeitstempel)',
|
|
formatParts: '(Parts-Format)',
|
|
formatTemplate: '(benutzerdefiniert)',
|
|
templateEmpty: 'Das Template darf im benutzerdefinierten Modus nicht leer sein.',
|
|
templatePlaceholder: '{date}_{part}.mp4',
|
|
templateHelp: 'Platzhalter: {title} {id} {channel} {date} {part} {part_padded} {trim_start} {trim_end} {trim_length} {date_custom="yyyy-MM-dd"}'
|
|
},
|
|
cutter: {
|
|
videoInfoFailed: 'Konnte Video-Informationen nicht lesen. FFprobe installiert?',
|
|
previewLoading: 'Lade Vorschau...',
|
|
previewUnavailable: 'Vorschau nicht verfugbar',
|
|
cutting: 'Schneidet...',
|
|
cut: 'Schneiden',
|
|
cutSuccess: 'Video erfolgreich geschnitten!',
|
|
cutFailed: 'Fehler beim Schneiden des Videos.',
|
|
infoDuration: 'Dauer',
|
|
infoResolution: 'Aufloesung',
|
|
infoFps: 'FPS',
|
|
infoSelection: 'Auswahl',
|
|
startLabel: 'Start:',
|
|
endLabel: 'Ende:'
|
|
},
|
|
merge: {
|
|
empty: 'Keine Videos ausgewahlt',
|
|
merging: 'Zusammenfugen...',
|
|
merge: 'Zusammenfugen',
|
|
success: 'Videos erfolgreich zusammengefugt!',
|
|
failed: 'Fehler beim Zusammenfugen der Videos.'
|
|
},
|
|
mergeGroup: {
|
|
btn: 'Zusammenfugen & Splitten',
|
|
phaseDownloading: 'VOD wird heruntergeladen',
|
|
phaseMerging: 'Zusammenfugen...',
|
|
phaseSplitting: 'Part wird erstellt',
|
|
phaseCleanup: 'Aufraumen...',
|
|
needMinTwo: 'Mindestens 2 VODs auswahlen',
|
|
titleTwo: 'Merge: {title1} + {title2}',
|
|
titleMany: 'Merge: {title1} + {count} weitere',
|
|
metaLabel: '{count} VODs',
|
|
},
|
|
updates: {
|
|
bannerDefault: 'Neue Version verfugbar!',
|
|
latest: 'Du hast die neueste Version!',
|
|
checking: 'Suche nach Updates...',
|
|
checkInProgress: 'Update-Prufung lauft bereits.',
|
|
readyToInstall: 'Update ist bereit zur Installation.',
|
|
checkFailed: 'Update-Prufung fehlgeschlagen.',
|
|
downloading: 'Wird heruntergeladen...',
|
|
downloadInProgress: 'Update-Download lauft bereits.',
|
|
downloadFailed: 'Update-Download fehlgeschlagen.',
|
|
available: 'verfugbar!',
|
|
downloadNow: 'Jetzt herunterladen',
|
|
downloadLabel: 'Download',
|
|
ready: 'bereit zur Installation!',
|
|
installNow: 'Jetzt installieren & neu starten',
|
|
modalAvailableTitle: 'Update verfugbar',
|
|
modalAvailableMessage: 'Version {version} ist verfugbar. Jetzt herunterladen?',
|
|
modalReadyTitle: 'Update bereit',
|
|
modalReadyMessage: 'Version {version} wurde heruntergeladen. Jetzt installieren und neu starten?',
|
|
modalDismiss: 'Nein',
|
|
modalDownloadConfirm: 'Ja, herunterladen',
|
|
modalInstallConfirm: 'Ja, installieren',
|
|
modalSkipVersion: 'Diese Version ueberspringen',
|
|
changelogLabel: 'Changelog',
|
|
showChangelog: 'Changelog anzeigen',
|
|
hideChangelog: 'Changelog ausblenden',
|
|
noChangelog: 'Kein Changelog verfugbar.',
|
|
releasedLabel: 'Release'
|
|
}
|
|
} as const;
|