: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 targetSdkVersion 30
versionCode 46 versionCode 46
versionName "2.9.22" versionName "2.9.23"
resValue "string", "app_version", resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}" "${defaultConfig.versionName}${versionNameSuffix ?: ""}"

View file

@ -141,10 +141,13 @@ object APIHolder {
return null return null
} }
fun LoadResponse.getId(): Int { fun getLoadResponseIdFromUrl(url : String, apiName: String) : Int {
return url.replace(getApiFromName(apiName).mainUrl, "").replace("/", "").hashCode() return url.replace(getApiFromName(apiName).mainUrl, "").replace("/", "").hashCode()
} }
fun LoadResponse.getId(): Int {
return getLoadResponseIdFromUrl(url,apiName)
}
/** /**
* Gets the website captcha token * 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.getKey
import com.lagradost.cloudstream3.utils.DataStore.removeKey import com.lagradost.cloudstream3.utils.DataStore.removeKey
import com.lagradost.cloudstream3.utils.DataStore.setKey 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.DataStoreHelper.setViewPos
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState
@ -680,6 +681,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
logError(e) logError(e)
} }
println("Loaded everything") println("Loaded everything")
ioSafe {
migrateResumeWatching()
}
/* /*
val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar
val displayName = "output.dex" //""output.dex" 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() } 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 // run code in parallel
/*fun <R> argpmap( /*fun <R> argpmap(
vararg transforms: () -> R, vararg transforms: () -> R,

View file

@ -222,9 +222,9 @@ open class SflixProvider : MainAPI() {
var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a") var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a")
if (seasonItems.isNullOrEmpty()) if (seasonItems.isNullOrEmpty())
seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item") seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item")
seasonItems.forEachIndexed { season, element -> seasonItems.apmapIndexed { season, element ->
val seasonId = element.attr("data-id") val seasonId = element.attr("data-id")
if (seasonId.isNullOrBlank()) return@forEachIndexed if (seasonId.isNullOrBlank()) return@apmapIndexed
var episode = 0 var episode = 0
val seasonEpisodes = app.get("$mainUrl/ajax/v2/season/episodes/$seasonId").document 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 { class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegionsListener {
companion object { 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( fun newInstance(
url: String, url: String,
apiName: String, apiName: String,
@ -194,11 +221,11 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
startValue: Int = 0 startValue: Int = 0
): Bundle { ): Bundle {
return Bundle().apply { return Bundle().apply {
putString("url", url) putString(URL_BUNDLE, url)
putString("apiName", apiName) putString(API_NAME_BUNDLE, apiName)
putInt("startAction", startAction) putInt(START_ACTION_BUNDLE, startAction)
putInt("startValue", startValue) putInt(START_VALUE_BUNDLE, startValue)
putBoolean("restart", true) putBoolean(RESTART_BUNDLE, true)
} }
} }
@ -682,9 +709,9 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
updateUIListener = ::updateUI updateUIListener = ::updateUI
val restart = arguments?.getBoolean("restart") ?: false val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
if (restart) { if (restart) {
arguments?.putBoolean("restart", false) arguments?.putBoolean(RESTART_BUNDLE, false)
} }
activity?.window?.decorView?.clearFocus() activity?.window?.decorView?.clearFocus()
@ -705,10 +732,12 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
// activity?.fixPaddingStatusbar(result_toolbar) // activity?.fixPaddingStatusbar(result_toolbar)
url = arguments?.getString("url") url = arguments?.getString(URL_BUNDLE)
val apiName = arguments?.getString("apiName") ?: return val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
startValue = arguments?.getInt("startValue") ?: START_VALUE_NORMAL startValue = arguments?.getInt(START_VALUE_BUNDLE)
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
syncModel.addFromUrl(url) syncModel.addFromUrl(url)
val api = getApiFromName(apiName) val api = getApiFromName(apiName)
@ -1165,9 +1194,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
.map { watchType -> Pair(watchType.internalId, watchType.stringRes) }, .map { watchType -> Pair(watchType.internalId, watchType.stringRes) },
//.map { watchType -> Triple(watchType.internalId, watchType.iconRes, 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 { ?.let {
result_play_movie?.text = it result_play_movie?.text = it
} }
println("startAction = $startAction")
when (startAction) { when (startAction) {
START_ACTION_RESUME_LATEST -> { START_ACTION_RESUME_LATEST -> {
@ -1488,13 +1516,28 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
} }
} }
START_ACTION_LOAD_EP -> { START_ACTION_LOAD_EP -> {
for (ep in episodeList) { if(episodeList.size == 1) {
if (ep.id == startValue) { // watched too much handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episodeList.first()))
println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}") } else {
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep)) var found = false
break 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 else -> Unit
} }

View file

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

View file

@ -298,9 +298,16 @@ object AppUtils {
fun Activity?.loadSearchResult( fun Activity?.loadSearchResult(
card: SearchResponse, card: SearchResponse,
startAction: Int = 0, 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?) { 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 = "result_watch_state"
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data" 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 = "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_SEASON = "result_season"
const val RESULT_DUB = "result_dub" const val RESULT_DUB = "result_dub"
@ -65,7 +67,7 @@ object DataStoreHelper {
@JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null, @JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null,
) : SearchResponse ) : SearchResponse
var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION private var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
fun getAllWatchStateIds(): List<Int>? { fun getAllWatchStateIds(): List<Int>? {
val folder = "$currentAccount/$RESULT_WATCH_STATE" 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( fun setLastWatched(
parentId: Int?, parentId: Int?,
episodeId: Int?, episodeId: Int?,
episode: Int?, episode: Int?,
season: Int?, season: Int?,
isFromDownload: Boolean = false isFromDownload: Boolean = false,
updateTime: Long? = null,
) { ) {
if (parentId == null || episodeId == null) return if (parentId == null) return
setKey( setKey(
"$currentAccount/$RESULT_RESUME_WATCHING", "$currentAccount/$RESULT_RESUME_WATCHING",
parentId.toString(), parentId.toString(),
@ -97,12 +126,17 @@ object DataStoreHelper {
episodeId, episodeId,
episode, episode,
season, season,
System.currentTimeMillis(), updateTime ?: System.currentTimeMillis(),
isFromDownload isFromDownload
) )
) )
} }
fun removeLastWatchedOld(parentId: Int?) {
if (parentId == null) return
removeKey("$currentAccount/$RESULT_RESUME_WATCHING_OLD", parentId.toString())
}
fun removeLastWatched(parentId: Int?) { fun removeLastWatched(parentId: Int?) {
if (parentId == null) return if (parentId == null) return
removeKey("$currentAccount/$RESULT_RESUME_WATCHING", parentId.toString()) 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) { fun setBookmarkedData(id: Int?, data: BookmarkedData) {
if (id == null) return if (id == null) return
setKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString(), data) setKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString(), data)

View file

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