small fixes

This commit is contained in:
reduplicated 2022-11-05 00:32:40 +01:00
parent 415c173524
commit e24dc692d0
5 changed files with 78 additions and 41 deletions

View File

@ -104,7 +104,7 @@ abstract class AbstractPlayerFragment(
throw NotImplementedError()
}
open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) {
open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
}

View File

@ -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) {
if (lastTimeStamp.skipToNextEpisode) {
handleEvent(CSPlayerEvent.NextEpisode)
} else {
seekTo(lastTimeStamp.endMs)
}
onTimestampSkipped?.invoke(lastTimeStamp)
break
getCurrentTimestamp()?.let { lastTimeStamp ->
if (lastTimeStamp.skipToNextEpisode) {
handleEvent(CSPlayerEvent.NextEpisode)
} else {
seekTo(lastTimeStamp.endMs + 1L)
}
onTimestampSkipped?.invoke(lastTimeStamp)
}
}
}
@ -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() {

View File

@ -646,8 +646,8 @@ class GeneratorPlayer : FullScreenPlayer() {
true,
{}) {
settingsManager.edit().putString(
ctx.getString(R.string.subtitles_encoding_key), prefValues[it]
).apply()
ctx.getString(R.string.subtitles_encoding_key), prefValues[it]
).apply()
updateForcedEncoding(ctx)
dismiss()
@ -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
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) {
skip_chapter_button.setText(timestamp.uiText)
displayTimeStamp(true)
skip_chapter_button?.handler?.postDelayed({
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)
}, 6000)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -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)
)

View File

@ -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,14 +38,14 @@ 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(
data: LoadResponse,
episode: ResultEpisode,
episodeDurationMs: Long,
hasNextEpisode : Boolean,
hasNextEpisode: Boolean,
): List<SkipStamp> {
cachedStamps[episode.id]?.let { list ->
return list
@ -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)