tachiyomi/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt
2023-11-04 23:28:41 -04:00

105 lines
3.9 KiB
Kotlin

package eu.kanade.tachiyomi.ui.reader.loader
import android.content.Context
import com.github.junrar.exception.UnsupportedRarV5Exception
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.model.StubSource
import tachiyomi.source.local.LocalSource
import tachiyomi.source.local.io.Format
/**
* Loader used to retrieve the [PageLoader] for a given chapter.
*/
class ChapterLoader(
private val context: Context,
private val downloadManager: DownloadManager,
private val downloadProvider: DownloadProvider,
private val manga: Manga,
private val source: Source,
) {
/**
* Assigns the chapter's page loader and loads the its pages. Returns immediately if the chapter
* is already loaded.
*/
suspend fun loadChapter(chapter: ReaderChapter) {
if (chapterIsReady(chapter)) {
return
}
chapter.state = ReaderChapter.State.Loading
withIOContext {
logcat { "Loading pages for ${chapter.chapter.name}" }
try {
val loader = getPageLoader(chapter)
chapter.pageLoader = loader
val pages = loader.getPages()
.onEach { it.chapter = chapter }
if (pages.isEmpty()) {
throw Exception(context.getString(R.string.page_list_empty_error))
}
// If the chapter is partially read, set the starting page to the last the user read
// otherwise use the requested page.
if (!chapter.chapter.read) {
chapter.requestedPage = chapter.chapter.last_page_read
}
chapter.state = ReaderChapter.State.Loaded(pages)
} catch (e: Throwable) {
chapter.state = ReaderChapter.State.Error(e)
throw e
}
}
}
/**
* Checks [chapter] to be loaded based on present pages and loader in addition to state.
*/
private fun chapterIsReady(chapter: ReaderChapter): Boolean {
return chapter.state is ReaderChapter.State.Loaded && chapter.pageLoader != null
}
/**
* Returns the page loader to use for this [chapter].
*/
private fun getPageLoader(chapter: ReaderChapter): PageLoader {
val dbChapter = chapter.chapter
val isDownloaded = downloadManager.isChapterDownloaded(
dbChapter.name,
dbChapter.scanlator,
manga.title,
manga.source,
skipCache = true,
)
return when {
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)
is Format.Zip -> ZipPageLoader(format.file)
is Format.Rar -> try {
RarPageLoader(format.file)
} catch (e: UnsupportedRarV5Exception) {
error(context.getString(R.string.loader_rar5_error))
}
is Format.Epub -> EpubPageLoader(format.file)
}
}
source is HttpSource -> HttpPageLoader(chapter, source)
source is StubSource -> error(context.getString(R.string.source_not_installed, source.toString()))
else -> error(context.getString(R.string.loader_not_implemented_error))
}
}
}