Skip to content

Commit

Permalink
add: support caption , vtt srt
Browse files Browse the repository at this point in the history
  • Loading branch information
ZTFtrue committed Jan 29, 2024
1 parent 7088b9c commit eca52da
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 88 deletions.
25 changes: 17 additions & 8 deletions app/src/main/java/com/ztftrue/music/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,16 @@ class MainActivity : ComponentActivity() {
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
cursor.moveToFirst()
val name = cursor.getString(nameIndex)
lyricsPath += if (name.endsWith(".txt")) {
lyricsPath += if (name.lowercase().endsWith(".lrc")) {
"lrc"
} else if (name.lowercase().endsWith(".srt")) {
"srt"
} else if (name.lowercase().endsWith(".vtt")) {
"vtt"
} else if (name.lowercase().endsWith(".txt")) {
"txt"
} else {
"lrc"
return@registerForActivityResult
}
val inputStream =
this@MainActivity.contentResolver.openInputStream(selectedFileUri)
Expand Down Expand Up @@ -349,9 +355,9 @@ class MainActivity : ComponentActivity() {

fun openFilePicker(filePath: String) {
lyricsPath = filePath
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "text/plain" // Specify the MIME type for text files
intent.addCategory(Intent.CATEGORY_OPENABLE)
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.type = "*/*" // Specify the MIME type for text files
// intent.addCategory(Intent.CATEGORY_OPENABLE)
// intent.type = "text/plain|application/octet-stream";
filePickerLauncher.launch(intent)
}
Expand Down Expand Up @@ -533,7 +539,7 @@ class MainActivity : ComponentActivity() {
// musicViewModel.musicQueue.value = musicViewModel.musicListMap[playList?.id]
} else if (it.getInt("type") == EVENT_MEDIA_ITEM_Change) {
// before switch to another music, must clear lyrics
musicViewModel.currentLyricsList.clear()
musicViewModel.currentCaptionList.clear()
val index = it.getInt("index")
if (index >= 0 && musicViewModel.musicQueue.size > index) {
musicViewModel.currentMusicCover.value = null
Expand Down Expand Up @@ -707,6 +713,8 @@ class MainActivity : ComponentActivity() {
musicViewModel.enableEcho.value = resultData.getBoolean("echoActive")
musicViewModel.echoFeedBack.value = resultData.getBoolean("echoFeedBack")
musicViewModel.repeatModel.intValue = resultData.getInt("repeat", Player.REPEAT_MODE_ALL)
musicViewModel.sliderPosition.floatValue = resultData.getFloat("position", 0F)
// SleepTime wait when play next
musicViewModel.playCompleted.value =
resultData.getBoolean("play_completed")
getSeek()
Expand Down Expand Up @@ -1039,7 +1047,7 @@ class MainActivity : ComponentActivity() {
musicViewModel.currentPlay.value = null
musicViewModel.playListCurrent.value = null
musicViewModel.currentPlayQueueIndex.intValue = 0
musicViewModel.currentLyricsList.clear()
musicViewModel.currentCaptionList.clear()
} else if (it == OperateType.SaveQueueToPlayList) {

showAddPlayListDialog = true
Expand Down Expand Up @@ -1077,7 +1085,8 @@ class MainActivity : ComponentActivity() {
musicViewModel.musicQueue.forEach {
ids.add(it.id)
}
val idPlayList = PlaylistManager.createPlaylist(context, playListName)
val idPlayList =
PlaylistManager.createPlaylist(context, playListName)
if (idPlayList != -1L) {
PlaylistManager.addMusicsToPlaylist(
context,
Expand Down
62 changes: 39 additions & 23 deletions app/src/main/java/com/ztftrue/music/MusicViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ 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.AnyListBase
import com.ztftrue.music.utils.Caption
import com.ztftrue.music.utils.EqualizerBand
import com.ztftrue.music.utils.Lyrics
import com.ztftrue.music.utils.LyricsType
import com.ztftrue.music.utils.PlayListType
import com.ztftrue.music.utils.ScrollDirectionType
import com.ztftrue.music.utils.Utils
Expand Down Expand Up @@ -85,8 +86,8 @@ class MusicViewModel : ViewModel() {

// lyrics
var itemDuration: Long = 1
var hasTime: Boolean = false
var currentLyricsList = mutableStateListOf<Lyrics>()
var hasTime: LyricsType = LyricsType.TEXT
var currentCaptionList = mutableStateListOf<Caption>()

// sleep time
var sleepTime = mutableLongStateOf(0L)
Expand All @@ -96,7 +97,7 @@ class MusicViewModel : ViewModel() {
var repeatModel = mutableIntStateOf(Player.REPEAT_MODE_ALL)
fun reset() {
if (currentPlay.value != null) {
currentLyricsList.clear()
currentCaptionList.clear()
}
mediaBrowser = null
mediaController = null
Expand Down Expand Up @@ -127,8 +128,8 @@ class MusicViewModel : ViewModel() {
}

fun dealLyrics(context: Context, currentPlay: MusicItem) {
currentLyricsList.clear()
if (currentLyricsList.isEmpty()) {
currentCaptionList.clear()
if (currentCaptionList.isEmpty()) {
val regexPattern = Regex("[<>\"/~'{}?,+=)(^&*%!@#\$]")
val artistsFolder = currentPlay.artist.replace(
regexPattern,
Expand All @@ -140,21 +141,23 @@ class MusicViewModel : ViewModel() {
)
folder?.mkdirs()
val id = currentPlay.name.replace(regexPattern, "_")
val pathLyrics: String =
context.getExternalFilesDir(folderPath)?.absolutePath + "/$id.lrc"
val path: String =
context.getExternalFilesDir(folderPath)?.absolutePath + "/$id.txt"
val lyrics = File(pathLyrics)
val text = File(path)
if (lyrics.exists()) {
hasTime = true
currentLyricsList.addAll(read(lyrics, context))
} else if (text.exists()) {
hasTime = false
currentLyricsList.addAll(read(text, context))
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))
} else if (File("$path.lrc").exists()) {
hasTime = LyricsType.LRC
} else if (File("$path.srt").exists()) {
hasTime = LyricsType.SRT
currentCaptionList.addAll(readCaptions(File("$path.srt"), LyricsType.SRT))
} else if (File("$path.vtt").exists()) {
hasTime = LyricsType.VTT
currentCaptionList.addAll(readCaptions(File("$path.vtt"), LyricsType.VTT))
} else {
currentLyricsList.add(
Lyrics(
currentCaptionList.add(
Caption(
text = "No Lyrics, Double click to import lyrics",
0,
)
Expand All @@ -164,11 +167,11 @@ class MusicViewModel : ViewModel() {
}
val duration = currentPlay.duration
// every lyrics line duration
itemDuration = duration / currentLyricsList.size
itemDuration = duration / currentCaptionList.size
}

private fun read(file: File, context: Context): ArrayList<Lyrics> {
val arrayList = arrayListOf<Lyrics>()
private fun readLyricsOrText(file: File, context: Context): ArrayList<Caption> {
val arrayList = arrayListOf<Caption>()
val inputStream: InputStream = file.inputStream()
val inputString = inputStream.bufferedReader().use { it.readText() }
inputString.split("\n").forEach {
Expand All @@ -181,6 +184,19 @@ class MusicViewModel : ViewModel() {
return arrayList
}

private fun readCaptions(
file: File,
captionType: LyricsType,
): ArrayList<Caption> {
val arrayList = arrayListOf<Caption>()
if (captionType == LyricsType.SRT) {
arrayList.addAll(Utils.parseSrtFile(file))
} else if (captionType == LyricsType.VTT) {
arrayList.addAll(Utils.parseVttFile(file))
}
return arrayList
}

fun getCover(path: String): Bitmap? {
try {
retriever.setDataSource(path)
Expand Down
29 changes: 18 additions & 11 deletions app/src/main/java/com/ztftrue/music/play/CreateNotification.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.media.session.MediaButtonReceiver
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import com.ztftrue.music.MainActivity
import com.ztftrue.music.R

Expand Down Expand Up @@ -67,14 +66,21 @@ class CreateNotification(service: Service, private val mediaSession: MediaSessio
service.stopForeground(STOP_FOREGROUND_REMOVE)
}

// exoPlayer: ExoPlayer,
fun updateNotification(
service: Service,
title: String,
subTitle: String,
exoPlayer: ExoPlayer
isPlaying: Boolean,
playSpeed: Float = 1f,
position: Long = 0L,
duration: Long = 0L
) {
val metadataBuilder = MediaMetadataCompat.Builder()
metadataBuilder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, exoPlayer.duration)
metadataBuilder.putLong(
MediaMetadataCompat.METADATA_KEY_DURATION,
duration
)
metadataBuilder.putText(MediaMetadataCompat.METADATA_KEY_TITLE, title)
metadataBuilder.putText(MediaMetadataCompat.METADATA_KEY_ARTIST, subTitle)
mediaSession?.setMetadata(metadataBuilder.build())
Expand All @@ -83,9 +89,9 @@ class CreateNotification(service: Service, private val mediaSession: MediaSessio
mediaSession?.setPlaybackState(
PlaybackStateCompat.Builder()
.setState(
if (exoPlayer.isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED,
exoPlayer.currentPosition,
exoPlayer.playbackParameters.speed
if (isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED,
position,
playSpeed
)
.setActions(
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
Expand All @@ -96,7 +102,8 @@ class CreateNotification(service: Service, private val mediaSession: MediaSessio
)
mediaSession?.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)
val builder = NotificationCompat.Builder(service, CHANNEL_ID)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle()
Expand All @@ -123,8 +130,8 @@ class CreateNotification(service: Service, private val mediaSession: MediaSessio
)
)
.setProgress(
(exoPlayer.duration / 1000).toInt(),
(exoPlayer.currentPosition / 1000).toInt(),
(duration / 1000).toInt(),
(position / 1000).toInt(),
false
)
.setAutoCancel(false)
Expand All @@ -136,12 +143,12 @@ class CreateNotification(service: Service, private val mediaSession: MediaSessio
)
)
builder.addAction(
if (exoPlayer.isPlaying) {
if (isPlaying) {
R.drawable.pause
} else {
R.drawable.play
},
if (exoPlayer.isPlaying) "Pause" else "Play",
if (isPlaying) "Pause" else "Play",
MediaButtonReceiver.buildMediaButtonPendingIntent(
service,
PlaybackStateCompat.ACTION_PLAY_PAUSE
Expand Down
Loading

0 comments on commit eca52da

Please sign in to comment.