Refactor LibraryUpdateService a bit for future changes

pull/4652/head
arkon 4 years ago
parent 94f5117941
commit b5c2934270

@ -71,6 +71,7 @@ class LibraryUpdateService(
private lateinit var notifier: LibraryUpdateNotifier private lateinit var notifier: LibraryUpdateNotifier
private lateinit var ioScope: CoroutineScope private lateinit var ioScope: CoroutineScope
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
private var updateJob: Job? = null private var updateJob: Job? = null
/** /**
@ -86,6 +87,8 @@ class LibraryUpdateService(
companion object { companion object {
private var instance: LibraryUpdateService? = null
/** /**
* Key for category to update. * Key for category to update.
*/ */
@ -116,17 +119,18 @@ class LibraryUpdateService(
* @return true if service newly started, false otherwise * @return true if service newly started, false otherwise
*/ */
fun start(context: Context, category: Category? = null, target: Target = Target.CHAPTERS): Boolean { fun start(context: Context, category: Category? = null, target: Target = Target.CHAPTERS): Boolean {
if (!isRunning(context)) { return if (!isRunning(context)) {
val intent = Intent(context, LibraryUpdateService::class.java).apply { val intent = Intent(context, LibraryUpdateService::class.java).apply {
putExtra(KEY_TARGET, target) putExtra(KEY_TARGET, target)
category?.let { putExtra(KEY_CATEGORY, it.id) } category?.let { putExtra(KEY_CATEGORY, it.id) }
} }
ContextCompat.startForegroundService(context, intent) ContextCompat.startForegroundService(context, intent)
return true true
} else {
instance?.addMangaToQueue(category?.id ?: -1, target)
false
} }
return false
} }
/** /**
@ -163,6 +167,9 @@ class LibraryUpdateService(
if (wakeLock.isHeld) { if (wakeLock.isHeld) {
wakeLock.release() wakeLock.release()
} }
if (instance == this) {
instance = null
}
super.onDestroy() super.onDestroy()
} }
@ -186,23 +193,25 @@ class LibraryUpdateService(
val target = intent.getSerializableExtra(KEY_TARGET) as? Target val target = intent.getSerializableExtra(KEY_TARGET) as? Target
?: return START_NOT_STICKY ?: return START_NOT_STICKY
// Unsubscribe from any previous subscription if needed. instance = this
// Unsubscribe from any previous subscription if needed
updateJob?.cancel() updateJob?.cancel()
// Update favorite manga. Destroy service when completed or in case of an error. // Update favorite manga
val selectedScheme = preferences.libraryUpdatePrioritization().get() val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
val mangaList = getMangaToUpdate(intent, target) addMangaToQueue(categoryId, target)
.sortedWith(rankingScheme[selectedScheme])
// Destroy service when completed or in case of an error.
val handler = CoroutineExceptionHandler { _, exception -> val handler = CoroutineExceptionHandler { _, exception ->
Timber.e(exception) Timber.e(exception)
stopSelf(startId) stopSelf(startId)
} }
updateJob = ioScope.launch(handler) { updateJob = ioScope.launch(handler) {
when (target) { when (target) {
Target.CHAPTERS -> updateChapterList(mangaList) Target.CHAPTERS -> updateChapterList()
Target.COVERS -> updateCovers(mangaList) Target.COVERS -> updateCovers()
Target.TRACKING -> updateTrackings(mangaList) Target.TRACKING -> updateTrackings()
} }
} }
updateJob?.invokeOnCompletion { stopSelf(startId) } updateJob?.invokeOnCompletion { stopSelf(startId) }
@ -211,32 +220,32 @@ class LibraryUpdateService(
} }
/** /**
* Returns the list of manga to be updated. * Adds list of manga to be updated.
* *
* @param intent the update intent. * @param category the ID of the category to update, or -1 if no category specified.
* @param target the target to update. * @param target the target to update.
* @return a list of manga to update
*/ */
fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> { fun addMangaToQueue(categoryId: Int, target: Target) {
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1) val libraryManga = db.getLibraryMangas().executeAsBlocking()
var listToUpdate = if (categoryId != -1) { var listToUpdate = if (categoryId != -1) {
db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId } libraryManga.filter { it.category == categoryId }
} else { } else {
val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt) val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt)
if (categoriesToUpdate.isNotEmpty()) { if (categoriesToUpdate.isNotEmpty()) {
db.getLibraryMangas().executeAsBlocking() libraryManga.filter { it.category in categoriesToUpdate }
.filter { it.category in categoriesToUpdate }
.distinctBy { it.id }
} else { } else {
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id } libraryManga
} }
} }
if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) { if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED } listToUpdate = listToUpdate.filterNot { it.status == SManga.COMPLETED }
} }
return listToUpdate val selectedScheme = preferences.libraryUpdatePrioritization().get()
mangaToUpdate = listToUpdate
.distinctBy { it.id }
.sortedWith(rankingScheme[selectedScheme])
} }
/** /**
@ -248,7 +257,7 @@ class LibraryUpdateService(
* @param mangaToUpdate the list to update * @param mangaToUpdate the list to update
* @return an observable delivering the progress of each update. * @return an observable delivering the progress of each update.
*/ */
suspend fun updateChapterList(mangaToUpdate: List<LibraryManga>) { suspend fun updateChapterList() {
val progressCount = AtomicInteger(0) val progressCount = AtomicInteger(0)
val newUpdates = mutableListOf<Pair<LibraryManga, Array<Chapter>>>() val newUpdates = mutableListOf<Pair<LibraryManga, Array<Chapter>>>()
val failedUpdates = mutableListOf<Pair<Manga, String?>>() val failedUpdates = mutableListOf<Pair<Manga, String?>>()
@ -342,7 +351,7 @@ class LibraryUpdateService(
return syncChaptersWithSource(db, chapters, manga, source) return syncChaptersWithSource(db, chapters, manga, source)
} }
private suspend fun updateCovers(mangaToUpdate: List<LibraryManga>) { private suspend fun updateCovers() {
var progressCount = 0 var progressCount = 0
mangaToUpdate.forEach { manga -> mangaToUpdate.forEach { manga ->
@ -375,7 +384,7 @@ class LibraryUpdateService(
* Method that updates the metadata of the connected tracking services. It's called in a * Method that updates the metadata of the connected tracking services. It's called in a
* background thread, so it's safe to do heavy operations or network calls here. * background thread, so it's safe to do heavy operations or network calls here.
*/ */
private suspend fun updateTrackings(mangaToUpdate: List<LibraryManga>) { private suspend fun updateTrackings() {
var progressCount = 0 var progressCount = 0
val loggedServices = trackManager.services.filter { it.isLogged } val loggedServices = trackManager.services.filter { it.isLogged }

@ -100,7 +100,8 @@ class LibraryUpdateServiceTest {
val intent = Intent() val intent = Intent()
val target = LibraryUpdateService.Target.CHAPTERS val target = LibraryUpdateService.Target.CHAPTERS
runBlocking { runBlocking {
service.updateChapterList(service.getMangaToUpdate(intent, target)) service.addMangaToQueue(intent, target)
service.updateChapterList()
// There are 3 network attempts and 2 insertions (1 request failed) // There are 3 network attempts and 2 insertions (1 request failed)
assertThat(service.db.getChapters(favManga[0]).executeAsBlocking()).hasSize(2) assertThat(service.db.getChapters(favManga[0]).executeAsBlocking()).hasSize(2)

Loading…
Cancel
Save