diff --git a/androidApp/src/main/java/com/maxrave/simpmusic/MainActivity.kt b/androidApp/src/main/java/com/maxrave/simpmusic/MainActivity.kt index 9c352afa1..a0e3531bd 100644 --- a/androidApp/src/main/java/com/maxrave/simpmusic/MainActivity.kt +++ b/androidApp/src/main/java/com/maxrave/simpmusic/MainActivity.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.core.net.toUri import androidx.core.os.LocaleListCompat +import androidx.lifecycle.lifecycleScope import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.NetworkType @@ -30,6 +31,7 @@ import com.maxrave.common.STATUS_DONE import com.maxrave.common.SUPPORTED_LANGUAGE import com.maxrave.common.SUPPORTED_LOCATION import com.maxrave.domain.data.model.intent.GenericIntent +import com.maxrave.domain.manager.DataStoreManager import com.maxrave.domain.mediaservice.handler.MediaPlayerHandler import com.maxrave.domain.mediaservice.handler.ToastType import com.maxrave.logger.Logger @@ -40,6 +42,7 @@ import com.maxrave.simpmusic.service.test.notification.NotifyWork import com.maxrave.simpmusic.utils.ComposeResUtils import com.maxrave.simpmusic.utils.VersionManager import com.maxrave.simpmusic.viewModel.SharedViewModel +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject import org.koin.core.context.loadKoinModules @@ -54,6 +57,7 @@ import java.util.concurrent.TimeUnit class MainActivity : AppCompatActivity() { val viewModel: SharedViewModel by inject() val mediaPlayerHandler by inject() + val dataStoreManager: DataStoreManager by inject() private var mBound = false private var shouldUnbind = false @@ -200,22 +204,30 @@ class MainActivity : AppCompatActivity() { ExistingPeriodicWorkPolicy.KEEP, request, ) - val rssRequest = - PeriodicWorkRequestBuilder( - 24L, - TimeUnit.HOURS, - ).addTag("Blog RSS Worker") - .setConstraints( - Constraints - .Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build(), - ).build() - WorkManager.getInstance(this).enqueueUniquePeriodicWork( - "Blog RSS Worker", - ExistingPeriodicWorkPolicy.KEEP, - rssRequest, - ) + lifecycleScope.launch { + dataStoreManager.blogNotificationEnabled.collect { enabled -> + if (enabled == DataStoreManager.TRUE) { + val rssRequest = + PeriodicWorkRequestBuilder( + 24L, + TimeUnit.HOURS, + ).addTag("Blog RSS Worker") + .setConstraints( + Constraints + .Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build(), + ).build() + WorkManager.getInstance(this@MainActivity).enqueueUniquePeriodicWork( + "Blog RSS Worker", + ExistingPeriodicWorkPolicy.KEEP, + rssRequest, + ) + } else { + WorkManager.getInstance(this@MainActivity).cancelUniqueWork("Blog RSS Worker") + } + } + } if (!EasyPermissions.hasPermissions(this, Manifest.permission.POST_NOTIFICATIONS)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/composeApp/proguard-desktop-rules.pro b/composeApp/proguard-desktop-rules.pro index bfcc6a5d8..7ab0b3862 100644 --- a/composeApp/proguard-desktop-rules.pro +++ b/composeApp/proguard-desktop-rules.pro @@ -1,3 +1,11 @@ +# ProGuard's return-type specialization narrows ActualParagraph()'s declared return type +# from the Paragraph interface down to its only impl (SkiaParagraph). The bytecode still +# pushes a Paragraph-typed value, so JVM 21's verifier rejects it at runtime with +# "VerifyError: Bad return type" the moment any Text() renders (androidx.compose.ui.text). +# Disable only method type-specialization; shrinking, obfuscation, class-merging, +# inlining and every other optimization stay on. +-optimizations !method/specialization/* + -keepclasseswithmembers class * { native ; } @@ -20,6 +28,22 @@ -dontnote org.slf4j.** -dontnote kotlinx.serialization.** +# Skiko / Skia + Compose AWT interop. ProGuard obfuscation renames these classes, which +# breaks compose.interop.blending on the transparent desktop window — Canvas/video then +# render see-through (you can see the desktop behind them). Keep them un-obfuscated. +-keep class org.jetbrains.skiko.** { *; } +-keep class org.jetbrains.skia.** { *; } +-keep class androidx.compose.ui.awt.** { *; } +-keep class androidx.compose.ui.interop.** { *; } +-dontwarn org.jetbrains.skiko.** +-dontwarn org.jetbrains.skia.** + +# compottie (Lottie renderer) draws via skiko (PlatformShader.skiko, SkikoPathBuilder). +# On release, proguard obfuscation mangles its internal classes so the renderer runs but +# paints nothing — the animation stays blank with no crash. Keep them un-obfuscated. +-keep class io.github.alexzhirkevich.compottie.** { *; } +-dontwarn io.github.alexzhirkevich.compottie.** + # Okhttp3 -keep class okhttp3.** { *; } -keep class okio.** { *; } diff --git a/composeApp/src/commonMain/composeResources/values-ca/strings.xml b/composeApp/src/commonMain/composeResources/values-ca/strings.xml index d23048a89..bf644da30 100644 --- a/composeApp/src/commonMain/composeResources/values-ca/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-ca/strings.xml @@ -60,6 +60,7 @@ El nom de la llista de reproducció no pot estar buit Aquesta aplicació ha d'accedir a la teva notificació S'ha compartit + Paraula per paraula Línia sincronitzada No sincronitzat Llista de reproducció buida @@ -72,6 +73,10 @@ País de contingut Canvia Qualitat + Preferir la reproducció a 320 kbps + Cercar automàticament la reproducció d'àudio a 320 kbps quan estiga disponible a Internet. Si no es troba, s'aplica la qualitat per defecte. + Qualitat de descàrrega + Qualitat de descàrrega de vídeo Esborra la memòria cau descarregada Esborra la memòria cau de les miniatures Afegeix @@ -118,8 +123,14 @@ Github maxrave-dev Compra'm un cafè + Blog del desenvolupador + Llegir notes de desenvolupament, tutorials & continguts entre bastidors + Novetats del desenvolupador + Acabe de llançar el meu blog personal a maxrave.dev — compartisc la història darrere de SimpMusic, anàlisis a fons sobre tecnologia musical i notes d'enginyeria. Dona-li una ullada si tens curiositat ✨ + Visita el blog PayPal Títol + Ordre personalitzat Àlbum URL de YouTube Descàrrega URL @@ -173,6 +184,7 @@ Desa l'última reproducció Desa la darrera pista reproduïda i la cua Nova actualització disponible + Versió %1$s disponible\nLlançament: %2$s\n Comproveu si hi ha actualitzacions Darrera comprovació a %1$s S'està comprovant @@ -185,6 +197,7 @@ Vista prèvia Música Off-topic POI destacat + Farciment SponsorBlock Activar SponsorBlock Seleccioneu el comportament de salt de segment @@ -206,6 +219,7 @@ Informació d'error La teva versió és la més nova Temporitzador de repòs: %1$s minut(s) + Temporitzador de la son - Final de la cançó Temporitzador Temps del compte enrere (minutes) Estableix @@ -251,6 +265,7 @@ Type language code (Eg: en) (2 letters). If you want to set same with SimpMusic's language, please make edit box empty. Invalid language code Lyrics proporcionada per Spotify + Lletres proporcionades per BetterLyrics Limit Player Cache Sense límit Llibreries de tercers @@ -298,6 +313,7 @@ Còdec Recompte de reproduccions/visualitzacions %1$d like(s), %2$d dislike(s) + Publicat en %1$s Menys Spotify Inicieu sessió a Spotify @@ -368,6 +384,10 @@ Port invàlid Per favor, introdueixi l'amfitrió del Proxy Per favor, introdueixi el port del Proxy + Nom d'usuari del Proxy + Contrasenya del Proxy + Introdueix el nom d'usuari del proxy (opcional) + Introdueix la contrasenya del proxy (opcional) Cinc segons Lletra proporcionada per LRCLIB Sincronitza aquesta llista amb YouTube Music primer @@ -378,6 +398,7 @@ Efecte de desenfocament amb la lletra a pantalla completa Effecte de desenfoc del fons de la pantalla de lletra de la cançó a pantalla completa + Velocitat de reproducció To Desenfoca el fons del reproductor @@ -402,6 +423,8 @@ Durada de l'efecte d'atenuació de l'àudio Durada Nombre invàlid + L'endpoint de reproducció aleatòria no està disponible + L'endpoint de la ràdio no està disponible Dades del visitant recuperades DataSyncId recuperat Recupera dades de YouTube @@ -410,6 +433,7 @@ Proveïdor d'IA OpenAI Gemini + Compatible amb OpenAI personalitzat La seva clau de l'API de la IA Clau de l'API de la IA invàlida ID de model d'IA personalitzat @@ -420,16 +444,24 @@ No hi ha podcasts preferits El seu paràmetre sp_dc de la cookie d'Spotify La seva cookie de YouTube + El teu token de Discord No pot estar buit Processant Lloc web Descarrega aquesta cançó/vídeo al seu dispositiu Finalitzar el servei en sortir Atura la reproducció en segon pla en sortir de l'aplicació + Reproductor d'escriptori + Crossfade (BETA) + Fer una transició suau entre cançons abaixant gradualment el volum de la pista actual mentre s'apuja el de la següent. Activat (%1$ds) Desactivat Durada del crosssfade Estableixi la duració del crossfade en segons (%1$ds) + Automàtic + Calcular la durada automàticament basant-se en els BPM (requereix la reproducció a 320 kbps amb dades de BPM) + Transició a l'estil DJ + Aplicar crossfade de filtres passa-baix i passa-alt durant l'encadenament per a una transició més suau a l'estil DJ (similar a l'Automix d'Apple Music) Idioma de la traducció dels subtítols de YouTube Escrigui el codi d'idioma (per exemple: ca) (dues lletres). Aquest és l'idioma per a la traducció dels subtítols de YouTube preferent Utilitza un nom anònim per contribuir @@ -442,16 +474,83 @@ Restauració en progrés Fer una còpia de seguretat de les dades descarregades Fer una còpia de seguretat de les dades de les cançons descarregades + Còpia de seguretat automàtica + Fer una còpia de seguretat de les dades automàticament a la carpeta Downloads/SimpMusic + Freqüència de la còpia de seguretat + Diàriament + Setmanalment + Mensualment + Conservar les còpies de seguretat + Conservar les últimes %1$s còpies de seguretat + Última còpia de seguretat + Mai + Còpia de seguretat automàtica completada amb èxit + Error en la còpia de seguretat automàtica No s'han trobat llistes de reproducció locals, per favor, creï'n una primer. Fes un llistat de totes les cookies d'aquesta web S'ha copiat al porta-retalls Canal d'actualitzacions Activa liquid glass (BETA) + Activa l'efecte de vidre líquid d'iOS en alguna posició (Android 13+) La seva biblioteca Reprodueix el contingut explícit Activa per reproduir contingut explícit El contingut explícit serà saltat Mescla per a vostè No s'han trobat mescles + No s'han trobat gràfics A causa de les limitacions de Compose Multiplatform, no puc implementar WebView a l’entorn d’escriptori.\nLlegeix això per obtenir més informació sobre com iniciar sessió a l’escriptori:\n + Obre l'entrada del blog + Integració amb Discord + Inicia sessió a Discord + Inicia sessió per activar el Rich Presence de Discord + Activa el Rich Presence + Mostra la informació de la sessió multimèdia al teu perfil de Discord + Música que t'agrada de YouTube + Mantingues el servei actiu + Mantingues actiu el servei del reproductor de música per evitar que el sistema l'ature + Continua mostrant la teva llista de reproducció de YouTube sense connexió + Desa la teva llista de reproducció de YT al dispositiu per continuar mostrant-la sense connexió + Substitueix Preferits per la Música que t'agrada de YouTube en iniciar sessió + Utilitza només la Música que t'agrada de YouTube (no es pot marcar «m'agrada» a les cançons sense connexió) + Aquest any + Últims 90 dies + Últims 30 dies + Últims 7 dies + Reproduccions + Top cançons + Cançons reproduïdes + Temps total d'escolta + Segons + Reproduït recentment + Els teus artistes més escoltats + Els teus àlbums més escoltats + Les teves cançons més escoltades + Interval de dates + Reprodueix música per veure les estadístiques + Valora la traducció + Valora la lletra + Vota la lletra + Votar a favor + Votar en contra + Gràcies per votar aquesta lletra! + No s'ha pogut enviar + Obri SimpMusic + Tanca el minireproductor + Obre el minireproductor + Surt de l'aplicació + Seguiment local de l'historial d'escolta + Registra l'historial d'escolta a la base de dades local + Llistes d'èxits de SimpMusic + Transició gradual + El teu URL de 320 kbps + Deixa-ho en blanc per seleccionar automàticament un URL operatiu des del verificador d'estat. + Cerca + No es pot canviar l'ordre d'una llista de reproducció sincronitzada + BPM + Tonalitat + Escala + No s'ha pogut connectar + Comprova la connexió a internet i torna-ho a provar, o escolta la música que tens baixada. + Escolta la música descarregada diff --git a/composeApp/src/commonMain/composeResources/values-es/strings.xml b/composeApp/src/commonMain/composeResources/values-es/strings.xml index b2cbd95f3..a313165f7 100644 --- a/composeApp/src/commonMain/composeResources/values-es/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-es/strings.xml @@ -124,6 +124,10 @@ maxrave-dev Cómprame un café + Leer notas de desarrollo, tutoriales & detrás de la escena + Algo nuevo del desarrollador + Acabo de lanzar mi blog personal en maxrave.dev — compartiendo la historia detrás de SimpMusic, inmersiones profundas de tecnología musical y notas de ingeniería. Dale un vistazo si eres curioso ✨ + Visita el blog PayPal Título Orden personalizado @@ -540,9 +544,13 @@ Gráficos SimpMusic Crossfade Su URL de 320kbps + Dejar en blanco para elegir automáticamente una URL funcional desde la comprobación de tiempo de activación. Buscar por No se puede cambiar el orden de la lista sincronizada BPM Clave Escala + No se puede conectar + Compruebe su conexión a Internet e inténtelo de nuevo, o escuche su música descargada. + Escucha la música descargada diff --git a/composeApp/src/commonMain/composeResources/values-fr/strings.xml b/composeApp/src/commonMain/composeResources/values-fr/strings.xml index 859275d9f..b1d74a43e 100644 --- a/composeApp/src/commonMain/composeResources/values-fr/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-fr/strings.xml @@ -97,7 +97,7 @@ À propos COMMENÇONS PAR UNE RADIO ! NOUS ALLONS SÉLECTIONNER UNE PLAYLIST POUR VOUS ! - + Genre QUEL EST LE MEILLEUR CHOIX AUJOURd'HUI ? Graphique @@ -541,6 +541,8 @@ Quitter l'application Historique d'écoute local Enregistrez votre historique d'écoute dans une base de données locale + Notifications relatives aux articles de blog + Recevez une notification dès qu'un nouvel article de blog est publié Classements SimpMusic Fondu enchaîné Votre URL 320 kbps diff --git a/composeApp/src/commonMain/composeResources/values-id/strings.xml b/composeApp/src/commonMain/composeResources/values-id/strings.xml index 48f4ba8e6..1dbf0e69a 100644 --- a/composeApp/src/commonMain/composeResources/values-id/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-id/strings.xml @@ -540,6 +540,8 @@ Keluar aplikasi Riwayat mendengarkan pelacakan lokal Catat riwayat mendengarkan Anda ke basis data lokal + Pemberitahuan postingan blog + Dapatkan pemberitahuan saat ada postingan blog baru yang diterbitkan Tangga lagu SimpMusic Memudar URL 320kbps Anda @@ -549,4 +551,7 @@ BPM Kunci Skala + Tidak dapat tersambung + Periksa sambungan internet Anda dan coba lagi, atau dengarkan musik yang sudah Anda unduh. + Dengarkan musik yang sudah diunduh diff --git a/composeApp/src/commonMain/composeResources/values-it/strings.xml b/composeApp/src/commonMain/composeResources/values-it/strings.xml index 5c49510af..c69ae0256 100644 --- a/composeApp/src/commonMain/composeResources/values-it/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-it/strings.xml @@ -5,15 +5,15 @@ Album • %1$s %1$s iscritti %1$s • %2$s - %1$s Tracce %2$s - %1$s Visualizzazioni + %1$s tracce %2$s + %1$s visualizzazioni Cancella la cronologia delle ricerche Piaciuti Mi piace Rimuovi frammenti vuoti Scarica Scaricato/i - Scaricamento in corso + Scaricando In preparazione Nascondi Mostra @@ -50,7 +50,7 @@ Disponibile online Non disponibile Tu - Buongiorno + Buondì Buon pomeriggio Buonasera Buonanotte @@ -78,13 +78,13 @@ Qualità di download Qualità download video Pulisci la cache dei Download - Elimina la cache delle miniature + Pulisci la cache delle copertine Aggiungi Nome della playlist Crea Modifica Modifica il titolo - Modifica la miniatura + Modifica la copertina Elimina la playlist Aggiungi alla playlist Condividi @@ -108,7 +108,7 @@ Testi Tutto Video - Contenuto + Contenuti Archiviazione Cache del lettore Cache dei download @@ -118,19 +118,19 @@ Salva tutti i dati delle tue playlist Ripristina i tuoi dati Ripristina i tuoi dati salvati - Riguardo a noi + Su di noi Versione Github maxrave-dev - Comprami un caffè + Offrimi un caffè Blog degli sviluppatori - Leggi le note degli sviluppatori, i tutorial & dietro le quinte + Leggi le note degli sviluppatori, i tutorial e i dietro le quinte Novità dagli sviluppatori Ho appena lanciato il mio blog personale, lo trovi su maxrave.dev — troverai la storia dietro SimpMusic, riflessioni su music-tech e note d'ingegneria Visita il blog PayPal Titolo - Ordine custom + Ordine personalizzato Album URL YouTube URL per il download @@ -227,7 +227,7 @@ Si prega di impostare l'ora nel formato corretto Rimuovere il timer di spegnimento? - Bentornato, + Felice di rivederti, Carica la tua cronologia di ascolto sul server YouTube Music, migliorerà il sistema di consigli di YT Music. Funzionante solo se loggato Invia i dati di ascolto a Google Video @@ -259,10 +259,10 @@ Abilita la traduzione dei testi utilizzando l'IA Lingua di traduzione Segui la lingua dell'applicazione - E-mail + Posta elettronica Password Per favore inserisci le tue credenziali - Digitare il codice della lingua (Es: en) (2 lettere). Se vuoi impostare lo stesso con la lingua di SimpMusic, lascia vuota la casella di modifica. + Digitare il codice della lingua (Es: it) (2 lettere). Se vuoi impostare lo stesso con la lingua di SimpMusic, lascia vuota la casella di modifica. Codice lingua non valido Testi forniti da YouTube Testi forniti da BetterLyrics @@ -272,7 +272,7 @@ Descrizione e licenze Autore Altre app - Database dell'applicazione + Database applicazioni Spazio libero Suggerimento Ricarica @@ -287,7 +287,7 @@ In primo piano Qualità audio Riproduci video per traccia video invece che solo audio - Come Musica Video, Testi Video, Podcast e altro ancora + Come video musicali, di testi, podcast e altro ancora Qualità video %d canzone @@ -316,7 +316,7 @@ Pubblicato il %1$s Meno Spotify - Accedi a Spotify + Accedi con Spotify Accedi per i testi, i Canvas e altro ancora da Spotify Abilita testi da Spotify Più testi senza traduzione @@ -352,9 +352,9 @@ Interfaccia Barra di navigazione inferiore traslucida Puoi vedere il contenuto sotto la barra inferiore - Se apprezzi il mio lavoro, offrimi un caffè + Se apprezzi il mio lavoro, donami un caffè Relax - Dormire + Riposo Energetico Triste Romantico @@ -386,8 +386,8 @@ Inserisci la tua porta proxy Nome utente proxy Password proxy - Inserisci il tuo nome utente Proxy (opzionale) - Inserisci la tua password Proxy (opzionale) + Inserisci il tuo nome utente proxy (opzionale) + Inserisci la tua password proxy (opzionale) Cinque secondi Testi forniti da LRCLIB Sincronizza prima questa playlist con YouTube Music @@ -417,7 +417,7 @@ Divertiti con SimpMusic Se ti piace usare SimpMusic, stella SimpMusic su GitHub o lasciare una recensione su "Se ami il mio lavoro, considera" - comprami un caffè. + di offrirmi un caffè. Effetto di dissolvenza audio Disattiva Durata effetto dissolvenza audio (ms) (Imposta a 0 per disattivare) @@ -443,8 +443,8 @@ Podcast preferiti Nessun podcast preferito Il tuo sp_dc param dei cookie di Spotify - Il Tuo Cookie Di YouTube - il tuo token di discord + Il tuo cookie di YouTube + Il tuo token di Discord Il campo non può essere vuoto In elaborazione Sito web @@ -463,7 +463,7 @@ Transizione in stile DJ Applica filtri passa-basso e passa-alto durante la dissolvenza incrociata per una transizione più fluida e simile a DJ (simile a Apple Music Automix). Lingua di traduzione dei sottotitoli di YouTube - Codice lingua tipo (Eg: it) (2 lettere). Questa è la lingua preferita per i sottotitoli di YouTube. + Codice lingua tipo (Es: it) (2 lettere). Questa è la lingua preferita per i sottotitoli di YouTube. Usa nome anonimo per contribuire Nome del collaboratore E-mail del collaboratore @@ -499,18 +499,18 @@ Mix per te Nessun mix trovato Nessuna classifica trovata - A causa delle limitazioni di Compose Multiplatform, non posso implementare WebView sul desktop.\nLeggi questo per saperne di più su come accedere al desktop:\n + A causa delle limitazioni di Compose Multiplatform, non posso implementare WebView sul desktop.\nLeggi questo per saperne di più su come accedere su desktop:\n Apri post del blog - integrazione discord - accedi su discord - + Integrazione con Discord + Accedi con Discord + Accedi per abilitare Discord Rich Presence Abilita Rich Presence Mostra le info della tua sessione nel tuo profilo di Discord Musica apprezzata su YouTube Tieni il servizio attivo Mantieni attivo il servizio del lettore musicale per evitare che venga chiuso dal sistema - mostra la tua playlist di youtube quando offline - salva la tua playlist di youtube in locale e tienila per averla offline + Mostra la tua playlist di YouTube quando offline + Salva la tua playlist di YouTube in locale per mantenerla anche senza connessione Combina i preferiti di YouTube con i mi piace quando accedi Uso esclusivo dei mi piace di YouTube (non supporta i titoli offline) Quest'anno @@ -541,13 +541,18 @@ Esci dall'applicazione Tracciamento locale della cronologia degli ascolti Registra la cronologia di ascolto nel database locale + Notifiche post blog + Ricevi una notifica quando viene pubblicato un nuovo post sul blog Classifica SimpMusic Dissolvenza incrociata Il tuo URL 320kbps - Lasciare vuoto per scegliere automaticamente un URL di lavoro dal checker uptime. + Lascia vuoto per scegliere automaticamente un URL di lavoro dal checker uptime. Cerca per La playlist sincronizzata non può cambiare ordine BPM Chiave Ridimensiona + Impossibile connettersi + Controlla la tua connessione internet e riprova o ascolta la tua musica già scaricata. + Ascolta la musica scaricata diff --git a/composeApp/src/commonMain/composeResources/values-ko/strings.xml b/composeApp/src/commonMain/composeResources/values-ko/strings.xml index cdec032a3..a6c9afd05 100644 --- a/composeApp/src/commonMain/composeResources/values-ko/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-ko/strings.xml @@ -12,7 +12,7 @@ 좋아요 안녕하세요 여기는 빈 부분이에요 다운로드 - 다운로드됨 + 다운로드 됨 다운로드 중 준비 중 숨김 @@ -23,13 +23,13 @@ 팔로우됨 가장 많이 재생된 노래 다운로드됨 - 즐겨 찾는 재생목록 - 즐겨 찾는 재생목록 없음 + 즐겨찿는 재생목록 + 즐겨찾는 재생목록 없음 다운로드한 재생목록 다운로드한 재생목록 없음 내 로컬 재생목록 추가한 재생목록 없음 - 최근 추가 + 최근 추가한 음악, 아티스트, 앨범, 재생목록 등 검색 당신이 원하는 모든 것 복원 실패 @@ -50,10 +50,10 @@ 온라인으로 이용가능 사용할 수 없음 - 좋은 아침 - 좋은 오후 - 좋은 저녁 - 좋은 밤 + 좋은 아침입니다 + 좋은 오후입니다 + 좋은 저녁입니다 + 좋은 저녁입니다 빠른 선택 음악을 재생할 수 없습니다 차트에서 @@ -73,6 +73,8 @@ 콘텐츠 국가 변경 품질 + 320kbps 스트림선호 + 인터넷에서 사용 가능한 경우 320kbps 오디오 스트림을 자동으로 검색합니다. 찾지 못하면 기본 품질로 돌아갑니다. 다운로드 품질 동영상 다운로드 품질 다운로드한 캐시 지우기 @@ -121,6 +123,11 @@ GitHub maxrave-dev Buy me a coffee + 개발자 블로그 + 개발 노트, 튜토리얼 & 비하인드 스토리를 읽어보세요 + 개발자의 새로운 소식 + SimpMusic의 탄생 비화, 음악 기술 심층 분석, 엔지니어링 노트 등을 공유하는 개인 블로그 maxrave.dev를 개설했습니다. 궁금하시면 읽어보세요. ✨️ + 블로그 방문하기 PayPal 제목 사용자 지정 순서 @@ -201,7 +208,7 @@ 동영상의 스폰서 구간 건너뛰기 알 수 없는 오류가 발생했습니다. 불편을 드려 죄송합니다. 앱 다시 시작 - SimpMusic 가사에서 가사 데이터베이스를 구축할 수 있도록 도움 + SimpMusic 가사에서 가사 데이터베이스를 구축할 수 있도록 돕기 저장된 가사를 SimpMusic 가사 데이터베이스로 전송 앱 종료 오류 정보 @@ -212,6 +219,7 @@ 오류 정보 최신 버전입니다 취침 타이머 - %1$s분 + 노래 종료 시 취침 타이머 카운트다운 시간 (분) 설정 @@ -257,6 +265,7 @@ 언어 코드 2글자(예: ko)를 입력합니다. SimpMusic 앱의 언어와 동일하게 설정하려면, 입력란을 비워 둡니다. 잘못된 언어 코드 YouTube에서 제공된 가사 + BetterLyrics 에서 제공하는 가사 플레이어 캐시 제한 무제한 서드파티 라이브러리 @@ -374,6 +383,10 @@ 잘못된 포트 프록시 호스트를 입력해 주십시오 프록시 포트를 입력해 주십시오 + 프록시 사용자 이름 + 프록시 비밀번호 + 프록시 사용자 이름을 입력하세요(선택 사항) + 프록시 비밀번호를 입력하세요(선택 사항) 5초 LRCLIB에서 제공된 가사 이 재생목록을 YouTube Music에 먼저 동기화 @@ -384,6 +397,7 @@ 전체화면 가사 배경 흐리게 전체화면 가사의 배경을 흐리게 처리 + 재생 속도 음정 플레이어 배경 흐리게 @@ -418,6 +432,7 @@ AI 제공자 OpenAI Gemini + 사용자 지정 OpenAI 호환 내 AI API 키 잘못된 API 키 사용자 AI 모델 ID @@ -435,11 +450,17 @@ 이 음악/동영상 파일을 기기로 다운로드 나갈 때 서비스 종료 앱을 종료할 때 백그라운드 음악 플레이어 멈춤 + 데스크톱 플레이어 크로스페이드 (베타) + 현재 트랙을 페이드아웃하면서 다음 트랙을 페이드인하여 곡 간 전환을 부드럽게 합니다. 켜짐 (%1$d초) 꺼짐 - 크로스페이드 시간 + 크로스페이드 지속 시간 크로스페이드 시간을 초 단위로 설정 (%1$d초) + 자동 + BPM을 기준으로 재생 시간을 자동으로 계산합니다(BPM 데이터가 포함된 320kbps 스트림 필요) + DJ 스타일 전환 + 크로스페이드 중에 로우패스 및 하이패스 필터 스윕을 적용하여 더욱 부드럽고 DJ와 같은 전환을 구현합니다(Apple Music Automix와 유사). YouTube 자막 번역 언어 언어 코드 2글자(예: ko)를 입력합니다. YouTube 자막의 기본 번역 언어에 해당합니다. 기여할 때 익명 사용 @@ -476,6 +497,7 @@ 연령 제한 콘텐츠 건너뜀 당신을 위한 믹스 믹스 없음 + 차트를 찾을 수 없습니다 Compose Multiplatform의 제한으로 인해 데스크톱에서 WebView를 구현할 수 없습니다.\n데스크톱에 로그인하는 방법을 자세히 알아보려면 다음을 읽어보세요.\n 블로그 게시물 열기 Discord 연동 @@ -485,7 +507,7 @@ Discord 프로필에 미디어 세션 정보를 표시합니다 YouTube 좋아요 표시한 음악 서비스 활성 유지 - 시스템이 종료하지 않게 음악 플레이어 서비스를 활성 상태로 유지합니다 + 시스템이 종료하지 않도록 음악 플레이어 서비스를 활성 상태로 유지합니다 오프라인일 때도 YouTube 재생목록 표시 YouTube 재생목록을 로컬에 저장한 뒤 오프라인일 때 표시합니다 로그인 시 즐겨찾기를 YouTube 좋아요 표시한 재생목록으로 교체 @@ -500,9 +522,9 @@ 총 재생 시간 최근 재생 - 내 최애 아티스트 - 내 최애 앨범 - 내 최애 음악 + 나의 인기 아티스트 + 나의 인기 앨범 + 나의 최애 음악 데이터 범위 분석을 확인하려면 음악을 재생해주세요 번역 평가 @@ -516,4 +538,18 @@ 미니 플레이어 닫기 미니 플레이어 열기 앱 종료 + 로컬 재생 기록 추적 + 로컬 데이터베이스에 나의 재생 기록 저장 + Simpmusic 차트 + 크로스페이드 중 + 320kbps URL + 가동 시간 검사기에서 작동하는 URL을 자동으로 선택하려면 비워 두세요. + 검색 + 청취 기록을 로컬 데이터베이스에 기록 + BPM + + 스케일 + 연결 할 수 없음 + 인터넷 연결을 확인하고 다시 시도하거나 다운로드한 음악을 들어보세요. + 다운로드한 음악 듣기 diff --git a/composeApp/src/commonMain/composeResources/values-pt/strings.xml b/composeApp/src/commonMain/composeResources/values-pt/strings.xml index 55d22bab2..834ff1dfa 100644 --- a/composeApp/src/commonMain/composeResources/values-pt/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-pt/strings.xml @@ -123,6 +123,11 @@ GitHub maxrave-dev Compre-me um café + Blog do Desenvolvedor + Leia notas de desenvolvimento, tutoriais & nos bastidores + Algo novo do desenvolvimento + Acabei de lançar meu blog pessoal no maxrave. ev — compartilhando a história por trás da SimpMusic, mergulhos profundos na música e notas de engenharia. Dê uma lida se você estiver curioso ✨ + Visite o Blog PayPal Título Manual @@ -379,6 +384,10 @@ Porta inválida Favor insira o seu servidor Proxy Favor insira a sua porta Proxy + Usuário do Proxy + Senha do proxy + Por favor, insira seu nome de usuário do Proxy (opcional) + Por favor, insira sua senha do Proxy (opcional) Cinco segundos Letras fornecidas pelo YouTube Sincronize esta lista de reprodução com o YouTube Music primeiro @@ -389,6 +398,7 @@ Desfocar o efeito letras em tela cheia Desfocando o fundo do efeito de tela em letras em tela cheia + Velocidade de reprodução Tonalidade Desfocar fundo do ‘player’ @@ -448,6 +458,8 @@ Desativado Duração da Transição Defina a duração da transição em segundos (%1$ds) + Auto + Calcular a duração automaticamente com base no BPM (requer o stream de 320kbps com dados BPM) Transição estilo DJ Aplica filtros passa-baixa e passa-alta durante o crossfade para uma transição mais suave, estilo DJ (semelhante ao Automix do Apple Music). Idioma da Tradução das Legendas do YouTube @@ -532,6 +544,13 @@ Paradas SimpMusic Crossfading Sua URL de 320kbps + Deixe vazio para escolher automaticamente uma URL de trabalho do verificador. Pesquisar por Playlist sincronizada não pode mudar a ordem + BPM + Tom + Escala + Falha na conexão + Verifique sua conexão com a internet e tente novamente mais tarde ou ouça suas músicas baixadas. + Ouvir músicas baixadas diff --git a/composeApp/src/commonMain/composeResources/values-ru/strings.xml b/composeApp/src/commonMain/composeResources/values-ru/strings.xml index f00a72776..df6222675 100644 --- a/composeApp/src/commonMain/composeResources/values-ru/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-ru/strings.xml @@ -30,11 +30,11 @@ Ваши локальные плейлисты Плейлисты не добавлены Недавно добавленные - Поиск песен, исполнителей, альбомов, плейлистов и многое другое + Искать песни, исполнителей, альбомы, плейлисты, и многое другое Все что вам нужно Ошибка восстановления Восстановление прошло успешно - Искать + Поиск Песни Альбомы Плейлисты @@ -553,4 +553,7 @@ BPM Ключ Шкала + Ошибка подключения + Проверьте подключение к Интернету и повторите попытку, или прослушивайте скачанную музыку. + Слушать скачанную музыку diff --git a/composeApp/src/commonMain/composeResources/values-th/strings.xml b/composeApp/src/commonMain/composeResources/values-th/strings.xml index eeadf1e64..2e922de31 100644 --- a/composeApp/src/commonMain/composeResources/values-th/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-th/strings.xml @@ -7,7 +7,7 @@ %1$s • %2$s %1$s แทร็ค %2$s การเข้าชม %1$s - เคลียร์ประวัติการค้นหา + ล้างประวัติการค้นหา ถูกใจแล้ว ถูกใจ สวัสดี blank fragment @@ -29,7 +29,7 @@ ยังไม่มีการดาวน์โหลดเพลย์ลิสต์ เพลย์ลิสต์ในอุปกรณ์ ยังไม่มีการเพิ่มเพลย์ลิสต์ - เพิ่มเมื่อล่าสุด + เพิ่มล่าสุด ค้นหา เพลง ศิลปิน อัลบั้ม เพลย์ลิสต์ และอื่นๆ อะไรก็ตามที่คุณต้องการ การกู้คืนล้มเหลว @@ -551,4 +551,7 @@ BPM คีย์ บันไดเสียง + ไม่สามารถเชื่อมต่อได้ + ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณแล้วลองใหม่อีกครั้ง หรือฟังเพลงที่คุณดาวน์โหลดไว้ + ฟังเพลงที่ดาวน์โหลด diff --git a/composeApp/src/commonMain/composeResources/values-uk/strings.xml b/composeApp/src/commonMain/composeResources/values-uk/strings.xml index f59cd88ff..ad8f85430 100644 --- a/composeApp/src/commonMain/composeResources/values-uk/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-uk/strings.xml @@ -1,12 +1,12 @@ - Композиція • %1$s - Список відтворення• %1$s + Трек • %1$s + Плейлист • %1$s Альбом • %1$s - %1$s Підписників + %1$s підписників %1$s • %2$s - %1$s Треків %2$s - %1$s Переглядів + %1$s треків %2$s + %s переглядів Очистити історію пошуку Вподобано Вподобати @@ -552,4 +552,7 @@ BPM Ключ Масштаб + Помилка підключення + Перевірте підключення до Інтернету і повторіть спробу, або слухайте вашу завантажену музику. + Слухати завантажену музику diff --git a/composeApp/src/commonMain/composeResources/values-zh-rCN/strings.xml b/composeApp/src/commonMain/composeResources/values-zh-rCN/strings.xml index 3b07c7658..48ba7e5e6 100644 --- a/composeApp/src/commonMain/composeResources/values-zh-rCN/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-zh-rCN/strings.xml @@ -60,6 +60,7 @@ 歌单名称不能为空 此应用需要通知权限 已分享 + 逐字逐句 已同步行 未同步 歌单为空 @@ -72,6 +73,8 @@ 内容国家/地区 更改 音质 + 优先使用 320kbps 串流 + 网络可用时,自动搜索320kbps 音频流。如果找不到的话,则跳回默认质量。 下载音质 视频下载质量 清除已下载缓存 @@ -120,6 +123,11 @@ Github maxrave-dev 请我喝杯咖啡(捐赠) + 开发者博客 + 阅读开发日志、教程& 及幕后花絮 + 开发中的一些新内容 + 我刚刚上线了个人博客 maxrave.dev,内容涵盖 SimpMusic 背后的故事、音乐科技深度解析以及工程技术笔记。感兴趣的话不妨去看看 ✨ + 访问博客 PayPal 标题 自定义顺序 @@ -167,7 +175,7 @@ 不支持此链接 已添加到歌单 描述 - 回放 + 播放 保存回放状态 保存随机和重复模式 跳过静音 @@ -211,6 +219,7 @@ 错误信息 您的版本是最新版本 睡眠计时器 - %1$s 分钟 + 睡眠定时器 - 歌曲结束 睡眠定时器 倒计时 (分钟) 设定 @@ -256,6 +265,7 @@ 输入语言代码 (例如: en) (2 字符)。如果您想使用 SimpMusic 相同的语言设置,请将编辑框置空。 无效的语言代码 歌词 by YouTube + 歌词由 BetterLyrics 提供 限制播放器缓存 无限制 第三方库 @@ -302,6 +312,7 @@ Codec 播放/查看计数 %1$d 赞(s), %2$d 踩(s) + 发布在 %1$s 减少 Spotify 登录Spotify @@ -314,6 +325,7 @@ 离线模式 添加到 YouTube 赞过 已从 YouTube 赞过中移除 + 获取主页数据限制 无专辑 播放器小部件 滑动以显示跳过和关闭按钮 @@ -337,6 +349,8 @@ 关闭循环播放 YouTube 字幕 界面 + 半透明底部导航栏 + 您可以看到底部栏下的内容 如果你喜欢我的作品,支持我一下 放松 睡眠 @@ -369,29 +383,170 @@ 无效的端口 请输入您的代理服务器 请输入您的代理端口 + 代理服务器用户名 + 代理服务器密码 + 请输入您的代理服务器用户名 (可选) + 请输入您的代理服务器密码 (可选) 5秒 歌词由 LRCLIB 提供 首先将此播放列表同步到 YouTube 音乐 + 无尽队列 不再显示 自动检查更新 当您打开应用程序时检查更新 模糊全屏歌词特效 + 模糊全屏歌词界面的背景效果 + + 播放速度 + 音调 播放界面背景模糊 + “正在播放”界面的背景模糊效果 + 正在合并音频和视频 + 出错了 + 正在下载音频: %1$s + 正在下载视频: %1$s + 好的 + " 到“下载”文件夹中" + 下载速度: %1$s + 随机播放 其他版本 + 稍后询问 + 给颗星星 + 享受SimpMusic吧 + 如果你喜欢SimpMusic,别忘了在Github给SimpMusic点星星或留好评 "如果你喜欢我的工作,请考虑: " + 软件称心多雅意,薄酬一杯解劳辛。 音频淡入淡出 停用 + 淡出音频效果持续时间(ms) (设置为0表示禁用) + 持续时间 随机播放功能暂不可用 + 随机播放功能不可用 + 已获取访客数据 + 检索到数据同步 获取 YouTube 数据 未找到结果 AI AI 提供商 OpenAI Gemini + 自定义 OpenAI 兼容 + 你的AI api密钥 + API 密钥无效 自定义 AI 模型 ID + 默认模型是“gemini-2.0-flash”和“gpt-4o” 无效的 + 请输入 AI 提供商提供的准确模型ID。 最喜爱的播客 没有最喜爱的播客 + 您的 Spotify Cookie 中的 sp_dc 参数 + 您的 YouTube Cookie + 您的 Discord 令牌 + 不能为空 + 正在处理 + 网站 + 将此歌曲/视频文件下载到您的设备 + 退出时关闭服务 + 退出应用时停止后台音乐播放器 + 桌面播放器 + 交叉淡入淡出 (BETA) + 淡出当前曲目,同时淡入下一首曲目,实现曲目间的平滑过渡。 + 已启用 (%1$ds) + 已禁用 + 交叉淡入淡出持续时间 + 设置交叉淡入淡出持续时间(%1$d秒) + 自动 + 基于BPM自动计算持续时间 (需要 320kbps 串流与BPM数据) + DJ风格过渡 + 在交叉淡入淡出期间应用低通和高通滤波扫频效果,以实现更平滑、类似 DJ 风格的过渡(类似于 Apple Music 的 Automix 功能)。 + YouTube 字幕翻译语言 + 输入语言代码 (Eg: en) (2 letters)。这是YouTube 字幕的首选翻译语言。 + 使用匿名名称来贡献信息 + 贡献者名称 + 贡献者邮箱 + 匿名 + SimpMusic 歌词 + 歌词由 BetterLyrics 提供 + 正在备份 + 正在还原 + 备份已下载数据 + 备份所有已下载的歌曲数据 + 自动备份 + 自动备份您的数据到 Downloads/SimpMusic 文件夹 + 备份频率 + 每天 + 每周 + 每月 + 保留备份 + 保留最后 %1$s 个备份 + 上次备份 + 从不 + 自动备份成功 + 自动备份失败 + 未找到本地播放列表, 请先创建一个 + 列出此页面的所有 cookie + 已复制到剪贴板 + 更新频道 + 启用液体玻璃(BETA) + 在部分区域启用类似于 iOS 的液体玻璃效果 (Android 13+) + 您的库 + 播放限制级内容 + 允许播放限制级内容 + 限制级内容已跳过 + 为您准备的音乐 + 未找到歌曲 + 未找到榜单 + 受 Compose 的多平台限制,目前无法在桌面端实现 WebView。\n +请参阅此处,了解如何在桌面端进行登录:\n + 打开博客文章 + Discord 集成 + 登录 Discord + 登录以启用 Discord 丰富媒体状态 + 启用丰富的临场效果 + 在 Discord 个人资料上显示媒体会话信息 + YouTube喜欢的音乐 + 保持服务活动状态 + 保持音乐播放器服务活跃,以免被系统关闭 + 离线时继续展示您的 YouTube 播放列表 + 将您的 YT 播放列表保存到本地并在离线时保持显示 + 登录后,将“收藏”替换为“YouTube点赞的内容” + 仅使用 YouTube 点赞赞功能(不支持离线点赞歌曲) + 今年 + 最近90天 + 最近30天 + 过去7天 + 热门歌曲 + 已播放歌曲 + 听歌时间总计 + + 您的近期播放 + 您最欣赏的艺人排行 + 您最欣赏的专辑排行 + 您最欣赏的歌曲排行 + 日期范围 + 请播放一些音乐以查看分析 + 评价翻译 + 评价歌词 + 给歌词投票 + 点赞 + 点踩 + 感谢您为这份歌词投票! + 发送失败 + 打开 SimpMusic + 关闭迷你播放器 + 打开迷你播放器 + 退出应用 + 在本地保存播放历史记录 + 将您的收听历史记录到本地数据库 + SimpMusic 排行榜 + 交叉淡入淡出 + 您的 320kbps URL + 留空则由可用性检查程序自动选择一个有效的 URL。 + 搜索 + 已经同步的播放列表不能更改顺序 + 无法连接 + 请检查您的网络连接并重试,或收听您已下载的音乐。 + 收听已下载的音乐 diff --git a/composeApp/src/commonMain/composeResources/values-zh-rTW/strings.xml b/composeApp/src/commonMain/composeResources/values-zh-rTW/strings.xml index 61de49be6..ad0f2fbc3 100644 --- a/composeApp/src/commonMain/composeResources/values-zh-rTW/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-zh-rTW/strings.xml @@ -75,8 +75,8 @@ 音質 建議使用 320kbps 碼率的音訊串流 自動搜尋網路上可用的 320kbps 音訊串流。如果找不到,則回退到預設音質。 - - + 下載音質 + 影片下載畫質 清除下載快取 清除縮圖快取 加入 @@ -123,7 +123,10 @@ Github maxrave-dev 求贊助QAQ - + 部落格 + 閱讀開發日誌、教學及幕後花絮 + 來自開發者的最新動態 + 我剛剛上線了個人部落格 maxrave.dev,內容涵蓋 SimpMusic 背後的故事、音樂科技深度解析以及工程技術筆記。如果你有興趣,歡迎去看看 ✨ 訪問紀錄 Paypal 標題 @@ -177,7 +180,7 @@ 儲存隨機播放和重複模式 跳過靜音部份 跳過無音樂部分 - + 連線逾時,請檢查網路連線(%1$s) 儲存上次播放 儲存上次播放的歌曲和佇列 有可用的更新 @@ -537,13 +540,18 @@ 退出app 本地追蹤收聽歷史記錄 將您的收聽歷史記錄到本機資料庫 + 部落格文章通知 + 在新文章發佈時接收通知 SimpMusic排行榜 交叉淡入淡出 您的 320kbps URL - 保持空白以自動選擇上一次工作中的URL + 保持空白以自動選擇上一次工作中的URL。 搜尋 已同步的播放清單無法變更順序 鼓點/分鐘 索引 規模 + 離線 + 請檢查您的網路連線並重試,或聆聽您已下載的音樂。 + 聆聽已下載的音樂 diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index a146f6bf3..b51a8aa18 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -547,6 +547,8 @@ Quit app Local tracking listening history Log your listening history to local database + Blog post notifications + Get notified when a new blog post is published SimpMusic Charts Crossfading Your 320kbps URL diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt index a0d3a5c56..40bf58925 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt @@ -181,6 +181,8 @@ import simpmusic.composeapp.generated.resources.baseline_close_24 import simpmusic.composeapp.generated.resources.baseline_people_alt_24 import simpmusic.composeapp.generated.resources.baseline_playlist_add_24 import simpmusic.composeapp.generated.resources.better_lyrics +import simpmusic.composeapp.generated.resources.blog_notification_description +import simpmusic.composeapp.generated.resources.blog_notification_title import simpmusic.composeapp.generated.resources.blur_fullscreen_lyrics import simpmusic.composeapp.generated.resources.blur_fullscreen_lyrics_description import simpmusic.composeapp.generated.resources.blur_player_background @@ -406,6 +408,7 @@ fun SettingScreen( val videoDownloadQuality by viewModel.videoDownloadQuality.collectAsStateWithLifecycle() val keepYoutubePlaylistOffline by viewModel.keepYouTubePlaylistOffline.collectAsStateWithLifecycle() val localTrackingEnabled by viewModel.localTrackingEnabled.collectAsStateWithLifecycle(initialValue = false) + val blogNotificationEnabled by viewModel.blogNotificationEnabled.collectAsStateWithLifecycle() val combineLocalAndYouTubeLiked by viewModel.combineLocalAndYouTubeLiked.collectAsStateWithLifecycle() val playVideo by remember { viewModel.playVideoInsteadOfAudio.map { it == TRUE } }.collectAsStateWithLifecycle(initialValue = false) val videoQuality by viewModel.videoQuality.collectAsStateWithLifecycle() @@ -2103,6 +2106,13 @@ fun SettingScreen( uriHandler.openUri("https://maxrave.dev") }, ) + if (getPlatform() == Platform.Android) { + SettingItem( + title = stringResource(Res.string.blog_notification_title), + subtitle = stringResource(Res.string.blog_notification_description), + switch = (blogNotificationEnabled to { viewModel.setBlogNotificationEnabled(it) }), + ) + } SettingItem( title = stringResource(Res.string.buy_me_a_coffee), subtitle = stringResource(Res.string.donation), diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt index 8341808e3..9592c618f 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt @@ -181,6 +181,9 @@ class SettingsViewModel( private val _localTrackingEnabled = MutableStateFlow(false) val localTrackingEnabled: StateFlow = _localTrackingEnabled + private val _blogNotificationEnabled = MutableStateFlow(true) + val blogNotificationEnabled: StateFlow = _blogNotificationEnabled + // Auto Backup private val _autoBackupEnabled = MutableStateFlow(false) val autoBackupEnabled: StateFlow = _autoBackupEnabled @@ -279,6 +282,7 @@ class SettingsViewModel( getDownloadQuality() getVideoDownloadQuality() getLocalTrackingEnabled() + getBlogNotificationEnabled() getAutoBackupEnabled() getAutoBackupFrequency() getAutoBackupMaxFiles() @@ -307,6 +311,21 @@ class SettingsViewModel( } } + private fun getBlogNotificationEnabled() { + viewModelScope.launch { + dataStoreManager.blogNotificationEnabled.collect { enabled -> + _blogNotificationEnabled.value = enabled == DataStoreManager.TRUE + } + } + } + + fun setBlogNotificationEnabled(enabled: Boolean) { + viewModelScope.launch { + dataStoreManager.setBlogNotificationEnabled(enabled) + getBlogNotificationEnabled() + } + } + private fun getDownloadQuality() { viewModelScope.launch { dataStoreManager.downloadQuality.collect { quality -> diff --git a/conveyor.conf b/conveyor.conf index e1f9e37af..d0b26499f 100644 --- a/conveyor.conf +++ b/conveyor.conf @@ -130,7 +130,10 @@ app { linux { desktop-file."Comment[en]" = "A FOSS YouTube Music client" desktop-file.Categories = "AudioVideo;Audio;Player;Music;" - desktop-file.StartupWMClass = "java-lang-Thread" + // Must match the runtime WM_CLASS forced by forceLinuxWmClass() in + // desktopApp/.../Main.kt. Was "java-lang-Thread" (a stale guess that broke + // once AWT started initializing on a coroutine worker thread). + desktop-file.StartupWMClass = "SimpMusic" url-schemes = [ "simpmusic" ] } @@ -150,6 +153,12 @@ app { jvm.mac.options += "--add-opens=java.desktop/sun.awt=ALL-UNNAMED" jvm.mac.options += "--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED" jvm.mac.options += "--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED" + + // Linux: allow forceLinuxWmClass() in Main.kt to reflectively overwrite + // sun.awt.X11.XToolkit.awtAppClassName so the dock shows "SimpMusic" instead + // of the coroutine-worker class name. JDK 17+ blocks setAccessible on sun.* + // without this open, and the reflection then silently no-ops. + jvm.linux.options += "--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED" } conveyor.compatibility-level = 21 diff --git a/core b/core index abce8402c..e96d288e6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit abce8402c5445e81afc91f145f0a8ed865a45924 +Subproject commit e96d288e6eaf0e49154620f199c5afeb39ebaabc diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts index bd2d19111..46992d5bf 100644 --- a/desktopApp/build.gradle.kts +++ b/desktopApp/build.gradle.kts @@ -378,7 +378,7 @@ tasks.register("packageConveyorAppImage") { |Icon=simpmusic |Terminal=false |Categories=Audio;AudioVideo; - |StartupWMClass=com-maxrave-simpmusic-MainKt + |StartupWMClass=SimpMusic |MimeType=x-scheme-handler/simpmusic; | """.trimMargin(), diff --git a/desktopApp/src/jvmMain/kotlin/com/maxrave/simpmusic/Main.kt b/desktopApp/src/jvmMain/kotlin/com/maxrave/simpmusic/Main.kt index 2c980f10a..33f7df75c 100644 --- a/desktopApp/src/jvmMain/kotlin/com/maxrave/simpmusic/Main.kt +++ b/desktopApp/src/jvmMain/kotlin/com/maxrave/simpmusic/Main.kt @@ -1,5 +1,7 @@ package com.maxrave.simpmusic +import java.awt.Toolkit + /** * Thin entry point for SimpMusic Desktop. * @@ -13,6 +15,36 @@ package com.maxrave.simpmusic * The :composeApp KMP library exposes runDesktopApp() publicly so this * stub can delegate without duplicating any window-construction logic. */ +/** + * Force the X11 WM_CLASS so the Linux taskbar/dock shows "SimpMusic" instead of + * the class name of whatever thread first touches AWT — with the Conveyor native + * launcher that ends up being a Kotlin coroutine worker + * (kotlinx.coroutines...CoroutineScheduler$Worker, hence the wrong dock label). + * + * JDK derives WM_CLASS from sun.awt.X11.XToolkit.awtAppClassName, read lazily at + * window-init time, and there is no supported system property to set it (see the + * still-open RFE JDK-6528430). So we overwrite the field by reflection AFTER the + * toolkit is constructed but BEFORE the first window opens. Because we set it + * post-construction, the value is used verbatim (no '.'->'-' mangling). + * + * Requires `--add-opens java.desktop/sun.awt.X11=ALL-UNNAMED` (set for Linux in + * conveyor.conf). The value MUST match StartupWMClass in the generated .desktop + * file, else GNOME/KDE won't bind the launcher icon to the window. + */ +private fun forceLinuxWmClass(appName: String = "SimpMusic") { + if (!System.getProperty("os.name").orEmpty().contains("linux", ignoreCase = true)) return + runCatching { + val toolkit = Toolkit.getDefaultToolkit() + // Only the X11/XWayland toolkit exposes awtAppClassName; skip WLToolkit/headless. + if (toolkit.javaClass.name != "sun.awt.X11.XToolkit") return + toolkit.javaClass.getDeclaredField("awtAppClassName").apply { + isAccessible = true + set(null, appName) + } + }.onFailure { System.err.println("forceLinuxWmClass failed: ${it.message}") } +} + fun main(args: Array) { + forceLinuxWmClass() runDesktopApp(args) } diff --git a/fastlane/metadata/android/en-US/changelogs/54.txt b/fastlane/metadata/android/en-US/changelogs/54.txt new file mode 100644 index 000000000..7386975ed --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/54.txt @@ -0,0 +1,5 @@ +- Add a toggle in About settings to turn blog post notifications on or off +- Desktop: fix an app crash that broke all text rendering +- Desktop: fix Canvas and video rendering see-through to the desktop +- Desktop: fix Lottie animations crashing the app +- Linux: fix the desktop icon and app name diff --git a/fastlane/metadata/android/vi-VN/changelogs/54.txt b/fastlane/metadata/android/vi-VN/changelogs/54.txt new file mode 100644 index 000000000..619130266 --- /dev/null +++ b/fastlane/metadata/android/vi-VN/changelogs/54.txt @@ -0,0 +1,5 @@ +- Thêm tùy chọn bật/tắt thông báo bài viết blog trong phần Cài đặt Giới thiệu +- Desktop: sửa lỗi crash làm hỏng toàn bộ hiển thị chữ +- Desktop: sửa lỗi Canvas và video bị trong suốt (nhìn xuyên thấu ra ngoài) +- Desktop: sửa lỗi ảnh động Lottie làm crash ứng dụng +- Linux: sửa biểu tượng và tên ứng dụng trên desktop diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ef97823b..e0221e8c9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # App version -version-name = "1.5.0" -version-code = "53" +version-name = "1.5.1" +version-code = "54" android = "9.2.1" kotlin = "2.4.0" @@ -68,11 +68,11 @@ sqlite = "2.6.2" okio = "3.17.0" vlcj = "4.12.1" vlc = "3.0.23" -material3-multiplatform = "1.12.0-alpha02" +material3-multiplatform = "1.12.0-alpha01" # alpha01 = skiko 0.148.1 (has Matrix33.makeTranslate) to match compottie 1.12 snapshot; alpha02 bumps skiko 0.148.2 which removed it → compottie crash adaptive = "1.2.0" material-icons-multiplatform = "1.7.3" componentsResources = "1.11.1" -compottie = "2.2.4" # 2.2.0 buggy +compottie = "2.2.2-compose-1.12-SNAPSHOT" # Compose 1.12 / skiko 0.148.2 snapshot — material3 1.12-alpha forces skiko 0.148.2, stable compottie needs 0.144.6 and crashes cmptoast = "1.0.71" uri = "0.0.21" buildkonfig = "0.22.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 8b8992763..9b7fd69f0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,9 +4,8 @@ pluginManagement { mavenCentral() gradlePluginPortal() maven { setUrl("https://jitpack.io") } - maven { - url = uri("https://oss.sonatype.org/content/repositories/snapshots/") - } + // oss.sonatype.org (legacy OSSRH) removed — Sonatype shut it down; its flaky + // 504s disabled the whole repo set and blocked resolution fallbacks. maven("https://jogamp.org/deployment/maven") } } @@ -17,9 +16,11 @@ dependencyResolutionManagement { mavenCentral() gradlePluginPortal() maven { url = uri("https://jitpack.io") } - maven { - url = uri("https://oss.sonatype.org/content/repositories/snapshots/") - } + // compottie's Compose-1.12 snapshot builds (skiko 0.148.2) are published to the + // Maven Central Portal snapshot repo below. The legacy OSSRH repo + // (oss.sonatype.org) was removed — Sonatype shut it down and its flaky 504s + // disabled the repo set, blocking fallback to this one. + maven("https://central.sonatype.com/repository/maven-snapshots/") maven("https://jogamp.org/deployment/maven") maven(url = "https://raw.githubusercontent.com/bravepipeproject/maven-repo/master/repository") } @@ -29,27 +30,14 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } -// prepare for git submodules -val coreDir = - if (File(rootDir, "../core").exists()) { - File(rootDir, "../core") - } else { - File(rootDir, "./core") - } - -val serviceDir = - if (File(rootDir, "../core/service").exists()) { - File(rootDir, "../core/service") - } else { - File(rootDir, "./core/service") - } - -val mediaDir = - if (File(rootDir, "../core/media").exists()) { - File(rootDir, "../core/media") - } else { - File(rootDir, "./core/media") - } +// Core modules live in the `core` git submodule INSIDE this repo. +// We intentionally resolve ONLY the in-repo submodule and no longer probe a +// sibling `../core` outside SimpMusic: another project (FPT Play `core`) shares +// the same folder name one level up, and the old co-development lookup bound to +// it by mistake, breaking configuration with ":common ... does not exist". +val coreDir = File(rootDir, "core") +val serviceDir = File(rootDir, "core/service") +val mediaDir = File(rootDir, "core/media") rootProject.name = "SimpMusic" include(