diff --git a/app/src/main/java/pl/lambada/songsync/data/remote/UserSettingsController.kt b/app/src/main/java/pl/lambada/songsync/data/remote/UserSettingsController.kt index 7ef190b..346f694 100644 --- a/app/src/main/java/pl/lambada/songsync/data/remote/UserSettingsController.kt +++ b/app/src/main/java/pl/lambada/songsync/data/remote/UserSettingsController.kt @@ -35,6 +35,9 @@ class UserSettingsController(private val dataStore: DataStore) { var multiPersonWordByWord by mutableStateOf(dataStore.get(multiPersonWordByWordKey, false)) private set + var syncedMusixmatch by mutableStateOf(dataStore.get(syncedMusixmatchKey, true)) + private set + var pureBlack by mutableStateOf(dataStore.get(pureBlackKey, false)) private set @@ -74,6 +77,11 @@ class UserSettingsController(private val dataStore: DataStore) { multiPersonWordByWord = to } + fun updateSyncedMusixmatch(to: Boolean) { + dataStore.set(syncedMusixmatchKey, to) + syncedMusixmatch = to + } + fun updateDisableMarquee(to: Boolean) { dataStore.set(disableMarqueeKey, to) disableMarquee = to @@ -96,6 +104,7 @@ private val blacklistedFoldersKey = stringPreferencesKey("blacklist") private val hideLyricsKey = booleanPreferencesKey("hide_lyrics") private val includeTranslationKey = booleanPreferencesKey("include_translation") private val multiPersonWordByWordKey = booleanPreferencesKey("multi_person_word_by_word") +private val syncedMusixmatchKey = booleanPreferencesKey("synced_lyrics") private val disableMarqueeKey = booleanPreferencesKey("marquee_disable") private val pureBlackKey = booleanPreferencesKey("pure_black") private val sdCardPathKey = stringPreferencesKey("sd_card_path") \ No newline at end of file diff --git a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/LyricsProviderService.kt b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/LyricsProviderService.kt index b915d81..23a81e2 100644 --- a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/LyricsProviderService.kt +++ b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/LyricsProviderService.kt @@ -31,8 +31,8 @@ class LyricsProviderService { // Apple Track ID private var appleID = 0L - // Musixmatch Track ID - private var musixmatchID = 0L + // Musixmatch Song Info + private var musixmatchSongInfo: SongInfo? = null // TODO: Use values from SongInfo object returned by search instead of storing them here /** @@ -69,7 +69,7 @@ class LyricsProviderService { } ?: throw NoTrackFoundException() Providers.MUSIXMATCH -> MusixmatchAPI().getSongInfo(query).also { - musixmatchID = it?.musixmatchID ?: 0 + musixmatchSongInfo = it } ?: throw NoTrackFoundException() } } catch (e: InternalErrorException) { @@ -94,7 +94,8 @@ class LyricsProviderService { provider: Providers, // TODO providers could be a sealed interface to include such parameters includeTranslationNetEase: Boolean = false, - multiPersonWordByWord: Boolean = false + multiPersonWordByWord: Boolean = false, + syncedMusixmatch: Boolean = true ): String? { return try { when (provider) { @@ -108,7 +109,10 @@ class LyricsProviderService { appleID, multiPersonWordByWord ) - Providers.MUSIXMATCH -> MusixmatchAPI().getSyncedLyrics(musixmatchID) + Providers.MUSIXMATCH -> MusixmatchAPI().getLyrics( + musixmatchSongInfo, + syncedMusixmatch + ) } } catch (e: Exception) { null diff --git a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/MusixmatchAPI.kt b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/MusixmatchAPI.kt index be0fa9e..f7501cb 100644 --- a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/MusixmatchAPI.kt +++ b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/MusixmatchAPI.kt @@ -5,7 +5,6 @@ import io.ktor.client.statement.bodyAsText import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import pl.lambada.songsync.domain.model.SongInfo -import pl.lambada.songsync.domain.model.lyrics_providers.others.MusixmatchLyricsResponse import pl.lambada.songsync.domain.model.lyrics_providers.others.MusixmatchSearchResponse import pl.lambada.songsync.util.EmptyQueryException import pl.lambada.songsync.util.networking.Ktor.client @@ -21,52 +20,53 @@ class MusixmatchAPI { * @return Search result as a SongInfo object. */ suspend fun getSongInfo(query: SongInfo): SongInfo? { - val search = withContext(Dispatchers.IO) { + val artistName = withContext(Dispatchers.IO) { URLEncoder.encode( - "${query.songName} ${query.artistName}", + "${query.artistName}", Charsets.UTF_8.toString() ) } - if (search == " ") + val songName = withContext(Dispatchers.IO) { + URLEncoder.encode( + "${query.songName}", + Charsets.UTF_8.toString() + ) + } + + if (artistName == "" || songName == "") throw EmptyQueryException() val response = client.get( - "$baseURL/search?q=$search" + "$baseURL/full?artist=$artistName&track=$songName" ) val responseBody = response.bodyAsText(Charsets.UTF_8) - if (response.status.value !in 200..299 || responseBody == "[]") + if (response.status.value !in 200..299) return null - val json = json.decodeFromString>(responseBody) - - val result = json[0] - + val result = json.decodeFromString(responseBody) + return SongInfo( songName = result.songName, artistName = result.artistName, songLink = result.url, albumCoverLink = result.artwork, musixmatchID = result.id, + hasSyncedLyrics = result.hasSyncedLyrics, + hasUnsyncedLyrics = result.hasSyncedLyrics, + syncedLyrics = result.syncedLyrics?.lyrics, + unsyncedLyrics = result.unsyncedLyrics?.lyrics ) } /** - * Searches for synced lyrics using the song name and artist name. - * @param id The ID of the song from search results. - * @return The synced lyrics as a string. + * Returns the lyrics. + * @param songInfo The SongInfo of the song from search results. + * @return The lyrics as a string or null if the lyrics were not found. */ - suspend fun getSyncedLyrics(id: Long): String? { - val response = client.get( - "$baseURL/lyrics?id=$id" - ) - val responseBody = response.bodyAsText(Charsets.UTF_8) - - if (response.status.value !in 200..299) - return null - - val json = json.decodeFromString(responseBody) - return json.lyrics + fun getLyrics(songInfo: SongInfo?, synced: Boolean = true): String? { + return if(synced) songInfo?.syncedLyrics + else songInfo?.unsyncedLyrics } } \ No newline at end of file diff --git a/app/src/main/java/pl/lambada/songsync/domain/model/SongInfo.kt b/app/src/main/java/pl/lambada/songsync/domain/model/SongInfo.kt index 598c8fc..1767b8a 100644 --- a/app/src/main/java/pl/lambada/songsync/domain/model/SongInfo.kt +++ b/app/src/main/java/pl/lambada/songsync/domain/model/SongInfo.kt @@ -23,4 +23,8 @@ data class SongInfo( var neteaseID: Long? = null, // Netease-only var appleID: Long? = null, // Apple-only var musixmatchID: Long? = null, // Musixmatch-only + var hasSyncedLyrics: Boolean? = null, // Musixmatch-only + var hasUnsyncedLyrics: Boolean? = null, // Musixmatch-only + var syncedLyrics: String? = null, // Musixmatch-only + var unsyncedLyrics: String? = null, // Musixmatch-only ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/pl/lambada/songsync/domain/model/lyrics_providers/others/Musixmatch.kt b/app/src/main/java/pl/lambada/songsync/domain/model/lyrics_providers/others/Musixmatch.kt index 223ce36..917052a 100644 --- a/app/src/main/java/pl/lambada/songsync/domain/model/lyrics_providers/others/Musixmatch.kt +++ b/app/src/main/java/pl/lambada/songsync/domain/model/lyrics_providers/others/Musixmatch.kt @@ -14,14 +14,24 @@ data class MusixmatchSearchResponse( val url: String, val albumId: Long, val hasSyncedLyrics: Boolean, - val hasUnsyncedLyrics: Boolean + val hasUnsyncedLyrics: Boolean, + val syncedLyrics: SyncedLyricsResponse? = null, + val unsyncedLyrics: UnsyncedLyricsResponse? = null ) @Serializable -data class MusixmatchLyricsResponse( +data class SyncedLyricsResponse( val id: Long, val duration: Int, val language: String, val updatedTime: String, + val lyrics: String +) + +@Serializable +data class UnsyncedLyricsResponse( + val id: Long, + val language: String, + val updatedTime: String, val lyrics: String, ) diff --git a/app/src/main/java/pl/lambada/songsync/ui/screens/about/AboutScreen.kt b/app/src/main/java/pl/lambada/songsync/ui/screens/about/AboutScreen.kt index 3099d88..57f1f06 100644 --- a/app/src/main/java/pl/lambada/songsync/ui/screens/about/AboutScreen.kt +++ b/app/src/main/java/pl/lambada/songsync/ui/screens/about/AboutScreen.kt @@ -29,6 +29,7 @@ import pl.lambada.songsync.ui.screens.about.components.MultiPersonSwitch import pl.lambada.songsync.ui.screens.about.components.PureBlackThemeSwitch import pl.lambada.songsync.ui.screens.about.components.SdCardPathSetting import pl.lambada.songsync.ui.screens.about.components.SupportSection +import pl.lambada.songsync.ui.screens.about.components.SyncedLyricsSwitch import pl.lambada.songsync.ui.screens.about.components.TranslationSwitch import pl.lambada.songsync.ui.screens.about.components.UpdateAvailableDialog import pl.lambada.songsync.util.ext.getVersion @@ -89,6 +90,13 @@ fun AboutScreen( ) } + item { + SyncedLyricsSwitch( + selected = userSettingsController.syncedMusixmatch, + onToggle = { userSettingsController.updateSyncedMusixmatch(it) } + ) + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { item { SdCardPathSetting( diff --git a/app/src/main/java/pl/lambada/songsync/ui/screens/about/components/SyncedLyricsSwitch.kt b/app/src/main/java/pl/lambada/songsync/ui/screens/about/components/SyncedLyricsSwitch.kt new file mode 100644 index 0000000..3c0aa1d --- /dev/null +++ b/app/src/main/java/pl/lambada/songsync/ui/screens/about/components/SyncedLyricsSwitch.kt @@ -0,0 +1,18 @@ +package pl.lambada.songsync.ui.screens.about.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import pl.lambada.songsync.R +import pl.lambada.songsync.ui.components.AboutItem +import pl.lambada.songsync.ui.components.SwitchItem + +@Composable +fun SyncedLyricsSwitch(selected: Boolean, onToggle: (Boolean) -> Unit) { + AboutItem(label = stringResource(id = R.string.synced_lyrics)) { + SwitchItem( + label = stringResource(id = R.string.synced_lyrics_summary), + selected = selected, + onClick = { onToggle(!selected) } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/lambada/songsync/ui/screens/home/HomeViewModel.kt b/app/src/main/java/pl/lambada/songsync/ui/screens/home/HomeViewModel.kt index fa742a4..0090cc3 100644 --- a/app/src/main/java/pl/lambada/songsync/ui/screens/home/HomeViewModel.kt +++ b/app/src/main/java/pl/lambada/songsync/ui/screens/home/HomeViewModel.kt @@ -278,7 +278,8 @@ class HomeViewModel( version, provider = userSettingsController.selectedProvider, includeTranslationNetEase = userSettingsController.includeTranslation, - multiPersonWordByWord = userSettingsController.multiPersonWordByWord + multiPersonWordByWord = userSettingsController.multiPersonWordByWord, + syncedMusixmatch = userSettingsController.syncedMusixmatch ) } diff --git a/app/src/main/java/pl/lambada/songsync/ui/screens/lyricsFetch/LyricsFetchViewModel.kt b/app/src/main/java/pl/lambada/songsync/ui/screens/lyricsFetch/LyricsFetchViewModel.kt index 4ff1f27..027baea 100644 --- a/app/src/main/java/pl/lambada/songsync/ui/screens/lyricsFetch/LyricsFetchViewModel.kt +++ b/app/src/main/java/pl/lambada/songsync/ui/screens/lyricsFetch/LyricsFetchViewModel.kt @@ -48,7 +48,8 @@ class LyricsFetchViewModel( version, userSettingsController.selectedProvider, userSettingsController.includeTranslation, - userSettingsController.multiPersonWordByWord + userSettingsController.multiPersonWordByWord, + userSettingsController.syncedMusixmatch ) fun loadSongInfo(context: Context, tryingAgain: Boolean = false) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c20f643..9fe76ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,4 +125,6 @@ You tried to embed the lyrics to a non-local file. Aborting operation. Multi-person word by word lyrics Use multi-person lyrics format when getting lyrics from Apple Music + Get Synced Lyrics + Toggle to switch between synced and unsynced lyrics from Musixmatch. \ No newline at end of file