forked from recloudstream/cloudstream
:okand: restored lost resume watching
This commit is contained in:
parent
109e1b9f17
commit
16b2924375
10 changed files with 136 additions and 32 deletions
|
@ -36,7 +36,7 @@ android {
|
|||
targetSdkVersion 30
|
||||
|
||||
versionCode 46
|
||||
versionName "2.9.22"
|
||||
versionName "2.9.23"
|
||||
|
||||
resValue "string", "app_version",
|
||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +1194,9 @@ 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.watchStatus) { watchType ->
|
||||
result_bookmark_button?.text = getString(watchType.stringRes)
|
||||
|
@ -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,14 +1516,29 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
|||
}
|
||||
}
|
||||
START_ACTION_LOAD_EP -> {
|
||||
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
|
||||
}
|
||||
arguments?.remove("startValue")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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?) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue