|
@@ -14,10 +14,12 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
|
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
|
|
import eu.kanade.domain.chapter.model.toDbChapter
|
|
|
import eu.kanade.domain.download.service.DownloadPreferences
|
|
|
+import eu.kanade.domain.library.model.LibraryManga
|
|
|
import eu.kanade.domain.library.service.LibraryPreferences
|
|
|
import eu.kanade.domain.manga.interactor.GetLibraryManga
|
|
|
import eu.kanade.domain.manga.interactor.GetManga
|
|
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
|
|
+import eu.kanade.domain.manga.model.Manga
|
|
|
import eu.kanade.domain.manga.model.toMangaUpdate
|
|
|
import eu.kanade.domain.track.interactor.GetTracks
|
|
|
import eu.kanade.domain.track.interactor.InsertTrack
|
|
@@ -26,10 +28,7 @@ import eu.kanade.domain.track.model.toDomainTrack
|
|
|
import eu.kanade.tachiyomi.R
|
|
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
|
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
|
-import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
|
|
-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.download.DownloadManager
|
|
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
|
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
|
|
@@ -75,7 +74,6 @@ import java.util.concurrent.CopyOnWriteArrayList
|
|
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
|
import java.util.concurrent.atomic.AtomicInteger
|
|
|
import eu.kanade.domain.chapter.model.Chapter as DomainChapter
|
|
|
-import eu.kanade.domain.manga.model.Manga as DomainManga
|
|
|
|
|
|
/**
|
|
|
* This class will take care of updating the chapters of the manga from the library. It can be
|
|
@@ -261,20 +259,20 @@ class LibraryUpdateService(
|
|
|
*
|
|
|
* @param categoryId the ID of the category to update, or -1 if no category specified.
|
|
|
*/
|
|
|
- fun addMangaToQueue(categoryId: Long) {
|
|
|
+ private fun addMangaToQueue(categoryId: Long) {
|
|
|
val libraryManga = runBlocking { getLibraryManga.await() }
|
|
|
|
|
|
val listToUpdate = if (categoryId != -1L) {
|
|
|
- libraryManga.filter { it.category.toLong() == categoryId }
|
|
|
+ libraryManga.filter { it.category == categoryId }
|
|
|
} else {
|
|
|
- val categoriesToUpdate = libraryPreferences.libraryUpdateCategories().get().map(String::toInt)
|
|
|
+ val categoriesToUpdate = libraryPreferences.libraryUpdateCategories().get().map { it.toLong() }
|
|
|
val listToInclude = if (categoriesToUpdate.isNotEmpty()) {
|
|
|
libraryManga.filter { it.category in categoriesToUpdate }
|
|
|
} else {
|
|
|
libraryManga
|
|
|
}
|
|
|
|
|
|
- val categoriesToExclude = libraryPreferences.libraryUpdateCategoriesExclude().get().map(String::toInt)
|
|
|
+ val categoriesToExclude = libraryPreferences.libraryUpdateCategoriesExclude().get().map { it.toLong() }
|
|
|
val listToExclude = if (categoriesToExclude.isNotEmpty()) {
|
|
|
libraryManga.filter { it.category in categoriesToExclude }
|
|
|
} else {
|
|
@@ -285,12 +283,12 @@ class LibraryUpdateService(
|
|
|
}
|
|
|
|
|
|
mangaToUpdate = listToUpdate
|
|
|
- .distinctBy { it.id }
|
|
|
- .sortedBy { it.title }
|
|
|
+ .distinctBy { it.manga.id }
|
|
|
+ .sortedBy { it.manga.title }
|
|
|
|
|
|
// Warn when excessively checking a single source
|
|
|
val maxUpdatesFromSource = mangaToUpdate
|
|
|
- .groupBy { it.source }
|
|
|
+ .groupBy { it.manga.source }
|
|
|
.filterKeys { sourceManager.get(it) !is UnmeteredSource }
|
|
|
.maxOfOrNull { it.value.size } ?: 0
|
|
|
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
|
@@ -309,8 +307,8 @@ class LibraryUpdateService(
|
|
|
private suspend fun updateChapterList() {
|
|
|
val semaphore = Semaphore(5)
|
|
|
val progressCount = AtomicInteger(0)
|
|
|
- val currentlyUpdatingManga = CopyOnWriteArrayList<LibraryManga>()
|
|
|
- val newUpdates = CopyOnWriteArrayList<Pair<DomainManga, Array<DomainChapter>>>()
|
|
|
+ val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
|
|
+ val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<DomainChapter>>>()
|
|
|
val skippedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
|
|
val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
|
|
val hasDownloads = AtomicBoolean(false)
|
|
@@ -319,60 +317,58 @@ class LibraryUpdateService(
|
|
|
val restrictions = libraryPreferences.libraryUpdateMangaRestriction().get()
|
|
|
|
|
|
withIOContext {
|
|
|
- mangaToUpdate.groupBy { it.source }
|
|
|
+ mangaToUpdate.groupBy { it.manga.source }
|
|
|
.values
|
|
|
.map { mangaInSource ->
|
|
|
async {
|
|
|
semaphore.withPermit {
|
|
|
- mangaInSource.forEach { manga ->
|
|
|
+ mangaInSource.forEach { libraryManga ->
|
|
|
+ val manga = libraryManga.manga
|
|
|
if (updateJob?.isActive != true) {
|
|
|
return@async
|
|
|
}
|
|
|
|
|
|
- // Don't continue to update if manga not in library
|
|
|
- manga.id?.let { getManga.await(it) } ?: return@forEach
|
|
|
+ // Don't continue to update if manga is not in library
|
|
|
+ manga.id.let { getManga.await(it) } ?: return@forEach
|
|
|
|
|
|
withUpdateNotification(
|
|
|
currentlyUpdatingManga,
|
|
|
progressCount,
|
|
|
manga,
|
|
|
- ) { mangaWithNotif ->
|
|
|
+ ) {
|
|
|
try {
|
|
|
when {
|
|
|
- MANGA_NON_COMPLETED in restrictions && mangaWithNotif.status == SManga.COMPLETED ->
|
|
|
- skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_completed))
|
|
|
+ MANGA_NON_COMPLETED in restrictions && manga.status.toInt() == SManga.COMPLETED ->
|
|
|
+ skippedUpdates.add(manga to getString(R.string.skipped_reason_completed))
|
|
|
|
|
|
- MANGA_HAS_UNREAD in restrictions && mangaWithNotif.unreadCount != 0 ->
|
|
|
- skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_caught_up))
|
|
|
+ MANGA_HAS_UNREAD in restrictions && libraryManga.unreadCount != 0L ->
|
|
|
+ skippedUpdates.add(manga to getString(R.string.skipped_reason_not_caught_up))
|
|
|
|
|
|
- MANGA_NON_READ in restrictions && mangaWithNotif.totalChapters > 0 && !mangaWithNotif.hasStarted ->
|
|
|
- skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_started))
|
|
|
+ MANGA_NON_READ in restrictions && libraryManga.totalChapters > 0L && !libraryManga.hasStarted ->
|
|
|
+ skippedUpdates.add(manga to getString(R.string.skipped_reason_not_started))
|
|
|
|
|
|
- mangaWithNotif.update_strategy != UpdateStrategy.ALWAYS_UPDATE ->
|
|
|
- skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_always_update))
|
|
|
+ manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE ->
|
|
|
+ skippedUpdates.add(manga to getString(R.string.skipped_reason_not_always_update))
|
|
|
|
|
|
else -> {
|
|
|
- // Convert to the manga that contains new chapters
|
|
|
- mangaWithNotif.toDomainManga()?.let { domainManga ->
|
|
|
- val newChapters = updateManga(domainManga)
|
|
|
- val newDbChapters = newChapters.map { it.toDbChapter() }
|
|
|
-
|
|
|
- if (newChapters.isNotEmpty()) {
|
|
|
- val categoryIds = getCategories.await(domainManga.id).map { it.id }
|
|
|
- if (domainManga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
|
|
|
- downloadChapters(mangaWithNotif, newDbChapters)
|
|
|
- hasDownloads.set(true)
|
|
|
- }
|
|
|
-
|
|
|
- // Convert to the manga that contains new chapters
|
|
|
- newUpdates.add(
|
|
|
- mangaWithNotif.toDomainManga()!! to
|
|
|
- newDbChapters
|
|
|
- .map { it.toDomainChapter()!! }
|
|
|
- .sortedByDescending { it.sourceOrder }
|
|
|
- .toTypedArray(),
|
|
|
- )
|
|
|
+ val newChapters = updateManga(manga)
|
|
|
+ val newDbChapters = newChapters.map { it.toDbChapter() }
|
|
|
+
|
|
|
+ if (newChapters.isNotEmpty()) {
|
|
|
+ val categoryIds = getCategories.await(manga.id).map { it.id }
|
|
|
+ if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
|
|
|
+ downloadChapters(manga, newDbChapters)
|
|
|
+ hasDownloads.set(true)
|
|
|
}
|
|
|
+
|
|
|
+ // Convert to the manga that contains new chapters
|
|
|
+ newUpdates.add(
|
|
|
+ manga to
|
|
|
+ newDbChapters
|
|
|
+ .map { it.toDomainChapter()!! }
|
|
|
+ .sortedByDescending { it.sourceOrder }
|
|
|
+ .toTypedArray(),
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -383,11 +379,11 @@ class LibraryUpdateService(
|
|
|
is SourceManager.SourceNotInstalledException -> getString(R.string.loader_not_implemented_error)
|
|
|
else -> e.message
|
|
|
}
|
|
|
- failedUpdates.add(mangaWithNotif to errorMessage)
|
|
|
+ failedUpdates.add(manga to errorMessage)
|
|
|
}
|
|
|
|
|
|
if (libraryPreferences.autoUpdateTrackers().get()) {
|
|
|
- updateTrackings(mangaWithNotif, loggedServices)
|
|
|
+ updateTrackings(manga, loggedServices)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -423,7 +419,7 @@ class LibraryUpdateService(
|
|
|
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
|
|
// We don't want to start downloading while the library is updating, because websites
|
|
|
// may don't like it and they could ban the user.
|
|
|
- downloadManager.downloadChapters(manga.toDomainManga()!!, chapters, false)
|
|
|
+ downloadManager.downloadChapters(manga, chapters, false)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -432,7 +428,7 @@ class LibraryUpdateService(
|
|
|
* @param manga the manga to update.
|
|
|
* @return a pair of the inserted and removed chapters.
|
|
|
*/
|
|
|
- private suspend fun updateManga(manga: DomainManga): List<DomainChapter> {
|
|
|
+ private suspend fun updateManga(manga: Manga): List<DomainChapter> {
|
|
|
val source = sourceManager.getOrStub(manga.source)
|
|
|
|
|
|
// Update manga metadata if needed
|
|
@@ -455,15 +451,16 @@ class LibraryUpdateService(
|
|
|
private suspend fun updateCovers() {
|
|
|
val semaphore = Semaphore(5)
|
|
|
val progressCount = AtomicInteger(0)
|
|
|
- val currentlyUpdatingManga = CopyOnWriteArrayList<LibraryManga>()
|
|
|
+ val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
|
|
|
|
|
withIOContext {
|
|
|
- mangaToUpdate.groupBy { it.source }
|
|
|
+ mangaToUpdate.groupBy { it.manga.source }
|
|
|
.values
|
|
|
.map { mangaInSource ->
|
|
|
async {
|
|
|
semaphore.withPermit {
|
|
|
- mangaInSource.forEach { manga ->
|
|
|
+ mangaInSource.forEach { libraryManga ->
|
|
|
+ val manga = libraryManga.manga
|
|
|
if (updateJob?.isActive != true) {
|
|
|
return@async
|
|
|
}
|
|
@@ -472,14 +469,14 @@ class LibraryUpdateService(
|
|
|
currentlyUpdatingManga,
|
|
|
progressCount,
|
|
|
manga,
|
|
|
- ) { mangaWithNotif ->
|
|
|
- val source = sourceManager.get(mangaWithNotif.source) ?: return@withUpdateNotification
|
|
|
+ ) {
|
|
|
+ val source = sourceManager.get(manga.source) ?: return@withUpdateNotification
|
|
|
try {
|
|
|
- val networkManga = source.getMangaDetails(mangaWithNotif.copy())
|
|
|
- mangaWithNotif.prepUpdateCover(coverCache, networkManga, true)
|
|
|
- mangaWithNotif.copyFrom(networkManga)
|
|
|
+ val networkManga = source.getMangaDetails(manga.toSManga())
|
|
|
+ val updatedManga = manga.prepUpdateCover(coverCache, networkManga, true)
|
|
|
+ .copyFrom(networkManga)
|
|
|
try {
|
|
|
- updateManga.await(mangaWithNotif.toDomainManga()!!.toMangaUpdate())
|
|
|
+ updateManga.await(updatedManga.toMangaUpdate())
|
|
|
} catch (e: Exception) {
|
|
|
logcat(LogPriority.ERROR) { "Manga doesn't exist anymore" }
|
|
|
}
|
|
@@ -506,12 +503,13 @@ class LibraryUpdateService(
|
|
|
var progressCount = 0
|
|
|
val loggedServices = trackManager.services.filter { it.isLogged }
|
|
|
|
|
|
- mangaToUpdate.forEach { manga ->
|
|
|
+ mangaToUpdate.forEach { libraryManga ->
|
|
|
+ val manga = libraryManga.manga
|
|
|
if (updateJob?.isActive != true) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- notifier.showProgressNotification(listOf(manga.toDomainManga()!!), progressCount++, mangaToUpdate.size)
|
|
|
+ notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
|
|
|
|
|
|
// Update the tracking details.
|
|
|
updateTrackings(manga, loggedServices)
|
|
@@ -520,8 +518,8 @@ class LibraryUpdateService(
|
|
|
notifier.cancelProgressNotification()
|
|
|
}
|
|
|
|
|
|
- private suspend fun updateTrackings(manga: LibraryManga, loggedServices: List<TrackService>) {
|
|
|
- getTracks.await(manga.id!!)
|
|
|
+ private suspend fun updateTrackings(manga: Manga, loggedServices: List<TrackService>) {
|
|
|
+ getTracks.await(manga.id)
|
|
|
.map { track ->
|
|
|
supervisorScope {
|
|
|
async {
|
|
@@ -532,7 +530,7 @@ class LibraryUpdateService(
|
|
|
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
|
|
|
|
|
if (service is EnhancedTrackService) {
|
|
|
- val chapters = getChapterByMangaId.await(manga.id!!)
|
|
|
+ val chapters = getChapterByMangaId.await(manga.id)
|
|
|
syncChaptersWithTrackServiceTwoWay.await(chapters, track, service)
|
|
|
}
|
|
|
} catch (e: Throwable) {
|
|
@@ -547,10 +545,10 @@ class LibraryUpdateService(
|
|
|
}
|
|
|
|
|
|
private suspend fun withUpdateNotification(
|
|
|
- updatingManga: CopyOnWriteArrayList<LibraryManga>,
|
|
|
+ updatingManga: CopyOnWriteArrayList<Manga>,
|
|
|
completed: AtomicInteger,
|
|
|
- manga: LibraryManga,
|
|
|
- block: suspend (LibraryManga) -> Unit,
|
|
|
+ manga: Manga,
|
|
|
+ block: suspend () -> Unit,
|
|
|
) {
|
|
|
if (updateJob?.isActive != true) {
|
|
|
return
|
|
@@ -558,12 +556,12 @@ class LibraryUpdateService(
|
|
|
|
|
|
updatingManga.add(manga)
|
|
|
notifier.showProgressNotification(
|
|
|
- updatingManga.map { it.toDomainManga()!! },
|
|
|
+ updatingManga,
|
|
|
completed.get(),
|
|
|
mangaToUpdate.size,
|
|
|
)
|
|
|
|
|
|
- block(manga)
|
|
|
+ block()
|
|
|
|
|
|
if (updateJob?.isActive != true) {
|
|
|
return
|
|
@@ -572,7 +570,7 @@ class LibraryUpdateService(
|
|
|
updatingManga.remove(manga)
|
|
|
completed.getAndIncrement()
|
|
|
notifier.showProgressNotification(
|
|
|
- updatingManga.map { it.toDomainManga()!! },
|
|
|
+ updatingManga,
|
|
|
completed.get(),
|
|
|
mangaToUpdate.size,
|
|
|
)
|