Update Tracking Backend (#1457)

* Update Tracking Library

* Update Bangumi

* Update Anilist

* Update MangaUpdates

* Update MAL

* Add private to bind track

* Use null

* Remove old nullable

* Remove custom implementation of supportsTrackDeletion

* Add private to updateTrack

* Some descriptions

* Another description
This commit is contained in:
Mitchell Syer
2025-06-22 10:38:22 -04:00
committed by GitHub
parent 972137c035
commit abea85d831
76 changed files with 1496 additions and 940 deletions

View File

@@ -22,7 +22,9 @@ import suwayomi.tachidesk.graphql.types.TrackStatusType
import suwayomi.tachidesk.graphql.types.TrackerType
import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager
import suwayomi.tachidesk.manga.impl.track.tracker.model.toTrack
import suwayomi.tachidesk.manga.impl.track.tracker.model.toTrackSearch
import suwayomi.tachidesk.manga.model.table.TrackRecordTable
import suwayomi.tachidesk.manga.model.table.TrackSearchTable
import suwayomi.tachidesk.server.JavalinSetup.future
class TrackerDataLoader : KotlinDataLoader<Int, TrackerType> {
@@ -116,7 +118,30 @@ class DisplayScoreForTrackRecordDataLoader : KotlinDataLoader<Int, String> {
.toList()
.map { it.toTrack() }
.associateBy { it.id!! }
.mapValues { TrackerManager.getTracker(it.value.sync_id)?.displayScore(it.value) }
.mapValues { TrackerManager.getTracker(it.value.tracker_id)?.displayScore(it.value) }
ids.map { trackRecords[it] }
}
}
}
}
class DisplayScoreForTrackSearchDataLoader : KotlinDataLoader<Int, String> {
override val dataLoaderName = "DisplayScoreForTrackRecordDataLoader"
override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader<Int, String> =
DataLoaderFactory.newDataLoader<Int, String> { ids ->
future {
transaction {
addLogger(Slf4jSqlDebugLogger)
val trackRecords =
TrackSearchTable
.selectAll()
.where { TrackSearchTable.id inList ids }
.toList()
.map { it.toTrackSearch() }
.associateBy { it.id!! }
.mapValues { TrackerManager.getTracker(it.value.tracker_id)?.displayScore(it.value) }
ids.map { trackRecords[it] }
}

View File

@@ -108,6 +108,8 @@ class TrackMutation {
val mangaId: Int,
val trackerId: Int,
val remoteId: Long,
@GraphQLDescription("This will only work if the tracker of the track record supports private tracking")
val private: Boolean? = null,
)
data class BindTrackPayload(
@@ -116,13 +118,14 @@ class TrackMutation {
)
fun bindTrack(input: BindTrackInput): CompletableFuture<BindTrackPayload> {
val (clientMutationId, mangaId, trackerId, remoteId) = input
val (clientMutationId, mangaId, trackerId, remoteId, private) = input
return future {
Track.bind(
mangaId,
trackerId,
remoteId,
private ?: false,
)
val trackRecord =
transaction {
@@ -238,8 +241,12 @@ class TrackMutation {
val status: Int? = null,
val lastChapterRead: Double? = null,
val scoreString: String? = null,
@GraphQLDescription("This will only work if the tracker of the track record supports reading dates")
val startDate: Long? = null,
@GraphQLDescription("This will only work if the tracker of the track record supports reading dates")
val finishDate: Long? = null,
@GraphQLDescription("This will only work if the tracker of the track record supports private tracking")
val private: Boolean? = null,
@GraphQLDeprecated("Replaced with \"unbindTrack\" mutation", replaceWith = ReplaceWith("unbindTrack"))
val unbind: Boolean? = null,
)
@@ -260,6 +267,7 @@ class TrackMutation {
input.startDate,
input.finishDate,
input.unbind,
input.private,
),
)

View File

@@ -17,6 +17,7 @@ import suwayomi.tachidesk.graphql.dataLoaders.ChapterDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ChapterMetaDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ChaptersForMangaDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.DisplayScoreForTrackRecordDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.DisplayScoreForTrackSearchDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.DownloadedChapterCountForMangaDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ExtensionDataLoader
import suwayomi.tachidesk.graphql.dataLoaders.ExtensionForSourceDataLoader
@@ -83,6 +84,7 @@ class TachideskDataLoaderRegistryFactory {
TrackerTokenExpiredDataLoader(),
TrackRecordsForMangaIdDataLoader(),
DisplayScoreForTrackRecordDataLoader(),
DisplayScoreForTrackSearchDataLoader(),
TrackRecordsForTrackerIdDataLoader(),
TrackRecordDataLoader(),
)

View File

@@ -9,6 +9,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
import suwayomi.tachidesk.manga.impl.track.Track
import suwayomi.tachidesk.manga.impl.track.tracker.DeletableTracker
import suwayomi.tachidesk.manga.impl.track.tracker.Tracker
import suwayomi.tachidesk.manga.model.table.TrackRecordTable
import suwayomi.tachidesk.manga.model.table.TrackSearchTable
@@ -20,7 +21,9 @@ class TrackerType(
val icon: String,
val isLoggedIn: Boolean,
val authUrl: String?,
val supportsTrackDeletion: Boolean?,
val supportsTrackDeletion: Boolean,
val supportsReadingDates: Boolean,
val supportsPrivateTracking: Boolean,
) : Node {
constructor(tracker: Tracker) : this(
tracker.isLoggedIn,
@@ -37,7 +40,9 @@ class TrackerType(
} else {
tracker.authUrl()
},
tracker.supportsTrackDeletion,
tracker is DeletableTracker,
tracker.supportsReadingDates,
tracker.supportsPrivateTracking,
)
fun statuses(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<TrackStatusType>> =
@@ -72,6 +77,7 @@ class TrackRecordType(
val remoteUrl: String,
val startDate: Long,
val finishDate: Long,
val private: Boolean,
) : Node {
constructor(row: ResultRow) : this(
row[TrackRecordTable.id].value,
@@ -87,6 +93,7 @@ class TrackRecordType(
row[TrackRecordTable.remoteUrl],
row[TrackRecordTable.startDate],
row[TrackRecordTable.finishDate],
row[TrackRecordTable.private],
)
fun displayScore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<String> =
@@ -103,7 +110,9 @@ class TrackSearchType(
val id: Int,
val trackerId: Int,
val remoteId: Long,
val libraryId: Long?,
val title: String,
val lastChapterRead: Double,
val totalChapters: Int,
val trackingUrl: String,
val coverUrl: String,
@@ -111,12 +120,19 @@ class TrackSearchType(
val publishingStatus: String,
val publishingType: String,
val startDate: String,
val status: Int,
val score: Double,
val startedReadingDate: Long,
val finishedReadingDate: Long,
val private: Boolean,
) {
constructor(row: ResultRow) : this(
row[TrackSearchTable.id].value,
row[TrackSearchTable.trackerId],
row[TrackSearchTable.remoteId],
row[TrackSearchTable.libraryId],
row[TrackSearchTable.title],
row[TrackSearchTable.lastChapterRead],
row[TrackSearchTable.totalChapters],
row[TrackSearchTable.trackingUrl],
row[TrackSearchTable.coverUrl],
@@ -124,10 +140,18 @@ class TrackSearchType(
row[TrackSearchTable.publishingStatus],
row[TrackSearchTable.publishingType],
row[TrackSearchTable.startDate],
row[TrackSearchTable.status],
row[TrackSearchTable.score],
row[TrackSearchTable.startedReadingDate],
row[TrackSearchTable.finishedReadingDate],
row[TrackSearchTable.private],
)
fun tracker(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackerType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", trackerId)
fun displayScore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<String> =
dataFetchingEnvironment.getValueFromDataLoader<Int, String>("DisplayScoreForTrackSearchDataLoader", id)
}
data class TrackRecordNodeList(