mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-24 03:11:53 +01:00
Reorder Library Update Service
Co-Authored-By: Carlos <carlosesco@users.noreply.github.com>
This commit is contained in:
parent
c67a5a2c0e
commit
8f410ca864
@ -117,96 +117,118 @@ class LibraryUpdateService(
|
|||||||
TRACKING // Tracking metadata
|
TRACKING // Tracking metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
/**
|
||||||
|
* Method called when the service receives an intent.
|
||||||
|
*
|
||||||
|
* @param intent the start intent from.
|
||||||
|
* @param flags the flags of the command.
|
||||||
|
* @param startId the start id of this command.
|
||||||
|
* @return the start value of the command.
|
||||||
|
*/
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
if (intent == null) return START_NOT_STICKY
|
||||||
|
val target = intent.getSerializableExtra(KEY_TARGET) as? Target ?: return START_NOT_STICKY
|
||||||
|
|
||||||
/**
|
instance = this
|
||||||
* Key for category to update.
|
|
||||||
*/
|
|
||||||
const val KEY_CATEGORY = "category"
|
|
||||||
|
|
||||||
fun categoryInQueue(id: Int?) = instance?.categoryIds?.contains(id) ?: false
|
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
|
||||||
private var instance: LibraryUpdateService? = null
|
val savedMangasList = intent.getLongArrayExtra(KEY_MANGAS)?.asList()
|
||||||
|
|
||||||
/**
|
val mangaList = (if (savedMangasList != null) {
|
||||||
* Key that defines what should be updated.
|
val mangas = db.getLibraryMangas().executeAsBlocking().filter {
|
||||||
*/
|
it.id in savedMangasList
|
||||||
const val KEY_TARGET = "target"
|
}.distinctBy { it.id }
|
||||||
|
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
||||||
|
if (categoryId > -1) categoryIds.add(categoryId)
|
||||||
|
mangas
|
||||||
|
} else {
|
||||||
|
getMangaToUpdate(intent, target)
|
||||||
|
}).sortedWith(rankingScheme[selectedScheme])
|
||||||
|
// Update favorite manga. Destroy service when completed or in case of an error.
|
||||||
|
launchTarget(target, mangaList, startId)
|
||||||
|
return START_REDELIVER_INTENT
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key for list of manga to be updated. (For dynamic categories)
|
* Method called when the service is created. It injects dagger dependencies and acquire
|
||||||
*/
|
* the wake lock.
|
||||||
const val KEY_MANGAS = "mangas"
|
*/
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
notifier = LibraryUpdateNotifier(this)
|
||||||
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||||
|
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
|
||||||
|
)
|
||||||
|
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30))
|
||||||
|
startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the status of the service.
|
* Method called when the service is destroyed. It cancels jobs and releases the wake lock.
|
||||||
*
|
*/
|
||||||
* @return true if the service is running, false otherwise.
|
override fun onDestroy() {
|
||||||
*/
|
job?.cancel()
|
||||||
fun isRunning(): Boolean {
|
if (instance == this)
|
||||||
return instance != null
|
instance = null
|
||||||
|
if (wakeLock.isHeld) {
|
||||||
|
wakeLock.release()
|
||||||
}
|
}
|
||||||
|
listener?.onUpdateManga(LibraryManga())
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> {
|
||||||
* Starts the service. It will be started only if there isn't another instance already
|
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
||||||
* running.
|
return getMangaToUpdate(categoryId, target)
|
||||||
*
|
}
|
||||||
* @param context the application context.
|
|
||||||
* @param category a specific category to update, or null for global update.
|
/**
|
||||||
* @param target defines what should be updated.
|
* Returns the list of manga to be updated.
|
||||||
*/
|
*
|
||||||
fun start(
|
* @param intent the update intent.
|
||||||
context: Context,
|
* @param target the target to update.
|
||||||
category: Category? = null,
|
* @return a list of manga to update
|
||||||
target: Target = Target.CHAPTERS,
|
*/
|
||||||
mangaToUse: List<LibraryManga>? = null
|
private fun getMangaToUpdate(categoryId: Int, target: Target): List<LibraryManga> {
|
||||||
) {
|
var listToUpdate = if (categoryId != -1) {
|
||||||
if (!isRunning()) {
|
categoryIds.add(categoryId)
|
||||||
val intent = Intent(context, LibraryUpdateService::class.java).apply {
|
db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId }
|
||||||
putExtra(KEY_TARGET, target)
|
} else {
|
||||||
category?.id?.let { id ->
|
val categoriesToUpdate =
|
||||||
putExtra(KEY_CATEGORY, id)
|
preferences.libraryUpdateCategories().getOrDefault().map(String::toInt)
|
||||||
if (mangaToUse != null) putExtra(
|
if (categoriesToUpdate.isNotEmpty()) {
|
||||||
KEY_MANGAS,
|
categoryIds.addAll(categoriesToUpdate)
|
||||||
mangaToUse.mapNotNull { it.id }.toLongArray()
|
db.getLibraryMangas().executeAsBlocking()
|
||||||
)
|
.filter { it.category in categoriesToUpdate }.distinctBy { it.id }
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
||||||
context.startService(intent)
|
|
||||||
} else {
|
|
||||||
context.startForegroundService(intent)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (target == Target.CHAPTERS) category?.id?.let {
|
categoryIds.addAll(db.getCategories().executeAsBlocking().mapNotNull { it.id } + 0)
|
||||||
if (mangaToUse != null) instance?.addMangaToQueue(it, mangaToUse)
|
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
|
||||||
else instance?.addCategory(it)
|
}
|
||||||
}
|
}
|
||||||
|
if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
|
||||||
|
listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED }
|
||||||
|
}
|
||||||
|
|
||||||
|
return listToUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchTarget(target: Target, mangaToAdd: List<LibraryManga>, startId: Int) {
|
||||||
|
val handler = CoroutineExceptionHandler { _, exception ->
|
||||||
|
Timber.e(exception)
|
||||||
|
stopSelf(startId)
|
||||||
|
}
|
||||||
|
if (target == Target.CHAPTERS) {
|
||||||
|
listener?.onUpdateManga(LibraryManga())
|
||||||
|
}
|
||||||
|
job = GlobalScope.launch(handler) {
|
||||||
|
when (target) {
|
||||||
|
Target.CHAPTERS -> updateChaptersJob(mangaToAdd)
|
||||||
|
Target.DETAILS -> updateDetails(mangaToAdd)
|
||||||
|
else -> updateTrackings(mangaToAdd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
job?.invokeOnCompletion { stopSelf(startId) }
|
||||||
* Stops the service.
|
|
||||||
*
|
|
||||||
* @param context the application context.
|
|
||||||
*/
|
|
||||||
fun stop(context: Context) {
|
|
||||||
instance?.job?.cancel()
|
|
||||||
GlobalScope.launch {
|
|
||||||
instance?.jobCount?.set(0)
|
|
||||||
instance?.finishUpdates()
|
|
||||||
}
|
|
||||||
context.stopService(Intent(context, LibraryUpdateService::class.java))
|
|
||||||
}
|
|
||||||
|
|
||||||
private var listener: LibraryServiceListener? = null
|
|
||||||
|
|
||||||
fun setListener(listener: LibraryServiceListener) {
|
|
||||||
this.listener = listener
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeListener(listener: LibraryServiceListener) {
|
|
||||||
if (this.listener == listener) this.listener = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addManga(mangaToAdd: List<LibraryManga>) {
|
private fun addManga(mangaToAdd: List<LibraryManga>) {
|
||||||
@ -259,69 +281,6 @@ class LibraryUpdateService(
|
|||||||
addManga(mangas)
|
addManga(mangas)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of manga to be updated.
|
|
||||||
*
|
|
||||||
* @param intent the update intent.
|
|
||||||
* @param target the target to update.
|
|
||||||
* @return a list of manga to update
|
|
||||||
*/
|
|
||||||
private fun getMangaToUpdate(categoryId: Int, target: Target): List<LibraryManga> {
|
|
||||||
var listToUpdate = if (categoryId != -1) {
|
|
||||||
categoryIds.add(categoryId)
|
|
||||||
db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId }
|
|
||||||
} else {
|
|
||||||
val categoriesToUpdate =
|
|
||||||
preferences.libraryUpdateCategories().getOrDefault().map(String::toInt)
|
|
||||||
if (categoriesToUpdate.isNotEmpty()) {
|
|
||||||
categoryIds.addAll(categoriesToUpdate)
|
|
||||||
db.getLibraryMangas().executeAsBlocking()
|
|
||||||
.filter { it.category in categoriesToUpdate }.distinctBy { it.id }
|
|
||||||
} else {
|
|
||||||
categoryIds.addAll(db.getCategories().executeAsBlocking().mapNotNull { it.id } + 0)
|
|
||||||
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
|
|
||||||
listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED }
|
|
||||||
}
|
|
||||||
|
|
||||||
return listToUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> {
|
|
||||||
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
|
||||||
return getMangaToUpdate(categoryId, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called when the service is created. It injects dagger dependencies and acquire
|
|
||||||
* the wake lock.
|
|
||||||
*/
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
notifier = LibraryUpdateNotifier(this)
|
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
|
|
||||||
)
|
|
||||||
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30))
|
|
||||||
startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called when the service is destroyed. It cancels jobs and releases the wake lock.
|
|
||||||
*/
|
|
||||||
override fun onDestroy() {
|
|
||||||
job?.cancel()
|
|
||||||
if (instance == this)
|
|
||||||
instance = null
|
|
||||||
if (wakeLock.isHeld) {
|
|
||||||
wakeLock.release()
|
|
||||||
}
|
|
||||||
listener?.onUpdateManga(LibraryManga())
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method needs to be implemented, but it's not used/needed.
|
* This method needs to be implemented, but it's not used/needed.
|
||||||
*/
|
*/
|
||||||
@ -329,57 +288,6 @@ class LibraryUpdateService(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called when the service receives an intent.
|
|
||||||
*
|
|
||||||
* @param intent the start intent from.
|
|
||||||
* @param flags the flags of the command.
|
|
||||||
* @param startId the start id of this command.
|
|
||||||
* @return the start value of the command.
|
|
||||||
*/
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
||||||
if (intent == null) return START_NOT_STICKY
|
|
||||||
val target = intent.getSerializableExtra(KEY_TARGET) as? Target ?: return START_NOT_STICKY
|
|
||||||
|
|
||||||
instance = this
|
|
||||||
|
|
||||||
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
|
|
||||||
val savedMangasList = intent.getLongArrayExtra(KEY_MANGAS)?.asList()
|
|
||||||
|
|
||||||
val mangaList = (if (savedMangasList != null) {
|
|
||||||
val mangas = db.getLibraryMangas().executeAsBlocking().filter {
|
|
||||||
it.id in savedMangasList
|
|
||||||
}.distinctBy { it.id }
|
|
||||||
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
|
||||||
if (categoryId > -1) categoryIds.add(categoryId)
|
|
||||||
mangas
|
|
||||||
} else {
|
|
||||||
getMangaToUpdate(intent, target)
|
|
||||||
}).sortedWith(rankingScheme[selectedScheme])
|
|
||||||
// Update favorite manga. Destroy service when completed or in case of an error.
|
|
||||||
launchTarget(target, mangaList, startId)
|
|
||||||
return START_REDELIVER_INTENT
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchTarget(target: Target, mangaToAdd: List<LibraryManga>, startId: Int) {
|
|
||||||
val handler = CoroutineExceptionHandler { _, exception ->
|
|
||||||
Timber.e(exception)
|
|
||||||
stopSelf(startId)
|
|
||||||
}
|
|
||||||
if (target == Target.CHAPTERS) {
|
|
||||||
listener?.onUpdateManga(LibraryManga())
|
|
||||||
}
|
|
||||||
job = GlobalScope.launch(handler) {
|
|
||||||
when (target) {
|
|
||||||
Target.CHAPTERS -> updateChaptersJob(mangaToAdd)
|
|
||||||
Target.DETAILS -> updateDetails(mangaToAdd)
|
|
||||||
else -> updateTrackings(mangaToAdd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
job?.invokeOnCompletion { stopSelf(startId) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateChaptersJob(mangaToAdd: List<LibraryManga>) {
|
private suspend fun updateChaptersJob(mangaToAdd: List<LibraryManga>) {
|
||||||
// Initialize the variables holding the progress of the updates.
|
// Initialize the variables holding the progress of the updates.
|
||||||
|
|
||||||
@ -614,6 +522,98 @@ class LibraryUpdateService(
|
|||||||
}
|
}
|
||||||
return File("")
|
return File("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for category to update.
|
||||||
|
*/
|
||||||
|
const val KEY_CATEGORY = "category"
|
||||||
|
|
||||||
|
fun categoryInQueue(id: Int?) = instance?.categoryIds?.contains(id) ?: false
|
||||||
|
private var instance: LibraryUpdateService? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key that defines what should be updated.
|
||||||
|
*/
|
||||||
|
const val KEY_TARGET = "target"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for list of manga to be updated. (For dynamic categories)
|
||||||
|
*/
|
||||||
|
const val KEY_MANGAS = "mangas"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the service.
|
||||||
|
*
|
||||||
|
* @return true if the service is running, false otherwise.
|
||||||
|
*/
|
||||||
|
fun isRunning(): Boolean {
|
||||||
|
return instance != null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the service. It will be started only if there isn't another instance already
|
||||||
|
* running.
|
||||||
|
*
|
||||||
|
* @param context the application context.
|
||||||
|
* @param category a specific category to update, or null for global update.
|
||||||
|
* @param target defines what should be updated.
|
||||||
|
*/
|
||||||
|
fun start(
|
||||||
|
context: Context,
|
||||||
|
category: Category? = null,
|
||||||
|
target: Target = Target.CHAPTERS,
|
||||||
|
mangaToUse: List<LibraryManga>? = null
|
||||||
|
) {
|
||||||
|
if (!isRunning()) {
|
||||||
|
val intent = Intent(context, LibraryUpdateService::class.java).apply {
|
||||||
|
putExtra(KEY_TARGET, target)
|
||||||
|
category?.id?.let { id ->
|
||||||
|
putExtra(KEY_CATEGORY, id)
|
||||||
|
if (mangaToUse != null) putExtra(
|
||||||
|
KEY_MANGAS,
|
||||||
|
mangaToUse.mapNotNull { it.id }.toLongArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
context.startService(intent)
|
||||||
|
} else {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (target == Target.CHAPTERS) category?.id?.let {
|
||||||
|
if (mangaToUse != null) instance?.addMangaToQueue(it, mangaToUse)
|
||||||
|
else instance?.addCategory(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the service.
|
||||||
|
*
|
||||||
|
* @param context the application context.
|
||||||
|
*/
|
||||||
|
fun stop(context: Context) {
|
||||||
|
instance?.job?.cancel()
|
||||||
|
GlobalScope.launch {
|
||||||
|
instance?.jobCount?.set(0)
|
||||||
|
instance?.finishUpdates()
|
||||||
|
}
|
||||||
|
context.stopService(Intent(context, LibraryUpdateService::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
private var listener: LibraryServiceListener? = null
|
||||||
|
|
||||||
|
fun setListener(listener: LibraryServiceListener) {
|
||||||
|
this.listener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeListener(listener: LibraryServiceListener) {
|
||||||
|
if (this.listener == listener) this.listener = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LibraryServiceListener {
|
interface LibraryServiceListener {
|
||||||
|
Loading…
Reference in New Issue
Block a user