Fix multiple issues with the E-Hentai updater

This commit is contained in:
Jobobby04 2024-11-07 22:21:02 -05:00
parent d88f570f65
commit f0b621dfe5
6 changed files with 158 additions and 7 deletions

View File

@ -31,7 +31,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy" applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 70 versionCode = 71
versionName = "1.11.0" versionName = "1.11.0"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")

View File

@ -30,6 +30,9 @@ object Notifications {
const val ID_LIBRARY_SIZE_WARNING = -103 const val ID_LIBRARY_SIZE_WARNING = -103
const val CHANNEL_LIBRARY_ERROR = "library_errors_channel" const val CHANNEL_LIBRARY_ERROR = "library_errors_channel"
const val ID_LIBRARY_ERROR = -102 const val ID_LIBRARY_ERROR = -102
const val CHANNEL_LIBRARY_EHENTAI = "library_ehentai_channel"
const val ID_EHENTAI_PROGRESS = -199
const val ID_EHENTAI_ERROR = -198
/** /**
* Notification channel and ids used by the downloader. * Notification channel and ids used by the downloader.
@ -166,6 +169,13 @@ object Notifications {
setGroup(GROUP_APK_UPDATES) setGroup(GROUP_APK_UPDATES)
setName(context.stringResource(MR.strings.channel_ext_updates)) setName(context.stringResource(MR.strings.channel_ext_updates))
}, },
// SY -->
buildNotificationChannel(CHANNEL_LIBRARY_EHENTAI, IMPORTANCE_LOW) {
setName("EHentai")
setGroup(GROUP_LIBRARY)
setShowBadge(false)
},
//SY <--
), ),
) )
} }

View File

@ -0,0 +1,109 @@
package exh.eh
import android.content.Context
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.core.app.NotificationCompat
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notify
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import uy.kohesive.injekt.injectLazy
import java.math.RoundingMode
import java.text.NumberFormat
class EHentaiUpdateNotifier(private val context: Context) {
private val securityPreferences: SecurityPreferences by injectLazy()
private val percentFormatter = NumberFormat.getPercentInstance().apply {
roundingMode = RoundingMode.DOWN
maximumFractionDigits = 0
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
val progressNotificationBuilder by lazy {
context.notificationBuilder(Notifications.CHANNEL_LIBRARY_EHENTAI) {
setContentTitle(context.stringResource(MR.strings.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
}
}
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that are being updated.
* @param current the current progress.
* @param total the total progress.
*/
fun showProgressNotification(manga: Manga, current: Int, total: Int) {
progressNotificationBuilder
.setContentTitle(
context.stringResource(
MR.strings.notification_updating_progress,
percentFormatter.format(current.toFloat() / total),
),
)
if (!securityPreferences.hideNotificationContent().get()) {
val updatingText = manga.title.chop(40)
progressNotificationBuilder.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
}
context.notify(
Notifications.ID_EHENTAI_PROGRESS,
progressNotificationBuilder
.setProgress(total, current, false)
.build(),
)
}
/**
* Shows notification containing update entries that failed with action to open full log.
*
* @param failed Number of entries that failed to update.
* @param uri Uri for error log file containing all titles that failed.
*/
fun showUpdateErrorNotification(failed: Int, uri: Uri) {
if (failed == 0) {
return
}
context.notify(
Notifications.ID_EHENTAI_ERROR,
Notifications.CHANNEL_LIBRARY_EHENTAI,
) {
setContentTitle(context.stringResource(MR.strings.notification_update_error, failed))
setContentText(context.stringResource(MR.strings.action_show_errors))
setSmallIcon(R.drawable.ic_tachi)
setContentIntent(NotificationReceiver.openErrorLogPendingActivity(context, uri))
}
}
/**
* Cancels the progress notification.
*/
fun cancelProgressNotification() {
context.cancelNotification(Notifications.ID_EHENTAI_PROGRESS)
}
}

View File

@ -1,11 +1,15 @@
package exh.eh package exh.eh
import android.content.Context import android.content.Context
import android.content.pm.ServiceInfo
import android.os.Build
import androidx.work.Constraints import androidx.work.Constraints
import androidx.work.CoroutineWorker import androidx.work.CoroutineWorker
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ForegroundInfo
import androidx.work.NetworkType import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.PeriodicWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.elvishew.xlog.Logger import com.elvishew.xlog.Logger
@ -14,8 +18,10 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toSManga import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.system.isConnectedToWifi import eu.kanade.tachiyomi.util.system.isConnectedToWifi
import eu.kanade.tachiyomi.util.system.setForegroundSafely
import eu.kanade.tachiyomi.util.system.workManager import eu.kanade.tachiyomi.util.system.workManager
import exh.debug.DebugToggles import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
@ -48,7 +54,7 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val preferences: UnsortedPreferences by injectLazy() private val preferences: UnsortedPreferences by injectLazy()
private val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
private val updateHelper: EHentaiUpdateHelper by injectLazy() private val updateHelper: EHentaiUpdateHelper by injectLazy()
private val logger: Logger = xLog() private val logger: Logger by lazy { xLog() }
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy() private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy()
private val getChaptersByMangaId: GetChaptersByMangaId by injectLazy() private val getChaptersByMangaId: GetChaptersByMangaId by injectLazy()
@ -56,22 +62,38 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val insertFlatMetadata: InsertFlatMetadata by injectLazy() private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
private val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy() private val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
private val updateNotifier by lazy { LibraryUpdateNotifier(context) } private val updateNotifier by lazy { EHentaiUpdateNotifier(context) }
private val libraryUpdateNotifier by lazy { LibraryUpdateNotifier(context) }
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
return try { return try {
if (requiresWifiConnection(preferences) && !context.isConnectedToWifi()) { if (requiresWifiConnection(preferences) && !context.isConnectedToWifi()) {
Result.success() // retry again later Result.success() // retry again later
} else { } else {
setForegroundSafely()
startUpdating() startUpdating()
logger.d("Update job completed!") logger.d("Update job completed!")
Result.success() Result.success()
} }
} catch (e: Exception) { } catch (e: Exception) {
Result.success() // retry again later Result.success() // retry again later
} finally {
updateNotifier.cancelProgressNotification()
} }
} }
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
Notifications.ID_EHENTAI_PROGRESS,
updateNotifier.progressNotificationBuilder.build(),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
} else {
0
},
)
}
private suspend fun startUpdating() { private suspend fun startUpdating() {
logger.d("Update job started!") logger.d("Update job started!")
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
@ -138,6 +160,11 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
} }
val (new, chapters) = try { val (new, chapters) = try {
updateNotifier.showProgressNotification(
manga,
updatedThisIteration + failuresThisIteration,
mangaMetaToUpdateThisIter.size,
)
updateEntryAndGetChapters(manga) updateEntryAndGetChapters(manga)
} catch (e: GalleryNotUpdatedException) { } catch (e: GalleryNotUpdatedException) {
if (e.network) { if (e.network) {
@ -193,8 +220,9 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
), ),
) )
updateNotifier.cancelProgressNotification()
if (updatedManga.isNotEmpty()) { if (updatedManga.isNotEmpty()) {
updateNotifier.showUpdateNotifications(updatedManga) libraryUpdateNotifier.showUpdateNotifications(updatedManga)
} }
} }
} }
@ -237,7 +265,11 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val logger by lazy { XLog.tag("EHUpdaterScheduler") } private val logger by lazy { XLog.tag("EHUpdaterScheduler") }
fun launchBackgroundTest(context: Context) { fun launchBackgroundTest(context: Context) {
context.workManager.enqueue(OneTimeWorkRequestBuilder<EHentaiUpdateWorker>().build()) context.workManager.enqueue(
OneTimeWorkRequestBuilder<EHentaiUpdateWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build(),
)
} }
fun scheduleBackground(context: Context, prefInterval: Int? = null, prefRestrictions: Set<String>? = null) { fun scheduleBackground(context: Context, prefInterval: Int? = null, prefRestrictions: Set<String>? = null) {

View File

@ -445,7 +445,7 @@ class FavoritesSyncHelper(val context: Context) {
} }
} }
sealed class FavoritesSyncStatus() { sealed class FavoritesSyncStatus {
abstract val message: String abstract val message: String
data class Error(override val message: String) : FavoritesSyncStatus() data class Error(override val message: String) : FavoritesSyncStatus()

View File

@ -24,6 +24,6 @@ enum class MangaDexRelation(val res: StringResource, val mdString: String?) {
; ;
companion object { companion object {
fun fromDex(mdString: String) = values().find { it.mdString == mdString } fun fromDex(mdString: String) = entries.find { it.mdString == mdString }
} }
} }