:okand: restored lost resume watching

This commit is contained in:
LagradOst 2022-05-02 23:32:28 +02:00
parent 109e1b9f17
commit 16b2924375
10 changed files with 136 additions and 32 deletions

View file

@ -36,7 +36,7 @@ android {
targetSdkVersion 30
versionCode 46
versionName "2.9.22"
versionName "2.9.23"
resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"

View file

@ -141,10 +141,13 @@ object APIHolder {
return null
}
fun LoadResponse.getId(): Int {
fun getLoadResponseIdFromUrl(url : String, apiName: String) : Int {
return url.replace(getApiFromName(apiName).mainUrl, "").replace("/", "").hashCode()
}
fun LoadResponse.getId(): Int {
return getLoadResponseIdFromUrl(url,apiName)
}
/**
* Gets the website captcha token

View file

@ -56,6 +56,7 @@ import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.removeKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState
@ -680,6 +681,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
logError(e)
}
println("Loaded everything")
ioSafe {
migrateResumeWatching()
}
/*
val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar
val displayName = "output.dex" //""output.dex"

View file

@ -34,6 +34,10 @@ fun <A, B> List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
map { async { f(it) } }.map { it.await() }
}
fun <A, B> List<A>.apmapIndexed(f: suspend (index: Int, A) -> B): List<B> = runBlocking {
mapIndexed { index, a -> async { f(index, a) } }.map { it.await() }
}
// run code in parallel
/*fun <R> argpmap(
vararg transforms: () -> R,

View file

@ -222,9 +222,9 @@ open class SflixProvider : MainAPI() {
var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a")
if (seasonItems.isNullOrEmpty())
seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item")
seasonItems.forEachIndexed { season, element ->
seasonItems.apmapIndexed { season, element ->
val seasonId = element.attr("data-id")
if (seasonId.isNullOrBlank()) return@forEachIndexed
if (seasonId.isNullOrBlank()) return@apmapIndexed
var episode = 0
val seasonEpisodes = app.get("$mainUrl/ajax/v2/season/episodes/$seasonId").document

View file

@ -187,6 +187,33 @@ fun ResultEpisode.getWatchProgress(): Float {
class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegionsListener {
companion object {
const val URL_BUNDLE = "url"
const val API_NAME_BUNDLE = "apiName"
const val SEASON_BUNDLE = "season"
const val EPISODE_BUNDLE = "episode"
const val START_ACTION_BUNDLE = "startAction"
const val START_VALUE_BUNDLE = "startValue"
const val RESTART_BUNDLE = "restart"
fun newInstance(
card: SearchResponse, startAction: Int = 0, startValue: Int? = null
): Bundle {
return Bundle().apply {
putString(URL_BUNDLE, card.url)
putString(API_NAME_BUNDLE, card.apiName)
if (card is DataStoreHelper.ResumeWatchingResult) {
println("CARD::::: $card")
if (card.season != null)
putInt(SEASON_BUNDLE, card.season)
if (card.episode != null)
putInt(EPISODE_BUNDLE, card.episode)
}
putInt(START_ACTION_BUNDLE, startAction)
if (startValue != null)
putInt(START_VALUE_BUNDLE, startValue)
putBoolean(RESTART_BUNDLE, true)
}
}
fun newInstance(
url: String,
apiName: String,
@ -194,11 +221,11 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
startValue: Int = 0
): Bundle {
return Bundle().apply {
putString("url", url)
putString("apiName", apiName)
putInt("startAction", startAction)
putInt("startValue", startValue)
putBoolean("restart", true)
putString(URL_BUNDLE, url)
putString(API_NAME_BUNDLE, apiName)
putInt(START_ACTION_BUNDLE, startAction)
putInt(START_VALUE_BUNDLE, startValue)
putBoolean(RESTART_BUNDLE, true)
}
}
@ -682,9 +709,9 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
updateUIListener = ::updateUI
val restart = arguments?.getBoolean("restart") ?: false
val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
if (restart) {
arguments?.putBoolean("restart", false)
arguments?.putBoolean(RESTART_BUNDLE, false)
}
activity?.window?.decorView?.clearFocus()
@ -705,10 +732,12 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
// activity?.fixPaddingStatusbar(result_toolbar)
url = arguments?.getString("url")
val apiName = arguments?.getString("apiName") ?: return
startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL
startValue = arguments?.getInt("startValue") ?: START_VALUE_NORMAL
url = arguments?.getString(URL_BUNDLE)
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
startValue = arguments?.getInt(START_VALUE_BUNDLE)
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
syncModel.addFromUrl(url)
val api = getApiFromName(apiName)
@ -1165,9 +1194,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
.map { watchType -> Pair(watchType.internalId, watchType.stringRes) },
//.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) },
) {
context?.let { localContext ->
viewModel.updateWatchStatus(WatchType.fromInternalId(this.itemId))
}
viewModel.updateWatchStatus(WatchType.fromInternalId(this.itemId))
}
}
@ -1475,6 +1502,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
?.let {
result_play_movie?.text = it
}
println("startAction = $startAction")
when (startAction) {
START_ACTION_RESUME_LATEST -> {
@ -1488,13 +1516,28 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
}
}
START_ACTION_LOAD_EP -> {
for (ep in episodeList) {
if (ep.id == startValue) { // watched too much
println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep))
break
if(episodeList.size == 1) {
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episodeList.first()))
} else {
var found = false
for (ep in episodeList) {
if (ep.id == startValue) { // watched too much
println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep))
found = true
break
}
}
if (!found)
for (ep in episodeList) {
if (ep.episode == resumeEpisode && ep.season == resumeSeason) {
println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep))
break
}
}
}
}
else -> Unit
}

View file

@ -19,7 +19,7 @@ object SearchHelper {
activity.loadSearchResult(card)
}
SEARCH_ACTION_PLAY_FILE -> {
if (card is DataStoreHelper.ResumeWatchingResult && card.id != null) {
if (card is DataStoreHelper.ResumeWatchingResult) {
if (card.isFromDownload) {
handleDownloadClick(
activity, card.name, DownloadClickEvent(
@ -38,7 +38,7 @@ object SearchHelper {
)
)
} else {
activity.loadSearchResult(card, START_ACTION_LOAD_EP, card.id!!)
activity.loadSearchResult(card, START_ACTION_LOAD_EP, card.id)
}
} else {
handleSearchClickCallback(

View file

@ -298,9 +298,16 @@ object AppUtils {
fun Activity?.loadSearchResult(
card: SearchResponse,
startAction: Int = 0,
startValue: Int = 0
startValue: Int? = null,
) {
(this as? AppCompatActivity?)?.loadResult(card.url, card.apiName, startAction, startValue)
this?.runOnUiThread {
// viewModelStore.clear()
this.navigate(
R.id.global_to_navigation_results,
ResultFragment.newInstance(card, startAction, startValue)
)
}
//(this as? AppCompatActivity?)?.loadResult(card.url, card.apiName, startAction, startValue)
}
fun Activity.requestLocalAudioFocus(focusRequest: AudioFocusRequest?) {

View file

@ -15,6 +15,8 @@ const val VIDEO_POS_DUR = "video_pos_dur"
const val RESULT_WATCH_STATE = "result_watch_state"
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
const val RESULT_RESUME_WATCHING = "result_resume_watching_2" // changed due to id changes
const val RESULT_RESUME_WATCHING_OLD = "result_resume_watching"
const val RESULT_RESUME_WATCHING_HAS_MIGRATED = "result_resume_watching_migrated"
const val RESULT_SEASON = "result_season"
const val RESULT_DUB = "result_dub"
@ -65,7 +67,7 @@ object DataStoreHelper {
@JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null,
) : SearchResponse
var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
private var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
fun getAllWatchStateIds(): List<Int>? {
val folder = "$currentAccount/$RESULT_WATCH_STATE"
@ -81,14 +83,41 @@ object DataStoreHelper {
}
}
private fun getAllResumeStateIdsOld(): List<Int>? {
val folder = "$currentAccount/$RESULT_RESUME_WATCHING_OLD"
return getKeys(folder)?.mapNotNull {
it.removePrefix("$folder/").toIntOrNull()
}
}
fun migrateResumeWatching() {
// if (getKey(RESULT_RESUME_WATCHING_HAS_MIGRATED, false) != true) {
setKey(RESULT_RESUME_WATCHING_HAS_MIGRATED, true)
getAllResumeStateIdsOld()?.forEach { id ->
getLastWatchedOld(id)?.let {
setLastWatched(
it.parentId,
null,
it.episode,
it.season,
it.isFromDownload,
it.updateTime
)
removeLastWatchedOld(it.parentId)
}
}
//}
}
fun setLastWatched(
parentId: Int?,
episodeId: Int?,
episode: Int?,
season: Int?,
isFromDownload: Boolean = false
isFromDownload: Boolean = false,
updateTime: Long? = null,
) {
if (parentId == null || episodeId == null) return
if (parentId == null) return
setKey(
"$currentAccount/$RESULT_RESUME_WATCHING",
parentId.toString(),
@ -97,12 +126,17 @@ object DataStoreHelper {
episodeId,
episode,
season,
System.currentTimeMillis(),
updateTime ?: System.currentTimeMillis(),
isFromDownload
)
)
}
fun removeLastWatchedOld(parentId: Int?) {
if (parentId == null) return
removeKey("$currentAccount/$RESULT_RESUME_WATCHING_OLD", parentId.toString())
}
fun removeLastWatched(parentId: Int?) {
if (parentId == null) return
removeKey("$currentAccount/$RESULT_RESUME_WATCHING", parentId.toString())
@ -116,6 +150,14 @@ object DataStoreHelper {
)
}
fun getLastWatchedOld(id: Int?): VideoDownloadHelper.ResumeWatching? {
if (id == null) return null
return getKey(
"$currentAccount/$RESULT_RESUME_WATCHING_OLD",
id.toString(),
)
}
fun setBookmarkedData(id: Int?, data: BookmarkedData) {
if (id == null) return
setKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString(), data)

View file

@ -29,7 +29,7 @@ object VideoDownloadHelper {
data class ResumeWatching(
@JsonProperty("parentId") val parentId: Int,
@JsonProperty("episodeId") val episodeId: Int,
@JsonProperty("episodeId") val episodeId: Int?,
@JsonProperty("episode") val episode: Int?,
@JsonProperty("season") val season: Int?,
@JsonProperty("updateTime") val updateTime: Long,