mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	autosync
This commit is contained in:
		
							parent
							
								
									8c5db9de11
								
							
						
					
					
						commit
						f85d32a308
					
				
					 10 changed files with 142 additions and 34 deletions
				
			
		| 
						 | 
				
			
			@ -12,7 +12,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper
 | 
			
		|||
import com.fasterxml.jackson.module.kotlin.KotlinModule
 | 
			
		||||
import com.lagradost.cloudstream3.animeproviders.*
 | 
			
		||||
import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider
 | 
			
		||||
import com.lagradost.cloudstream3.metaproviders.MultiAnimeProvider
 | 
			
		||||
import com.lagradost.cloudstream3.movieproviders.*
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +309,7 @@ abstract class MainAPI {
 | 
			
		|||
        var overrideData: HashMap<String, ProvidersInfoJson>? = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public fun overrideWithNewData(data: ProvidersInfoJson) {
 | 
			
		||||
    fun overrideWithNewData(data: ProvidersInfoJson) {
 | 
			
		||||
        this.name = data.name
 | 
			
		||||
        this.mainUrl = data.url
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -760,6 +759,10 @@ interface LoadResponse {
 | 
			
		|||
            // TODO add kitsu sync
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addTMDbId(id: String?) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.setDuration(input: String?) {
 | 
			
		||||
            val cleanInput = input?.trim()?.replace(" ", "") ?: return
 | 
			
		||||
            Regex("([0-9]*)h.*?([0-9]*)m").find(cleanInput)?.groupValues?.let { values ->
 | 
			
		||||
| 
						 | 
				
			
			@ -985,7 +988,7 @@ fun fetchUrls(text: String?): List<String> {
 | 
			
		|||
        return listOf()
 | 
			
		||||
    }
 | 
			
		||||
    val linkRegex =
 | 
			
		||||
        Regex("""(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*))""")
 | 
			
		||||
        Regex("""(https?://(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))""")
 | 
			
		||||
    return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,10 @@ fun <T, R> Iterable<T>.pmap(
 | 
			
		|||
    return ArrayList<R>(destination)
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
fun <K, V, R> Map<out K, V>.apmap(f: suspend (Map.Entry<K, V>) -> R): List<R> = runBlocking {
 | 
			
		||||
    map { async { f(it) } }.map { it.await() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun <A, B> List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
 | 
			
		||||
    map { async { f(it) } }.map { it.await() }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,10 @@ const val SKIP_OP_VIDEO_PERCENTAGE = 50
 | 
			
		|||
const val PRELOAD_NEXT_EPISODE_PERCENTAGE = 80
 | 
			
		||||
 | 
			
		||||
// when the player should mark the episode as watched and resume watching the next
 | 
			
		||||
const val NEXT_WATCH_EPISODE_PERCENTAGE = 95
 | 
			
		||||
const val NEXT_WATCH_EPISODE_PERCENTAGE = 90
 | 
			
		||||
 | 
			
		||||
// when the player should sync the progress of "watched", TODO MAKE SETTING
 | 
			
		||||
const val UPDATE_SYNC_PROGRESS_PERCENTAGE = 80
 | 
			
		||||
 | 
			
		||||
abstract class AbstractPlayerFragment(
 | 
			
		||||
    val player: IPlayer = CS3IPlayer()
 | 
			
		||||
| 
						 | 
				
			
			@ -329,6 +332,7 @@ abstract class AbstractPlayerFragment(
 | 
			
		|||
                SKIP_OP_VIDEO_PERCENTAGE,
 | 
			
		||||
                PRELOAD_NEXT_EPISODE_PERCENTAGE,
 | 
			
		||||
                NEXT_WATCH_EPISODE_PERCENTAGE,
 | 
			
		||||
                UPDATE_SYNC_PROGRESS_PERCENTAGE,
 | 
			
		||||
            ), subtitlesUpdates = ::subtitlesChanged
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.player
 | 
			
		|||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +13,7 @@ import androidx.appcompat.app.AlertDialog
 | 
			
		|||
import androidx.core.view.isGone
 | 
			
		||||
import androidx.core.view.isVisible
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import com.google.android.exoplayer2.util.MimeTypes
 | 
			
		||||
import com.google.android.material.button.MaterialButton
 | 
			
		||||
import com.hippo.unifile.UniFile
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +27,7 @@ import com.lagradost.cloudstream3.mvvm.observe
 | 
			
		|||
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
 | 
			
		||||
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.settings.SettingsFragment.Companion.isTvSettings
 | 
			
		||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
 | 
			
		||||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
| 
						 | 
				
			
			@ -39,13 +42,18 @@ import kotlinx.coroutines.Job
 | 
			
		|||
class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		||||
    companion object {
 | 
			
		||||
        private var lastUsedGenerator: IGenerator? = null
 | 
			
		||||
        fun newInstance(generator: IGenerator): Bundle {
 | 
			
		||||
        fun newInstance(generator: IGenerator, syncData: HashMap<String, String>? = null): Bundle {
 | 
			
		||||
            Log.i(TAG, "newInstance = $syncData")
 | 
			
		||||
            lastUsedGenerator = generator
 | 
			
		||||
            return Bundle()
 | 
			
		||||
            return Bundle().apply {
 | 
			
		||||
                if (syncData != null)
 | 
			
		||||
                    putSerializable("syncData", syncData)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lateinit var viewModel: PlayerGeneratorViewModel //by activityViewModels()
 | 
			
		||||
    private lateinit var sync: SyncViewModel
 | 
			
		||||
    private var currentLinks: Set<Pair<ExtractorLink?, ExtractorUri?>> = setOf()
 | 
			
		||||
    private var currentSubs: Set<SubtitleData> = setOf()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +131,11 @@ class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		|||
                    if (isNextEpisode) 0L else getPos()
 | 
			
		||||
                },
 | 
			
		||||
                currentSubs,
 | 
			
		||||
                (if(sameEpisode) currentSelectedSubtitles else null) ?: getAutoSelectSubtitle(currentSubs, settings = true, downloads = true),
 | 
			
		||||
                (if (sameEpisode) currentSelectedSubtitles else null) ?: getAutoSelectSubtitle(
 | 
			
		||||
                    currentSubs,
 | 
			
		||||
                    settings = true,
 | 
			
		||||
                    downloads = true
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -422,6 +434,18 @@ class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		|||
        var isOpVisible = false
 | 
			
		||||
        when (val meta = currentMeta) {
 | 
			
		||||
            is ResultEpisode -> {
 | 
			
		||||
                if (percentage >= UPDATE_SYNC_PROGRESS_PERCENTAGE) {
 | 
			
		||||
                    context?.let { ctx ->
 | 
			
		||||
                        val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
 | 
			
		||||
                        if (settingsManager.getBoolean(
 | 
			
		||||
                                ctx.getString(R.string.episode_sync_enabled_key),
 | 
			
		||||
                                true
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                            sync.modifyMaxEpisode(meta.episode)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (meta.tvType.isAnimeOp())
 | 
			
		||||
                    isOpVisible = percentage < SKIP_OP_VIDEO_PERCENTAGE
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -429,7 +453,7 @@ class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		|||
        player_skip_op?.isVisible = isOpVisible
 | 
			
		||||
        player_skip_episode?.isVisible = !isOpVisible && viewModel.hasNextEpisode() == true
 | 
			
		||||
 | 
			
		||||
        if (percentage > PRELOAD_NEXT_EPISODE_PERCENTAGE) {
 | 
			
		||||
        if (percentage >= PRELOAD_NEXT_EPISODE_PERCENTAGE) {
 | 
			
		||||
            viewModel.preLoadNextLinks()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -554,6 +578,13 @@ class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		|||
        setPlayerDimen(widthHeight)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun unwrapBundle(savedInstanceState: Bundle?) {
 | 
			
		||||
        Log.i(TAG, "unwrapBundle = $savedInstanceState")
 | 
			
		||||
        savedInstanceState?.let { bundle ->
 | 
			
		||||
            sync.addSyncs(bundle.getSerializable("syncData") as? HashMap<String, String>?)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater,
 | 
			
		||||
        container: ViewGroup?,
 | 
			
		||||
| 
						 | 
				
			
			@ -564,13 +595,23 @@ class GeneratorPlayer : FullScreenPlayer() {
 | 
			
		|||
            if (context?.isTvSettings() == true) R.layout.fragment_player_tv else R.layout.fragment_player
 | 
			
		||||
 | 
			
		||||
        viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]
 | 
			
		||||
        sync = ViewModelProvider(this)[SyncViewModel::class.java]
 | 
			
		||||
 | 
			
		||||
        viewModel.attachGenerator(lastUsedGenerator)
 | 
			
		||||
        unwrapBundle(savedInstanceState)
 | 
			
		||||
        unwrapBundle(arguments)
 | 
			
		||||
 | 
			
		||||
        return super.onCreateView(inflater, container, savedInstanceState)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        unwrapBundle(savedInstanceState)
 | 
			
		||||
        unwrapBundle(arguments)
 | 
			
		||||
 | 
			
		||||
        sync.updateUserData()
 | 
			
		||||
 | 
			
		||||
        preferredAutoSelectSubtitles = SubtitlesFragment.getAutoSelectLanguageISO639_1()
 | 
			
		||||
 | 
			
		||||
        if (currentSelectedLink == null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,8 +12,8 @@ interface IGenerator {
 | 
			
		|||
    fun prev()
 | 
			
		||||
    fun goto(index: Int)
 | 
			
		||||
 | 
			
		||||
    fun getCurrentId(): Int?   // this is used to save data or read data about this id
 | 
			
		||||
    fun getCurrent(offset : Int = 0): Any?     // this is used to get metadata about the current playing, can return null
 | 
			
		||||
    fun getCurrentId(): Int?                    // this is used to save data or read data about this id
 | 
			
		||||
    fun getCurrent(offset : Int = 0): Any?      // this is used to get metadata about the current playing, can return null
 | 
			
		||||
 | 
			
		||||
    /* not safe, must use try catch */
 | 
			
		||||
    suspend fun generateLinks(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -428,7 +428,8 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
    private var currentHeaderName: String? = null
 | 
			
		||||
    private var currentType: TvType? = null
 | 
			
		||||
    private var currentEpisodes: List<ResultEpisode>? = null
 | 
			
		||||
    var downloadButton: EasyDownloadButton? = null
 | 
			
		||||
    private var downloadButton: EasyDownloadButton? = null
 | 
			
		||||
    private var syncdata: Map<String, String>? = null
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater,
 | 
			
		||||
| 
						 | 
				
			
			@ -645,6 +646,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateUI() {
 | 
			
		||||
        syncModel.updateUserData()
 | 
			
		||||
        viewModel.reloadEpisodes()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1089,10 +1091,11 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                ACTION_PLAY_EPISODE_IN_PLAYER -> {
 | 
			
		||||
                    viewModel.getGenerator(episodeClick.data)
 | 
			
		||||
                        ?.let { generator ->
 | 
			
		||||
                            println("LANUCJ:::: $syncdata")
 | 
			
		||||
                            activity?.navigate(
 | 
			
		||||
                                R.id.global_to_navigation_player,
 | 
			
		||||
                                GeneratorPlayer.newInstance(
 | 
			
		||||
                                    generator
 | 
			
		||||
                                    generator, syncdata?.let { HashMap(it) }
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1296,10 +1299,16 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
 | 
			
		||||
 | 
			
		||||
            val newList = list.filter { it.isSynced }
 | 
			
		||||
 | 
			
		||||
            result_mini_sync?.isVisible = newList.isNotEmpty()
 | 
			
		||||
            (result_mini_sync?.adapter as? ImageAdapter?)?.updateList(newList.map { it.icon })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        observe(syncModel.syncIds) {
 | 
			
		||||
            println("VALUES::: $it")
 | 
			
		||||
            syncdata = it
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var currentSyncProgress = 0
 | 
			
		||||
 | 
			
		||||
        fun setSyncMaxEpisodes(totalEpisodes: Int?) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1642,12 +1651,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                    setActors(d.actors)
 | 
			
		||||
 | 
			
		||||
                    if (SettingsFragment.accountEnabled) {
 | 
			
		||||
                        var isValid = false
 | 
			
		||||
                        for ((prefix, id) in d.syncData) {
 | 
			
		||||
                            isValid = isValid || syncModel.addSync(prefix, id)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (isValid) {
 | 
			
		||||
                        if (syncModel.addSyncs(d.syncData)) {
 | 
			
		||||
                            syncModel.updateMetaAndUser()
 | 
			
		||||
                            syncModel.updateSynced()
 | 
			
		||||
                        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
 | 
			
		|||
import androidx.lifecycle.MutableLiveData
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import com.lagradost.cloudstream3.apmap
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.Resource
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +41,10 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
    val userData: LiveData<Resource<SyncAPI.SyncStatus>?> get() = _userDataResponse
 | 
			
		||||
 | 
			
		||||
    // prefix, id
 | 
			
		||||
    private val syncIds = hashMapOf<String, String>()
 | 
			
		||||
    private var syncs = mutableMapOf<String, String>()
 | 
			
		||||
    private val _syncIds: MutableLiveData<MutableMap<String, String>> =
 | 
			
		||||
        MutableLiveData(mutableMapOf())
 | 
			
		||||
    val syncIds: LiveData<MutableMap<String, String>> get() = _syncIds
 | 
			
		||||
 | 
			
		||||
    private val _currentSynced: MutableLiveData<List<CurrentSynced>> =
 | 
			
		||||
        MutableLiveData(getMissing())
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +57,7 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
            CurrentSynced(
 | 
			
		||||
                it.name,
 | 
			
		||||
                it.idPrefix,
 | 
			
		||||
                syncIds.containsKey(it.idPrefix),
 | 
			
		||||
                syncs.containsKey(it.idPrefix),
 | 
			
		||||
                it.hasAccount(),
 | 
			
		||||
                it.icon,
 | 
			
		||||
            )
 | 
			
		||||
| 
						 | 
				
			
			@ -65,19 +69,30 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
        _currentSynced.postValue(getMissing())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addSync(idPrefix: String, id : String) : Boolean {
 | 
			
		||||
        if(syncIds[idPrefix] == id) return false
 | 
			
		||||
    private fun addSync(idPrefix: String, id: String): Boolean {
 | 
			
		||||
        if (syncs[idPrefix] == id) return false
 | 
			
		||||
        Log.i(TAG, "addSync $idPrefix = $id")
 | 
			
		||||
        syncIds[idPrefix] = id
 | 
			
		||||
 | 
			
		||||
        syncs[idPrefix] = id
 | 
			
		||||
        _syncIds.postValue(syncs)
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setMalId(id: String?) : Boolean {
 | 
			
		||||
        return addSync(malApi.idPrefix,id ?: return false)
 | 
			
		||||
    fun addSyncs(map: Map<String, String>?): Boolean {
 | 
			
		||||
        var isValid = false
 | 
			
		||||
 | 
			
		||||
        map?.forEach { (prefix, id) ->
 | 
			
		||||
            isValid = isValid || addSync(prefix, id)
 | 
			
		||||
        }
 | 
			
		||||
        return isValid
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setAniListId(id: String?) : Boolean {
 | 
			
		||||
        return addSync(aniListApi.idPrefix,id ?: return false)
 | 
			
		||||
    fun setMalId(id: String?): Boolean {
 | 
			
		||||
        return addSync(malApi.idPrefix, id ?: return false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setAniListId(id: String?): Boolean {
 | 
			
		||||
        return addSync(aniListApi.idPrefix, id ?: return false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var hasAddedFromUrl: HashSet<String> = hashSetOf()
 | 
			
		||||
| 
						 | 
				
			
			@ -153,20 +168,45 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
        Log.i(TAG, "publishUserData")
 | 
			
		||||
        val user = userData.value
 | 
			
		||||
        if (user is Resource.Success) {
 | 
			
		||||
            for ((prefix, id) in syncIds) {
 | 
			
		||||
            syncs.forEach { (prefix, id) ->
 | 
			
		||||
                repos.firstOrNull { it.idPrefix == prefix }?.score(id, user.value)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        updateUserData()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateUserData() = viewModelScope.launch {
 | 
			
		||||
    fun modifyMaxEpisode(episodeNum: Int) {
 | 
			
		||||
        Log.i(TAG, "modifyMaxEpisode = $episodeNum")
 | 
			
		||||
        modifyData { status ->
 | 
			
		||||
            status.copy(watchedEpisodes = maxOf(episodeNum, status.watchedEpisodes ?: return@modifyData null))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// modifies the current sync data, return null if you don't want to change it
 | 
			
		||||
    private fun modifyData(update: ((SyncAPI.SyncStatus) -> (SyncAPI.SyncStatus?))) =
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            syncs.apmap { (prefix, id) ->
 | 
			
		||||
                repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->
 | 
			
		||||
                    if (repo.hasAccount()) {
 | 
			
		||||
                        val result = repo.getStatus(id)
 | 
			
		||||
                        if (result is Resource.Success) {
 | 
			
		||||
                            update(result.value)?.let { newData ->
 | 
			
		||||
                                Log.i(TAG, "modifyData ${repo.name} => $newData")
 | 
			
		||||
                                repo.score(id, newData)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    fun updateUserData() = viewModelScope.launch {
 | 
			
		||||
        Log.i(TAG, "updateUserData")
 | 
			
		||||
        _userDataResponse.postValue(Resource.Loading())
 | 
			
		||||
        var lastError: Resource<SyncAPI.SyncStatus> = Resource.Failure(false, null, null, "No data")
 | 
			
		||||
        for ((prefix, id) in syncIds) {
 | 
			
		||||
        syncs.forEach { (prefix, id) ->
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->
 | 
			
		||||
                if(repo.hasAccount()) {
 | 
			
		||||
                if (repo.hasAccount()) {
 | 
			
		||||
                    val result = repo.getStatus(id)
 | 
			
		||||
                    if (result is Resource.Success) {
 | 
			
		||||
                        _userDataResponse.postValue(result)
 | 
			
		||||
| 
						 | 
				
			
			@ -185,9 +225,9 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
 | 
			
		||||
        _metaResponse.postValue(Resource.Loading())
 | 
			
		||||
        var lastError: Resource<SyncAPI.SyncResult> = Resource.Failure(false, null, null, "No data")
 | 
			
		||||
        for ((prefix, id) in syncIds) {
 | 
			
		||||
        syncs.forEach { (prefix, id) ->
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->
 | 
			
		||||
                if(repo.hasAccount()) {
 | 
			
		||||
                if (repo.hasAccount()) {
 | 
			
		||||
                    val result = repo.getResult(id)
 | 
			
		||||
                    if (result is Resource.Success) {
 | 
			
		||||
                        _metaResponse.postValue(result)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
    android:height="24dp"
 | 
			
		||||
    android:viewportWidth="24"
 | 
			
		||||
    android:viewportHeight="24"
 | 
			
		||||
    android:tint="?attr/colorControlNormal">
 | 
			
		||||
    android:tint="?attr/white">
 | 
			
		||||
  <path
 | 
			
		||||
      android:fillColor="@android:color/white"
 | 
			
		||||
      android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
    <string name="backup_key" translatable="false">backup_key</string>
 | 
			
		||||
    <string name="prefer_media_type_key" translatable="false">prefer_media_type_key</string>
 | 
			
		||||
    <string name="app_theme_key" translatable="false">app_theme_key</string>
 | 
			
		||||
    <string name="episode_sync_enabled_key" translatable="false">episode_sync_enabled_key</string>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +203,9 @@
 | 
			
		|||
        overlay
 | 
			
		||||
    </string>
 | 
			
		||||
 | 
			
		||||
    <string name="episode_sync_settings">Update watch progress</string>
 | 
			
		||||
    <string name="episode_sync_settings_des">Automatically sync your current episode progress</string>
 | 
			
		||||
 | 
			
		||||
    <string name="restore_settings">Restore data from backup</string>
 | 
			
		||||
    <string name="killswitch_settings">Download latest metadata from github</string>
 | 
			
		||||
    <string name="killswitch_settings_des">If you want access to all providers (even broken ones) turn this off</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,6 +63,14 @@
 | 
			
		|||
                android:title="@string/double_tap_to_pause_settings"
 | 
			
		||||
                android:summary="@string/double_tap_to_pause_settings_des"
 | 
			
		||||
                app:defaultValue="false" />
 | 
			
		||||
 | 
			
		||||
        <SwitchPreference
 | 
			
		||||
                android:icon="@drawable/baseline_sync_24"
 | 
			
		||||
                app:key="@string/episode_sync_enabled_key"
 | 
			
		||||
                android:title="@string/episode_sync_settings"
 | 
			
		||||
                android:summary="@string/episode_sync_settings_des"
 | 
			
		||||
                app:defaultValue="true" />
 | 
			
		||||
 | 
			
		||||
        <Preference
 | 
			
		||||
                android:key="@string/video_buffer_disk_key"
 | 
			
		||||
                android:title="@string/video_buffer_disk_settings"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue