@@ -62,8 +62,6 @@ import kotlinx.coroutines.flow.filter
6262import kotlinx.coroutines.flow.update
6363import kotlinx.coroutines.isActive
6464import kotlinx.coroutines.launch
65- import kotlinx.coroutines.sync.Mutex
66- import kotlinx.coroutines.sync.withLock
6765import logcat.LogPriority
6866import mihon.domain.items.episode.interactor.FilterEpisodesForDownload
6967import tachiyomi.core.common.i18n.stringResource
@@ -84,7 +82,6 @@ import tachiyomi.domain.entries.anime.interactor.GetDuplicateLibraryAnime
8482import tachiyomi.domain.entries.anime.interactor.SetAnimeEpisodeFlags
8583import tachiyomi.domain.entries.anime.interactor.SetAnimeSeasonFlags
8684import tachiyomi.domain.entries.anime.model.Anime
87- import tachiyomi.domain.entries.anime.model.AnimeUpdate
8885import tachiyomi.domain.entries.anime.model.NoSeasonsException
8986import tachiyomi.domain.entries.anime.repository.AnimeRepository
9087import tachiyomi.domain.entries.applyFilter
@@ -180,8 +177,6 @@ class AnimeScreenModel(
180177
181178 internal var isFromChangeCategory: Boolean = false
182179
183- private val updateFetchTypeMutex = Mutex ()
184-
185180 internal val autoOpenTrack: Boolean
186181 get() = successState?.hasLoggedInTrackers == true && trackPreferences.trackOnAddingToLibrary().get()
187182
@@ -249,8 +244,8 @@ class AnimeScreenModel(
249244 }
250245
251246 val needRefreshInfo = ! anime.initialized
252- val needRefreshEpisode = episodes.isEmpty() && anime.fetchType != FetchType .Seasons
253- val needRefreshSeason = seasons.isEmpty() && anime.fetchType != FetchType .Episodes
247+ val needRefreshEpisode = episodes.isEmpty() && anime.fetchType == FetchType .Episodes
248+ val needRefreshSeason = seasons.isEmpty() && anime.fetchType == FetchType .Seasons
254249
255250 // Show what we have earlier
256251 mutableState.update {
@@ -281,38 +276,6 @@ class AnimeScreenModel(
281276 }
282277 }
283278
284- /* *
285- * Update the fetch type of an anime. If the fetch type is the same as the one
286- * in the database, we don't need to update again. If they differ, an exception
287- * is thrown so it doesn't continue syncing.
288- */
289- private suspend fun updateFetchMode (anime : Anime , fetchType : FetchType ) {
290- updateFetchTypeMutex.withLock {
291- val anime = animeRepository.getAnimeById(anime.id)
292- if (fetchType == anime.fetchType) return @withLock
293- when (anime.fetchType) {
294- FetchType .Seasons -> {
295- throw NoEpisodesException ()
296- }
297- FetchType .Episodes -> {
298- throw NoSeasonsException ()
299- }
300- FetchType .Unknown -> {}
301- }
302-
303- val update = AnimeUpdate (
304- id = anime.id,
305- fetchType = fetchType,
306- )
307-
308- updateAnime.await(update)
309-
310- updateSuccessState {
311- it.copy(anime = anime.copy(fetchType = fetchType))
312- }
313- }
314- }
315-
316279 fun fetchAllFromSource (manualFetch : Boolean = true) {
317280 screenModelScope.launch {
318281 updateSuccessState { it.copy(isRefreshingData = true ) }
@@ -634,113 +597,88 @@ class AnimeScreenModel(
634597 }
635598 }
636599
637- private suspend fun CoroutineScope.fetchEpisodesFromSource (
638- anime : Anime ,
639- source : AnimeSource ,
640- manualFetch : Boolean = false,
641- ): Result <Unit > {
642- return runCatching {
643- if (anime.fetchType == FetchType .Seasons ) throw NoEpisodesException ()
644- val episodes = source.getEpisodeList(anime.toSAnime())
645-
646- if (episodes.isNotEmpty()) {
647- updateFetchMode(anime, FetchType .Episodes )
600+ private suspend fun fetchEpisodesFromSource (manualFetch : Boolean = false) {
601+ val state = successState ? : return
602+ try {
603+ withIOContext {
604+ updateEpisodesFromSource(state.anime, state.source, manualFetch)
605+ }
606+ } catch (e: Throwable ) {
607+ val message = if (e is NoEpisodesException ) {
608+ context.stringResource(AYMR .strings.no_episodes_error)
609+ } else {
610+ logcat(LogPriority .ERROR , e)
611+ with (context) { e.formattedMessage }
648612 }
649613
650- val newEpisodes = syncEpisodesWithSource.await(
651- episodes,
652- anime,
653- source,
654- manualFetch,
655- )
656-
657- if (manualFetch) {
658- downloadNewEpisodes(newEpisodes)
614+ screenModelScope.launch {
615+ snackbarHostState.showSnackbar(message = message)
659616 }
617+ val newAnime = animeRepository.getAnimeById(animeId)
618+ updateSuccessState { it.copy(anime = newAnime, isRefreshingData = false ) }
660619 }
661620 }
662621
663- /* *
664- * Requests an updated list of episodes and seasons from the source.
665- */
666- private suspend fun CoroutineScope.fetchEpisodesAndSeasonsFromSource (manualFetch : Boolean = false) {
667- val state = successState ? : return
668-
669- val fetchFromSourceTasks = listOf (
670- async(Dispatchers .IO ) {
671- fetchEpisodesFromSource(state.anime, state.source, manualFetch)
672- },
673- async(Dispatchers .IO ) {
674- runCatching {
675- if (state.anime.fetchType == FetchType .Episodes ) throw NoSeasonsException ()
676- val seasons = state.source.getSeasonList(state.anime.toSAnime())
677-
678- if (seasons.isNotEmpty()) {
679- updateFetchMode(state.anime, FetchType .Seasons )
680- }
622+ private suspend fun updateEpisodesFromSource (
623+ anime : Anime ,
624+ source : AnimeSource ,
625+ manualFetch : Boolean = false,
626+ ) {
627+ val episodes = source.getEpisodeList(anime.toSAnime())
681628
682- val newSeasons = syncSeasonsWithSource.await(
683- seasons,
684- state.anime,
685- state.source,
686- )
629+ val newEpisodes = syncEpisodesWithSource.await(
630+ episodes,
631+ anime,
632+ source,
633+ manualFetch,
634+ )
687635
688- if (libraryPreferences.updateSeasonOnRefresh().get()) {
689- fetchEpisodesFromSeasons(newSeasons, manualFetch)
690- }
691- }
692- },
693- ).awaitAll()
636+ if (manualFetch) {
637+ downloadNewEpisodes(newEpisodes)
638+ }
639+ }
694640
695- val newAnime = animeRepository.getAnimeById(animeId)
696- val (episodeError, seasonError) = fetchFromSourceTasks.map { it.exceptionOrNull() }
641+ private suspend fun fetchSeasonsFromSource (manualFetch : Boolean = false) {
642+ val state = successState ? : return
643+ try {
644+ withIOContext {
645+ val seasons = state.source.getSeasonList(state.anime.toSAnime())
697646
698- val isEpisodeError = newAnime.fetchType == FetchType .Episodes && episodeError != null
699- val isSeasonError = newAnime.fetchType == FetchType .Seasons && seasonError != null
647+ val newSeasons = syncSeasonsWithSource.await(
648+ seasons,
649+ state.anime,
650+ state.source,
651+ )
700652
701- val message = with (context) {
702- when {
703- newAnime.fetchType == FetchType .Unknown && episodeError != null && seasonError != null -> {
704- when {
705- episodeError !is NoEpisodesException -> {
706- logcat(LogPriority .ERROR , episodeError)
707- episodeError.formattedMessage
708- }
709- seasonError !is NoSeasonsException -> {
710- logcat(LogPriority .ERROR , seasonError)
711- seasonError.formattedMessage
712- }
713- else -> stringResource(AYMR .strings.no_entries_error)
714- }
653+ if (libraryPreferences.updateSeasonOnRefresh().get()) {
654+ fetchEpisodesFromSeasons(newSeasons, manualFetch)
715655 }
716- isSeasonError -> {
717- if (seasonError is NoSeasonsException ) {
718- stringResource(AYMR .strings.no_seasons_error)
719- } else {
720- logcat(LogPriority .ERROR , seasonError)
721- seasonError.formattedMessage
722- }
723- }
724- isEpisodeError -> {
725- if (episodeError is NoEpisodesException ) {
726- stringResource(AYMR .strings.no_episodes_error)
727- } else {
728- logcat(LogPriority .ERROR , episodeError)
729- episodeError.formattedMessage
730- }
731- }
732- else -> null
733656 }
734- }
657+ } catch (e: Throwable ) {
658+ val message = if (e is NoSeasonsException ) {
659+ context.stringResource(AYMR .strings.no_seasons_error)
660+ } else {
661+ logcat(LogPriority .ERROR , e)
662+ with (context) { e.formattedMessage }
663+ }
735664
736- message?.let {
737665 screenModelScope.launch {
738666 snackbarHostState.showSnackbar(message = message)
739667 }
668+ val newAnime = animeRepository.getAnimeById(animeId)
669+ updateSuccessState { it.copy(anime = newAnime, isRefreshingData = false ) }
740670 }
671+ }
741672
742- if (isEpisodeError || isSeasonError) {
743- updateSuccessState { it.copy(anime = newAnime, isRefreshingData = false ) }
673+ /* *
674+ * Requests an updated list of episodes and seasons from the source.
675+ */
676+ private suspend fun fetchEpisodesAndSeasonsFromSource (manualFetch : Boolean = false) {
677+ val state = successState ? : return
678+
679+ when (state.anime.fetchType) {
680+ FetchType .Seasons -> fetchSeasonsFromSource(manualFetch)
681+ FetchType .Episodes -> fetchEpisodesFromSource(manualFetch)
744682 }
745683 }
746684
@@ -754,7 +692,11 @@ class AnimeScreenModel(
754692 // Only fetch seasons with `Episodes` fetch type and only for non completed, unless they
755693 // haven't been fetched at all.
756694 if (s.fetchType == = FetchType .Episodes && (s.lastUpdate == 0L || s.status.toInt() != SAnime .COMPLETED )) {
757- fetchEpisodesFromSource(s, state.source, manualFetch)
695+ try {
696+ updateEpisodesFromSource(s, state.source, manualFetch)
697+ } catch (e: Throwable ) {
698+ logcat(LogPriority .ERROR , e)
699+ }
758700 }
759701 }
760702
@@ -1535,7 +1477,6 @@ class AnimeScreenModel(
15351477 fun showSettingsDialog () {
15361478 updateSuccessState {
15371479 when (it.anime.fetchType) {
1538- FetchType .Unknown -> it
15391480 FetchType .Seasons -> it.copy(dialog = Dialog .SeasonSettingsSheet )
15401481 FetchType .Episodes -> it.copy(dialog = Dialog .EpisodeSettingsSheet )
15411482 }
0 commit comments