Compare commits

...

6 Commits

Author SHA1 Message Date
Hosted Weblate 324936e0c8 Translated using Weblate
Currently translated at 100.0% (1208 of 1208 strings) (Chinese (Traditional Han script))
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/zh_Hant/

Translated using Weblate

Currently translated at 100.0% (1208 of 1208 strings) (Catalan)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/ca/

Co-authored-by: Ondo <SparkyOndo@proton.me>
Co-authored-by: York <goog10216922@gmail.com>
2026-05-05 05:09:50 +00:00
Hosted Weblate 868ec15b16 Added translation using Weblate (Thai)
Translated using Weblate

Currently translated at 100.0% (1208 of 1208 strings) (Spanish)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/es/

Translated using Weblate

Currently translated at 100.0% (1208 of 1208 strings) (Polish)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/pl/

Translated using Weblate

Currently translated at 100.0% (1208 of 1208 strings) (Czech)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/cs/

Co-authored-by: Anucha Hlownonkor <anucha.initdz@gmail.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: Fordas <fordas15@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: skajmer <skajmer@protonmail.com>
2026-05-03 12:06:39 +02:00
Hosted Weblate 775c4e68fa Translated using Weblate
Currently translated at 81.3% (981 of 1206 strings) (Russian)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/ru/

Translated using Weblate

Currently translated at 100.0% (1206 of 1206 strings) (Chinese (Traditional Han script))
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/zh_Hant/

Translated using Weblate

Currently translated at 85.6% (1033 of 1206 strings) (Basque)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/eu/

Co-authored-by: Aitor Astorga <a.astorga.sdv@protonmail.com>
Co-authored-by: York <goog10216922@gmail.com>
Co-authored-by: spoon <monkeyfart907@gmail.com>
2026-05-02 04:34:18 +00:00
jeffvli 34e0c4bd4a prevent first lyric line highlight before timestamp (#1965) 2026-05-01 21:33:40 -07:00
jeffvli 323130a877 add toggle for app-suspension for powersave block (#1992) 2026-05-01 21:24:45 -07:00
jeffvli 3b2aab74ac enforce web player seek by seconds when less than 1 (#1993) 2026-05-01 21:12:20 -07:00
16 changed files with 208 additions and 55 deletions
+5 -2
View File
@@ -409,7 +409,8 @@
"input_skipDuplicates": "salta't els duplicats",
"success": "s'ha afegit $t(entity.trackWithCount, {\"count\": {{message}} }) a $t(entity.playlistWithCount, {\"count\": {{numOfPlaylists}} })",
"create": "crea $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "cerca $t(entity.playlist, {\"count\": 2}) o escriu per crear-ne una de nova"
"searchOrCreate": "cerca $t(entity.playlist, {\"count\": 2}) o escriu per crear-ne una de nova",
"noneAdded": "no s'han afegit pistes a la $t(entity.playlist, {\"count\": 1}) '{{playlist}}'"
},
"createPlaylist": {
"input_description": "$t(common.description)",
@@ -935,7 +936,9 @@
"sidePlayQueueLayout_optionHorizontal": "horitzontal",
"sidePlayQueueLayout_optionVertical": "vertical",
"waveformLoadingDelay": "demora de càrrega de la forma d'ona",
"waveformLoadingDelay_description": "demora en segons abans de carregar la forma d'ona. incrementeu aquest valor si patiu interrupcions en fer servir el reproductor web."
"waveformLoadingDelay_description": "demora en segons abans de carregar la forma d'ona. incrementeu aquest valor si patiu interrupcions en fer servir el reproductor web.",
"preventSuspendOnPlayback_description": "evita que l'aplicació quedi suspesa mentre es reprodueix música",
"preventSuspendOnPlayback": "evita la suspensió durant la reproducció"
},
"table": {
"column": {
+5 -2
View File
@@ -427,7 +427,9 @@
"waveformLoadingDelay": "zpoždění načítání vlnové křivky",
"waveformLoadingDelay_description": "zpoždění v sekundách před načtením vlnové křivky. zvyšte, pokud jste během používání webového přehrávače zaznamenali záseky.",
"playerbarWaveformStretch": "natáhnutí vlnové křivky",
"playerbarWaveformStretch_description": "natáhně vlnovou křivku tak, aby vyplnila dostupný prostor"
"playerbarWaveformStretch_description": "natáhně vlnovou křivku tak, aby vyplnila dostupný prostor",
"preventSuspendOnPlayback_description": "zabránit aplikaci v uspání během přehrávání hudby",
"preventSuspendOnPlayback": "zabránit uspání při přehrávání"
},
"action": {
"editPlaylist": "upravit $t(entity.playlist, {\"count\": 1})",
@@ -1045,7 +1047,8 @@
"input_skipDuplicates": "přeskočit duplicity",
"input_playlists": "$t(entity.playlist, {\"count\": 2})",
"create": "vytvořit $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "vyhledejte $t(entity.playlist, {\"count\": 2}) nebo pište pro vytvoření nového"
"searchOrCreate": "vyhledejte $t(entity.playlist, {\"count\": 2}) nebo pište pro vytvoření nového",
"noneAdded": "do $t(entity.playlist, {\"count\": 1}) '{{playlist}}' nebyly přidány žádné skladby"
},
"updateServer": {
"title": "upravit server",
+2
View File
@@ -1008,6 +1008,8 @@
"audioFadeOnStatusChange_description": "enables fade out and fade in when play/pause status changes",
"preventSleepOnPlayback_description": "prevent the display from sleeping while music is playing",
"preventSleepOnPlayback": "prevent sleep on playback",
"preventSuspendOnPlayback_description": "prevent the application from suspending while music is playing",
"preventSuspendOnPlayback": "prevent suspend on playback",
"remotePassword_description": "sets the password for the remote control server. These credentials are by default transferred insecurely, so you should use a unique password that you do not care about",
"remotePassword": "remote control server password",
"remotePort_description": "sets the port for the remote control server",
+5 -2
View File
@@ -427,7 +427,9 @@
"waveformLoadingDelay": "Retraso de carga de la forma de onda",
"waveformLoadingDelay_description": "Retraso en segundos antes de cargar la forma de onda. Incrementa este valor si estás experimentando tartamudeos al usar el reproductor web.",
"playerbarWaveformStretch": "Estiramiento de la forma de onda",
"playerbarWaveformStretch_description": "Estira la forma de onda para rellenar el espacio disponible"
"playerbarWaveformStretch_description": "Estira la forma de onda para rellenar el espacio disponible",
"preventSuspendOnPlayback": "Evitar la suspensión durante la reproducción",
"preventSuspendOnPlayback_description": "Evita que la aplicación se suspenda mientras se reproduce música"
},
"action": {
"editPlaylist": "editar $t(entity.playlist, {\"count\": 1})",
@@ -936,7 +938,8 @@
"input_skipDuplicates": "saltar duplicados",
"input_playlists": "$t(entity.playlist, {\"count\": 2})",
"create": "Crear $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "Buscar $t(entity.playlist, {\"count\": 2}) o escribir para crear uno nuevo"
"searchOrCreate": "Buscar $t(entity.playlist, {\"count\": 2}) o escribir para crear uno nuevo",
"noneAdded": "Ninguna pista fue añadida a $t(entity.playlist, {\"count\": 1}) '{{playlist}}'"
},
"updateServer": {
"title": "actualizar servidor",
+50 -9
View File
@@ -157,7 +157,8 @@
"doNotShowAgain": "ez erakutsi hau berriro",
"numberOfResults": "{{numberOfResults}} emaitza",
"rename": "berrizendatu",
"newVersionAvailable": "bertsio berri bat eskuragarri dago"
"newVersionAvailable": "bertsio berri bat eskuragarri dago",
"gridRows": "sareta-errenkadak"
},
"player": {
"repeat": "errepikatu",
@@ -409,7 +410,8 @@
"fromYear": "urtetik aurrera",
"explicitStatus": "$t(common.explicitStatus)",
"matchAnd": "eta",
"matchOr": "edo"
"matchOr": "edo",
"sortName": "izenaren arabera ordenatu"
},
"setting": {
"hotkey_playbackPause": "pausatu",
@@ -643,7 +645,7 @@
"passwordStore_description": "zein pasahitz/sekretu biltegi erabili. aldatu hau pasahitzak gordetzeko arazoak badituzu",
"playerFilters": "Iragazi ilarako abestiak",
"sidePlayQueueStyle_description": "alboko erreprodukzio-ilararen estiloa ezartzen du",
"mediaSession_description": "Windows Media Session integrazioa gaitzen du, multimedia kontrolak eta metadatuak sistemaren bolumenaren gainjartzean eta blokeo pantailan bistaratuz (Windows bakarrik)",
"mediaSession_description": "Media Session integrazioa gaitzen du, multimedia kontrolak eta metadatuak sistemaren bolumenaren gainjartzean eta blokeo pantailan bistaratuz",
"sidePlayQueueStyle": "alboko erreprodukzio-ilarako estiloa",
"skipPlaylistPage": "saltatu erreprodukzio-zerrenda orria",
"startMinimized_description": "abiarazi aplikazioa sistemaren erretiluan",
@@ -714,7 +716,19 @@
"preservePitch": "mantendu tonua",
"preventSleepOnPlayback": "erreprodukzioan loa saihestu",
"replayGainClipping_description": "Saihestu {{ReplayGain}}-k eragindako mozketa irabazpena automatikoki jaitsiz",
"replayGainMode_description": "doitu bolumenaren irabazia fitxategiaren metadatuetan gordetako {{ReplayGain}} balioen arabera"
"replayGainMode_description": "doitu bolumenaren irabazia fitxategiaren metadatuetan gordetako {{ReplayGain}} balioen arabera",
"listenbrainz": "erakutsi ListenBrainz estekak",
"sidebarPlaylistSorting": "alboko barrako erreprodukzio-zerrenda ordenatzea",
"sidebarPlaylistListFilterRegex_description": "ezkutatu alboko barran adierazpen erregular honekin bat datozen erreprodukzio-zerrendak",
"sidebarPlaylistListFilterRegex_placeholder": "adib. ^Eguneroko Nahasketa.*",
"sidebarPlaylistListFilterRegex": "erreprodukzio-zerrenda iragazteko adierazpen erregularra",
"sidePlayQueueLayout": "alboko erreprodukzio-ilararen diseinua",
"sidePlayQueueLayout_description": "erantsitako alboko erreprodukzio-ilararen diseinua ezartzen du",
"sidePlayQueueLayout_optionHorizontal": "horizontala",
"sidePlayQueueLayout_optionVertical": "bertikala",
"skipDuration_description": "erreproduzitzailearen barran saltatzeko botoiak erabiltzean saltatzeko iraupena ezartzen du",
"skipPlaylistPage_description": "erreprodukzio-zerrenda batera nabigatzean, joan erreprodukzio-zerrendako abestien zerrendara lehenetsitako orrialdera joan beharrean",
"translationApiKey_description": "itzulpenerako api gakoa (zerbitzu globalaren amaiera-puntua soilik)"
},
"form": {
"addServer": {
@@ -731,7 +745,9 @@
"success": "zerbitzaria behar bezala gehitu da",
"input_preferInstantMix": "nahiago izan berehalako nahasketa",
"input_preferInstantMixDescription": "erabili berehalako nahasketa soilik antzeko abestiak lortzeko. erabilgarria portaera hau aldatzen duten pluginak badituzu",
"input_remoteUrl": "URL publikoa"
"input_remoteUrl": "URL publikoa",
"input_preferRemoteUrl": "url publikoa nahiago izan",
"input_remoteUrlPlaceholder": "aukerakoa: kanpoko funtzioetarako url publikoa"
},
"addToPlaylist": {
"input_playlists": "$t(entity.playlist, {\"count\": 2})",
@@ -739,7 +755,8 @@
"input_skipDuplicates": "saltatu bikoiztuak",
"title": "gehitu $t(entity.playlist, {\"count\": 1})-(a)ri",
"create": "sortu $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "bilatu $t(entity.playlist, {\"count\": 2}) edo idatzi berri bat sortzeko"
"searchOrCreate": "bilatu $t(entity.playlist, {\"count\": 2}) edo idatzi berri bat sortzeko",
"noneAdded": "ez da pistarik gehitu honi $t(entity.playlist, {\"count\": 1}) '{{playlist}}'"
},
"createPlaylist": {
"input_description": "$t(common.description)",
@@ -760,7 +777,9 @@
"success": "partekatzeko esteka arbelera kopiatu da (edo egin klik hemen irekitzeko)",
"expireInvalid": "iraungitze-data etorkizunean izan behar da",
"allowDownloading": "baimendu deskargatzea",
"createFailed": "partekatzea sortzeak huts egin du (partekatzea gaituta al dago?)"
"createFailed": "partekatzea sortzeak huts egin du (partekatzea gaituta al dago?)",
"copyToClipboard": "Kopiatu arbelean: Ctrl+C, Enter",
"successMustClick": "partekatzea behar bezala sortu da. egin klik hemen irekitzeko"
},
"deletePlaylist": {
"success": "$t(entity.playlist, {\"count\": 1}) behar bezala ezabatu da",
@@ -988,7 +1007,10 @@
"recentReleases": "azken argitalpenak",
"viewDiscography": "ikusi diskografia",
"groupingTypeAll": "argitalpen mota guztiak",
"groupingTypePrimary": "argitalpen mota nagusiak"
"groupingTypePrimary": "argitalpen mota nagusiak",
"favoriteSongs": "abesti gogokoenak",
"topSongsCommunity": "komunitatea",
"topSongsPersonal": "pertsonala"
},
"itemDetail": {
"copyPath": "kopiatu bidea arbelean",
@@ -1006,6 +1028,13 @@
},
"radioList": {
"title": "irrati-kateak"
},
"releasenotes": {
"noStableReleaseToCompare": "ez dago bertsio egonkorrik alderatzeko"
},
"windowBar": {
"paused": "(Pausatuta) ",
"privateMode": "(Modu pribatua)"
}
},
"releaseType": {
@@ -1038,7 +1067,19 @@
"notContains": "ez dauka",
"startsWith": "honekin hasten da",
"endsWith": "honekin amaitzen da",
"isNot": "ez da"
"isNot": "ez da",
"afterDate": "(data) ondoren da",
"after": "ondoren da",
"before": "lehenago da",
"beforeDate": "(data) baino lehenagokoa da",
"inTheLast": "azkenengoan dago",
"inPlaylist": "bertan dago",
"inTheRange": "tartean dago",
"inTheRangeDate": "(data) tartean dago",
"isGreaterThan": "hau baino handiagoa da",
"isLessThan": "hau baino gutxiago da",
"notInPlaylist": "ez dago barruan",
"notInTheLast": "ez dago azkenengoan"
},
"visualizer": {
"general": "Orokorra",
+7 -2
View File
@@ -352,7 +352,8 @@
"input_skipDuplicates": "pomiń duplikaty",
"input_playlists": "$t(entity.playlist, {\"count\": 2})",
"create": "utwórz $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "wyszukaj $t(entity.playlist, {\"count\": 2}) lub wpisz, aby utworzyć nową"
"searchOrCreate": "wyszukaj $t(entity.playlist, {\"count\": 2}) lub wpisz, aby utworzyć nową",
"noneAdded": "nie dodano utworów do $t(entity.playlist, {\"count\": 1}) '{{playlist}}'"
},
"updateServer": {
"title": "uaktualnij serwer",
@@ -1066,7 +1067,11 @@
"sidePlayQueueLayout_optionHorizontal": "poziomy",
"sidePlayQueueLayout_optionVertical": "pionowy",
"waveformLoadingDelay": "opóźnienie załadowania fali",
"waveformLoadingDelay_description": "opóźnienie w sekundach przed załadowaniem fali. zwiększ tą wartość jeżeli doświadczasz zawieszania się odtwarzacza przeglądarkowego."
"waveformLoadingDelay_description": "opóźnienie w sekundach przed załadowaniem fali. zwiększ tą wartość jeżeli doświadczasz zawieszania się odtwarzacza przeglądarkowego.",
"playerbarWaveformStretch": "rozciąganie przebiegu",
"playerbarWaveformStretch_description": "rozciąga przebieg aby wypełnić dostępną przestrzeń",
"preventSuspendOnPlayback_description": "powstrzymuj wstrzymanie podczas odtwarzania muzyki",
"preventSuspendOnPlayback": "powstrzymuje wstrzymanie przy odtwarzaniu"
},
"table": {
"config": {
+37 -10
View File
@@ -170,7 +170,8 @@
"explicit": "нецензурная лексика",
"externalLinks": "внешние ссылки",
"explicitStatus": "признак нецензурного контента",
"newVersionAvailable": "доступна новая версия"
"newVersionAvailable": "доступна новая версия",
"numberOfResults": "{{numberOfResults}} результатов"
},
"entity": {
"album_one": "альбом",
@@ -438,7 +439,17 @@
"home": "$t(common.home)",
"myLibrary": "Моя библиотека",
"shared": "Публичные плейлисты $t(entity.playlist, {\"count\": 2})",
"collections": "коллекции"
"collections": "коллекции",
"albumArtists": "$t(entity.albumArtist, {\"count\": 2})",
"albums": "$t(entity.album, {\"count\": 2})",
"artists": "$t(entity.artist, {\"count\": 2})",
"favorites": "$t(entity.favorite, {\"count\": 2})",
"folders": "$t(entity.folder, {\"count\": 2})",
"genres": "$t(entity.genre, {\"count\": 2})",
"radio": "$t(entity.radioStation, {\"count\": 2})",
"playlists": "$t(entity.playlist, {\"count\": 2})",
"settings": "$t(common.setting, {\"count\": 2})",
"tracks": "$t(entity.track, {\"count\": 2})"
},
"fullscreenPlayer": {
"config": {
@@ -455,7 +466,9 @@
"useImageAspectRatio": "использовать соотношение сторон изображения",
"lyricGap": "пробел между словами",
"dynamicIsImage": "включить фоновое изображение",
"dynamicImageBlur": "сила размытия изображения"
"dynamicImageBlur": "сила размытия изображения",
"lyricOpacityNonActive": "непрозрачность неактивных слов",
"lyricScaleNonActive": "размер неактивных слов"
},
"upNext": "играет",
"lyrics": "слова",
@@ -478,7 +491,8 @@
"selectMusicFolder": "выбрать папку с музыкой",
"noMusicFolder": "папка с музыкой не выбрана",
"multipleMusicFolders": "{{count}} выбрано музыкальных папок",
"commandPalette": "открыть командную строку"
"commandPalette": "открыть командную строку",
"settings": "$t(common.setting, {\"count\": 2})"
},
"manageServers": {
"title": "сервера",
@@ -522,7 +536,8 @@
"title": "$t(common.home)",
"explore": "откройте новое",
"recentlyPlayed": "игралось недавно",
"recentlyReleased": "Новинки"
"recentlyReleased": "Новинки",
"genres": "$t(entity.genre, {\"count\": 2})"
},
"albumDetail": {
"moreFromArtist": "больше от $t(entity.artist, {\"count\": 1})",
@@ -556,10 +571,13 @@
},
"genreList": {
"showAlbums": "показать $t(entity.genre, {\"count\": 1}) $t(entity.album, {\"count\": 2})",
"showTracks": "показать $t(entity.genre, {\"count\": 1}) $t(entity.track, {\"count\": 2})"
"showTracks": "показать $t(entity.genre, {\"count\": 1}) $t(entity.track, {\"count\": 2})",
"title": "$t(entity.genre, {\"count\": 2})"
},
"trackList": {
"artistTracks": "Треки {{artist}}"
"artistTracks": "Треки {{artist}}",
"genreTracks": "\"{{genre}}\" $t(entity.track, {\"count\": 2})",
"title": "$t(entity.track, {\"count\": 2})"
},
"globalSearch": {
"commands": {
@@ -620,6 +638,12 @@
},
"favorites": {
"title": "$t(entity.favorite, {\"count\": 2})"
},
"folderList": {
"title": "$t(entity.folder, {\"count\": 2})"
},
"playlistList": {
"title": "$t(entity.playlist, {\"count\": 2})"
}
},
"form": {
@@ -660,7 +684,8 @@
"input_skipDuplicates": "не добавлять дубликаты",
"create": "создать $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "для создания нового списка выполните поиск по $t(entity.playlist, {\"count\": 2}) или введите соответствующий текст",
"input_playlists": "$t(entity.playlist, {\"count\": 2})"
"input_playlists": "$t(entity.playlist, {\"count\": 2})",
"noneAdded": "в плейлист $t(entity.playlist, {\"count\": 1}) '{{playlist}}' не было добавлено ни одного трека"
},
"updateServer": {
"title": "обновление сервера",
@@ -1060,7 +1085,8 @@
"audioFadeOnStatusChange": "плавное изменение звука",
"audioFadeOnStatusChange_description": "включает эффекты затухания и появления звука при изменении статуса (пауза/проигрывание)",
"preventSleepOnPlayback_description": "запрещает спящий режим экрана, пока играет музыка",
"preventSleepOnPlayback": "не переходить в спящий режим"
"preventSleepOnPlayback": "не переходить в спящий режим",
"discordLinkType_none": "$t(common.none)"
},
"releaseType": {
"secondary": {
@@ -1081,7 +1107,8 @@
"other": "другие",
"broadcast": "транслировать",
"ep": "эп",
"single": "сингл"
"single": "сингл",
"album": "$t(entity.album, {\"count\": 1})"
}
},
"datetime": {
+1
View File
@@ -0,0 +1 @@
{}
+5 -2
View File
@@ -796,7 +796,9 @@
"waveformLoadingDelay": "波形載入延遲",
"waveformLoadingDelay_description": "載入波形前的延遲(以秒為單位)。如果您在使用網頁播放器時遇到卡頓,請增加此值。",
"playerbarWaveformStretch": "波形拉伸",
"playerbarWaveformStretch_description": "拉伸波形來填補可用空間"
"playerbarWaveformStretch_description": "拉伸波形來填補可用空間",
"preventSuspendOnPlayback_description": "音樂播放時防止應用程式進入休眠",
"preventSuspendOnPlayback": "在播放時防止應用程式暫停"
},
"table": {
"config": {
@@ -1046,7 +1048,8 @@
"success": "新增 $t(entity.trackWithCount, {\"count\": {{message}} }) 到 $t(entity.playlistWithCount, {\"count\": {{numOfPlaylists}} })",
"title": "新增到$t(entity.playlist, {\"count\": 1})",
"create": "建立 $t(entity.playlist, {\"count\": 1}) {{playlist}}",
"searchOrCreate": "搜尋$t(entity.playlist, {\"count\": 2}) 或輸入內容以建立新項目"
"searchOrCreate": "搜尋$t(entity.playlist, {\"count\": 2}) 或輸入內容以建立新項目",
"noneAdded": "沒有曲目新增到 $t(entity.playlist, {\"count\": 1}) '{{playlist}}'"
},
"createPlaylist": {
"input_description": "$t(common.description)",
+4 -2
View File
@@ -931,12 +931,14 @@ ipcMain.on(
},
);
ipcMain.handle('power-save-blocker-start', () => {
ipcMain.handle('power-save-blocker-start', (_event, { full }: { full: boolean }) => {
if (powerSaveBlockerId !== null) {
return powerSaveBlockerId;
}
powerSaveBlockerId = powerSaveBlocker.start('prevent-display-sleep');
powerSaveBlockerId = powerSaveBlocker.start(
full ? 'prevent-display-sleep' : 'prevent-app-suspension',
);
return powerSaveBlockerId;
});
@@ -95,18 +95,20 @@ export const SynchronizedLyrics = ({
const programmaticScrollRef = useRef(false);
const getCurrentLyric = (timeInMs: number) => {
if (lyricRef.current) {
const activeLyrics = lyricRef.current;
for (let idx = 0; idx < activeLyrics.length; idx += 1) {
if (timeInMs <= activeLyrics[idx][0]) {
return idx === 0 ? idx : idx - 1;
}
}
return activeLyrics.length - 1;
const activeLyrics = lyricRef.current;
if (!activeLyrics?.length) {
return -1;
}
return -1;
let index = -1;
for (let idx = 0; idx < activeLyrics.length; idx += 1) {
if (timeInMs < activeLyrics[idx][0]) {
break;
}
index = idx;
}
return index;
};
const setCurrentLyricRef = useRef<
@@ -141,7 +143,20 @@ export const SynchronizedLyrics = ({
.forEach((node) => node.classList.remove('active'));
if (index === -1) {
lyricRef.current = null;
const activeLyrics = lyricRef.current;
if (!activeLyrics?.length) {
return;
}
const firstTime = activeLyrics[0][0];
if (timeInMs < firstTime) {
const elapsed = performance.now() - start;
const delay = Math.max(0, firstTime - timeInMs - elapsed);
lyricTimer.current = setTimeout(() => {
setCurrentLyricRef.current(firstTime, nextEpoch, 0);
}, delay);
}
return;
}
@@ -153,7 +168,6 @@ export const SynchronizedLyrics = ({
const offsetTop = currentLyric?.offsetTop - doc?.clientHeight / 2 || 0;
if (currentLyric === null) {
lyricRef.current = null;
return;
}
@@ -140,9 +140,15 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
};
},
seekTo(seekTo: number) {
let type: 'fraction' | 'seconds' | undefined = undefined;
if (seekTo < 1) {
type = 'seconds';
}
playerNum === 1
? player1Ref.current?.seekTo(seekTo)
: player2Ref.current?.seekTo(seekTo);
? player1Ref.current?.seekTo(seekTo, type)
: player2Ref.current?.seekTo(seekTo, type);
},
setVolume(volume: number) {
setInternalVolume1(volume / 100 || 0);
@@ -240,10 +240,16 @@ export function WebPlayer() {
}
}
let type: 'fraction' | 'seconds' | undefined = undefined;
if (timestamp < 1) {
type = 'seconds';
}
if (num === 1) {
playerRef.current?.player1()?.ref?.seekTo(timestamp);
playerRef.current?.player1()?.ref?.seekTo(timestamp, type);
} else {
playerRef.current?.player2()?.ref?.seekTo(timestamp);
playerRef.current?.player2()?.ref?.seekTo(timestamp, type);
}
},
onPlayerStatus: async (properties) => {
@@ -8,17 +8,17 @@ const ipc = isElectron() ? window.api.ipc : null;
export const usePowerSaveBlocker = () => {
const status = usePlayerStatus();
const { preventSleepOnPlayback } = useWindowSettings();
const { preventSleepOnPlayback, preventSuspendOnPlayback } = useWindowSettings();
const startPowerSaveBlocker = useCallback(async () => {
if (!ipc) return;
try {
await ipc.invoke('power-save-blocker-start');
await ipc.invoke('power-save-blocker-start', { full: preventSleepOnPlayback });
} catch (error) {
console.error('Failed to start power save blocker:', error);
}
}, []);
}, [preventSleepOnPlayback]);
const stopPowerSaveBlocker = useCallback(async () => {
if (!ipc) return;
@@ -31,16 +31,21 @@ export const usePowerSaveBlocker = () => {
}, []);
useEffect(() => {
if (!preventSleepOnPlayback) return;
if (!preventSleepOnPlayback || !preventSuspendOnPlayback) return;
if (status === PlayerStatus.PLAYING) {
startPowerSaveBlocker();
} else {
stopPowerSaveBlocker();
}
}, [status, preventSleepOnPlayback, startPowerSaveBlocker, stopPowerSaveBlocker]);
}, [
status,
preventSleepOnPlayback,
startPowerSaveBlocker,
stopPowerSaveBlocker,
preventSuspendOnPlayback,
]);
// Clean up on unmount
useEffect(() => {
return () => {
stopPowerSaveBlocker();
@@ -56,8 +61,11 @@ const PowerSaveBlockerHookInner = () => {
export const PowerSaveBlockerHook = () => {
const isElectronEnv = isElectron();
const preventSleepOnPlayback = useSettingsStore((state) => state.window.preventSleepOnPlayback);
const preventSuspendOnPlayback = useSettingsStore(
(state) => state.window.preventSuspendOnPlayback,
);
if (!isElectronEnv || !preventSleepOnPlayback) {
if (!isElectronEnv || !preventSleepOnPlayback || !preventSuspendOnPlayback) {
return null;
}
@@ -184,7 +184,7 @@ export const WindowSettings = memo(() => {
<Switch
aria-label="Toggle prevent sleep on playback"
defaultChecked={settings.preventSleepOnPlayback}
disabled={!isElectron()}
disabled={!isElectron() || settings.preventSuspendOnPlayback}
onChange={(e) => {
if (!e) return;
localSettings?.set(
@@ -206,6 +206,33 @@ export const WindowSettings = memo(() => {
isHidden: !isElectron(),
title: t('setting.preventSleepOnPlayback', { postProcess: 'sentenceCase' }),
},
{
control: (
<Switch
aria-label="Toggle prevent suspend on playback"
defaultChecked={settings.preventSuspendOnPlayback}
disabled={!isElectron() || settings.preventSleepOnPlayback}
onChange={(e) => {
if (!e) return;
localSettings?.set(
'window_prevent_suspend_on_playback',
e.currentTarget.checked,
);
setSettings({
window: {
preventSuspendOnPlayback: e.currentTarget.checked,
},
});
}}
/>
),
description: t('setting.preventSuspendOnPlayback', {
context: 'description',
postProcess: 'sentenceCase',
}),
isHidden: !isElectron(),
title: t('setting.preventSuspendOnPlayback', { postProcess: 'sentenceCase' }),
},
];
return (
+2
View File
@@ -638,6 +638,7 @@ const WindowSettingsSchema = z.object({
exitToTray: z.boolean(),
minimizeToTray: z.boolean(),
preventSleepOnPlayback: z.boolean(),
preventSuspendOnPlayback: z.boolean(),
releaseChannel: z.enum(['alpha', 'beta', 'latest']),
startMinimized: z.boolean(),
tray: z.boolean(),
@@ -1914,6 +1915,7 @@ const initialState: SettingsState = {
exitToTray: false,
minimizeToTray: false,
preventSleepOnPlayback: false,
preventSuspendOnPlayback: false,
releaseChannel: 'latest',
startMinimized: false,
tray: true,