mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
a6ee0668c8
* feat(crossfade): add "trim silence between tracks" toggle
New persisted setting `crossfadeTrimSilence` (default off; existing
installs rehydrate off via the persist default-merge). Surfaced in
Settings -> Audio and in the crossfade popovers of the queue toolbar
and the mini-player.
Crossfade buttons now separate the two actions: left-click toggles
crossfade on/off, right-click opens the settings popover (seconds +
trim). Shared the mini popover positioning into useMiniAnchoredPopover
(now backing both volume and crossfade). Mini bridge carries
crossfadeSecs/crossfadeTrimSilence and gains mini:set-crossfade-secs /
mini:set-crossfade-trim-silence.
The actual silence-trimming playback behaviour is wired in a follow-up;
this commit only persists the user intent. i18n added across 9 locales.
* feat(crossfade): trim silence between tracks (waveform-driven)
Wire the actual silence-aware crossfade behind the (default-off)
crossfadeTrimSilence toggle. Detection is derived on the fly from the
cached 500-bin waveform + track duration — no new analysis pass or
cache fields.
- waveformSilence.ts: computeWaveformSilence(bins, duration) → lead/trail
silence + content bounds, using the peak curve, a low absolute cut and
a per-side cap. Unit-tested.
- A-tail (JS): handleAudioProgress advances the crossfade early, at
contentEnd - crossfadeSecs, when the current track ends in real
trailing silence, so the fade overlaps music. Guarded once per play
generation.
- B-head: audio_play gains an additive optional start_secs; the freshly
built source is try_seek'd past the next track's leading silence before
append, then seek_offset/samples_played are re-anchored so position is
content-relative. Non-seekable / cold sources degrade to today.
- Pre-buffer: crossfade next-track download + B-head probe moved to
crossfadePreload.ts with a fixed ~30 s budget before the track needs to
play (widened by trailing silence so the early advance keeps the
budget). Also fired right after a seek into the window so jumping near
the end still buffers in time.
Checks: tsc, vitest (store suite + new units), cargo test/clippy for
psysonic-audio.
* feat(crossfade): recommend hot cache for trim; probe B-head regardless
Add a "for reliable results, enable the Hot playback cache" note to the
trim-silence toggle description across all 9 locales — hot cache keeps
the next track on disk so it starts instantly past its lead silence.
Fix: the leading-silence probe (B-head) now runs even when hot cache is
on; only the redundant byte pre-download is gated on !hotCache. Without
this, enabling hot cache (the recommended setting) would have skipped the
probe and disabled leading-silence trimming.
* feat(crossfade): content-driven smart crossfade overlap
Smart crossfade derives the per-transition overlap purely from the
waveform envelopes — max(A outro fade, B intro rise) clamped 0.5–12s —
instead of the fixed crossfadeSecs ("work by fact"). The JS early
advance arms the computed overlap and audio_play applies it through a
new crossfade_secs_override (capping only this swap's fade); plain
loud→loud endings fall back to the engine crossfade at crossfadeSecs.
* feat(crossfade): "Crossfade | Smart crossfade" mode switch in UI
Replace the standalone "trim silence" toggle with a Crossfade / Smart
crossfade segmented control in settings and both crossfade popovers
(queue toolbar + mini-player). Classic Crossfade shows the seconds
slider; Smart crossfade is content-driven with no duration to set.
Adds smartCrossfade / smartCrossfadeDesc strings to all nine locales
and the "smart crossfade" search keyword.
* feat(crossfade): don't double-fade a track that already fades out
Decouple the outgoing track's fade-out from the incoming fade-in. When
A carries its own recorded fade-out (outroFadeA ≥ 1s and ≥ B's intro
rise), planCrossfadeTransition now sets outgoingFadeSec = 0; the engine
then skips A's TriggeredFadeOut so A keeps full gain and its recording
carries it down while B rises underneath — no more double attenuation
that made A vanish early and B blare in. Hard-cut endings still get an
engine fade over the overlap.
audio_play gains outgoing_fade_secs_override (Some(0) = ride A's own
fade), threaded via SinkSwapInputs.outgoing_fade_secs; the JS advance
arms it alongside the overlap.
* feat(crossfade): rename the smart crossfade mode to "AutoDJ"
User-facing rename of the content-driven crossfade mode from "Smart
crossfade" to "AutoDJ" across the settings segmented switch, the queue
and mini-player popovers, all nine locales, and the settings search
keywords. The underlying store flag (crossfadeTrimSilence) is unchanged.
* feat(crossfade): standard ~2s blend for hard loud→loud meetings
When AutoDJ trims a track's protective trailing silence and the loud
ending butts straight into a loud intro, neither edge fades, so the old
0.5s anti-click floor sounded like an abrupt cut. Use a standard ~2s
equal-power crossfade for that case (both edges analysed, nothing
fades); real fade-outs/buildups keep their longer content-driven span,
and the bare floor only survives when an envelope is missing.
* fix(crossfade): keep B's fade-in across the B-head start-offset seek
EqualPowerFadeIn::try_seek jumped straight to unity gain for any seek
≥100ms, which also hit the initial start-offset seek that skips the
incoming track's leading silence — so a crossfaded track with trimmed
lead silence popped in at full gain instead of fading in. Only skip the
fade-in for mid-playback seeks (sample_count > 0); a seek before any
audio has played keeps the fade-in.
* feat(crossfade): gate AutoDJ early fade on next-track readiness
The early, content-driven advance now fires only when the next track's
audio is actually available — in the engine RAM preload slot
(enginePreloadedTrackId) or local on disk (offline library, favourite-auto
or hot-cache ephemeral) — via isCrossfadeNextReady(). Analysis alone is
not enough: a cold, still-buffering stream would fade in over silence.
When B isn't ready the gen guard stays unset so it re-checks on later
ticks; if B never readies, the plain engine crossfade handles the
transition (graceful degrade) instead of a broken fade. A RAM preload
copy suffices — the full track need not be cached to disk.
* feat(crossfade): suppress engine auto-crossfade for AutoDJ + eager preload
With the hot cache off the readiness gate alone wasn't enough: the engine's
progress task autonomously fires its crossfade audio:ended ~crossfadeSecs
before the end, independently of JS, and would start a still-buffering next
track and fade over it — an audible jump.
- Engine: add autodj_suppress_autocrossfade flag (audio_set_autodj_suppress);
the progress task treats it like crossfade-off, so the early timer never
fires and audio:ended only comes from real source exhaustion / watchdog.
- JS drives the transition: set the flag when a content fade is pending
(wantEarly) and clear it for plain loud→loud / non-AutoDJ, so the normal
engine crossfade is preserved there. When the next track never readies, A
plays out and we degrade to a clean sequential start instead of a jump.
- audio_preload gains an `eager` flag; the crossfade/AutoDJ pre-buffer passes
it to skip the 8s start throttle so the RAM slot fills before the fade.
* docs(changelog): AutoDJ content-aware crossfade (PR #1122)
Add the 1.49.0 Added entry and the cucadmuh credits line for AutoDJ.
704 lines
47 KiB
TypeScript
704 lines
47 KiB
TypeScript
export const settings = {
|
||
title: 'Einstellungen',
|
||
language: 'Sprache',
|
||
languageEn: 'English',
|
||
languageDe: 'Deutsch',
|
||
languageEs: 'Español',
|
||
languageFr: 'Français',
|
||
languageNl: 'Nederlands',
|
||
languageNb: 'Norsk',
|
||
languageRu: 'Русский',
|
||
languageZh: '中文',
|
||
languageRo: 'Română',
|
||
font: 'Schriftart',
|
||
fontHintOpenDyslexic: 'Legasthenie-freundlich · keine Chinesisch-Unterstützung',
|
||
theme: 'Design',
|
||
appearance: 'Darstellung',
|
||
servers: 'Server',
|
||
serverName: 'Server-Name',
|
||
serverUrl: 'Server-URL',
|
||
serverUrlPlaceholder: '192.168.1.100:4533 oder https://music.example.com',
|
||
serverAlternateUrl: 'Zweite Adresse (optional)',
|
||
serverAlternateUrlPlaceholderPublic: 'https://music.example.com',
|
||
serverAlternateUrlPlaceholderLocal: '192.168.1.100:4533',
|
||
serverAlternateUrlHintAddPublic: 'Du kannst eine öffentliche Adresse hinzufügen, um außerhalb deines Heimnetzwerks zuzugreifen.',
|
||
serverAlternateUrlHintAddLocal: 'Du kannst eine lokale Adresse hinzufügen, um zu Hause schneller zu verbinden.',
|
||
serverBothLanError: 'Beide Adressen sind lokal — eine entfernen oder eine öffentliche hinzufügen.',
|
||
dualAddressVerifying: 'Prüfe, ob beide Adressen denselben Server meinen…',
|
||
dualAddressMismatch: 'Die beiden Adressen zeigen auf unterschiedliche Server. Schreibweise prüfen und erneut versuchen.',
|
||
dualAddressInsufficient: 'Konnte nicht bestätigen, dass beide Adressen derselbe Server sind. Entferne eine Adresse, um fortzufahren.',
|
||
dualAddressUnreachable: 'Konnte {{host}} nicht erreichen. Adresse und Netzwerk prüfen, dann erneut versuchen.',
|
||
urlRemigrationTitle: 'Bibliotheksdaten verschieben?',
|
||
urlRemigrationMessage: 'Beim Ändern der Adresse werden alle Bibliotheks-, Analyse- und Cover-Cache-Daten von {{oldKey}} nach {{newKey}} verschoben. Das kann nicht rückgängig gemacht werden.',
|
||
urlRemigrationConfirm: 'Daten verschieben',
|
||
urlRemigrationProgress: 'Bibliotheksdaten werden verschoben…',
|
||
urlRemigrationFailureInspect: 'Konnte nicht prüfen, was verschoben würde. Erneut versuchen oder das Debug-Log öffnen.',
|
||
urlRemigrationFailureRun: 'Verschieben der Bibliotheksdaten ist fehlgeschlagen. Deine gespeicherten Daten sind unverändert — erneut versuchen.',
|
||
urlRemigrationFailureCoverRename: 'Bibliotheksdaten wurden verschoben, aber Cover-Dateien konnten nicht umbenannt werden. Cover werden beim nächsten Zugriff neu aufgebaut.',
|
||
shareUsesLocalUrl: 'Lokale Adresse in Freigabe-Links verwenden',
|
||
shareUsesLocalUrlDesc: 'Wirkt sich auf Orbit-Einladungen und Bibliotheks-Freigaben aus. Standard: öffentliche Adresse.',
|
||
serverUsername: 'Benutzername',
|
||
serverPassword: 'Passwort',
|
||
addServer: 'Server hinzufügen',
|
||
addServerTitle: 'Neuen Server hinzufügen',
|
||
editServer: 'Bearbeiten',
|
||
editServerTitle: 'Server bearbeiten',
|
||
useServer: 'Verwenden',
|
||
deleteServer: 'Löschen',
|
||
noServers: 'Keine Server gespeichert.',
|
||
serverActive: 'Aktiv',
|
||
serverVersionUnknown: 'Serverversion unbekannt',
|
||
confirmDeleteServer: 'Server „{{name}}" löschen?',
|
||
confirmDeleteServerLibrary: 'Auch den lokalen Bibliotheksindex dieses Servers löschen? Auf Abbrechen klicken, um die zwischengespeicherte Kopie für die Offline-Nutzung zu behalten.',
|
||
serverConnecting: 'Verbinde…',
|
||
serverConnected: 'Verbunden!',
|
||
serverFailed: 'Verbindung fehlgeschlagen.',
|
||
testBtn: 'Verbindung testen',
|
||
testingBtn: 'Teste…',
|
||
serverCompatible: 'Für Navidrome entwickelt. Andere Subsonic-kompatible Server (Gonic, Airsonic, …) funktionieren ggf. eingeschränkt, weil Psysonic viele Navidrome-spezifische API-Endpunkte nutzt.',
|
||
userMgmtTitle: 'Benutzerverwaltung',
|
||
userMgmtDesc: 'Benutzer auf diesem Server verwalten. Erfordert Admin-Rechte.',
|
||
userMgmtNoAdmin: 'Du brauchst Admin-Rechte, um Benutzer auf diesem Server zu verwalten.',
|
||
userMgmtLoadError: 'Benutzer konnten nicht geladen werden.',
|
||
userMgmtLoadFriendly: 'Server hat nicht geantwortet — meistens ein Einzelfall.',
|
||
userMgmtRetry: 'Erneut versuchen',
|
||
userMgmtEmpty: 'Keine Benutzer gefunden.',
|
||
userMgmtYouBadge: 'Du',
|
||
userMgmtAdminBadge: 'Admin',
|
||
userMgmtAddUser: 'Benutzer hinzufügen',
|
||
userMgmtAddUserTitle: 'Neuen Benutzer anlegen',
|
||
userMgmtEditUserTitle: 'Benutzer bearbeiten',
|
||
userMgmtUsername: 'Benutzername',
|
||
userMgmtName: 'Anzeigename',
|
||
userMgmtEmail: 'E-Mail',
|
||
userMgmtPassword: 'Passwort',
|
||
userMgmtPasswordEditHint: 'Neues Passwort eingeben, um es zu ändern.',
|
||
userMgmtRoleAdmin: 'Admin',
|
||
userMgmtLibraries: 'Bibliotheken',
|
||
userMgmtLibrariesAdminHint: 'Admin-Benutzer haben automatisch Zugriff auf alle Bibliotheken.',
|
||
userMgmtLibrariesEmpty: 'Keine Bibliotheken auf diesem Server vorhanden.',
|
||
userMgmtLibrariesValidation: 'Mindestens eine Bibliothek auswählen.',
|
||
userMgmtLibrariesUpdateError: 'Benutzer gespeichert, aber Bibliothekszuweisung fehlgeschlagen',
|
||
userMgmtNoLibraries: 'Keine Bibliotheken zugewiesen',
|
||
userMgmtNeverSeen: 'Nie',
|
||
userMgmtSave: 'Speichern',
|
||
userMgmtCancel: 'Abbrechen',
|
||
userMgmtDelete: 'Löschen',
|
||
userMgmtEdit: 'Bearbeiten',
|
||
userMgmtConfirmDelete: 'Benutzer „{{username}}" löschen? Das kann nicht rückgängig gemacht werden.',
|
||
userMgmtCreateError: 'Benutzer konnte nicht angelegt werden.',
|
||
userMgmtUpdateError: 'Benutzer konnte nicht aktualisiert werden.',
|
||
userMgmtDeleteError: 'Benutzer konnte nicht gelöscht werden.',
|
||
userMgmtCreated: 'Benutzer angelegt.',
|
||
userMgmtUpdated: 'Benutzer aktualisiert.',
|
||
userMgmtDeleted: 'Benutzer gelöscht.',
|
||
userMgmtValidationMissing: 'Benutzername, Anzeigename und Passwort sind erforderlich.',
|
||
userMgmtValidationMissingIdentity: 'Benutzername und Anzeigename sind erforderlich.',
|
||
userMgmtMagicStringGenerate: 'Magic-String erzeugen',
|
||
userMgmtSaveAndMagicString: 'Speichern und Magic-String kopieren',
|
||
userMgmtMagicStringPasswordNavHint:
|
||
'Navidrome speichert dieses Passwort für den Benutzer. Weicht es vom aktuellen ab, wird das Anmeldepasswort auf dem Server aktualisiert.',
|
||
userMgmtMagicStringPlaintextWarning:
|
||
'Teilen Sie den Magic-String vorsichtig: Er enthält das Passwort im Klartext (Kodierung ist keine Verschlüsselung). Wer die vollständige Zeichenkette hat, kann sich als dieser Benutzer anmelden.',
|
||
userMgmtMagicStringCopied: 'Magic-String in die Zwischenablage kopiert.',
|
||
userMgmtMagicStringCopyFailed: 'Kopieren in die Zwischenablage fehlgeschlagen.',
|
||
userMgmtMagicStringLoginFailed: 'Passwortprüfung fehlgeschlagen — Anmeldedaten konnten nicht verifiziert werden.',
|
||
userMgmtMagicStringModalTitle: 'Magic-String erzeugen',
|
||
userMgmtMagicStringModalDesc: 'Subsonic-Passwort für „{{username}}" eingeben — es wird in den kopierten Magic-String übernommen.',
|
||
userMgmtMagicStringModalConfirm: 'String kopieren',
|
||
audiomuseTitle: 'AudioMuse-AI (Navidrome)',
|
||
audiomuseBadge: 'AudioMuse-AI',
|
||
audiomuseStatusActive: 'Aktiv',
|
||
audiomuseStatusChecking: 'Wird geprüft…',
|
||
audiomuseStatusNotDetected: 'Nicht erkannt',
|
||
audiomuseStatusProbeFailed: 'Prüfung fehlgeschlagen',
|
||
audiomuseDesc:
|
||
'Aktivieren, wenn dieser Server das <pluginLink>AudioMuse-AI-Navidrome-Plugin</pluginLink> nutzt. Schaltet Instant Mix pro Titel frei und nutzt ähnliche Künstler vom Server statt Last.fm auf Künstlerseiten.',
|
||
audiomuseIssueHint:
|
||
'Instant Mix ist kürzlich fehlgeschlagen — Navidrome-Plugin und AudioMuse-API prüfen. Ohne Server-Treffer werden ähnliche Künstler über Last.fm geladen.',
|
||
connected: 'Verbunden',
|
||
failed: 'Fehlgeschlagen',
|
||
eqTitle: 'Equalizer',
|
||
eqEnabled: 'Equalizer aktivieren',
|
||
eqPreset: 'Preset',
|
||
eqPresetCustom: 'Benutzerdefiniert',
|
||
eqPresetBuiltin: 'Eingebaute Presets',
|
||
eqPresetCustomGroup: 'Meine Presets',
|
||
eqSavePreset: 'Als Preset speichern',
|
||
eqPresetName: 'Preset-Name…',
|
||
eqDeletePreset: 'Preset löschen',
|
||
eqResetBands: 'Auf Flat zurücksetzen',
|
||
eqPreGain: 'Vorverstärkung',
|
||
eqResetPreGain: 'Vorverstärkung zurücksetzen',
|
||
eqAutoEqTitle: 'AutoEQ Kopfhörer-Suche',
|
||
eqAutoEqPlaceholder: 'Kopfhörer / IEM Modell suchen…',
|
||
eqAutoEqSearching: 'Suche…',
|
||
eqAutoEqNoResults: 'Keine Ergebnisse gefunden',
|
||
eqAutoEqError: 'Suche fehlgeschlagen',
|
||
eqAutoEqRateLimit: 'GitHub Rate-Limit erreicht — in einer Minute erneut versuchen',
|
||
eqAutoEqFetchError: 'EQ-Profil konnte nicht geladen werden',
|
||
behavior: 'App-Verhalten',
|
||
cacheTitle: 'Max. Speichergröße',
|
||
cacheDesc: 'Browser-Cache für Cover und Künstlerbilder (IndexedDB). Wenn voll, werden die ältesten Einträge automatisch entfernt.',
|
||
cacheUsedImages: 'Bilder:',
|
||
cacheUsedOffline: 'Offline-Tracks:',
|
||
cacheUsedHot: 'Belegter Speicher:',
|
||
hotCacheTrackCount: 'Titel im Cache:',
|
||
cacheMaxLabel: 'Max. Größe',
|
||
imageCacheScopeLabel: 'Bereich',
|
||
imageCacheSubTitle: 'Vorschauen im Browser',
|
||
coverDiskCacheSubTitle: 'Cover-Cache auf der Festplatte',
|
||
coverCacheStrategyTitle: 'Cover-Cache',
|
||
coverCacheStrategyDesc: 'Du kannst für jeden Server eine Strategie wählen: Lazy — Cover bei Bedarf laden; Aggressive — bei Bedarf laden plus zusätzliches Vorladen im Hintergrund.',
|
||
coverCacheStrategyLabel: 'Strategie',
|
||
coverCacheStrategyServerLabel: 'Server',
|
||
coverCacheStrategyProgressLabel: 'Cache',
|
||
coverCacheStrategyActionsLabel: 'Aktionen',
|
||
coverCacheStrategyLazy: 'Lazy',
|
||
coverCacheStrategyLazyDesc: 'Lädt Cover nur, wenn sie benötigt werden.',
|
||
coverCacheStrategyAggressive: 'Aggressive',
|
||
coverCacheStrategyAggressiveDesc: 'Lazy-Verhalten plus zusätzliches Vorladen im Hintergrund.',
|
||
coverCacheStrategyDiskUsage: 'Auf der Festplatte: {{size}}',
|
||
coverCacheStrategyProgressValue: '{{percent}}% ({{done}}/{{total}}) · {{size}}',
|
||
coverCacheStrategyClearAction: 'Cover-Cache leeren',
|
||
coverCacheStrategyClearTitle: 'Cover-Cache leeren?',
|
||
coverCacheStrategyClearDesc: 'Entfernt alle gecachten Cover-Bilder für {{server}}. Sie werden bei Bedarf neu heruntergeladen.',
|
||
coverCacheStrategyClearConfirm: 'Leeren',
|
||
coverCacheStrategyClearCancel: 'Abbrechen',
|
||
coverCacheStrategyClearSuccess: 'Cover-Cache für diesen Server geleert.',
|
||
coverCacheStrategyClearError: 'Cover-Cache konnte nicht geleert werden.',
|
||
coverCacheStrategyServerRemoved: 'entfernter Server',
|
||
cacheClearBtn: 'Cache leeren',
|
||
cacheClearWarning: 'Löscht alle gecachten Cover- und Künstlerbilder im Browser-Speicher. Sie werden bei Bedarf neu geladen.',
|
||
cacheClearConfirm: 'Bild-Cache leeren',
|
||
cacheClearCancel: 'Abbrechen',
|
||
mediaDirTitle: 'Medienordner',
|
||
mediaDirDesc: 'Stammordner für lokale Wiedergabe. Offline-Bibliothek: library/; Warteschlangen-Puffer: cache/.',
|
||
mediaDirDefault: 'Standard (App-Daten)',
|
||
mediaDirChange: 'Ordner ändern',
|
||
mediaDirClear: 'Auf Standard zurücksetzen',
|
||
mediaDirHint: 'Neue Downloads nutzen diesen Ort. Bestehende Dateien bleiben am ursprünglichen Pfad, bis du sie entfernst.',
|
||
offlineStorageTitle: 'Offline-Speicher',
|
||
offlineDirTitle: 'Offline-Bibliothek (In-App)',
|
||
offlineDirDesc: 'Speicherort für Titel, die du innerhalb von Psysonic offline verfügbar machst.',
|
||
offlineDirDefault: 'Standard (App-Daten)',
|
||
offlineDirChange: 'Verzeichnis ändern',
|
||
offlineDirClear: 'Auf Standard zurücksetzen',
|
||
offlineDirHint: 'Neue Downloads werden an diesem Ort gespeichert. Bestehende Downloads verbleiben am ursprünglichen Pfad.',
|
||
hotCacheTitle: 'Hot-Playback-Cache',
|
||
hotCacheDisclaimer: 'Lädt kommende Warteschlangen-Titel vor und behält zuletzt gespielte. Bei aktivierter Option: Speicherplatz und Netzwerk.',
|
||
hotCacheDirDefault: 'Standard (App-Daten)',
|
||
hotCacheDirChange: 'Ordner ändern',
|
||
hotCacheDirClear: 'Auf Standard zurücksetzen',
|
||
hotCacheDirHint: 'Beim Ordnerwechsel wird der App-Index zurückgesetzt; alte Dateien bleiben am alten Ort, bis Sie sie löschen.',
|
||
hotCacheEnabled: 'Hot-Playback-Cache aktivieren',
|
||
hotCacheMaxMb: 'Maximale Cache-Größe',
|
||
hotCacheDebounce: 'Debounce bei Warteschlangen-Änderungen',
|
||
hotCacheDebounceImmediate: 'Sofort',
|
||
hotCacheDebounceSeconds: '{{n}} s',
|
||
hotCacheClearBtn: 'Hot-Cache leeren',
|
||
audioOutputDevice: 'Audio-Ausgabegerät',
|
||
audioOutputDeviceDesc: 'Wähle das Audiogerät, über das Psysonic spielt. Änderungen werden sofort übernommen und starten den aktuellen Track neu.',
|
||
audioOutputDeviceDefault: 'Systemstandard',
|
||
audioOutputDeviceRefresh: 'Geräteliste aktualisieren',
|
||
audioOutputDeviceOsDefaultNow: 'aktuelle Systemausgabe',
|
||
audioOutputDeviceListError: 'Audiogeräteliste konnte nicht geladen werden.',
|
||
audioOutputDeviceNotInCurrentList: 'nicht in der aktuellen Liste',
|
||
audioOutputDeviceMacNotice: 'Auf macOS folgt die Wiedergabe aus technischen Gründen zurzeit immer dem System-Ausgabegerät. Du kannst das Ziel über Systemeinstellungen → Ton oder das Lautsprecher-Symbol in der Menüleiste wechseln. Hintergrund: CoreAudio löst beim Öffnen eines nicht-Default-Streams eine Mikrofonberechtigungsabfrage aus — wir vermeiden sie, indem wir stets den System-Default verwenden.',
|
||
hiResTitle: 'Native Hi-Res-Wiedergabe',
|
||
hiResEnabled: 'Native Hi-Res-Wiedergabe aktivieren',
|
||
hiResDesc: "Standardmäßig wird auf 44,1 kHz begrenzt (maximale Stabilität). Nur aktivieren, wenn Hardware und Netzwerk zuverlässig hohe Abtastraten (88,2 kHz+) unterstützen.",
|
||
showArtistImages: 'Künstlerbilder anzeigen',
|
||
showArtistImagesDesc: 'Lädt und zeigt Künstlerbilder in der Künstlerübersicht. Standardmäßig deaktiviert, um Server-I/O und Netzwerklast bei großen Bibliotheken zu reduzieren.',
|
||
showOrbitTrigger: '„Orbit" im Header zeigen',
|
||
showOrbitTriggerDesc: 'Der Kopfzeilen-Button zum Starten oder Beitreten einer gemeinsamen Hör-Session. Ausblenden, wenn du Orbit nicht nutzt — hier lässt er sich jederzeit wieder einschalten.',
|
||
showTrayIcon: 'Tray-Icon anzeigen',
|
||
showTrayIconDesc: 'Psysonic-Icon im System-Tray / in der Menüleiste anzeigen.',
|
||
minimizeToTray: 'Im Tray minimieren',
|
||
minimizeToTrayDesc: 'Beim Schließen des Fensters läuft Psysonic weiter im System-Tray statt zu beenden.',
|
||
clockFormat: 'Uhrzeitformat',
|
||
clockFormatDesc: 'Format für die Queue-ETA und die Vorschau des Sleep-Timers.',
|
||
clockFormatAuto: 'Automatisch (Systemsprache)',
|
||
clockFormatTwentyFour: '24-Stunden',
|
||
clockFormatTwelve: '12-Stunden (AM/PM)',
|
||
preloadMiniPlayer: 'Mini-Player vorladen',
|
||
preloadMiniPlayerDesc: 'Baut das Mini-Player-Fenster beim App-Start im Hintergrund auf, damit es beim ersten Öffnen sofort Inhalt zeigt. Kostet etwas mehr RAM.',
|
||
discordRichPresence: 'Discord Rich Presence',
|
||
discordRichPresenceDesc: 'Zeigt den aktuell gespielten Titel im Discord-Profil an. Discord muss dafür geöffnet sein.',
|
||
discordRichPresenceNotice: 'Achtung: Dies ist die in Psysonic integrierte Discord Rich Presence. Wenn du stattdessen das offizielle Navidrome-Discord-Rich-Presence-Plugin nutzen möchtest, lass diese Funktion deaktiviert und aktiviere stattdessen weiter unten auf dieser Seite „Im Livefenster anzeigen".',
|
||
useCustomTitlebar: 'Eigene Titelleiste',
|
||
useCustomTitlebarDesc: 'Ersetzt die System-Titelleiste durch eine eingebaute, die zum App-Theme passt. Deaktivieren, um die native GNOME/GTK-Titelleiste zu verwenden.',
|
||
windowButtonStyle: 'Fenster-Buttons',
|
||
windowButtonStyleDesc: 'Wähle das Aussehen der Minimieren-, Maximieren- und Schließen-Buttons.',
|
||
windowButtonsDots: 'Punkte',
|
||
windowButtonsDotsGlyph: 'Punkte + Symbole',
|
||
windowButtonsFlat: 'Flach',
|
||
windowButtonsPill: 'Pille',
|
||
windowButtonsOutline: 'Umriss',
|
||
windowButtonsGlyph: 'Minimal',
|
||
showMinimizeButton: 'Minimieren-Button anzeigen',
|
||
showMinimizeButtonDesc: 'Ausschalten, um nur Maximieren und Schließen anzuzeigen.',
|
||
linuxWebkitSmoothScroll: 'Sanftes Mausrad (Linux)',
|
||
linuxWebkitSmoothScrollDesc: 'An: mit Nachlauf. Aus: zeilenweise wie in GTK-Apps.',
|
||
linuxWebkitInputForceRepaint: 'Eingabefelder beim Fokus neu zeichnen (Linux)',
|
||
linuxWebkitInputForceRepaintDesc: 'Behelf für WebKitGTK 2.50.x, wo Textfelder beim Klick einfrieren. Such-Icons flackern beim Fokus kurz.',
|
||
linuxWaylandTextRender: 'Wayland-Textdarstellung (Linux)',
|
||
linuxWaylandTextRenderDesc:
|
||
'Kantenglättung in der Oberfläche wirkt sofort. Die WebKit-Beschleunigungsrichtlinie (scharf/GPU) wird gespeichert und beim nächsten App-Start angewendet — ein Live-Umschalten kann WebKitGTK einfrieren.',
|
||
linuxWaylandTextRenderBalanced: 'Ausgewogen',
|
||
linuxWaylandTextRenderSharp: 'Scharf (CPU-freundlich)',
|
||
linuxWaylandTextRenderGpu: 'GPU zuerst',
|
||
linuxWaylandTextRenderMinimal: 'Minimal (Standard-CSS-Glättung)',
|
||
discordCoverSource: 'Cover-Quelle',
|
||
discordCoverSourceDesc: 'Woher das Album-Cover für dein Discord-Profil geladen wird.',
|
||
discordCoverNone: 'Keine (nur App-Symbol)',
|
||
discordCoverServer: 'Server (über Album-Info)',
|
||
discordCoverApple: 'Apple Music',
|
||
discordOptions: 'Erweiterte Discord-Optionen',
|
||
discordTemplates: 'Benutzerdefinierte Textvorlagen',
|
||
discordTemplatesDesc: 'Passen Sie an, welche Informationen in Ihrem Discord-Profil angezeigt werden. Variablen: {title}, {artist}, {album}',
|
||
discordTemplateDetails: 'Primäre Zeile (details)',
|
||
discordTemplateState: 'Sekundäre Zeile (state)',
|
||
discordTemplateLargeText: 'Album-Tooltip (largeText)',
|
||
discordTemplateName: 'Userliste-Zeile (name)',
|
||
nowPlayingEnabled: 'Im Livefenster anzeigen',
|
||
nowPlayingEnabledDesc: 'Überträgt den aktuell gespielten Titel an die Livehörer-Ansicht des Servers. Deaktivieren, um keine Wiedergabedaten zu senden.',
|
||
nowPlayingPluginNote: 'Notwendig bei Verwendung des offiziellen Navidrome-Discord-Rich-Presence-Plugins.',
|
||
enableBandsintown: 'Bandsintown-Tourdaten',
|
||
enableBandsintownDesc: 'Zeigt anstehende Konzerte des aktuellen Künstlers im Info-Tab. Daten werden über die öffentliche Bandsintown-API abgerufen.',
|
||
lyricsServerFirst: 'Server-Lyrics bevorzugen',
|
||
lyricsServerFirstDesc: 'Server-seitige Lyrics (eingebettete Tags, Sidecar-Dateien) vor LRCLIB abfragen. Deaktivieren, um LRCLIB zuerst zu verwenden.',
|
||
enableNeteaselyrics: 'Netease Cloud Music Lyrics',
|
||
enableNeteaselyricsDesc: 'Netease Cloud Music als letzte Lyrics-Quelle verwenden, wenn Server und LRCLIB nichts liefern. Besonders gut für asiatische und internationale Musik.',
|
||
lyricsSourcesTitle: 'Lyrics-Quellen',
|
||
lyricsSourcesDesc: 'Wähle, welche Quellen für Lyrics abgefragt werden und in welcher Reihenfolge. Ziehen zum Sortieren. Deaktivierte Quellen werden übersprungen.',
|
||
lyricsSourceServer: 'Server',
|
||
lyricsSourceLrclib: 'LRCLIB',
|
||
lyricsSourceNetease: 'Netease Cloud Music',
|
||
lyricsYouLyPlus: 'YouLyPlus (Karaoke)',
|
||
lyricsYouLyPlusDesc: 'Wort-für-Wort-Sync über ein Community-Backend (Apple Music, Spotify, Musixmatch, QQ). Wird zuerst versucht; die aktivierten Quellen unten dienen als Fallback.',
|
||
lyricsSourcesFallbackHint: 'Dienen als Fallback, wenn YouLyPlus nichts findet. Zum Sortieren ziehen.',
|
||
lyricsSourcesPrimaryHint: 'Werden der Reihe nach genutzt. Zum Sortieren ziehen. Alle aus = Lyrics deaktiviert.',
|
||
lyricsStaticOnly: 'Nur statische Lyrics anzeigen',
|
||
lyricsStaticOnlyDesc: 'Synchronisierte Lyrics werden ohne Auto-Scroll und ohne Wort-Hervorhebung als statischer Text dargestellt.',
|
||
downloadsTitle: 'ZIP-Export & Archivierung',
|
||
downloadsFolderDesc: 'Zielverzeichnis für Alben, die du als ZIP-Datei auf deinen Computer herunterlädst.',
|
||
downloadsDefault: 'Standard-Downloads-Ordner',
|
||
pickFolder: 'Auswählen',
|
||
pickFolderTitle: 'Download-Ordner auswählen',
|
||
clearFolder: 'Download-Ordner löschen',
|
||
logout: 'Abmelden',
|
||
aboutTitle: 'Über Psysonic',
|
||
aboutDesc: 'Ein moderner Desktop-Musikplayer für Navidrome. Nutzt die Subsonic-API plus Navidrome-spezifische Erweiterungen. Basiert auf Tauri v2 mit einer nativen Rust-Audio-Engine — schlank und schnell, aber vollgepackt mit Features: Wellenform-Seekbar, synchronisierte Lyrics, Last.fm-Integration, 10-Band-EQ, Crossfade, nahtlose Wiedergabe, Replay Gain, Genre-Browser und eine große Theme-Bibliothek.',
|
||
aboutLicense: 'Lizenz',
|
||
aboutLicenseText: 'GNU GPL v3 — kostenlos nutzbar, veränderbar und unter gleicher Lizenz weiterzugeben.',
|
||
aboutRepo: 'Quellcode auf GitHub',
|
||
aboutVersion: 'Version',
|
||
aboutBuiltWith: 'Gebaut mit Tauri · React · TypeScript · Rust/rodio',
|
||
aboutMaintainersLabel: 'Projektleitung',
|
||
aboutReleaseNotesLabel: 'Release Notes',
|
||
aboutReleaseNotesLink: 'Neuigkeiten dieser Version öffnen',
|
||
aboutContributorsLabel: 'Mitwirkende',
|
||
showChangelogOnUpdate: "'Was ist neu' bei Update anzeigen",
|
||
showChangelogOnUpdateDesc: 'Blendet nach einem Update einen dezenten Changelog-Banner über Now Playing ein. Klick öffnet die Release Notes, X blendet ihn aus.',
|
||
libraryGridMaxColumnsTitle: 'Kartenraster in der Bibliothek',
|
||
libraryGridMaxColumnsPerfHint: 'Mehr Spalten bedeuten mehr Kacheln pro Zeile und oft mehr Layout- und Zeichenaufwand — bei sehr großen Bibliotheken oder langsamerer Hardware spürbarer.',
|
||
libraryGridMaxColumnsRangeLabel: 'Maximale Spalten ({{min}}–{{max}})',
|
||
libraryGridMaxColumnsDesc: 'Gilt für Album-, Künstler-, Wiedergabelisten-, Radio-, Offline- und andere Kartenansichten. Weniger Spalten = größere Kacheln und meist weniger CPU-Last.',
|
||
libraryIndexTitle: 'Lokaler Bibliotheksindex (Vorschau)',
|
||
libraryIndexDesc: 'Behält eine lokale Kopie der Track-Datenbank jedes Servers vor, damit Stöbern und Suche schnell bleiben und offline funktionieren. Die Erstsynchronisation läuft für alle konfigurierten Server; offline Server werden automatisch erneut versucht.',
|
||
libraryIndexDeltaHint: 'Die Hintergrund-Delta-Synchronisation prüft gebundene Server alle 30 Sekunden und startet bei Bedarf — typischerweise alle 5–45 Minuten, abhängig von Bibliotheksgröße und Last.',
|
||
libraryIndexEnable: 'Lokalen Bibliotheksindex aktivieren',
|
||
libraryIndexEnableAllDesc: 'Alle konfigurierten Server im Hintergrund indizieren und synchronisieren.',
|
||
libraryIndexNoServer: 'Zuerst einen Server hinzufügen.',
|
||
libraryIndexServerListTitle: 'Indizierte Server',
|
||
libraryIndexAllExcluded: 'Alle Server sind von der Synchronisation ausgeschlossen. Index wieder aktivieren oder Server hinzufügen.',
|
||
libraryIndexServerOffline: 'Server offline — Synchronisation verschoben',
|
||
libraryIndexServerDeferred: 'Verschoben',
|
||
libraryIndexServerSyncing: 'Synchronisiert…',
|
||
libraryIndexFullResync: 'Vollständige Neusynchronisation',
|
||
libraryIndexDeltaSync: 'Delta-Synchronisation',
|
||
libraryIndexExcludeServer: 'Von Synchronisation ausschließen',
|
||
libraryIndexExcludingServer: 'Wird ausgeschlossen…',
|
||
libraryIndexExcludedTitle: 'Von Synchronisation ausgeschlossen',
|
||
libraryIndexIncludeServer: 'Wieder einschließen',
|
||
libraryIndexIncludingServer: 'Wird eingeschlossen…',
|
||
libraryIndexStatus: 'Status',
|
||
libraryIndexStatusIdle: 'Bereit',
|
||
libraryIndexStatusProbing: 'Server wird geprüft…',
|
||
libraryIndexStatusInitial: 'Erst-Synchronisation…',
|
||
libraryIndexStatusReady: 'Fertig ({{count}} Titel)',
|
||
libraryIndexStatusError: 'Fehler — siehe Logs',
|
||
libraryIndexProgressIngest: '{{count}} Titel indiziert…',
|
||
libraryIndexProgressVerify: '{{checked}} geprüft ({{deleted}} entfernt)',
|
||
libraryIndexSyncNow: 'Jetzt synchronisieren',
|
||
libraryIndexVerify: 'Bibliotheksintegrität prüfen',
|
||
libraryIndexCancel: 'Abbrechen',
|
||
libraryIndexAutoReconcile: 'Automatischer Abgleich bei Titelrückgang',
|
||
libraryIndexAutoReconcileDesc: 'Automatisch nach entfernten Titeln suchen, wenn der Server weniger als erwartet meldet.',
|
||
libraryIndexSyncError: 'Bibliotheks-Synchronisation fehlgeschlagen: {{error}}',
|
||
libraryIndexBindError: 'Index konnte nicht aktiviert werden: {{error}}',
|
||
randomMixTitle: 'Zufallsmix-Blacklist',
|
||
luckyMixMenuTitle: 'Glücks-Mix im Menü anzeigen',
|
||
luckyMixMenuDesc: 'Aktiviert Glücks-Mix im "Mix erstellen"-Hub und als separaten Menüeintrag bei getrennter Navigation. Sichtbar nur bei aktiviertem AudioMuse auf dem aktiven Server.',
|
||
randomMixBlacklistTitle: 'Eigene Filter-Keywords',
|
||
randomMixBlacklistDesc: 'Songs werden ausgeschlossen, wenn ein Keyword auf Genre, Titel, Album oder Künstler zutrifft (aktiv wenn die Checkbox oben an ist).',
|
||
randomMixBlacklistPlaceholder: 'Keyword hinzufügen…',
|
||
randomMixBlacklistAdd: 'Hinzufügen',
|
||
randomMixBlacklistEmpty: 'Noch keine eigenen Keywords hinzugefügt.',
|
||
randomMixHardcodedTitle: 'Eingebaute Keywords (aktiv wenn Checkbox an)',
|
||
tabAudio: 'Audio',
|
||
tabStorage: 'Offline & Cache',
|
||
tabAppearance: 'Darstellung',
|
||
tabThemes: 'Themes',
|
||
themesYourThemesTitle: 'Deine Themes',
|
||
themesCvdTooltip: 'Farbfehlsichtigkeits-sicher – Deuteranopie, Protanopie, Tritanopie',
|
||
themeAnimationWarning: 'Dieses Theme nutzt Animationen, die auf deinem Setup (Nvidia/Linux oder Compositing aus) die CPU-Last erhöhen können.',
|
||
themeStoreTitle: 'Theme-Store',
|
||
themeStoreSubmitText: 'Eigenes Theme gebaut? Teil es mit der Community — mehr Infos im Themes-Repository.',
|
||
themeStoreSubmitLink: 'Themes-Repository öffnen',
|
||
themeStoreNetworkNotice: 'Der Theme-Store lädt Katalog und Vorschauen von GitHub. Es werden keine persönlichen Daten gesendet.',
|
||
themeStoreStatsNotice: 'Die „Zuletzt geändert“-Daten werden einmal täglich aktualisiert (gegen 04:17 UTC).',
|
||
themeStoreSearchPlaceholder: 'Themes suchen…',
|
||
themeStoreFilterMode: 'Nach Modus filtern',
|
||
themeStoreModeAll: 'Alle',
|
||
themeStoreModeDark: 'Dunkel',
|
||
themeStoreModeLight: 'Hell',
|
||
themeStoreRefresh: 'Aktualisieren',
|
||
themeStoreLoading: 'Themes werden geladen…',
|
||
themeStoreError: 'Theme-Store konnte nicht geladen werden. Prüfe deine Verbindung.',
|
||
themeStoreRetry: 'Erneut versuchen',
|
||
themeStoreOfflineTitle: 'Der Theme-Store ist offline',
|
||
themeStoreEmpty: 'Keine Themes passen zu deinen Filtern.',
|
||
themeStoreActive: 'Aktiv',
|
||
themeStoreEnlarge: 'Vorschau vergrößern',
|
||
themeStoreSortNewest: 'Neueste',
|
||
themeStoreSortName: 'Alphabetisch',
|
||
themeStoreAnimAll: 'Alle',
|
||
themeStoreAnimAnimated: 'Animiert',
|
||
themeStoreAnimStatic: 'Statisch',
|
||
themeStoreByAuthor: 'von {{author}}',
|
||
themeStoreLastChanged: 'Zuletzt geändert',
|
||
themeMigrationNoticeTitle: 'Theme in den Store gezogen',
|
||
themeMigrationNoticeBody: '{{themes}} ist nicht mehr in der App enthalten. Du kannst es im Theme-Store neu installieren (Einstellungen → Themes) oder ein anderes Theme wählen.',
|
||
themeMigrationNoticeOpen: 'Theme-Store öffnen',
|
||
themeStoreOffline: 'Zeige den zuletzt gecachten Katalog — du scheinst offline zu sein.',
|
||
themeStoreInstall: 'Installieren',
|
||
themeStoreInstalling: 'Installiere…',
|
||
themeStoreApply: 'Anwenden',
|
||
themeStoreUpdate: 'Aktualisieren',
|
||
themeStoreUpdating: 'Aktualisiere…',
|
||
themeStoreUninstall: 'Deinstallieren',
|
||
themeStoreInstallFailed: 'Installation fehlgeschlagen',
|
||
themeStorePagePrev: 'Vorherige Seite',
|
||
themeStorePageNext: 'Nächste Seite',
|
||
themeStorePageStatus: 'Seite {{page}} von {{total}}',
|
||
themeImportTitle: 'Theme importieren',
|
||
themeImportButton: 'Theme importieren…',
|
||
themeImporting: 'Importiere…',
|
||
themeImportHint: 'Lädt ein als .zip verpacktes Theme (manifest.json + theme.css).',
|
||
themeImportSuccess: '„{{name}}“ importiert.',
|
||
themeImportErrorTitle: 'Dieses Theme konnte nicht importiert werden',
|
||
themeImportErrorBody: 'Es entspricht nicht dem Psysonic-Theme-Format. Vielleicht wurde es für eine andere Version erstellt oder die Datei ist unvollständig — prüfe, ob du die richtige .zip gewählt hast, oder frag den Autor des Themes.',
|
||
themeImportErrorDetails: 'Technische Details',
|
||
themeImportConfirmTitle: 'Theme installieren?',
|
||
themeImportConfirmBody: '„{{name}}“ von {{author}} installieren?',
|
||
themeImportConfirmRisk: 'Importierte Themes werden nicht geprüft — installiere nur Themes, denen du vertraust.',
|
||
tabLibrary: 'Bibliothek',
|
||
tabServers: 'Server',
|
||
tabLyrics: 'Songtexte',
|
||
tabPersonalisation: 'Personalisierung',
|
||
tabIntegrations: 'Integrationen',
|
||
inputKeybindingsTitle: 'Tastenkombinationen',
|
||
aboutContributorsCount_one: '{{count}} Beitrag',
|
||
aboutContributorsCount_other: '{{count}} Beiträge',
|
||
searchPlaceholder: 'Einstellungen durchsuchen…',
|
||
searchNoResults: 'Keine Treffer für deine Suche.',
|
||
integrationsPrivacyTitle: 'Hinweis zum Datenschutz',
|
||
integrationsPrivacyBody: 'Alle Integrationen auf diesem Tab sind <strong>Opt-in</strong> und senden, sobald aktiviert, Daten an externe Dienste oder an deinen Navidrome-Server. Last.fm erhält deinen Wiedergabeverlauf, Discord zeigt den aktuell laufenden Track in deinem Profil an, Bandsintown wird pro Künstler für Tour-Daten abgefragt, und der „Jetzt läuft"-Hinweis veröffentlicht deinen aktuellen Titel für andere Benutzer deines Navidrome-Servers. Wer das nicht möchte, lässt den jeweiligen Abschnitt einfach deaktiviert.',
|
||
homeCustomizerTitle: 'Mainstage',
|
||
queueModeTitle: 'Warteschlangen-Ansicht',
|
||
queueModeQueueSub: 'Zeigt nur kommende Titel. Der laufende Titel bleibt im Kopf und verschwindet aus der Liste, sobald er gespielt wurde.',
|
||
queueModePlaylistSub: 'Behält die ganze Warteschlange in der Liste, der laufende Titel oben hervorgehoben; gespielte Titel bleiben stehen.',
|
||
queueModeTimelineSub: 'Aktuellen Titel zentrieren — gespielter Verlauf darüber, kommende Titel (in Shuffle-Reihenfolge) darunter.',
|
||
queueToolbarTitle: 'Warteschlangen-Toolbar',
|
||
queueToolbarReset: 'Zurücksetzen',
|
||
queueToolbarSeparator: 'Trennlinie',
|
||
sidebarTitle: 'Seitenleiste',
|
||
sidebarReset: 'Zurücksetzen',
|
||
artistLayoutTitle: 'Künstlerseiten-Abschnitte',
|
||
artistLayoutDesc: 'Per Drag & Drop neu anordnen, einzelne Abschnitte der Künstlerseite ein- oder ausblenden. Abschnitte ohne Daten werden automatisch übersprungen.',
|
||
artistLayoutReset: 'Zurücksetzen',
|
||
artistLayoutBio: 'Künstler-Biografie',
|
||
artistLayoutTopTracks: 'Top-Tracks',
|
||
artistLayoutSimilar: 'Ähnliche Künstler*innen',
|
||
artistLayoutAlbums: 'Alben',
|
||
artistLayoutFeatured: 'Auch enthalten auf',
|
||
playlistLayoutTitle: 'Playlist-Seitenlayout',
|
||
playlistLayoutDesc: 'Einzelne Elemente auf der Playlist-Seite ein- oder ausblenden.',
|
||
playlistLayoutReset: 'Zurücksetzen',
|
||
playerBarTitle: 'Player-Leiste',
|
||
playerBarReset: 'Zurücksetzen',
|
||
playerBarStarRating: 'Sterne-Bewertung',
|
||
playerBarFavorite: 'Favorit (Herz)',
|
||
playerBarLastfmLove: 'Love-Button',
|
||
playerBarPlaybackRate: 'Wiedergabegeschwindigkeit',
|
||
playerBarEqualizer: 'Equalizer',
|
||
playerBarMiniPlayer: 'Mini-Player',
|
||
playbackRateTitle: 'Wiedergabegeschwindigkeit',
|
||
playbackRateEnabled: 'Wiedergabegeschwindigkeit aktivieren',
|
||
playbackRateEnabledDesc: 'Globale Geschwindigkeit für alle Titel. Gilt nicht für Radio und Vorschau.',
|
||
playbackRateStrategy: 'Strategie',
|
||
playbackRateStrategySpeed: 'Geschwindigkeit',
|
||
playbackRateStrategyVarispeed: 'Tonhöhe folgt dem Tempo',
|
||
playbackRateStrategyVarispeedSemitones: 'Halbtöne',
|
||
playbackRateStrategyPreserve: 'Tonhöhe',
|
||
playbackRateStrategySpeedTip: 'Ändert das Tempo; die Tonhöhe wird automatisch korrigiert.',
|
||
playbackRateStrategyVarispeedTip: 'Geschwindigkeit und Tonhöhe ändern sich gemeinsam, wie bei Tonband. Tonhöhe aus Geschwindigkeit: 12 × log2(Geschwindigkeit).',
|
||
playbackRateStrategyVarispeedSemitonesTip: 'Wie „Tonhöhe folgt dem Tempo“, aber direkt in Halbtönen eingestellt. Geschwindigkeit = 2^(Ht/12).',
|
||
playbackRateStrategyPreserveTip: 'Einstellbares Tempo plus manuelle Tonhöhenverschiebung (±12 Ht).',
|
||
playbackRateSpeed: 'Geschwindigkeit',
|
||
playbackRatePitch: 'Tonhöhe',
|
||
playbackRateDerivedPitch: 'Tonhöhenverschiebung durch Geschwindigkeit: {{value}}',
|
||
playbackRateDerivedSpeed: 'Geschwindigkeit aus Halbtönen: {{value}}',
|
||
playbackRateFineStep: 'Feinabstimmung',
|
||
playbackRateFineStepDesc: 'Kleinere Schieberegler-Schritte: 0,01× für Geschwindigkeit und 0,01 Ht für Tonhöhe.',
|
||
playbackRateAutoPitch: 'Die Tonhöhe wird automatisch korrigiert.',
|
||
playbackRateHint: '„Geschwindigkeit“ behält die Tonhöhe bei. „Tonhöhe folgt dem Tempo“ verschiebt die Tonhöhe mit der Geschwindigkeit. „Tonhöhe folgt dem Tempo (Halbtöne)“ stellt diese Tonhöhenänderung direkt in Halbtönen ein. „Tonhöhe“ fügt eine manuelle Verschiebung hinzu. Höhere CPU-Last als bei „Tonhöhe folgt dem Tempo“. Nicht für Radio, Vorschau oder Orbit.',
|
||
playbackRateNeutral: 'Bei 1,0× und ohne Tonverschiebung ist die Wiedergabe normal.',
|
||
playbackRateOrbitPaused: 'Während Orbit-Sessions nicht aktiv — Wiedergabe bleibt bei 1,0× für die Synchronisation.',
|
||
playbackRateOrbitPausedShort: 'Orbit: 1,0× für Sync.',
|
||
advancedMode: 'Erweitert',
|
||
advancedModeTooltip: 'Erweiterte Optionen in allen Settings-Tabs anzeigen. Community-Beiträge, die nicht zwingend der Design-Philosophie der Maintainer von Psysonic entsprechen.',
|
||
advancedBadge: 'Erweitert',
|
||
sidebarDrag: 'Ziehen zum Umsortieren',
|
||
sidebarFixed: 'Immer sichtbar',
|
||
nowPlayingTopTitle: 'Now Playing oben',
|
||
nowPlayingTopDesc: '"Now Playing" oben in der Seitenleiste anheften statt unten.',
|
||
randomNavSplitTitle: 'Mix-Navigation aufteilen',
|
||
randomNavSplitDesc: '"Zufallsmix", "Zufallsalben" und "Glücks-Mix" als separate Sidebar-Einträge statt als "Mix erstellen"-Hub anzeigen.',
|
||
tabInput: 'Eingabe',
|
||
tabUsers: 'Benutzer',
|
||
shortcutsReset: 'Auf Standard zurücksetzen',
|
||
shortcutListening: 'Taste drücken…',
|
||
shortcutUnbound: '—',
|
||
shortcutClear: 'Löschen',
|
||
globalShortcutsTitle: 'Globale Shortcuts',
|
||
globalShortcutsNote: 'Funktionieren systemweit, auch wenn Psysonic im Hintergrund läuft. Mindestens Ctrl, Alt oder Super als Modifier erforderlich.',
|
||
shortcutPlayPause: 'Wiedergabe / Pause',
|
||
shortcutNext: 'Nächster Titel',
|
||
shortcutPrev: 'Vorheriger Titel',
|
||
shortcutVolumeUp: 'Lautstärke erhöhen',
|
||
shortcutVolumeDown: 'Lautstärke verringern',
|
||
shortcutSeekForward: '10s vorspulen',
|
||
shortcutSeekBackward: '10s zurückspulen',
|
||
shortcutToggleQueue: 'Warteschlange ein-/ausblenden',
|
||
shortcutOpenFolderBrowser: '{{folderBrowser}} öffnen',
|
||
shortcutFullscreenPlayer: 'Vollbild-Player',
|
||
shortcutNativeFullscreen: 'Nativer Vollbildmodus',
|
||
shortcutOpenMiniPlayer: 'Mini-Player öffnen',
|
||
shortcutStartSearch: 'Suche starten',
|
||
shortcutStartAdvancedSearch: 'Erweiterte Suche starten',
|
||
shortcutToggleSidebar: 'Seitenleiste umschalten',
|
||
shortcutMuteSound: 'Stumm schalten',
|
||
shortcutToggleEqualizer: 'Equalizer öffnen / umschalten',
|
||
shortcutToggleRepeat: 'Wiederholen umschalten',
|
||
shortcutOpenNowPlaying: '„Now Playing" öffnen',
|
||
shortcutShowLyrics: 'Songtexte anzeigen',
|
||
shortcutFavoriteCurrentTrack: 'Aktuellen Titel zu Favoriten hinzufügen',
|
||
shortcutOpenHelp: 'Hilfe',
|
||
tabSystem: 'System',
|
||
loggingTitle: 'Protokollierung',
|
||
loggingModeDesc: 'Steuert die Ausführlichkeit der Backend-Protokolle im Terminal.',
|
||
loggingModeOff: 'Aus',
|
||
loggingModeNormal: 'Normal',
|
||
loggingModeDebug: 'Debug',
|
||
loggingExport: 'Protokolle exportieren',
|
||
loggingExportSuccess: 'Protokolle exportiert ({{count}} Zeilen).',
|
||
loggingExportError: 'Protokolle konnten nicht exportiert werden.',
|
||
ratingsSectionTitle: 'Bewertungen',
|
||
ratingsSkipStarTitle: 'Skip → 1 Stern',
|
||
ratingsSkipStarDesc:
|
||
'Wird ein Titel mehrmals hintereinander übersprungen, bekommt er automatisch 1★. Nur für noch nicht bewertete Titel.',
|
||
ratingsSkipStarThresholdLabel: 'Skips',
|
||
ratingsMixFilterTitle: 'Nach Bewertung filtern',
|
||
ratingsMixFilterDesc:
|
||
'Gering bewertete Titel in {{mix}} und {{albums}} ausblenden. Nochmals auf den gewählten Stern klicken, um den Filter zu deaktivieren.',
|
||
ratingsMixMinSong: 'Titel',
|
||
ratingsMixMinAlbum: 'Alben',
|
||
ratingsMixMinArtist: 'Interpreten',
|
||
ratingsMixMinThresholdAria: 'Mindest-Sterne: {{label}}',
|
||
backupTitle: 'Backup & Wiederherstellung',
|
||
backupExport: 'Einstellungen exportieren',
|
||
backupExportDesc: 'Speichert alle Einstellungen, Serverprofile, Last.fm-Konfiguration, Theme, EQ und Tastenkürzel in eine .psybkp-Datei. Passwörter werden im Klartext gespeichert — Datei sicher aufbewahren.',
|
||
backupImport: 'Einstellungen importieren',
|
||
backupImportDesc: 'Stellt Einstellungen aus einer .psybkp-Datei wieder her. Die App wird nach dem Import neu geladen.',
|
||
backupImportConfirm: 'Alle aktuellen Einstellungen werden überschrieben. Fortfahren?',
|
||
backupSuccess: 'Backup gespeichert',
|
||
backupImportSuccess: 'Einstellungen wiederhergestellt — wird neu geladen…',
|
||
backupImportError: 'Ungültige oder beschädigte Backup-Datei.',
|
||
playbackTitle: 'Wiedergabe',
|
||
replayGain: 'Replay Gain',
|
||
replayGainDesc: 'Lautstärke mit ReplayGain-Metadaten normalisieren',
|
||
replayGainMode: 'Modus',
|
||
replayGainAuto: 'Auto',
|
||
replayGainAutoDesc: 'Wählt Album-Gain, wenn benachbarte Tracks in der Warteschlange vom selben Album sind, sonst Track-Gain.',
|
||
replayGainTrack: 'Track',
|
||
replayGainAlbum: 'Album',
|
||
replayGainPreGain: 'Pre-Gain (getaggte Dateien)',
|
||
replayGainPreGainDesc: 'Pauschaler Boost, der auf jede ReplayGain-Berechnung aufaddiert wird. Hilft, wenn deine Bibliothek insgesamt zu leise wirkt.',
|
||
replayGainFallback: 'Fallback (ohne Tags / Radio)',
|
||
replayGainFallbackDesc: 'Wird auf Titel (und Radio-Streams) ohne ReplayGain-Tags angewendet, damit Untagged-Inhalt nicht lauter aus dem Mix springt.',
|
||
normalization: 'Normalisierung',
|
||
normalizationDesc: 'Empfundene Lautstärke über Titel, Alben und Radio angleichen.',
|
||
normalizationOff: 'Aus',
|
||
normalizationReplayGain: 'ReplayGain',
|
||
normalizationLufs: 'LUFS',
|
||
loudnessTargetLufs: 'Ziel-LUFS',
|
||
loudnessTargetLufsDesc: 'Referenz-Lautstärke, an die alle Titel angepasst werden. Niedrigere Werte = lautere Ausgabe. Streaming-Dienste liegen meist bei etwa -14 LUFS.',
|
||
loudnessPreAnalysisAttenuation: 'Dämpfung vor Messung',
|
||
loudnessPreAnalysisAttenuationDesc:
|
||
'Zusätzliche Dämpfung, bis die Loudness des Titels gespeichert ist. Beim Streamen folgen nur grobe Schätzungen, keine volle Messung. 0 dB = aus; negativer = leiser. Rechts steht der wirksame dB-Wert für die gewählte Ziel-LUFS.',
|
||
loudnessPreAnalysisAttenuationRef: 'Wirksam {{eff}} dB bei Ziel {{tgt}} LUFS.',
|
||
loudnessPreAnalysisAttenuationReset: 'Standard',
|
||
loudnessFirstPlayNote:
|
||
'Beim ersten Abspielen eines neuen Titels kann die Lautstärke kurz schwanken, während gemessen wird. Beim nächsten Mal greift die gespeicherte Messung und alles bleibt stabil. Kommende Queue-Titel werden meist schon während des vorherigen Songs analysiert — in der Praxis tritt das daher selten auf.',
|
||
crossfade: 'Crossfade',
|
||
crossfadeDesc: 'Überblendung zwischen Tracks',
|
||
crossfadeSecs: '{{n}} s',
|
||
crossfadeTrimSilence: 'Stille zwischen Tracks kürzen',
|
||
crossfadeTrimSilenceDesc: 'Stille am Ende des aktuellen und am Anfang des nächsten Tracks überspringen, damit die Überblendung Musik statt Leere überlappt. Für zuverlässige Ergebnisse den Hot-Playback-Cache aktivieren, damit der nächste Track rechtzeitig bereit ist',
|
||
autoDj: 'AutoDJ',
|
||
autoDjDesc: 'Keine feste Dauer — AutoDJ richtet sich nach dem tatsächlichen Klang und überlappt echte Aus- und Einblendungen statt einer festen Sekundenzahl. Für zuverlässige Ergebnisse den Hot-Playback-Cache aktivieren.',
|
||
notWithGapless: 'Nicht verfügbar wenn Nahtlose Wiedergabe aktiv ist',
|
||
notWithCrossfade: 'Nicht verfügbar wenn Crossfade aktiv ist',
|
||
gapless: 'Nahtlose Wiedergabe',
|
||
gaplessDesc: 'Nächsten Track vorpuffern um Lücken zwischen Songs zu vermeiden',
|
||
preservePlayNextOrder: '„Als Nächstes"-Reihenfolge bewahren',
|
||
preservePlayNextOrderDesc: 'Neu hinzugefügte „Als Nächstes"-Titel reihen sich hinten an statt sich vorn einzuschieben.',
|
||
trackPreviewsTitle: 'Track-Vorschau',
|
||
trackPreviewsToggle: 'Track-Vorschau aktivieren',
|
||
trackPreviewsDesc: 'Inline Play- und Vorschau-Buttons in den Tracklisten anzeigen für eine kurze Hörprobe mitten im Song.',
|
||
trackPreviewStart: 'Startposition',
|
||
trackPreviewStartDesc: 'Wie weit der Track schon gespielt sein soll wenn die Vorschau startet (% der Länge).',
|
||
trackPreviewDuration: 'Dauer',
|
||
trackPreviewDurationDesc: 'Wie lange jede Vorschau spielt bevor sie automatisch stoppt.',
|
||
trackPreviewDurationSecs: '{{n}} s',
|
||
trackPreviewLocationsTitle: 'Wo Vorschauen erscheinen',
|
||
trackPreviewLocationsDesc: 'Wähle aus, in welchen Listen die Vorschau-Buttons angezeigt werden.',
|
||
trackPreviewLocation_suggestions: 'In Playlist-Vorschlägen',
|
||
trackPreviewLocation_albums: 'In Album-Tracklisten',
|
||
trackPreviewLocation_playlists: 'In Playlists',
|
||
trackPreviewLocation_favorites: 'In Favoriten',
|
||
trackPreviewLocation_artist: 'In Künstler-Top-Tracks',
|
||
trackPreviewLocation_randomMix: 'In Random Mix',
|
||
nextTrackBufferingTitle: 'Pufferung',
|
||
infiniteQueue: 'Endlose Warteschlange',
|
||
infiniteQueueDesc: 'Automatisch Zufallstitel anhängen wenn die Warteschlange leer wird',
|
||
experimental: 'Experimentell',
|
||
sidebarLyricsStyle: 'Text-Scroll-Stil',
|
||
sidebarLyricsStyleClassic: 'Klassisch',
|
||
sidebarLyricsStyleClassicDesc: 'Aktive Zeile wird zentriert.',
|
||
sidebarLyricsStyleApple: 'Apple Music-like',
|
||
sidebarLyricsStyleAppleDesc: 'Aktive Zeile oben mit sanfter Animation.',
|
||
seekbarStyle: 'Seekbar-Stil',
|
||
seekbarStyleDesc: 'Aussehen der Wiedergabe-Seekbar auswählen',
|
||
seekbarTruewave: 'Echte Wellenform',
|
||
seekbarPseudowave: 'Pseudo-Wellenform',
|
||
seekbarLinedot: 'Linie & Punkt',
|
||
seekbarBar: 'Balken',
|
||
seekbarThick: 'Dicker Balken',
|
||
seekbarSegmented: 'Segmentiert',
|
||
seekbarNeon: 'Neonröhre',
|
||
seekbarPulsewave: 'Pulswelle',
|
||
seekbarParticletrail: 'Partikel-Spur',
|
||
seekbarLiquidfill: 'Flüssigkeit',
|
||
seekbarRetrotape: 'Retro-Band',
|
||
themeSchedulerTitle: 'Theme-Zeitplan',
|
||
themeSchedulerEnable: 'Theme-Zeitplan aktivieren',
|
||
themeSchedulerEnableSub: 'Wechselt automatisch zwischen zwei Themes basierend auf der Uhrzeit',
|
||
themeSchedulerDayTheme: 'Tages-Theme',
|
||
themeSchedulerDayStart: 'Tag beginnt um',
|
||
themeSchedulerNightTheme: 'Nacht-Theme',
|
||
themeSchedulerNightStart: 'Nacht beginnt um',
|
||
themeSchedulerActiveHint: 'Theme-Zeitplan ist aktiv - Themes werden automatisch gewechselt.',
|
||
visualOptionsTitle: 'Visuelle Optionen',
|
||
coverArtBackground: 'Cover-Hintergrund',
|
||
coverArtBackgroundSub: 'Zeigt verschwommenes Cover als Hintergrund in Album/Playlist-Kopfzeilen',
|
||
playlistCoverPhoto: 'Playlist-Coverfoto',
|
||
playlistCoverPhotoSub: 'Zeigt Coverfoto-Raster in der Playlist-Detailansicht',
|
||
showBitrate: 'Bitrate anzeigen',
|
||
showBitrateSub: 'Audio-Bitrate in Track-Listen anzeigen',
|
||
floatingPlayerBar: 'Schwebende Player-Leiste',
|
||
floatingPlayerBarSub: 'Player-Leiste über dem Inhalt schweben lassen',
|
||
uiScaleTitle: 'Interface-Skalierung',
|
||
uiScaleLabel: 'Zoom',
|
||
waveformCacheClearBtn: 'Waveform-Cache leeren',
|
||
waveformCacheCleared: 'Waveform-Cache geleert ({{count}} Zeilen).',
|
||
waveformCacheClearFailed: 'Waveform-Cache konnte nicht geleert werden.',
|
||
analyticsStrategyTitle: 'Analysestrategien',
|
||
analyticsStrategyDesc: 'Wähle den Analysemodus für die Bibliothek.',
|
||
analyticsStrategyLabel: 'Strategie',
|
||
analyticsStrategyLazy: 'Lazy',
|
||
analyticsStrategyLazyDesc: 'Analysiert nur, wenn Tracks abgespielt werden oder in den Hot-/Offline-Cache kommen — minimale CPU- und Netzlast.',
|
||
analyticsStrategyAdvanced: 'Aggressiv',
|
||
analyticsStrategyAdvancedDesc: 'Aggressiver Hintergrundscan. Nach Abschluss erhältst du BPM für alle Tracks sowie sofort verfügbare Loudness- und Waveform-Daten.',
|
||
analyticsStrategyPriorityTitle: 'Analyse-Priorität (immer aktiv)',
|
||
analyticsStrategyPriorityHigh: '1 — Aktuell laufender Track: zuerst herunterladen und analysieren (Playback-Bytes, Loudness-Backfill oder HTTP falls nötig).',
|
||
analyticsStrategyPriorityMiddle: '2 — Als Nächstes: die nächsten ~5 Queue-Tracks und Hot-Cache-Nachbarn — Analyse bevorzugt aus Cache/Downloads; HTTP-Backfill nur bei Miss.',
|
||
analyticsStrategyPriorityLow: '3 — Bibliotheks-Batch (nur Aggressiv): automatische Hintergrund-Queue am Ende; wird per Watermark (~3× Worker) nachgefüllt, ohne auf eine leere Queue zu warten.',
|
||
analyticsStrategyServerLabel: 'Server',
|
||
analyticsStrategyProgressLabel: 'Analysefortschritt:',
|
||
analyticsStrategyProgressValue: '{{percent}}% ({{done}}/{{total}})',
|
||
analyticsStrategyActionsLabel: 'Aktionen',
|
||
analyticsStrategyParallelismLabel: 'Parallele Worker',
|
||
analyticsStrategyParallelismValue: '{{n}} Threads',
|
||
analyticsStrategyParallelismDesc: 'Wie viele Tracks gleichzeitig heruntergeladen und analysiert werden (HTTP + CPU). Höhere Werte beschleunigen das Aufholen der Bibliothek, nutzen aber mehr Netz und CPU.',
|
||
analyticsStrategyAdvancedWarning: 'Aggressiv nutzt mehr CPU und Netzwerkbandbreite, während der Bibliotheks-Batch im Hintergrund läuft.',
|
||
analyticsStrategyServerRemoved: 'Entfernter Server',
|
||
analyticsStrategyClearAction: 'Analyse löschen',
|
||
analyticsStrategyClearTitle: 'Analyse löschen?',
|
||
analyticsStrategyClearDesc: 'Das Löschen der Analyse für {{server}} entfernt zwischengespeicherte Waveforms und Loudness-Daten. Beim späteren erneuten Hinzufügen kann eine lange Neuindizierung nötig sein.',
|
||
analyticsStrategyClearCancel: 'Abbrechen',
|
||
analyticsStrategyClearConfirm: 'Analyse löschen',
|
||
analyticsStrategyClearSuccess: 'Analyse für den entfernten Server wurde gelöscht.',
|
||
analyticsStrategyClearError: 'Analyse für den entfernten Server konnte nicht gelöscht werden.',
|
||
analyticsStrategyProgressEmptyAfterFailed: '100% (0/0, durch fehlgeschlagene Tracks blockiert)',
|
||
analyticsFailedTracksOpenTitle: 'Fehlgeschlagene Tracks: {{count}}',
|
||
analyticsFailedTracksTitle: 'Fehlgeschlagene Analyse-Tracks — {{server}}',
|
||
analyticsFailedTracksDesc: 'Diese Tracks sind bei Decode/Enrichment wiederholt fehlgeschlagen und vom automatischen Hintergrund-Analyseprozess ausgeschlossen.',
|
||
analyticsFailedTracksLoading: 'Liste fehlgeschlagener Tracks wird geladen…',
|
||
analyticsFailedTracksEmpty: 'Für diesen Server gibt es keine fehlgeschlagenen Tracks.',
|
||
analyticsFailedTracksClose: 'Schließen',
|
||
analyticsFailedTracksExport: 'Liste exportieren',
|
||
analyticsFailedTracksExportSuccess: 'Liste fehlgeschlagener Tracks exportiert ({{count}}).',
|
||
analyticsFailedTracksExportError: 'Liste fehlgeschlagener Tracks konnte nicht exportiert werden.',
|
||
analyticsFailedTracksRescan: 'Fehlgeschlagene Tracks neu scannen',
|
||
analyticsFailedTracksRescanSuccess: 'Neu-Scan für {{count}} fehlgeschlagene Tracks eingeplant.',
|
||
analyticsFailedTracksRescanError: 'Neu-Scan fehlgeschlagener Tracks konnte nicht gestartet werden.',
|
||
analyticsFailedTracksLoadError: 'Fehlgeschlagene Tracks konnten nicht geladen werden.',
|
||
backupImportAny: 'Backup importieren',
|
||
backupImportAnyConfirm: 'Ausgewählte Backup-Datei importieren und Inhalt anwenden (Einstellungen, Bibliotheksdatenbanken oder vollständig). Fortfahren?',
|
||
backupModeFull: 'Vollständig',
|
||
backupModeLibrary: 'Bibliotheksdatenbanken',
|
||
backupModeConfig: 'Konfiguration',
|
||
backupFullDesc: 'Archiviert Einstellungen und Bibliotheksdatenbanken in einer Backup-Datei.',
|
||
backupFullExport: 'Vollständiges Backup exportieren',
|
||
backupFullImport: 'Vollständiges Backup importieren',
|
||
backupFullImportConfirm: 'Dadurch werden Einstellungen überschrieben, aktuelle Bibliotheksdatenbanken ersetzt und nach .bak verschoben. Fortfahren?',
|
||
backupFullExportSuccess: 'Vollständiges Backup exportiert.',
|
||
backupFullImportSuccess: 'Vollständiges Backup importiert — lade neu…',
|
||
backupFullImportError: 'Vollständiges Backup konnte nicht importiert werden.',
|
||
backupLibraryExport: 'Datenbanken exportieren',
|
||
backupLibraryExportDesc: 'Erstellt ein komprimiertes Archiv mit sauberen SQLite-Snapshots der Bibliotheksdatenbanken.',
|
||
backupLibraryImport: 'Datenbanken importieren',
|
||
backupLibraryImportDesc: 'Stellt Bibliotheksdatenbanken aus einer Archivdatei wieder her. Aktuelle Datenbanken werden vor dem Wechsel nach .bak verschoben.',
|
||
backupLibraryImportConfirm: 'Dadurch werden aktuelle Bibliotheksdatenbanken ersetzt und nach .bak verschoben. Fortfahren?',
|
||
backupLibraryExportSuccess: 'Datenbank-Backup exportiert.',
|
||
backupLibraryImportSuccess: 'Datenbank-Backup importiert.',
|
||
backupLibraryImportError: 'Datenbank-Backup konnte nicht importiert werden.',
|
||
backupOverlayExportTitle: 'Backup wird erstellt…',
|
||
backupOverlayImportTitle: 'Backup wird wiederhergestellt…',
|
||
backupOverlayHint: 'Das Fenster kann geöffnet bleiben, während wir Dateien verarbeiten. Eingaben sind vorübergehend gesperrt.',
|
||
};
|