Move LibraryManga to domain layer (#8126)

This commit is contained in:
AntsyLich
2022-10-01 21:30:51 +06:00
committed by GitHub
parent b04d1e5f50
commit ea8383978b
20 changed files with 217 additions and 232 deletions

View File

@@ -1,35 +0,0 @@
package eu.kanade.tachiyomi.data.database.models
class LibraryManga : MangaImpl() {
var unreadCount: Int = 0
var readCount: Int = 0
val totalChapters
get() = readCount + unreadCount
val hasStarted
get() = readCount > 0
var category: Int = 0
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is LibraryManga) return false
if (!super.equals(other)) return false
if (unreadCount != other.unreadCount) return false
if (readCount != other.readCount) return false
if (category != other.category) return false
return true
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + unreadCount
result = 31 * result + readCount
result = 31 * result + category
return result
}
}

View File

@@ -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() }
val newChapters = updateManga(manga)
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(),
)
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,
)