Refactor some tracking-related logic
This commit is contained in:
parent
7644d7c31e
commit
98d6ce2eaf
28 changed files with 104 additions and 151 deletions
|
@ -1,8 +1,8 @@
|
|||
package eu.kanade.domain
|
||||
|
||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.download.interactor.DeleteDownload
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionSources
|
||||
|
@ -127,7 +127,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { SetReadStatus(get(), get(), get(), get()) }
|
||||
addFactory { ShouldUpdateDbChapter() }
|
||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get(), get()) }
|
||||
addFactory { SyncChapterProgressWithTrack(get(), get(), get()) }
|
||||
|
||||
addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
|
||||
addFactory { GetHistory(get()) }
|
||||
|
|
|
@ -11,7 +11,7 @@ import tachiyomi.domain.chapter.model.toChapterUpdate
|
|||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.domain.track.model.Track
|
||||
|
||||
class SyncChaptersWithTrackServiceTwoWay(
|
||||
class SyncChapterProgressWithTrack(
|
||||
private val updateChapter: UpdateChapter,
|
||||
private val insertTrack: InsertTrack,
|
||||
private val getChapterByMangaId: GetChapterByMangaId,
|
|
@ -1,14 +1,13 @@
|
|||
package eu.kanade.domain.track.interactor
|
||||
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
|
||||
|
@ -16,28 +15,34 @@ class RefreshTracks(
|
|||
private val getTracks: GetTracks,
|
||||
private val trackManager: TrackManager,
|
||||
private val insertTrack: InsertTrack,
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay,
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaId: Long) {
|
||||
supervisorScope {
|
||||
getTracks.await(mangaId)
|
||||
/**
|
||||
* Fetches updated tracking data from all logged in trackers.
|
||||
*
|
||||
* @return Failed updates.
|
||||
*/
|
||||
suspend fun await(mangaId: Long): List<Pair<TrackService?, Throwable>> {
|
||||
return supervisorScope {
|
||||
return@supervisorScope getTracks.await(mangaId)
|
||||
.map { track ->
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLoggedIn) {
|
||||
try {
|
||||
return@async try {
|
||||
if (service?.isLoggedIn == true) {
|
||||
val updatedTrack = service.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, track, service)
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
syncChapterProgressWithTrack.await(mangaId, track, service)
|
||||
}
|
||||
null
|
||||
} catch (e: Throwable) {
|
||||
service to e
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ private fun ColumnScope.FilterPage(
|
|||
trackServices.map { service ->
|
||||
val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState()
|
||||
TriStateItem(
|
||||
label = stringResource(service.nameRes()),
|
||||
label = service.name,
|
||||
state = filterTracker,
|
||||
onClick = { screenModel.toggleTracker(service.id.toInt()) },
|
||||
)
|
||||
|
|
|
@ -114,9 +114,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
if (enhancedTrackers.second.isNotEmpty()) {
|
||||
val missingSourcesInfo = stringResource(
|
||||
R.string.enhanced_services_not_installed,
|
||||
enhancedTrackers.second
|
||||
.map { stringResource(it.nameRes()) }
|
||||
.joinToString(),
|
||||
enhancedTrackers.second.joinToString { it.name },
|
||||
)
|
||||
enhancedTrackerInfo += "\n\n$missingSourcesInfo"
|
||||
}
|
||||
|
@ -130,37 +128,37 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
title = stringResource(R.string.services),
|
||||
preferenceItems = listOf(
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.myAnimeList.nameRes()),
|
||||
title = trackManager.myAnimeList.name,
|
||||
service = trackManager.myAnimeList,
|
||||
login = { context.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.myAnimeList) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.aniList.nameRes()),
|
||||
title = trackManager.aniList.name,
|
||||
service = trackManager.aniList,
|
||||
login = { context.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.aniList) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.kitsu.nameRes()),
|
||||
title = trackManager.kitsu.name,
|
||||
service = trackManager.kitsu,
|
||||
login = { dialog = LoginDialog(trackManager.kitsu, R.string.email) },
|
||||
logout = { dialog = LogoutDialog(trackManager.kitsu) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.mangaUpdates.nameRes()),
|
||||
title = trackManager.mangaUpdates.name,
|
||||
service = trackManager.mangaUpdates,
|
||||
login = { dialog = LoginDialog(trackManager.mangaUpdates, R.string.username) },
|
||||
logout = { dialog = LogoutDialog(trackManager.mangaUpdates) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.shikimori.nameRes()),
|
||||
title = trackManager.shikimori.name,
|
||||
service = trackManager.shikimori,
|
||||
login = { context.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.shikimori) },
|
||||
),
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(trackManager.bangumi.nameRes()),
|
||||
title = trackManager.bangumi.name,
|
||||
service = trackManager.bangumi,
|
||||
login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
|
||||
logout = { dialog = LogoutDialog(trackManager.bangumi) },
|
||||
|
@ -173,7 +171,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
preferenceItems = enhancedTrackers.first
|
||||
.map { service ->
|
||||
Preference.PreferenceItem.TrackingPreference(
|
||||
title = stringResource(service.nameRes()),
|
||||
title = service.name,
|
||||
service = service,
|
||||
login = { (service as EnhancedTrackService).loginNoop() },
|
||||
logout = service::logout,
|
||||
|
@ -202,7 +200,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(R.string.login_title, stringResource(service.nameRes())),
|
||||
text = stringResource(R.string.login_title, service.name),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
IconButton(onClick = onDismissRequest) {
|
||||
|
@ -310,7 +308,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.logout_title, stringResource(service.nameRes())),
|
||||
text = stringResource(R.string.logout_title, service.name),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
|
|
@ -40,7 +40,7 @@ fun TrackingPreferenceWidget(
|
|||
) {
|
||||
TrackLogoIcon(service)
|
||||
Text(
|
||||
text = stringResource(service.nameRes()),
|
||||
text = service.name,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp),
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
|
@ -36,7 +35,7 @@ fun TrackLogoIcon(
|
|||
) {
|
||||
Image(
|
||||
painter = painterResource(service.getLogo()),
|
||||
contentDescription = stringResource(service.nameRes()),
|
||||
contentDescription = service.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class BackupFileValidator(
|
|||
val missingTrackers = trackers
|
||||
.mapNotNull { trackManager.getService(it.toLong()) }
|
||||
.filter { !it.isLoggedIn }
|
||||
.map { context.getString(it.nameRes()) }
|
||||
.map { it.name }
|
||||
.sorted()
|
||||
|
||||
return Results(missingSources, missingTrackers)
|
||||
|
|
|
@ -283,7 +283,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
}
|
||||
|
||||
if (libraryPreferences.autoUpdateTrackers().get()) {
|
||||
refreshTracks.await(manga.id)
|
||||
refreshTracks(manga.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,13 +409,20 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
|
||||
val manga = libraryManga.manga
|
||||
notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
|
||||
refreshTracks.await(manga.id)
|
||||
refreshTracks(manga.id)
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refreshTracks(mangaId: Long) {
|
||||
refreshTracks.await(mangaId).forEach { (_, e) ->
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingManga: CopyOnWriteArrayList<Manga>,
|
||||
completed: AtomicInteger,
|
||||
|
|
|
@ -30,7 +30,7 @@ class TrackManager(context: Context) {
|
|||
val kitsu = Kitsu(KITSU)
|
||||
val shikimori = Shikimori(SHIKIMORI)
|
||||
val bangumi = Bangumi(BANGUMI)
|
||||
val komga = Komga(context, KOMGA)
|
||||
val komga = Komga(KOMGA)
|
||||
val mangaUpdates = MangaUpdates(MANGA_UPDATES)
|
||||
val kavita = Kavita(context, KAVITA)
|
||||
val suwayomi = Suwayomi(SUWAYOMI)
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.annotation.CallSuper
|
|||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
|
@ -28,20 +28,16 @@ import uy.kohesive.injekt.injectLazy
|
|||
import java.time.ZoneOffset
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
abstract class TrackService(val id: Long) {
|
||||
abstract class TrackService(val id: Long, val name: String) {
|
||||
|
||||
val trackPreferences: TrackPreferences by injectLazy()
|
||||
val networkService: NetworkHelper by injectLazy()
|
||||
private val insertTrack: InsertTrack by injectLazy()
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay by injectLazy()
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy()
|
||||
|
||||
open val client: OkHttpClient
|
||||
get() = networkService.client
|
||||
|
||||
// Name of the manga sync service to display
|
||||
@StringRes
|
||||
abstract fun nameRes(): Int
|
||||
|
||||
// Application and remote support for reading dates
|
||||
open val supportsReadingDates: Boolean = false
|
||||
|
||||
|
@ -103,7 +99,7 @@ abstract class TrackService(val id: Long) {
|
|||
}
|
||||
|
||||
// TODO: move this to an interactor, and update all trackers based on common data
|
||||
suspend fun registerTracking(item: Track, mangaId: Long) {
|
||||
suspend fun register(item: Track, mangaId: Long) {
|
||||
item.manga_id = mangaId
|
||||
try {
|
||||
withIOContext {
|
||||
|
@ -147,7 +143,7 @@ abstract class TrackService(val id: Long) {
|
|||
}
|
||||
}
|
||||
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, track, this@TrackService)
|
||||
syncChapterProgressWithTrack.await(mangaId, track, this@TrackService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { Injekt.get<Application>().toast(e.message) }
|
||||
|
|
|
@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Anilist(id: Long) : TrackService(id), DeletableTrackService {
|
||||
class Anilist(id: Long) : TrackService(id, "AniList"), DeletableTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -49,9 +49,6 @@ class Anilist(id: Long) : TrackService(id), DeletableTrackService {
|
|||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_anilist
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_anilist
|
||||
|
||||
override fun getLogoColor() = Color.rgb(18, 25, 35)
|
||||
|
|
|
@ -10,7 +10,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Bangumi(id: Long) : TrackService(id) {
|
||||
class Bangumi(id: Long) : TrackService(id, "Bangumi") {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
|
@ -18,9 +18,6 @@ class Bangumi(id: Long) : TrackService(id) {
|
|||
|
||||
private val api by lazy { BangumiApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_bangumi
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import tachiyomi.domain.manga.model.Manga
|
|||
import java.security.MessageDigest
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Kavita(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService {
|
||||
class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita"), EnhancedTrackService {
|
||||
|
||||
companion object {
|
||||
const val UNREAD = 1
|
||||
|
@ -27,9 +27,6 @@ class Kavita(private val context: Context, id: Long) : TrackService(id), Enhance
|
|||
private val interceptor by lazy { KavitaInterceptor(this) }
|
||||
val api by lazy { KavitaApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_kavita
|
||||
|
||||
override fun getLogo(): Int = R.drawable.ic_tracker_kavita
|
||||
|
||||
override fun getLogoColor() = Color.rgb(74, 198, 148)
|
||||
|
|
|
@ -115,8 +115,8 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
}
|
||||
|
||||
private fun getLatestChapterRead(url: String): Float {
|
||||
val serieId = getIdFromUrl(url)
|
||||
val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$serieId"
|
||||
val seriesId = getIdFromUrl(url)
|
||||
val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$seriesId"
|
||||
try {
|
||||
with(json) {
|
||||
authClient.newCall(GET(requestUrl)).execute().use {
|
||||
|
@ -137,21 +137,21 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
|
||||
suspend fun getTrackSearch(url: String): TrackSearch = withIOContext {
|
||||
try {
|
||||
val serieDto: SeriesDto = with(json) {
|
||||
val seriesDto: SeriesDto = with(json) {
|
||||
authClient.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
|
||||
val track = serieDto.toTrack()
|
||||
val track = seriesDto.toTrack()
|
||||
track.apply {
|
||||
cover_url = serieDto.thumbnail_url.toString()
|
||||
cover_url = seriesDto.thumbnail_url.toString()
|
||||
tracking_url = url
|
||||
total_chapters = getTotalChapters(url)
|
||||
|
||||
title = serieDto.name
|
||||
status = when (serieDto.pagesRead) {
|
||||
serieDto.pages -> Kavita.COMPLETED
|
||||
title = seriesDto.name
|
||||
status = when (seriesDto.pagesRead) {
|
||||
seriesDto.pages -> Kavita.COMPLETED
|
||||
0 -> Kavita.UNREAD
|
||||
else -> Kavita.READING
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class Kitsu(id: Long) : TrackService(id), DeletableTrackService {
|
||||
class Kitsu(id: Long) : TrackService(id, "Kitsu"), DeletableTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -22,9 +22,6 @@ class Kitsu(id: Long) : TrackService(id), DeletableTrackService {
|
|||
const val PLAN_TO_READ = 5
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_kitsu
|
||||
|
||||
override val supportsReadingDates: Boolean = true
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.tachiyomi.data.track.komga
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -14,7 +13,7 @@ import okhttp3.OkHttpClient
|
|||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Komga(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService {
|
||||
class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService {
|
||||
|
||||
companion object {
|
||||
const val UNREAD = 1
|
||||
|
@ -29,9 +28,6 @@ class Komga(private val context: Context, id: Long) : TrackService(id), Enhanced
|
|||
|
||||
val api by lazy { KomgaApi(client) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_komga
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_komga
|
||||
|
||||
override fun getLogoColor() = Color.rgb(51, 37, 50)
|
||||
|
|
|
@ -17,7 +17,7 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.system.logcat
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
const val READLIST_API = "/api/v1/readlists"
|
||||
private const val READLIST_API = "/api/v1/readlists"
|
||||
|
||||
class KomgaApi(private val client: OkHttpClient) {
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
|
|||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
|
||||
class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService {
|
||||
class MangaUpdates(id: Long) : TrackService(id, "MangaUpdates"), DeletableTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING_LIST = 0
|
||||
|
@ -24,9 +24,6 @@ class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService {
|
|||
|
||||
private val api by lazy { MangaUpdatesApi(interceptor, client) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes(): Int = R.string.tracker_manga_updates
|
||||
|
||||
override fun getLogo(): Int = R.drawable.ic_manga_updates
|
||||
|
||||
override fun getLogoColor(): Int = Color.rgb(146, 160, 173)
|
||||
|
|
|
@ -11,7 +11,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService {
|
||||
class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), DeletableTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -30,9 +30,6 @@ class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService {
|
|||
private val interceptor by lazy { MyAnimeListInterceptor(this, getPassword()) }
|
||||
private val api by lazy { MyAnimeListApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_myanimelist
|
||||
|
||||
override val supportsReadingDates: Boolean = true
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_mal
|
||||
|
|
|
@ -11,7 +11,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Shikimori(id: Long) : TrackService(id), DeletableTrackService {
|
||||
class Shikimori(id: Long) : TrackService(id, "Shikimori"), DeletableTrackService {
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
|
@ -28,9 +28,6 @@ class Shikimori(id: Long) : TrackService(id), DeletableTrackService {
|
|||
|
||||
private val api by lazy { ShikimoriApi(client, interceptor) }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_shikimori
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun findLibManga(track: Track, user_id: String): Track? {
|
||||
suspend fun findLibManga(track: Track, userId: String): Track? {
|
||||
return withIOContext {
|
||||
val urlMangas = "$apiUrl/mangas".toUri().buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
|
@ -134,7 +134,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||
}
|
||||
|
||||
val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
|
||||
.appendQueryParameter("user_id", user_id)
|
||||
.appendQueryParameter("user_id", userId)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
|
|
|
@ -11,13 +11,10 @@ import eu.kanade.tachiyomi.source.Source
|
|||
import tachiyomi.domain.manga.model.Manga as DomainManga
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Suwayomi(id: Long) : TrackService(id), EnhancedTrackService {
|
||||
class Suwayomi(id: Long) : TrackService(id, "Suwayomi"), EnhancedTrackService {
|
||||
|
||||
val api by lazy { TachideskApi() }
|
||||
|
||||
@StringRes
|
||||
override fun nameRes() = R.string.tracker_suwayomi
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_suwayomi
|
||||
|
||||
override fun getLogoColor() = Color.rgb(255, 35, 35) // TODO
|
||||
|
|
|
@ -28,19 +28,19 @@ class TachideskApi {
|
|||
private val network: NetworkHelper by injectLazy()
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
val client: OkHttpClient =
|
||||
private val client: OkHttpClient =
|
||||
network.client.newBuilder()
|
||||
.dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing
|
||||
.build()
|
||||
|
||||
fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
|
||||
private fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
|
||||
if (basePassword.isNotEmpty() && baseLogin.isNotEmpty()) {
|
||||
val credentials = Credentials.basic(baseLogin, basePassword)
|
||||
add("Authorization", credentials)
|
||||
}
|
||||
}
|
||||
|
||||
val headers: Headers by lazy { headersBuilder().build() }
|
||||
private val headers: Headers by lazy { headersBuilder().build() }
|
||||
|
||||
private val baseUrl by lazy { getPrefBaseUrl() }
|
||||
private val baseLogin by lazy { getPrefBaseLogin() }
|
||||
|
@ -100,7 +100,7 @@ class TachideskApi {
|
|||
return getTrackSearch(track.tracking_url)
|
||||
}
|
||||
|
||||
val tachideskExtensionId by lazy {
|
||||
private val tachideskExtensionId by lazy {
|
||||
val key = "tachidesk/en/1"
|
||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
||||
|
@ -110,6 +110,10 @@ class TachideskApi {
|
|||
Injekt.get<Application>().getSharedPreferences("source_$tachideskExtensionId", 0x0000)
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
|
||||
private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
|
||||
private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
|
||||
|
||||
companion object {
|
||||
private const val ADDRESS_TITLE = "Server URL Address"
|
||||
private const val ADDRESS_DEFAULT = ""
|
||||
|
@ -118,8 +122,4 @@ class TachideskApi {
|
|||
private const val PASSWORD_TITLE = "Password (Basic Auth)"
|
||||
private const val PASSWORD_DEFAULT = ""
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
|
||||
private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
|
||||
private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel
|
|||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import eu.kanade.core.preference.asState
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDomainManga
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
|
@ -77,7 +77,7 @@ class BrowseSourceScreenModel(
|
|||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val insertTrack: InsertTrack = Injekt.get(),
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack = Injekt.get(),
|
||||
) : StateScreenModel<BrowseSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLoggedIn } }
|
||||
|
@ -297,7 +297,7 @@ class BrowseSourceScreenModel(
|
|||
(service as TrackService).bind(track)
|
||||
insertTrack.await(track.toDomainTrack()!!)
|
||||
|
||||
syncChaptersWithTrackServiceTwoWay.await(manga.id, track.toDomainTrack()!!, service)
|
||||
syncChapterProgressWithTrack.await(manga.id, track.toDomainTrack()!!, service)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" }
|
||||
|
|
|
@ -323,7 +323,7 @@ class MangaScreenModel(
|
|||
launchIO {
|
||||
try {
|
||||
service.match(manga)?.let { track ->
|
||||
(service as TrackService).registerTracking(track, mangaId)
|
||||
(service as TrackService).register(track, mangaId)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) {
|
||||
|
|
|
@ -39,9 +39,8 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
|
|||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.track.TrackChapterSelector
|
||||
import eu.kanade.presentation.track.TrackDateSelector
|
||||
|
@ -74,7 +73,6 @@ import tachiyomi.domain.manga.interactor.GetManga
|
|||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.domain.track.model.Track
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
@ -208,7 +206,7 @@ data class TrackInfoDialogHomeScreen(
|
|||
val manga = Injekt.get<GetManga>().await(mangaId) ?: return@launchNonCancellable
|
||||
try {
|
||||
val matchResult = item.service.match(manga) ?: throw Exception()
|
||||
item.service.registerTracking(matchResult, mangaId)
|
||||
item.service.register(matchResult, mangaId)
|
||||
} catch (e: Exception) {
|
||||
withUIContext { Injekt.get<Application>().toast(R.string.error_no_match) }
|
||||
}
|
||||
|
@ -216,38 +214,25 @@ data class TrackInfoDialogHomeScreen(
|
|||
}
|
||||
|
||||
private suspend fun refreshTrackers() {
|
||||
val insertTrack = Injekt.get<InsertTrack>()
|
||||
val syncChaptersWithTrackServiceTwoWay = Injekt.get<SyncChaptersWithTrackServiceTwoWay>()
|
||||
val refreshTracks = Injekt.get<RefreshTracks>()
|
||||
val context = Injekt.get<Application>()
|
||||
|
||||
try {
|
||||
val trackItems = getTracks.await(mangaId).mapToTrackItem()
|
||||
for (trackItem in trackItems) {
|
||||
try {
|
||||
val track = trackItem.track ?: continue
|
||||
val domainTrack = trackItem.service.refresh(track.toDbTrack()).toDomainTrack() ?: continue
|
||||
insertTrack.await(domainTrack)
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, domainTrack, trackItem.service)
|
||||
} catch (e: Exception) {
|
||||
logcat(
|
||||
LogPriority.ERROR,
|
||||
e,
|
||||
) { "Failed to refresh track data mangaId=$mangaId for service ${trackItem.service.id}" }
|
||||
withUIContext {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.track_error,
|
||||
context.getString(trackItem.service.nameRes()),
|
||||
e.message,
|
||||
),
|
||||
)
|
||||
}
|
||||
refreshTracks.await(mangaId)
|
||||
.filter { it.first != null }
|
||||
.forEach { (track, e) ->
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Failed to refresh track data mangaId=$mangaId for service ${track!!.id}"
|
||||
}
|
||||
withUIContext {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.track_error,
|
||||
track!!.name,
|
||||
e.message,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to refresh track data mangaId=$mangaId" }
|
||||
withUIContext { context.toast(e.message) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Track>.mapToTrackItem(): List<TrackItem> {
|
||||
|
@ -581,7 +566,7 @@ private data class TrackDateRemoverScreen(
|
|||
)
|
||||
},
|
||||
text = {
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
Text(
|
||||
text = if (start) {
|
||||
stringResource(R.string.track_remove_start_date_conf_text, serviceName)
|
||||
|
@ -618,7 +603,7 @@ private data class TrackDateRemoverScreen(
|
|||
private val start: Boolean,
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun removeDate() {
|
||||
coroutineScope.launchNonCancellable {
|
||||
|
@ -703,7 +688,7 @@ data class TrackServiceSearchScreen(
|
|||
}
|
||||
|
||||
fun registerTracking(item: TrackSearch) {
|
||||
coroutineScope.launchNonCancellable { service.registerTracking(item, mangaId) }
|
||||
coroutineScope.launchNonCancellable { service.register(item, mangaId) }
|
||||
}
|
||||
|
||||
fun updateSelection(selected: TrackSearch) {
|
||||
|
@ -734,7 +719,7 @@ private data class TrackServiceRemoveScreen(
|
|||
service = Injekt.get<TrackManager>().getService(serviceId)!!,
|
||||
)
|
||||
}
|
||||
val serviceName = stringResource(sm.getServiceNameRes())
|
||||
val serviceName = sm.getServiceName()
|
||||
var removeRemoteTrack by remember { mutableStateOf(false) }
|
||||
AlertDialogContent(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
|
||||
|
@ -799,7 +784,7 @@ private data class TrackServiceRemoveScreen(
|
|||
private val deleteTrack: DeleteTrack = Injekt.get(),
|
||||
) : ScreenModel {
|
||||
|
||||
fun getServiceNameRes() = service.nameRes()
|
||||
fun getServiceName() = service.name
|
||||
|
||||
fun isServiceDeletable() = service is DeletableTrackService
|
||||
|
||||
|
|
|
@ -697,15 +697,6 @@
|
|||
<string name="are_you_sure">Are you sure?</string>
|
||||
|
||||
<!-- Tracking Screen -->
|
||||
<string name="tracker_anilist" translatable="false">AniList</string>
|
||||
<string name="tracker_myanimelist" translatable="false">MyAnimeList</string>
|
||||
<string name="tracker_kitsu" translatable="false">Kitsu</string>
|
||||
<string name="tracker_komga" translatable="false">Komga</string>
|
||||
<string name="tracker_bangumi" translatable="false">Bangumi</string>
|
||||
<string name="tracker_shikimori" translatable="false">Shikimori</string>
|
||||
<string name="tracker_manga_updates" translatable="false">MangaUpdates</string>
|
||||
<string name="tracker_kavita" translatable="false">Kavita</string>
|
||||
<string name="tracker_suwayomi" translatable="false">Suwayomi</string>
|
||||
<string name="manga_tracking_tab">Tracking</string>
|
||||
<plurals name="num_trackers">
|
||||
<item quantity="one">%d tracker</item>
|
||||
|
|
Reference in a new issue