mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-17 13:09:17 +01:00
Download ahead (#7226)
This commit is contained in:
parent
2e81e1b7d8
commit
f207e87722
@ -157,6 +157,20 @@ class DownloadManager(
|
|||||||
downloader.queueChapters(manga, chapters, autoStart)
|
downloader.queueChapters(manga, chapters, autoStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the downloader to enqueue the given list of downloads at the start of the queue.
|
||||||
|
*
|
||||||
|
* @param downloads the list of downloads to enqueue.
|
||||||
|
*/
|
||||||
|
fun addDownloadsToStartOfQueue(downloads: List<Download>) {
|
||||||
|
val wasEmpty = queue.isEmpty()
|
||||||
|
queue.toMutableList().apply {
|
||||||
|
addAll(0, downloads)
|
||||||
|
reorderQueue(this)
|
||||||
|
}
|
||||||
|
if (wasEmpty) startDownloads()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the page list of a downloaded chapter.
|
* Builds the page list of a downloaded chapter.
|
||||||
*
|
*
|
||||||
|
@ -275,11 +275,13 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
|
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
|
||||||
|
|
||||||
fun downloadNewChapter() = flowPrefs.getBoolean("download_new", false)
|
fun downloadNewChapters() = flowPrefs.getBoolean("download_new", false)
|
||||||
|
|
||||||
fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
|
fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
|
||||||
fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
|
fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
|
||||||
|
|
||||||
|
fun autoDownloadWhileReading() = flowPrefs.getInt("auto_download_while_reading", 0)
|
||||||
|
|
||||||
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
||||||
|
|
||||||
fun categorizedDisplaySettings() = flowPrefs.getBoolean("categorized_display", false)
|
fun categorizedDisplaySettings() = flowPrefs.getBoolean("categorized_display", false)
|
||||||
|
@ -19,8 +19,10 @@ import eu.kanade.domain.track.interactor.GetTracks
|
|||||||
import eu.kanade.domain.track.interactor.InsertTrack
|
import eu.kanade.domain.track.interactor.InsertTrack
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.saver.Image
|
import eu.kanade.tachiyomi.data.saver.Image
|
||||||
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
||||||
@ -32,6 +34,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
@ -63,6 +66,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter as DbChapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter used by the activity to perform background operations.
|
* Presenter used by the activity to perform background operations.
|
||||||
@ -119,6 +123,8 @@ class ReaderPresenter(
|
|||||||
|
|
||||||
private val imageSaver: ImageSaver by injectLazy()
|
private val imageSaver: ImageSaver by injectLazy()
|
||||||
|
|
||||||
|
private var chapterDownload: Download? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chapter list for the active manga. It's retrieved lazily and should be accessed for the first
|
* Chapter list for the active manga. It's retrieved lazily and should be accessed for the first
|
||||||
* time in a background thread to avoid blocking the UI.
|
* time in a background thread to avoid blocking the UI.
|
||||||
@ -191,6 +197,9 @@ class ReaderPresenter(
|
|||||||
if (currentChapters != null) {
|
if (currentChapters != null) {
|
||||||
currentChapters.unref()
|
currentChapters.unref()
|
||||||
saveReadingProgress(currentChapters.currChapter)
|
saveReadingProgress(currentChapters.currChapter)
|
||||||
|
chapterDownload?.let {
|
||||||
|
downloadManager.addDownloadsToStartOfQueue(listOf(it))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +327,7 @@ class ReaderPresenter(
|
|||||||
newChapters.ref()
|
newChapters.ref()
|
||||||
oldChapters?.unref()
|
oldChapters?.unref()
|
||||||
|
|
||||||
|
chapterDownload = deleteChapterFromDownloadQueue(newChapters.currChapter)
|
||||||
viewerChaptersRelay.call(newChapters)
|
viewerChaptersRelay.call(newChapters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,7 +426,6 @@ class ReaderPresenter(
|
|||||||
selectedChapter.chapter.read = true
|
selectedChapter.chapter.read = true
|
||||||
updateTrackChapterRead(selectedChapter)
|
updateTrackChapterRead(selectedChapter)
|
||||||
deleteChapterIfNeeded(selectedChapter)
|
deleteChapterIfNeeded(selectedChapter)
|
||||||
deleteChapterFromDownloadQueue(currentChapters.currChapter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedChapter != currentChapters.currChapter) {
|
if (selectedChapter != currentChapters.currChapter) {
|
||||||
@ -425,15 +434,56 @@ class ReaderPresenter(
|
|||||||
setReadStartTime()
|
setReadStartTime()
|
||||||
loadNewChapter(selectedChapter)
|
loadNewChapter(selectedChapter)
|
||||||
}
|
}
|
||||||
|
val pages = page.chapter.pages ?: return
|
||||||
|
val inDownloadRange = page.number.toDouble() / pages.size > 0.2
|
||||||
|
if (inDownloadRange) {
|
||||||
|
downloadNextChapters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadNextChapters() {
|
||||||
|
val manga = manga ?: return
|
||||||
|
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
||||||
|
val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return
|
||||||
|
val chaptersNumberToDownload = preferences.autoDownloadWhileReading().get()
|
||||||
|
if (chaptersNumberToDownload == 0 || !manga.favorite) return
|
||||||
|
val isNextChapterDownloaded =
|
||||||
|
downloadManager.isChapterDownloaded(nextChapter.name, nextChapter.scanlator, manga.title, manga.source)
|
||||||
|
if (isNextChapterDownloaded) {
|
||||||
|
downloadAutoNextChapters(chaptersNumberToDownload, nextChapter.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadAutoNextChapters(choice: Int, nextChapterId: Long?) {
|
||||||
|
val chaptersToDownload = getNextUnreadChaptersSorted(nextChapterId).take(choice - 1)
|
||||||
|
if (chaptersToDownload.isNotEmpty()) {
|
||||||
|
downloadChapters(chaptersToDownload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNextUnreadChaptersSorted(nextChapterId: Long?): List<DbChapter> {
|
||||||
|
return chapterList.map { it.chapter.toDomainChapter()!! }
|
||||||
|
.filter { !it.read || it.id == nextChapterId }
|
||||||
|
.sortedWith(getChapterSort(manga?.toDomainManga()!!, false))
|
||||||
|
.map { it.toDbChapter() }
|
||||||
|
.takeLastWhile { it.id != nextChapterId }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads the given list of chapters with the manager.
|
||||||
|
* @param chapters the list of chapters to download.
|
||||||
|
*/
|
||||||
|
private fun downloadChapters(chapters: List<DbChapter>) {
|
||||||
|
downloadManager.downloadChapters(manga?.toDomainManga()!!, chapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes [currentChapter] from download queue
|
* Removes [currentChapter] from download queue
|
||||||
* if setting is enabled and [currentChapter] is queued for download
|
* if setting is enabled and [currentChapter] is queued for download
|
||||||
*/
|
*/
|
||||||
private fun deleteChapterFromDownloadQueue(currentChapter: ReaderChapter) {
|
private fun deleteChapterFromDownloadQueue(currentChapter: ReaderChapter): Download? {
|
||||||
downloadManager.getChapterDownloadOrNull(currentChapter.chapter)?.let { download ->
|
return downloadManager.getChapterDownloadOrNull(currentChapter.chapter)?.apply {
|
||||||
downloadManager.deletePendingDownload(download)
|
downloadManager.deletePendingDownload(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,6 +498,9 @@ class ReaderPresenter(
|
|||||||
val removeAfterReadSlots = preferences.removeAfterReadSlots()
|
val removeAfterReadSlots = preferences.removeAfterReadSlots()
|
||||||
val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots)
|
val chapterToDelete = chapterList.getOrNull(currentChapterPosition - removeAfterReadSlots)
|
||||||
|
|
||||||
|
if (removeAfterReadSlots != 0 && chapterDownload != null) {
|
||||||
|
downloadManager.addDownloadsToStartOfQueue(listOf(chapterDownload!!))
|
||||||
|
}
|
||||||
// Check if deleting option is enabled and chapter exists
|
// Check if deleting option is enabled and chapter exists
|
||||||
if (removeAfterReadSlots != -1 && chapterToDelete != null) {
|
if (removeAfterReadSlots != -1 && chapterToDelete != null) {
|
||||||
enqueueDeleteReadChapters(chapterToDelete)
|
enqueueDeleteReadChapters(chapterToDelete)
|
||||||
|
@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|||||||
import eu.kanade.tachiyomi.util.preference.bindTo
|
import eu.kanade.tachiyomi.util.preference.bindTo
|
||||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||||
import eu.kanade.tachiyomi.util.preference.entriesRes
|
import eu.kanade.tachiyomi.util.preference.entriesRes
|
||||||
|
import eu.kanade.tachiyomi.util.preference.infoPreference
|
||||||
import eu.kanade.tachiyomi.util.preference.intListPreference
|
import eu.kanade.tachiyomi.util.preference.intListPreference
|
||||||
import eu.kanade.tachiyomi.util.preference.multiSelectListPreference
|
import eu.kanade.tachiyomi.util.preference.multiSelectListPreference
|
||||||
import eu.kanade.tachiyomi.util.preference.onClick
|
import eu.kanade.tachiyomi.util.preference.onClick
|
||||||
@ -129,10 +130,10 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
titleRes = R.string.pref_category_auto_download
|
titleRes = R.string.pref_download_new
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
bindTo(preferences.downloadNewChapter())
|
bindTo(preferences.downloadNewChapters())
|
||||||
titleRes = R.string.pref_download_new
|
titleRes = R.string.pref_download_new
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
@ -142,7 +143,7 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
DownloadCategoriesDialog().showDialog(router)
|
DownloadCategoriesDialog().showDialog(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
visibleIf(preferences.downloadNewChapter()) { it }
|
visibleIf(preferences.downloadNewChapters()) { it }
|
||||||
|
|
||||||
fun updateSummary() {
|
fun updateSummary() {
|
||||||
val selectedCategories = preferences.downloadNewChapterCategories().get()
|
val selectedCategories = preferences.downloadNewChapterCategories().get()
|
||||||
@ -178,6 +179,25 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
.launchIn(viewScope)
|
.launchIn(viewScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.download_ahead
|
||||||
|
|
||||||
|
intListPreference {
|
||||||
|
bindTo(preferences.autoDownloadWhileReading())
|
||||||
|
titleRes = R.string.auto_download_while_reading
|
||||||
|
entries = arrayOf(
|
||||||
|
context.getString(R.string.disabled),
|
||||||
|
context.resources.getQuantityString(R.plurals.next_unread_chapters, 2, 2),
|
||||||
|
context.resources.getQuantityString(R.plurals.next_unread_chapters, 3, 3),
|
||||||
|
context.resources.getQuantityString(R.plurals.next_unread_chapters, 5, 5),
|
||||||
|
context.resources.getQuantityString(R.plurals.next_unread_chapters, 10, 10),
|
||||||
|
)
|
||||||
|
entryValues = arrayOf("0", "2", "3", "5", "10")
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
infoPreference(R.string.download_ahead_info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
@ -57,8 +57,8 @@ fun DomainManga.shouldDownloadNewChapters(dbCategories: List<Long>, preferences:
|
|||||||
val categories = dbCategories.ifEmpty { listOf(0L) }
|
val categories = dbCategories.ifEmpty { listOf(0L) }
|
||||||
|
|
||||||
// Boolean to determine if user wants to automatically download new chapters.
|
// Boolean to determine if user wants to automatically download new chapters.
|
||||||
val downloadNewChapter = preferences.downloadNewChapter().get()
|
val downloadNewChapters = preferences.downloadNewChapters().get()
|
||||||
if (!downloadNewChapter) return false
|
if (!downloadNewChapters) return false
|
||||||
|
|
||||||
val includedCategories = preferences.downloadNewChapterCategories().get().map { it.toLong() }
|
val includedCategories = preferences.downloadNewChapterCategories().get().map { it.toLong() }
|
||||||
val excludedCategories = preferences.downloadNewChapterCategoriesExclude().get().map { it.toLong() }
|
val excludedCategories = preferences.downloadNewChapterCategoriesExclude().get().map { it.toLong() }
|
||||||
|
@ -417,11 +417,18 @@
|
|||||||
<string name="pref_category_auto_download">Auto-download</string>
|
<string name="pref_category_auto_download">Auto-download</string>
|
||||||
<string name="pref_download_new">Download new chapters</string>
|
<string name="pref_download_new">Download new chapters</string>
|
||||||
<string name="pref_download_new_categories_details">Manga in excluded categories will not be downloaded even if they are also in included categories.</string>
|
<string name="pref_download_new_categories_details">Manga in excluded categories will not be downloaded even if they are also in included categories.</string>
|
||||||
|
<string name="download_ahead">Download ahead</string>
|
||||||
|
<string name="auto_download_while_reading">Auto download while reading</string>
|
||||||
|
<plurals name="next_unread_chapters">
|
||||||
|
<item quantity="one">Next unread chapter</item>
|
||||||
|
<item quantity="other">Next %d unread chapters</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="download_ahead_info">Only works on entries in library and if the current chapter plus the next one are already downloaded</string>
|
||||||
<string name="save_chapter_as_cbz">Save as CBZ archive</string>
|
<string name="save_chapter_as_cbz">Save as CBZ archive</string>
|
||||||
<string name="split_tall_images">Split tall images</string>
|
<string name="split_tall_images">Split tall images</string>
|
||||||
<string name="split_tall_images_summary">Improves reader performance</string>
|
<string name="split_tall_images_summary">Improves reader performance</string>
|
||||||
|
|
||||||
<!-- Tracking section -->
|
<!-- Tracking section -->
|
||||||
<string name="tracking_guide">Tracking guide</string>
|
<string name="tracking_guide">Tracking guide</string>
|
||||||
<string name="pref_auto_update_manga_sync">Update progress after reading</string>
|
<string name="pref_auto_update_manga_sync">Update progress after reading</string>
|
||||||
<string name="services">Services</string>
|
<string name="services">Services</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user