Skip to content

Commit

Permalink
Chapter selection feature (mpv)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuroyami committed Jan 6, 2024
1 parent ae9484b commit 5f5f879
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 79 deletions.
43 changes: 23 additions & 20 deletions androidApp/src/main/java/com/yuroyami/syncplay/WatchActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.C.STREAM_TYPE_MUSIC
import com.yuroyami.syncplay.player.BasePlayer.ENGINE
import com.yuroyami.syncplay.player.PlayerUtils.getEngineForString
Expand All @@ -32,10 +33,12 @@ import com.yuroyami.syncplay.player.mpv.MpvPlayer
import com.yuroyami.syncplay.player.mpv.mpvRoomSettings
import com.yuroyami.syncplay.settings.DataStoreKeys
import com.yuroyami.syncplay.settings.DataStoreKeys.PREF_INROOM_PIP
import com.yuroyami.syncplay.settings.DataStoreKeys.PREF_INROOM_PLAYER_SUBTITLE_SIZE
import com.yuroyami.syncplay.settings.SettingObtainerCallback
import com.yuroyami.syncplay.settings.obtainerCallback
import com.yuroyami.syncplay.settings.settingBoolean
import com.yuroyami.syncplay.settings.valueBlockingly
import com.yuroyami.syncplay.settings.valueSuspendingly
import com.yuroyami.syncplay.utils.UIUtils.cutoutMode
import com.yuroyami.syncplay.utils.UIUtils.hideSystemUI
import com.yuroyami.syncplay.utils.changeLanguage
Expand All @@ -47,6 +50,8 @@ import com.yuroyami.syncplay.watchroom.RoomUI
import com.yuroyami.syncplay.watchroom.gestureCallback
import com.yuroyami.syncplay.watchroom.isSoloMode
import com.yuroyami.syncplay.watchroom.viewmodel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

@Suppress("deprecation")
class WatchActivity : ComponentActivity() {
Expand Down Expand Up @@ -94,7 +99,7 @@ class WatchActivity : ComponentActivity() {
}

obtainerCallback = object: SettingObtainerCallback {
override fun getMoreRoomSettings() = mpvRoomSettings
override fun getMoreRoomSettings() = if (viewmodel?.player?.engine == ENGINE.ANDROID_MPV) mpvRoomSettings else listOf()
}

gestureCallback = object : GestureCallback {
Expand Down Expand Up @@ -168,25 +173,20 @@ class WatchActivity : ComponentActivity() {
// /** Applying track choices again so the player doesn't forget about track choices **/
// reapplyTrackChoices()
// }
//
// override fun onDestroy() {
// super.onDestroy()
// unregisterReceiver(pipBroadcastReceiver)
// }
//
// /** the onStart() follows the onCreate(), it means all the UI is ready
// * It precedes any activity results. onCreate -> onStart -> ActivityResults -> onResume */
// override fun onStart() {
// super.onStart()
//
//
// /** Loading subtitle appearance */
// lifecycleScope.launch(Dispatchers.Main) {
// val ccsize = DataStoreKeys.DATASTORE_INROOM_PREFERENCES.obtainInt(PREF_INROOM_PLAYER_SUBTITLE_SIZE, 16)
// retweakSubtitleAppearance(ccsize.toFloat())
// }
// }
//


/** the onStart() follows the onCreate(), it means all the UI is ready
* It precedes any activity results. onCreate -> onStart -> ActivityResults -> onResume */
override fun onStart() {
super.onStart()

/* Loading subtitle appearance */
lifecycleScope.launch(Dispatchers.Main) {
val ccsize = valueSuspendingly(PREF_INROOM_PLAYER_SUBTITLE_SIZE, 16)
(viewmodel?.player as? ExoPlayer)?.retweakSubtitleAppearance(ccsize.toFloat())
}
}


@SuppressLint("MissingSuperCall")
override fun onBackPressed() {
Expand Down Expand Up @@ -291,6 +291,9 @@ class WatchActivity : ComponentActivity() {
registerReceiver(pipBroadcastReceiver, filter)

hideSystemUI(false)

/** Applying track choices again so the player doesn't forget about track choices **/
viewmodel?.player?.reapplyTrackChoices()
}

override fun onDestroy() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.yuroyami.syncplay.player.exo

import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.Typeface
import android.util.TypedValue
import android.view.LayoutInflater
import androidx.compose.runtime.Composable
Expand All @@ -21,12 +23,14 @@ import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.session.MediaSession
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.CaptionStyleCompat
import androidx.media3.ui.PlayerView
import cafe.adriel.lyricist.Lyricist
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import com.yuroyami.syncplay.databinding.ExoviewBinding
import com.yuroyami.syncplay.lyricist.Stringies
import com.yuroyami.syncplay.models.Chapter
import com.yuroyami.syncplay.models.MediaFile
import com.yuroyami.syncplay.models.Track
import com.yuroyami.syncplay.player.BasePlayer
Expand All @@ -46,6 +50,7 @@ import kotlinx.coroutines.launch
import java.io.IOException
import java.util.Collections
import kotlin.math.abs
import kotlin.math.roundToInt

class ExoPlayer : BasePlayer() {
override val engine = ENGINE.ANDROID_EXOPLAYER
Expand Down Expand Up @@ -268,6 +273,18 @@ class ExoPlayer : BasePlayer() {
}
}

override fun analyzeChapters(mediafile: MediaFile) {
//TODO("Not yet implemented")
}

override fun jumpToChapter(chapter: Chapter) {
//TODO("Not yet implemented")
}

override fun skipChapter() {
//TODO("Not yet implemented")
}

override fun reapplyTrackChoices() {
/* We need to cast MediaController to ExoPlayer since they're roughly the same */
analyzeTracks(viewmodel?.media ?: return)
Expand Down Expand Up @@ -352,8 +369,12 @@ class ExoPlayer : BasePlayer() {
.setUri(viewmodel?.media?.uri)
.setMediaId(viewmodel?.media?.uri.toString())
.apply {
setSubtitleConfigurations(Collections.singletonList(viewmodel?.media?.externalSub
as? MediaItem.SubtitleConfiguration ?: return@apply))
setSubtitleConfigurations(
Collections.singletonList(
viewmodel?.media?.externalSub
as? MediaItem.SubtitleConfiguration ?: return@apply
)
)
}
.build()

Expand Down Expand Up @@ -437,11 +458,24 @@ class ExoPlayer : BasePlayer() {
}

/** EXO-EXCLUSIVE */

private fun TRACKTYPE.getExoType(): Int {
return when (this) {
TRACKTYPE.AUDIO -> C.TRACK_TYPE_AUDIO
TRACKTYPE.SUBTITLE -> C.TRACK_TYPE_TEXT
}
}

fun retweakSubtitleAppearance(
size: Float,
captionStyle: CaptionStyleCompat = CaptionStyleCompat(
Color.WHITE, Color.TRANSPARENT, Color.TRANSPARENT,
CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW, Color.BLACK, Typeface.DEFAULT_BOLD
)
) {
if (::exoView.isInitialized) {
exoView.subtitleView?.setStyle(captionStyle)
changeSubtitleSize(size.roundToInt())

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.media3.common.MimeTypes
import cafe.adriel.lyricist.Lyricist
import com.yuroyami.syncplay.databinding.MpvviewBinding
import com.yuroyami.syncplay.lyricist.Stringies
import com.yuroyami.syncplay.models.Chapter
import com.yuroyami.syncplay.models.MediaFile
import com.yuroyami.syncplay.models.Track
import com.yuroyami.syncplay.player.BasePlayer
Expand All @@ -25,6 +26,7 @@ import com.yuroyami.syncplay.utils.RoomUtils.sendPlayback
import com.yuroyami.syncplay.utils.collectInfoLocalAndroid
import com.yuroyami.syncplay.utils.getFileName
import com.yuroyami.syncplay.utils.loggy
import com.yuroyami.syncplay.utils.timeStamper
import com.yuroyami.syncplay.watchroom.dispatchOSD
import com.yuroyami.syncplay.watchroom.isSoloMode
import com.yuroyami.syncplay.watchroom.lyricist
Expand All @@ -38,6 +40,7 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import kotlin.math.roundToLong

class MpvPlayer : BasePlayer() {

Expand All @@ -56,10 +59,6 @@ class MpvPlayer : BasePlayer() {
ctx = mpvView.context.applicationContext

copyAssets(ctx)

//TODO: LoadControl
//TODO: AudioLock
//TODO: TrackSelection applying default language
}

@Composable
Expand Down Expand Up @@ -92,7 +91,7 @@ class MpvPlayer : BasePlayer() {
// so use ?: continue instead of !!
for (i in 0 until count) {
val type = MPVLib.getPropertyString("track-list/$i/type") ?: continue
if (type != "audio" && type != "sub") continue;
if (type != "audio" && type != "sub") continue
val mpvId = MPVLib.getPropertyInt("track-list/$i/id") ?: continue
val lang = MPVLib.getPropertyString("track-list/$i/lang")
val title = MPVLib.getPropertyString("track-list/$i/title")
Expand Down Expand Up @@ -160,6 +159,32 @@ class MpvPlayer : BasePlayer() {
}
}

override fun analyzeChapters(mediafile: MediaFile) {
if (!ismpvInit) return
val chapters = mpvView.loadChapters()
if (chapters.isEmpty()) return
mediafile.chapters.clear()
mediafile.chapters.addAll(chapters.map {
val timestamp = " (${timeStamper(it.time.roundToLong())})"
Chapter(
it.index,
(it.title ?: "Chapter ${it.index}") + timestamp,
(it.time * 1000).roundToLong()
)
})
}

override fun jumpToChapter(chapter: Chapter) {
if (!ismpvInit) return
MPVLib.setPropertyInt("chapter", chapter.index)
}

override fun skipChapter() {
if (!ismpvInit) return

MPVLib.command(arrayOf("add", "chapter", "1"))
}

override fun reapplyTrackChoices() {
val subIndex = viewmodel?.currentTrackChoices?.subtitleSelectionIndexMpv
val audioIndex = viewmodel?.currentTrackChoices?.audioSelectionIndexMpv
Expand Down Expand Up @@ -307,6 +332,7 @@ class MpvPlayer : BasePlayer() {
newSize > 16 -> {
1.0 + (newSize - 16) * 0.05
}

else -> {
1.0 - (16 - newSize) * (1.0 / 16)
}
Expand Down Expand Up @@ -466,25 +492,21 @@ class MpvPlayer : BasePlayer() {

fun toggleHardwareAcceleration(b: Boolean) {
if (!ismpvInit) return

MPVLib.setOptionString("hwdec", if (b) "auto" else "no" )
MPVLib.setOptionString("hwdec", if (b) "auto" else "no")
}

fun toggleGpuNext(b: Boolean) {
if (!ismpvInit) return

MPVLib.setOptionString("vo", if (b) "gpu-next" else "gpu")
}

fun toggleInterpolation(b: Boolean) {
if (!ismpvInit) return

MPVLib.setOptionString("interpolation", if (b) "yes" else "no")
}

fun toggleDebugMode(i: Int) {
if (!ismpvInit) return

loggy("STATS $i", 0)
MPVLib.command(arrayOf("script-binding", "stats/display-page-$i"))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.yuroyami.syncplay.models

data class Chapter(
val index: Int,
val name: String,
val timestamp: Long
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ data class MediaFile(
/** The duration of the file (ms) **/
var fileDuration: Double = -1.0,

/** the subtitle and audio tracks for this file **/
/** the subtitle tracks, audio tracks and chapters for this file **/
var audioTracks: MutableList<Track> = mutableListOf(),
var subtitleTracks: MutableList<Track> = mutableListOf(),
val chapters: MutableList<Chapter> = mutableListOf(),


/** This refers to any external subtitle file that was loaded **/
var externalSub: Any? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.yuroyami.syncplay.player

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.yuroyami.syncplay.models.Chapter
import com.yuroyami.syncplay.models.MediaFile
import com.yuroyami.syncplay.utils.sha256
import com.yuroyami.syncplay.utils.toHex
Expand Down Expand Up @@ -55,6 +56,10 @@ abstract class BasePlayer {

abstract fun selectTrack(type: TRACKTYPE, index: Int)

abstract fun analyzeChapters(mediafile: MediaFile)
abstract fun jumpToChapter(chapter: Chapter)
abstract fun skipChapter()

abstract fun reapplyTrackChoices()

/** Loads an external sub given the [uri] */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class PlayerOptions private constructor() {
companion object {
fun get(): PlayerOptions {
val options = PlayerOptions()
options.maxBuffer = valueBlockingly(DataStoreKeys.PREF_MAX_BUFFER, 30000)
options.minBuffer = valueBlockingly(DataStoreKeys.PREF_MIN_BUFFER, 15000)
options.maxBuffer = valueBlockingly(DataStoreKeys.PREF_MAX_BUFFER, 30) * 1000
options.minBuffer = valueBlockingly(DataStoreKeys.PREF_MIN_BUFFER, 15) * 1000
options.playbackBuffer = valueBlockingly(DataStoreKeys.PREF_SEEK_BUFFER, 2000)

options.ccPreference = valueBlockingly(DataStoreKeys.PREF_CC_LANG, "eng")
Expand All @@ -35,8 +35,8 @@ class PlayerOptions private constructor() {

suspend fun getSuspendingly(): PlayerOptions {
val options = PlayerOptions()
options.maxBuffer = valueSuspendingly(DataStoreKeys.PREF_MAX_BUFFER, 30000)
options.minBuffer = valueSuspendingly(DataStoreKeys.PREF_MIN_BUFFER, 15000)
options.maxBuffer = valueSuspendingly(DataStoreKeys.PREF_MAX_BUFFER, 30) * 1000
options.minBuffer = valueSuspendingly(DataStoreKeys.PREF_MIN_BUFFER, 15) * 1000
options.playbackBuffer = valueSuspendingly(DataStoreKeys.PREF_SEEK_BUFFER, 2000)

options.ccPreference = valueSuspendingly(DataStoreKeys.PREF_CC_LANG, "eng")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,6 @@ object PlayerUtils {
}
}
}
//
// /** Changes the subtitle appearance given the size and captionStyle (otherwise, default will be used) */
// fun WatchActivity.retweakSubtitleAppearance(
// size: Float = 16f,
// captionStyle: CaptionStyleCompat = CaptionStyleCompat(
// Color.WHITE, Color.TRANSPARENT, Color.TRANSPARENT,
// CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW, Color.BLACK, Typeface.DEFAULT_BOLD
// ),
// ) {
// runOnUiThread {
// //TODO
// if (player?.engine == HighLevelPlayer.ENGINE.EXOPLAYER) {
// player?.exoView?.subtitleView?.setStyle(captionStyle)
// player?.exoView?.subtitleView?.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, size)
// }
// }
// }

/** Tracks progress CONTINUOUSLY and updates it to UI (and server, if no solo mode) */
fun trackProgress() {
Expand Down
Loading

0 comments on commit 5f5f879

Please sign in to comment.