diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index 32df314f..63895cab 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -337,6 +337,9 @@ object CommonActivity { KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4, KeyEvent.KEYCODE_4 -> { PlayerEventType.SkipOp } + KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_NUMPAD_5, KeyEvent.KEYCODE_5 -> { + PlayerEventType.SkipOp + } KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation PlayerEventType.PlayPauseToggle } diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index eb83b08a..b2395bea 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -88,6 +88,9 @@ import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_result_swipe.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import okhttp3.internal.applyConnectionSpec import java.io.File import java.net.URI import java.nio.charset.Charset @@ -179,6 +182,7 @@ var app = Requests(responseParser = object : ResponseParser { } }).apply { defaultHeaders = mapOf("user-agent" to USER_AGENT) + //baseClient = baseClient.newBuilder().connectionSpecs(listOf(ConnectionSpec.COMPATIBLE_TLS)).build() } class MainActivity : AppCompatActivity(), ColorPickerDialogListener { diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/RequestsHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/network/RequestsHelper.kt index 13299002..67ffa732 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/RequestsHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/RequestsHelper.kt @@ -6,10 +6,8 @@ import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.ignoreAllSSLErrors -import okhttp3.Cache -import okhttp3.Headers +import okhttp3.* import okhttp3.Headers.Companion.toHeaders -import okhttp3.OkHttpClient import java.io.File diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index 9a0debcf..d7076ae6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -38,6 +38,7 @@ import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils.requestLocalAudioFocus +import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.UIHelper import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage @@ -103,6 +104,10 @@ abstract class AbstractPlayerFragment( throw NotImplementedError() } + open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { + + } + open fun exitedPipMode() { throw NotImplementedError() } @@ -373,7 +378,8 @@ abstract class AbstractPlayerFragment( ), subtitlesUpdates = ::subtitlesChanged, embeddedSubtitlesFetched = ::embeddedSubtitlesFetched, - onTracksInfoChanged = ::onTracksInfoChanged + onTracksInfoChanged = ::onTracksInfoChanged, + onTimestampInvoked = ::onTimestamp ) if (player is CS3IPlayer) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index f60d8c78..0f8a63e2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -18,7 +18,10 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector import com.google.android.exoplayer2.trackselection.TrackSelectionOverride import com.google.android.exoplayer2.trackselection.TrackSelector import com.google.android.exoplayer2.ui.SubtitleView -import com.google.android.exoplayer2.upstream.* +import com.google.android.exoplayer2.upstream.DataSource +import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource +import com.google.android.exoplayer2.upstream.HttpDataSource import com.google.android.exoplayer2.upstream.cache.CacheDataSource import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor import com.google.android.exoplayer2.upstream.cache.SimpleCache @@ -32,6 +35,7 @@ import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle +import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLinkPlayList import com.lagradost.cloudstream3.utils.ExtractorUri @@ -113,6 +117,7 @@ class CS3IPlayer : IPlayer { private var playerUpdated: ((Any?) -> Unit)? = null private var embeddedSubtitlesFetched: ((List) -> Unit)? = null private var onTracksInfoChanged: (() -> Unit)? = null + private var onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)? = null override fun releaseCallbacks() { playerUpdated = null @@ -126,6 +131,7 @@ class CS3IPlayer : IPlayer { prevEpisode = null subtitlesUpdates = null onTracksInfoChanged = null + onTimestampInvoked = null requestSubtitleUpdate = null } @@ -142,6 +148,7 @@ class CS3IPlayer : IPlayer { subtitlesUpdates: (() -> Unit)?, embeddedSubtitlesFetched: ((List) -> Unit)?, onTracksInfoChanged: (() -> Unit)?, + onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)?, ) { this.playerUpdated = playerUpdated this.updateIsPlaying = updateIsPlaying @@ -155,6 +162,7 @@ class CS3IPlayer : IPlayer { this.subtitlesUpdates = subtitlesUpdates this.embeddedSubtitlesFetched = embeddedSubtitlesFetched this.onTracksInfoChanged = onTracksInfoChanged + this.onTimestampInvoked = onTimestampInvoked } // I know, this is not a perfect solution, however it works for fixing subs @@ -789,6 +797,16 @@ class CS3IPlayer : IPlayer { CSPlayerEvent.SeekBack -> seekTime(-seekActionTime) CSPlayerEvent.NextEpisode -> nextEpisode?.invoke() 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) { + seekTo(lastTimeStamp.endMs) + break + } + } + } } } } catch (e: Exception) { @@ -1007,6 +1025,21 @@ class CS3IPlayer : IPlayer { } } + private var lastTimeStamps: List = emptyList() + override fun addTimeStamps(timeStamps: List) { + lastTimeStamps = timeStamps + timeStamps.forEach { timestamp -> + exoPlayer?.createMessage { _, payload -> + + } + ?.setLooper(Looper.getMainLooper()) + ?.setPosition(timestamp.startMs) + // .setPayload(customPayloadData) + ?.setDeleteAfterDelivery(false) + ?.send() + } + } + fun onRenderFirst() { if (!hasUsedFirstRender) { // this insures that we only call this once per player load Log.i(TAG, "Rendered first frame") diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt index 52125c68..0f9a6548 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt @@ -1141,6 +1141,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() { PlayerEventType.Play -> { player.handleEvent(CSPlayerEvent.Play) } + PlayerEventType.SkipCurrentChapter -> { + player.handleEvent(CSPlayerEvent.SkipCurrentChapter) + } PlayerEventType.Resize -> { nextResize() } @@ -1254,6 +1257,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() { player.handleEvent(CSPlayerEvent.PlayPauseToggle) } + skip_chapter_button?.setOnClickListener { + player.handleEvent(CSPlayerEvent.SkipCurrentChapter) + } + // init clicks player_resize_btt?.setOnClickListener { autoHide() diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index f466dd7e..180311f4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -36,8 +36,8 @@ import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSub import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.result.ResultFragment import com.lagradost.cloudstream3.ui.result.SyncViewModel +import com.lagradost.cloudstream3.ui.result.setText import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings -import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getAutoSelectLanguageISO639_1 import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.Coroutines.ioSafe @@ -58,7 +58,6 @@ import kotlinx.android.synthetic.main.player_select_source_and_subs.* import kotlinx.android.synthetic.main.player_select_source_and_subs.subtitles_click_settings import kotlinx.android.synthetic.main.player_select_tracks.* import kotlinx.coroutines.Job -import kotlinx.coroutines.delay class GeneratorPlayer : FullScreenPlayer() { companion object { @@ -165,6 +164,7 @@ class GeneratorPlayer : FullScreenPlayer() { isActive = true setPlayerDimen(null) setTitle() + hasRequestedStamps = false loadExtractorJob(link.first) // load player @@ -878,7 +878,7 @@ class GeneratorPlayer : FullScreenPlayer() { } var maxEpisodeSet: Int? = null - + var hasRequestedStamps: Boolean = false override fun playerPositionChanged(posDur: Pair) { // Don't save livestream data if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return @@ -888,10 +888,15 @@ class GeneratorPlayer : FullScreenPlayer() { val (position, duration) = posDur if (duration == 0L) return // idk how you achieved this, but div by zero crash + if (!hasRequestedStamps) { + hasRequestedStamps = true + viewModel.loadStamps(duration) + } viewModel.getId()?.let { DataStoreHelper.setViewPos(it, position, duration) } + val percentage = position * 100L / duration val nextEp = percentage >= NEXT_WATCH_EPISODE_PERCENTAGE @@ -1174,6 +1179,10 @@ class GeneratorPlayer : FullScreenPlayer() { return super.onCreateView(inflater, container, savedInstanceState) } + override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { + skip_chapter_button.setText(timestamp.uiText) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) var langFilterList = listOf() @@ -1203,7 +1212,7 @@ class GeneratorPlayer : FullScreenPlayer() { sync.updateUserData() - preferredAutoSelectSubtitles = SubtitlesFragment.getAutoSelectLanguageISO639_1() + preferredAutoSelectSubtitles = getAutoSelectLanguageISO639_1() if (currentSelectedLink == null) { viewModel.loadLinks() @@ -1218,6 +1227,10 @@ class GeneratorPlayer : FullScreenPlayer() { activity?.popCurrentPage() } + observe(viewModel.currentStamps) { stamps -> + player.addTimeStamps(stamps) + } + observe(viewModel.loadingLinks) { when (it) { is Resource.Loading -> { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt index 473b3e65..2f71ef79 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.player import android.content.Context import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle +import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorUri @@ -12,9 +13,9 @@ enum class PlayerEventType(val value: Int) { SeekForward(2), SeekBack(3), - //SkipCurrentChapter(4), + SkipCurrentChapter(4), NextEpisode(5), - PrevEpisode(5), + PrevEpisode(6), PlayPauseToggle(7), ToggleMute(8), Lock(9), @@ -32,7 +33,7 @@ enum class CSPlayerEvent(val value: Int) { SeekForward(2), SeekBack(3), - //SkipCurrentChapter(4), + SkipCurrentChapter(4), NextEpisode(5), PrevEpisode(6), PlayPauseToggle(7), @@ -54,7 +55,8 @@ interface Track { **/ val id: String? val label: String? -// val isCurrentlyPlaying: Boolean + + // val isCurrentlyPlaying: Boolean val language: String? } @@ -124,6 +126,7 @@ interface IPlayer { subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way embeddedSubtitlesFetched: ((List) -> 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 ) fun releaseCallbacks() @@ -131,6 +134,8 @@ interface IPlayer { fun updateSubtitleStyle(style: SaveCaptionStyle) fun saveData() + fun addTimeStamps(timeStamps: List) + fun loadPlayer( context: Context, sameEpisode: Boolean, diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt index 0ed26b71..bbd82482 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt @@ -9,10 +9,12 @@ import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.launchSafe import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.utils.Coroutines.ioSafe +import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorUri import kotlinx.coroutines.Job -import kotlinx.coroutines.launch class PlayerGeneratorViewModel : ViewModel() { companion object { @@ -30,6 +32,9 @@ class PlayerGeneratorViewModel : ViewModel() { private val _loadingLinks = MutableLiveData>() val loadingLinks: LiveData> = _loadingLinks + private val _currentStamps = MutableLiveData>(emptyList()) + val currentStamps: LiveData> = _currentStamps + fun getId(): Int? { return generator?.getCurrentId() } @@ -113,10 +118,25 @@ class PlayerGeneratorViewModel : ViewModel() { } private var currentJob: Job? = null + private var currentStampJob: Job? = null + + fun loadStamps(duration: Long) { + println("Starting loadStamps with duration = $duration") + //currentStampJob?.cancel() + currentStampJob = ioSafe { + val meta = generator?.getCurrent() + val page = (generator as? RepoLinkGenerator?)?.page + if (page != null && meta is ResultEpisode) { + _currentStamps.postValue(listOf()) + _currentStamps.postValue(EpisodeSkip.getStamps(page, meta, duration)) + } + } + } fun loadLinks(clearCache: Boolean = false, isCasting: Boolean = false) { Log.i(TAG, "loadLinks") currentJob?.cancel() + currentJob = viewModelScope.launchSafe { val currentLinks = mutableSetOf>() val currentSubs = mutableSetOf() @@ -142,5 +162,6 @@ class PlayerGeneratorViewModel : ViewModel() { _currentLinks.postValue(currentLinks) _currentSubs.postValue(currentSubs) } + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt index d0ab245d..2ce53ea5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.player import android.util.Log import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.utils.ExtractorLink @@ -11,7 +12,8 @@ import kotlin.math.min class RepoLinkGenerator( private val episodes: List, - private var currentIndex: Int = 0 + private var currentIndex: Int = 0, + val page: LoadResponse? = null, ) : IGenerator { companion object { const val TAG = "RepoLink" diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt index 6b04ebf9..0c26f69c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt @@ -416,7 +416,7 @@ class ResultViewModel2 : ViewModel() { return this?.firstOrNull { it.season == season } } - fun updateWatchStatus(currentResponse : LoadResponse, status: WatchType) { + fun updateWatchStatus(currentResponse: LoadResponse, status: WatchType) { val currentId = currentResponse.getId() val resultPage = currentResponse @@ -793,7 +793,7 @@ class ResultViewModel2 : ViewModel() { fun updateWatchStatus(status: WatchType) { - updateWatchStatus(currentResponse ?: return,status) + updateWatchStatus(currentResponse ?: return, status) _watchStatus.postValue(status) } @@ -1681,10 +1681,10 @@ class ResultViewModel2 : ViewModel() { preferDubStatus = indexer.dubStatus generator = if (isMovie) { - getMovie()?.let { RepoLinkGenerator(listOf(it)) } + getMovie()?.let { RepoLinkGenerator(listOf(it), page = currentResponse) } } else { episodes?.let { list -> - RepoLinkGenerator(list) + RepoLinkGenerator(list, page = currentResponse) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt new file mode 100644 index 00000000..35084131 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt @@ -0,0 +1,114 @@ +package com.lagradost.cloudstream3.utils + +import android.util.Log +import androidx.annotation.StringRes +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.lagradost.cloudstream3.* +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 + +object EpisodeSkip { + data class SkipStamp( + @StringRes + private val name: Int, + val startMs: Long, + val endMs: Long, + ) { + val uiText = txt(R.string.skip_type_format, txt(name)) + } + + private val cachedStamps = HashMap>() + + suspend fun getStamps( + data: LoadResponse, + episode: ResultEpisode, + episodeDurationMs: Long + ): List { + cachedStamps[episode.id]?.let { list -> + return list + } + + val out = mutableListOf() + println("CALLING WITH : ${data.syncData} $episode $episodeDurationMs") + 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 name = when (stamp.skipType) { + "op" -> R.string.skip_type_op + "ed" -> R.string.skip_type_ed + "recap" -> R.string.skip_type_recap + "mixed-ed" -> R.string.skip_type_mixed_ed + "mixed-op" -> R.string.skip_type_mixed_op + else -> null + } ?: return@mapNotNull null + SkipStamp( + name, + (stamp.interval.startTime * 1000.0).toLong(), + (stamp.interval.endTime * 1000.0).toLong() + ) + }?.let { list -> + out.addAll(list) + } + } + } + if (out.isNotEmpty()) + cachedStamps[episode.id] = out + return out + } +} + +// taken from https://github.com/saikou-app/saikou/blob/3803f8a7a59b826ca193664d46af3a22bbc989f7/app/src/main/java/ani/saikou/others/AniSkip.kt +// the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md +object AniSkip { + suspend fun getResult(malId: Int, episodeNumber: Int, episodeLength: Long): List? { + 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}" + println("URLLLL::::$url") + + val a = app.get(url) + println("GOT RESPONSE:::.") + val res = a.parsed() + Log.i("AniSkip", "Response = $res") + if (res.found) res.results else null + } catch (t: Throwable) { + Log.i("AniSkip", "error = ${t.message}") + logError(t) + null + } + } + + + data class AniSkipResponse( + @JsonSerialize val found: Boolean, + @JsonSerialize val results: List?, + @JsonSerialize val message: String?, + @JsonSerialize val statusCode: Int + ) + + data class Stamp( + @JsonSerialize val interval: AniSkipInterval, + @JsonSerialize val skipType: String, + @JsonSerialize val skipId: String, + @JsonSerialize val episodeLength: Double + ) + + + //fun String.getType(): String { + // + // + // + // + // + // + // + // + //} + + data class AniSkipInterval( + @JsonSerialize val startTime: Double, + @JsonSerialize val endTime: Double + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/widget/TopCropImageView.kt b/app/src/main/java/com/lagradost/cloudstream3/widget/TopCropImageView.kt new file mode 100644 index 00000000..11ac0160 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/widget/TopCropImageView.kt @@ -0,0 +1,56 @@ +package com.lagradost.cloudstream3.widget + +import android.content.Context +import android.graphics.Matrix +import android.graphics.drawable.Drawable +import android.util.AttributeSet + +// taken from https://gist.github.com/arriolac/3843346 +class TopCropImageView : androidx.appcompat.widget.AppCompatImageView { + constructor(context: Context) : super(context) { + init() + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init() + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + init() + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + recomputeImgMatrix() + } + + override fun setFrame(l: Int, t: Int, r: Int, b: Int): Boolean { + recomputeImgMatrix() + return super.setFrame(l, t, r, b) + } + + private fun init() { + scaleType = ScaleType.MATRIX + } + + private fun recomputeImgMatrix() { + val drawable: Drawable = drawable ?: return + val matrix: Matrix = imageMatrix + val scale: Float + val viewWidth: Int = width - paddingLeft - paddingRight + val viewHeight: Int = height - paddingTop - paddingBottom + val drawableWidth: Int = drawable.intrinsicWidth + val drawableHeight: Int = drawable.intrinsicHeight + scale = if (drawableWidth * viewHeight > drawableHeight * viewWidth) { + viewHeight.toFloat() / drawableHeight.toFloat() + } else { + viewWidth.toFloat() / drawableWidth.toFloat() + } + matrix.setScale(scale, scale) + imageMatrix = matrix + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 232dcaa0..412f7b5b 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -1,130 +1,130 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/player_background" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" + android:orientation="horizontal" + android:screenOrientation="sensorLandscape" + app:backgroundTint="@android:color/black" + app:surface_type="texture_view"> + android:id="@+id/player_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" + app:auto_show="true" + app:backgroundTint="@android:color/black" + app:controller_layout_id="@layout/player_custom_layout" + app:hide_on_touch="false" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:show_timeout="0" /> + android:id="@+id/player_loading_overlay" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" + android:backgroundTint="@android:color/black" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:text="@string/skip_loading" + android:textAllCaps="false" + android:textColor="?attr/textColor" + android:visibility="gone" + app:cornerRadius="4dp" + app:icon="@drawable/ic_baseline_skip_next_24" + app:iconTint="?attr/textColor" + app:rippleColor="?attr/colorPrimary" + tools:visibility="visible" /> + android:id="@+id/main_load" + android:layout_width="50dp" + android:layout_height="50dp" + android:layout_gravity="center" /> + android:id="@+id/video_go_back_holder_holder" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="5dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:layout_width="30dp" + android:layout_height="30dp" + android:layout_gravity="center" + android:contentDescription="@string/go_back_img_des" + android:src="@drawable/ic_baseline_arrow_back_24" + app:tint="@android:color/white" /> + android:id="@+id/player_loading_go_back" + android:layout_width="70dp" + android:layout_height="70dp" + android:layout_gravity="center" + android:background="@drawable/video_tap_button_always_white" + android:clickable="true" + android:contentDescription="@string/go_back_img_des" + android:focusable="true" /> + + + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:gravity="start" + android:textColor="@color/white" + android:textStyle="bold" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="78% at 18kb/s" /> - - + android:id="@+id/video_torrent_seeders" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="0dp" + android:gravity="start" + android:textColor="@color/white" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toBottomOf="@+id/player_video_title" + tools:text="17 seeders" /> \ No newline at end of file diff --git a/app/src/main/res/layout/player_custom_layout.xml b/app/src/main/res/layout/player_custom_layout.xml index 9bbded4e..65b24a17 100644 --- a/app/src/main/res/layout/player_custom_layout.xml +++ b/app/src/main/res/layout/player_custom_layout.xml @@ -318,6 +318,22 @@ + + #66000000 #C0121212 + #C0121212 #121212 #66B5B5B5 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5665ea5c..144d2477 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -638,4 +638,13 @@ Browser App not found All Languages + + Skip %s + Opening + Ending + Recap + Mixed ending + Mixed opening + Credits + Intro