forked from recloudstream/cloudstream
small fixes
This commit is contained in:
parent
415c173524
commit
e24dc692d0
5 changed files with 78 additions and 41 deletions
|
@ -104,7 +104,7 @@ abstract class AbstractPlayerFragment(
|
|||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) {
|
||||
open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ class CS3IPlayer : IPlayer {
|
|||
private var playerUpdated: ((Any?) -> Unit)? = null
|
||||
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
|
||||
private var onTracksInfoChanged: (() -> Unit)? = null
|
||||
private var onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)? = null
|
||||
private var onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)? = null
|
||||
private var onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)? = null
|
||||
|
||||
override fun releaseCallbacks() {
|
||||
|
@ -150,7 +150,7 @@ class CS3IPlayer : IPlayer {
|
|||
subtitlesUpdates: (() -> Unit)?,
|
||||
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)?,
|
||||
onTracksInfoChanged: (() -> Unit)?,
|
||||
onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)?,
|
||||
onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)?,
|
||||
onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)?,
|
||||
) {
|
||||
this.playerUpdated = playerUpdated
|
||||
|
@ -731,7 +731,7 @@ class CS3IPlayer : IPlayer {
|
|||
source
|
||||
}
|
||||
|
||||
println("PLAYBACK POS $playbackPosition")
|
||||
//println("PLAYBACK POS $playbackPosition")
|
||||
return exoPlayerBuilder.build().apply {
|
||||
setPlayWhenReady(playWhenReady)
|
||||
seekTo(currentWindow, playbackPosition)
|
||||
|
@ -747,8 +747,22 @@ class CS3IPlayer : IPlayer {
|
|||
}
|
||||
}
|
||||
|
||||
fun updatedTime() {
|
||||
val position = exoPlayer?.currentPosition
|
||||
private fun getCurrentTimestamp(writePosition : Long? = null): EpisodeSkip.SkipStamp? {
|
||||
val position = writePosition ?: this@CS3IPlayer.getPosition() ?: return null
|
||||
for (lastTimeStamp in lastTimeStamps) {
|
||||
if (lastTimeStamp.startMs <= position && position < lastTimeStamp.endMs) {
|
||||
return lastTimeStamp
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun updatedTime(writePosition : Long? = null) {
|
||||
getCurrentTimestamp(writePosition)?.let { timestamp ->
|
||||
onTimestampInvoked?.invoke(timestamp)
|
||||
}
|
||||
|
||||
val position = writePosition ?: exoPlayer?.currentPosition
|
||||
val duration = exoPlayer?.contentDuration
|
||||
if (duration != null && position != null) {
|
||||
playerPositionChanged?.invoke(Pair(position, duration))
|
||||
|
@ -760,12 +774,12 @@ class CS3IPlayer : IPlayer {
|
|||
}
|
||||
|
||||
override fun seekTo(time: Long) {
|
||||
updatedTime()
|
||||
updatedTime(time)
|
||||
exoPlayer?.seekTo(time)
|
||||
}
|
||||
|
||||
private fun ExoPlayer.seekTime(time: Long) {
|
||||
updatedTime()
|
||||
updatedTime(currentPosition + time)
|
||||
seekTo(currentPosition + time)
|
||||
}
|
||||
|
||||
|
@ -803,18 +817,13 @@ class CS3IPlayer : IPlayer {
|
|||
CSPlayerEvent.PrevEpisode -> prevEpisode?.invoke()
|
||||
CSPlayerEvent.SkipCurrentChapter -> {
|
||||
//val dur = this@CS3IPlayer.getDuration() ?: return@apply
|
||||
val pos = this@CS3IPlayer.getPosition() ?: return@apply
|
||||
for (lastTimeStamp in lastTimeStamps) {
|
||||
if (lastTimeStamp.startMs <= pos && pos < lastTimeStamp.endMs) {
|
||||
getCurrentTimestamp()?.let { lastTimeStamp ->
|
||||
if (lastTimeStamp.skipToNextEpisode) {
|
||||
handleEvent(CSPlayerEvent.NextEpisode)
|
||||
} else {
|
||||
seekTo(lastTimeStamp.endMs)
|
||||
seekTo(lastTimeStamp.endMs + 1L)
|
||||
}
|
||||
|
||||
onTimestampSkipped?.invoke(lastTimeStamp)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1039,16 +1048,18 @@ class CS3IPlayer : IPlayer {
|
|||
override fun addTimeStamps(timeStamps: List<EpisodeSkip.SkipStamp>) {
|
||||
lastTimeStamps = timeStamps
|
||||
timeStamps.forEach { timestamp ->
|
||||
exoPlayer?.createMessage { _, payload ->
|
||||
if (payload is EpisodeSkip.SkipStamp) // this should always be true
|
||||
onTimestampInvoked?.invoke(payload)
|
||||
exoPlayer?.createMessage { _, _ ->
|
||||
updatedTime()
|
||||
//if (payload is EpisodeSkip.SkipStamp) // this should always be true
|
||||
// onTimestampInvoked?.invoke(payload)
|
||||
}
|
||||
?.setLooper(Looper.getMainLooper())
|
||||
?.setPosition(timestamp.startMs)
|
||||
?.setPayload(timestamp)
|
||||
//?.setPayload(timestamp)
|
||||
?.setDeleteAfterDelivery(false)
|
||||
?.send()
|
||||
}
|
||||
updatedTime()
|
||||
}
|
||||
|
||||
fun onRenderFirst() {
|
||||
|
|
|
@ -869,7 +869,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
if ((currentMeta as? ResultEpisode)?.tvType == TvType.NSFW) return
|
||||
|
||||
val (position, duration) = posDur
|
||||
if (duration == 0L) return // idk how you achieved this, but div by zero crash
|
||||
if (duration <= 0L) return // idk how you achieved this, but div by zero crash
|
||||
if (!hasRequestedStamps) {
|
||||
hasRequestedStamps = true
|
||||
viewModel.loadStamps(duration)
|
||||
|
@ -1151,8 +1151,13 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
|
||||
var timestampShowState = false
|
||||
|
||||
var skipAnimator: ValueAnimator? = null
|
||||
var skipIndex = 0
|
||||
|
||||
private fun displayTimeStamp(show: Boolean) {
|
||||
if (timestampShowState == show) return
|
||||
skipIndex++
|
||||
println("displayTimeStamp = $show")
|
||||
timestampShowState = show
|
||||
skip_chapter_button?.apply {
|
||||
val showWidth = 170.toPx
|
||||
|
@ -1163,14 +1168,14 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
val to = if (show) showWidth else noShowWidth
|
||||
val from = if (!show) showWidth else noShowWidth
|
||||
|
||||
skipAnimator?.cancel()
|
||||
isVisible = true
|
||||
|
||||
// just in case
|
||||
val lay = layoutParams
|
||||
lay.width = from
|
||||
layoutParams = lay
|
||||
|
||||
ValueAnimator.ofInt(
|
||||
skipAnimator = ValueAnimator.ofInt(
|
||||
from, to
|
||||
).apply {
|
||||
addListener(onEnd = {
|
||||
|
@ -1192,12 +1197,18 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
displayTimeStamp(false)
|
||||
}
|
||||
|
||||
override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) {
|
||||
override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
|
||||
if (timestamp != null) {
|
||||
skip_chapter_button.setText(timestamp.uiText)
|
||||
displayTimeStamp(true)
|
||||
val currentIndex = skipIndex
|
||||
skip_chapter_button?.handler?.postDelayed({
|
||||
if (skipIndex == currentIndex)
|
||||
displayTimeStamp(false)
|
||||
}, 6000)
|
||||
} else {
|
||||
displayTimeStamp(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
|
|
@ -126,7 +126,7 @@ interface IPlayer {
|
|||
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
|
||||
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
|
||||
onTracksInfoChanged: (() -> Unit)? = null, // Callback when tracks are changed, used for UI changes
|
||||
onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)? = null, // Callback when timestamps appear
|
||||
onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)? = null, // Callback when timestamps appear, null when it should disappear
|
||||
onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)? = null, // callback for when a chapter is skipped, aka when event is handled (or for future use when skip automatically ads/sponsor)
|
||||
)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId
|
|||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import java.lang.Long.min
|
||||
|
||||
object EpisodeSkip {
|
||||
private const val TAG = "EpisodeSkip"
|
||||
|
@ -37,7 +38,7 @@ object EpisodeSkip {
|
|||
private val cachedStamps = HashMap<Int, List<SkipStamp>>()
|
||||
|
||||
private fun shouldSkipToNextEpisode(endMs: Long, episodeDurationMs: Long): Boolean {
|
||||
return episodeDurationMs - endMs < 12_000L
|
||||
return episodeDurationMs - endMs < 20_000L // some might have outro that we don't care about tbh
|
||||
}
|
||||
|
||||
suspend fun getStamps(
|
||||
|
@ -55,7 +56,14 @@ object EpisodeSkip {
|
|||
|
||||
if (data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.OVA)) {
|
||||
data.getMalId()?.toIntOrNull()?.let { malId ->
|
||||
AniSkip.getResult(malId, episode.episode, episodeDurationMs)?.mapNotNull { stamp ->
|
||||
val (resultLength, stamps) = AniSkip.getResult(
|
||||
malId,
|
||||
episode.episode,
|
||||
episodeDurationMs
|
||||
) ?: return@let null
|
||||
// because it also returns an expected episode length we use that just in case it is mismatched with like 2s next episode will still work
|
||||
val dur = min(episodeDurationMs, resultLength)
|
||||
stamps.mapNotNull { stamp ->
|
||||
val skipType = when (stamp.skipType) {
|
||||
"op" -> SkipType.Opening
|
||||
"ed" -> SkipType.Ending
|
||||
|
@ -68,7 +76,10 @@ object EpisodeSkip {
|
|||
val start = (stamp.interval.startTime * 1000.0).toLong()
|
||||
SkipStamp(
|
||||
type = skipType,
|
||||
skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(end, episodeDurationMs),
|
||||
skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(
|
||||
end,
|
||||
dur
|
||||
),
|
||||
startMs = start,
|
||||
endMs = end
|
||||
)
|
||||
|
@ -87,7 +98,11 @@ object EpisodeSkip {
|
|||
// the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md
|
||||
object AniSkip {
|
||||
private const val TAG = "AniSkip"
|
||||
suspend fun getResult(malId: Int, episodeNumber: Int, episodeLength: Long): List<Stamp>? {
|
||||
suspend fun getResult(
|
||||
malId: Int,
|
||||
episodeNumber: Int,
|
||||
episodeLength: Long
|
||||
): Pair<Long, List<Stamp>>? {
|
||||
return try {
|
||||
val url =
|
||||
"https://api.aniskip.com/v2/skip-times/$malId/$episodeNumber?types[]=ed&types[]=mixed-ed&types[]=mixed-op&types[]=op&types[]=recap&episodeLength=${episodeLength / 1000L}"
|
||||
|
@ -96,7 +111,7 @@ object AniSkip {
|
|||
val a = app.get(url)
|
||||
val res = a.parsed<AniSkipResponse>()
|
||||
Log.i(TAG, "Found ${res.found} with ${res.results?.size} results")
|
||||
if (res.found) res.results else null
|
||||
if (res.found && !res.results.isNullOrEmpty()) (res.results[0].episodeLength * 1000).toLong() to res.results else null
|
||||
} catch (t: Throwable) {
|
||||
Log.i(TAG, "error = ${t.message}")
|
||||
logError(t)
|
||||
|
|
Loading…
Reference in a new issue