Refactor tracker

This commit is contained in:
Koitharu
2023-08-11 10:36:58 +03:00
parent fa0289eb27
commit 746eed698f
4 changed files with 43 additions and 31 deletions

View File

@@ -135,7 +135,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
get() = prefs.getEnumValue(KEY_ZOOM_MODE, ZoomMode.FIT_CENTER)
val trackSources: Set<String>
get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: setOf(TRACK_FAVOURITES)
var appPassword: String?
get() = prefs.getString(KEY_APP_PASSWORD, null)

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.core.util.ext
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.ActivityManager
@@ -13,6 +14,7 @@ import android.content.ContextWrapper
import android.content.OperationApplicationException
import android.content.SharedPreferences
import android.content.SyncResult
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.database.SQLException
import android.graphics.Color
@@ -28,6 +30,8 @@ import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.IntegerRes
import androidx.core.app.ActivityOptionsCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.os.LocaleListCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
@@ -220,3 +224,9 @@ inline fun Activity.catchingWebViewUnavailability(block: () -> Unit): Boolean {
}
}
}
fun Context.checkNotificationPermission(): Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
} else {
NotificationManagerCompat.from(this).areNotificationsEnabled()
}

View File

@@ -25,7 +25,7 @@ class Tracker @Inject constructor(
if (sources.isEmpty()) {
return emptyList()
}
val knownIds = HashSet<Manga>()
val knownManga = HashSet<Long>()
val result = ArrayList<TrackingItem>()
// Favourites
if (AppSettings.TRACK_FAVOURITES in sources) {
@@ -42,7 +42,7 @@ class Tracker @Inject constructor(
null
}
for (track in categoryTracks) {
if (knownIds.add(track.manga)) {
if (knownManga.add(track.manga.id)) {
result.add(TrackingItem(track, channelId))
}
}
@@ -58,7 +58,7 @@ class Tracker @Inject constructor(
null
}
for (track in historyTracks) {
if (knownIds.add(track.manga)) {
if (knownManga.add(track.manga.id)) {
result.add(TrackingItem(track, channelId))
}
}

View File

@@ -1,6 +1,5 @@
package org.koitharu.kotatsu.tracker.work
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.os.Build
@@ -34,11 +33,11 @@ import dagger.Reusable
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
@@ -49,6 +48,7 @@ import org.koitharu.kotatsu.core.logs.FileLogger
import org.koitharu.kotatsu.core.logs.TrackerLogger
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
import org.koitharu.kotatsu.core.util.ext.trySetForeground
import org.koitharu.kotatsu.details.ui.DetailsActivity
@@ -70,6 +70,7 @@ class TrackWorker @AssistedInject constructor(
private val tracker: Tracker,
@TrackerLogger private val logger: FileLogger,
) : CoroutineWorker(context, workerParams) {
private val notificationManager by lazy { NotificationManagerCompat.from(applicationContext) }
override suspend fun doWork(): Result {
@@ -121,35 +122,36 @@ class TrackWorker @AssistedInject constructor(
private suspend fun checkUpdatesAsync(tracks: List<TrackingItem>): List<MangaUpdates?> {
val semaphore = Semaphore(MAX_PARALLELISM)
return supervisorScope {
tracks.map { (track, channelId) ->
async {
return channelFlow {
for ((track, channelId) in tracks) {
launch {
semaphore.withPermit {
runCatchingCancellable {
tracker.fetchUpdates(track, commit = true)
}.onFailure { e ->
if (e is CloudFlareProtectedException) {
CaptchaNotifier(applicationContext).notify(e)
}
logger.log("checkUpdatesAsync", e)
}.onSuccess { updates ->
if (updates.isValid && updates.isNotEmpty()) {
showNotification(
manga = updates.manga,
channelId = channelId,
newChapters = updates.newChapters,
)
}
}.getOrNull()
send(
runCatchingCancellable {
tracker.fetchUpdates(track, commit = true)
}.onFailure { e ->
if (e is CloudFlareProtectedException) {
CaptchaNotifier(applicationContext).notify(e)
}
logger.log("checkUpdatesAsync", e)
}.onSuccess { updates ->
if (updates.isValid && updates.isNotEmpty()) {
showNotification(
manga = updates.manga,
channelId = channelId,
newChapters = updates.newChapters,
)
}
}.getOrNull(),
)
}
}
}.awaitAll()
}
}
}.toList(ArrayList(tracks.size))
}
@SuppressLint("MissingPermission")
private suspend fun showNotification(manga: Manga, channelId: String?, newChapters: List<MangaChapter>) {
if (newChapters.isEmpty() || channelId == null || !notificationManager.areNotificationsEnabled()) {
if (newChapters.isEmpty() || channelId == null || !applicationContext.checkNotificationPermission()) {
return
}
val id = manga.url.hashCode()