diff --git a/app/build.gradle b/app/build.gradle
index fc3665e1..f1fbb206 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -36,7 +36,7 @@ android {
targetSdkVersion 30
versionCode 46
- versionName "2.9.22"
+ versionName "2.9.23"
resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
index 83797ec2..a3426106 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
@@ -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
diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
index 4b5913e9..a3568d35 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
@@ -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"
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt b/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt
index 2009ace8..badb6631 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt
@@ -34,6 +34,10 @@ fun List.apmap(f: suspend (A) -> B): List = runBlocking {
map { async { f(it) } }.map { it.await() }
}
+fun List.apmapIndexed(f: suspend (index: Int, A) -> B): List = runBlocking {
+ mapIndexed { index, a -> async { f(index, a) } }.map { it.await() }
+}
+
// run code in parallel
/*fun argpmap(
vararg transforms: () -> R,
diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt
index 2c293741..145e91d5 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt
@@ -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
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
index fb832ea8..3029256d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
@@ -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
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHelper.kt
index 1211962d..5f71c0a8 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHelper.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHelper.kt
@@ -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(
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
index 881d8fb5..52bdb270 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
@@ -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?) {
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
index 1d5488db..f1744f6e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
@@ -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? = null,
) : SearchResponse
- var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
+ private var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
fun getAllWatchStateIds(): List? {
val folder = "$currentAccount/$RESULT_WATCH_STATE"
@@ -81,14 +83,41 @@ object DataStoreHelper {
}
}
+ private fun getAllResumeStateIdsOld(): List? {
+ 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)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadHelper.kt
index 0a41aa4f..a76cc115 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadHelper.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadHelper.kt
@@ -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,