From f77dcfba64109d198f8f792343f08c725368038f Mon Sep 17 00:00:00 2001 From: ztftrue Date: Thu, 8 Feb 2024 17:39:00 +0800 Subject: [PATCH] fix:support for lyrics --- .../java/com/ztftrue/music/MusicViewModel.kt | 59 +++++++++++++------ .../com/ztftrue/music/ui/play/LyricsView.kt | 43 +++++++------- .../com/ztftrue/music/utils/model/Model.kt | 4 +- 3 files changed, 67 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/ztftrue/music/MusicViewModel.kt b/app/src/main/java/com/ztftrue/music/MusicViewModel.kt index 70062f3..f91f5e4 100644 --- a/app/src/main/java/com/ztftrue/music/MusicViewModel.kt +++ b/app/src/main/java/com/ztftrue/music/MusicViewModel.kt @@ -22,15 +22,15 @@ import com.ztftrue.music.sqlData.model.DictionaryApp import com.ztftrue.music.sqlData.model.MainTab import com.ztftrue.music.sqlData.model.MusicItem import com.ztftrue.music.ui.play.Lyrics -import com.ztftrue.music.utils.model.ListStringCaption -import com.ztftrue.music.utils.model.AnyListBase -import com.ztftrue.music.utils.model.Caption import com.ztftrue.music.utils.CaptionUtils -import com.ztftrue.music.utils.model.EqualizerBand import com.ztftrue.music.utils.LyricsType import com.ztftrue.music.utils.PlayListType import com.ztftrue.music.utils.ScrollDirectionType import com.ztftrue.music.utils.Utils +import com.ztftrue.music.utils.model.AnyListBase +import com.ztftrue.music.utils.model.Caption +import com.ztftrue.music.utils.model.EqualizerBand +import com.ztftrue.music.utils.model.ListStringCaption import java.io.File import java.io.InputStream @@ -93,7 +93,7 @@ class MusicViewModel : ViewModel() { // lyrics var itemDuration: Long = 1 - var hasTime: LyricsType = LyricsType.TEXT + var lyricsType: LyricsType = LyricsType.TEXT var currentCaptionList = mutableStateListOf() var fontSize = mutableIntStateOf(18) @@ -152,18 +152,18 @@ class MusicViewModel : ViewModel() { folder?.mkdirs() val id = currentPlay.name.replace(regexPattern, "_") val path = "${context.getExternalFilesDir(folderPath)?.absolutePath}/$id" -// context.getExternalFilesDir(folderPath)?.absolutePath + "/$id.lrc" val text = File("$path.txt") if (text.exists()) { - hasTime = LyricsType.TEXT - currentCaptionList.addAll(readLyricsOrText(text, context)) + lyricsType = LyricsType.TEXT + currentCaptionList.addAll(readText(text, context)) } else if (File("$path.lrc").exists()) { - hasTime = LyricsType.LRC + lyricsType = LyricsType.LRC + currentCaptionList.addAll(readLyrics(File("$path.lrc"), context)) } else if (File("$path.srt").exists()) { - hasTime = LyricsType.SRT + lyricsType = LyricsType.SRT currentCaptionList.addAll(readCaptions(File("$path.srt"), LyricsType.SRT)) } else if (File("$path.vtt").exists()) { - hasTime = LyricsType.VTT + lyricsType = LyricsType.VTT currentCaptionList.addAll(readCaptions(File("$path.vtt"), LyricsType.VTT)) } else { return @@ -174,23 +174,48 @@ class MusicViewModel : ViewModel() { itemDuration = duration / if (currentCaptionList.size == 0) 1 else currentCaptionList.size } - private fun readLyricsOrText(file: File, context: Context): ArrayList { + private fun readLyrics(file: File, context: Context): ArrayList { val arrayList = arrayListOf() val inputStream: InputStream = file.inputStream() val inputString = inputStream.bufferedReader().use { it.readText() } - inputString.split("\n").forEach { + val lyricsHashMap: LinkedHashMap = + linkedMapOf() + inputString.split("\n").forEachIndexed { _, it -> if (it.startsWith("offset:")) { -// TODO + // TODO } else { val captions = CaptionUtils.parseLyricLine(it, context) val an = ListStringCaption( - text = captions.text.split(Regex("[\\n\\r\\s]+")), + text = ArrayList(captions.text.split(Regex("[\\r\\s]+"))), timeStart = captions.timeStart, timeEnd = captions.timeEnd ) - arrayList.add(an) + val temp = lyricsHashMap[captions.timeStart] + if (temp != null) { + temp.text.add("\n") + temp.text.addAll(captions.text.split("[\\r\\s]+")) + } else { + lyricsHashMap[captions.timeStart] = an + } } } + arrayList.addAll(lyricsHashMap.values) + return arrayList + } + + private fun readText(file: File, context: Context): ArrayList { + val arrayList = arrayListOf() + val inputStream: InputStream = file.inputStream() + val inputString = inputStream.bufferedReader().use { it.readText() } + inputString.split("\n").forEach { + val captions = CaptionUtils.parseLyricLine(it, context) + val an = ListStringCaption( + text = ArrayList(captions.text.split(Regex("[\\n\\r\\s]+"))), + timeStart = captions.timeStart, + timeEnd = captions.timeEnd + ) + arrayList.add(an) + } return arrayList } @@ -207,7 +232,7 @@ class MusicViewModel : ViewModel() { val arrayList = arrayListOf() captions.forEach { val an = ListStringCaption( - text = it.text.split(Regex("[\\n\\r\\s]+")), + text = ArrayList(it.text.split(Regex("[\\n\\r\\s]+"))), timeStart = it.timeStart, timeEnd = it.timeEnd ) diff --git a/app/src/main/java/com/ztftrue/music/ui/play/LyricsView.kt b/app/src/main/java/com/ztftrue/music/ui/play/LyricsView.kt index 8bf021a..95ca598 100644 --- a/app/src/main/java/com/ztftrue/music/ui/play/LyricsView.kt +++ b/app/src/main/java/com/ztftrue/music/ui/play/LyricsView.kt @@ -66,9 +66,9 @@ import androidx.compose.ui.window.PopupProperties import androidx.media3.common.util.UnstableApi import com.ztftrue.music.MainActivity import com.ztftrue.music.MusicViewModel -import com.ztftrue.music.utils.model.ListStringCaption import com.ztftrue.music.utils.LyricsType import com.ztftrue.music.utils.Utils +import com.ztftrue.music.utils.model.ListStringCaption import com.ztftrue.music.utils.textToolbar.CustomTextToolbar import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -91,26 +91,29 @@ fun LyricsView( var showMenu by remember { mutableStateOf(false) } LaunchedEffect(musicViewModel.sliderPosition.floatValue) { val timeState = musicViewModel.sliderPosition.floatValue - - if (musicViewModel.hasTime == LyricsType.LRC) { - for ((index, entry) in musicViewModel.currentCaptionList.withIndex()) { - if (entry.timeStart > timeState) { - if (currentI != index) { - currentI = index - if (musicViewModel.autoScroll.value && isSelected && !showMenu) { - launch(Dispatchers.Main) { - // TODO calculate the scroll position by  - listState.scrollToItem( - if ((currentI - 1) < 0) 0 else (currentI - 1), - 0 - ) - } - } - } + if (musicViewModel.lyricsType == LyricsType.LRC) { + var cIndex = 0; + for (index in musicViewModel.currentCaptionList.size - 1 downTo 0) { + val entry = musicViewModel.currentCaptionList[index] + if (timeState > entry.timeStart) { + cIndex = index break } } - } else if (musicViewModel.hasTime == LyricsType.VTT || musicViewModel.hasTime == LyricsType.SRT) { + if (cIndex != currentI) { + currentI = cIndex + if (musicViewModel.autoScroll.value && isSelected && !showMenu) { + launch(Dispatchers.Main) { + // TODO calculate the scroll position by  + listState.scrollToItem( + if (currentI < 2) 0 else (currentI - 2), + 0 + ) + } + } + } + + } else if (musicViewModel.lyricsType == LyricsType.VTT || musicViewModel.lyricsType == LyricsType.SRT) { val cIndex = musicViewModel.currentCaptionList.binarySearch { if (it.timeStart <= timeState.toLong() && it.timeEnd >= timeState.toLong()) 0 else if (it.timeStart > timeState) { @@ -124,7 +127,7 @@ fun LyricsView( if (musicViewModel.autoScroll.value && isSelected && !showMenu) { launch(Dispatchers.Main) { // TODO calculate the scroll position by  - listState.scrollToItem(if ((currentI - 1) < 0) 0 else (currentI - 1), 0) + listState.scrollToItem(if (currentI < 2) 0 else (currentI - 2), 0) } } } @@ -135,7 +138,7 @@ fun LyricsView( }.text.isNotEmpty()) { if (musicViewModel.autoScroll.value && isSelected && !showMenu) { launch(Dispatchers.Main) { - listState.scrollToItem(if ((currentI - 1) < 0) 0 else (currentI - 1), 0) + listState.scrollToItem(if (currentI <2) 0 else (currentI - 2), 0) } } } diff --git a/app/src/main/java/com/ztftrue/music/utils/model/Model.kt b/app/src/main/java/com/ztftrue/music/utils/model/Model.kt index 02f82d8..3e5da1c 100644 --- a/app/src/main/java/com/ztftrue/music/utils/model/Model.kt +++ b/app/src/main/java/com/ztftrue/music/utils/model/Model.kt @@ -80,13 +80,13 @@ data class EqualizerBand( ) : Parcelable data class Caption( - val text: String, + var text: String, val timeStart: Long, val timeEnd: Long=0 ) data class ListStringCaption( - val text: List, + val text: ArrayList, val timeStart: Long, val timeEnd: Long=0 ) \ No newline at end of file