Downloader Queries and Mutations (#610)

* Add downloader GraphQL endpoints

* Fix names

* DeleteDownloadedChapter(s)

* DequeueChapterDownload(s)
This commit is contained in:
Mitchell Syer
2023-08-03 18:08:47 -04:00
committed by GitHub
parent c3fb08d634
commit cdb083ff48
7 changed files with 356 additions and 31 deletions

View File

@@ -0,0 +1,260 @@
package suwayomi.tachidesk.graphql.mutations
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.types.ChapterType
import suwayomi.tachidesk.graphql.types.DownloadStatus
import suwayomi.tachidesk.manga.impl.Chapter
import suwayomi.tachidesk.manga.impl.download.DownloadManager
import suwayomi.tachidesk.manga.impl.download.model.Status
import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds
class DownloadMutation {
data class DeleteDownloadedChaptersInput(
val clientMutationId: String? = null,
val ids: List<Int>
)
data class DeleteDownloadedChaptersPayload(
val clientMutationId: String?,
val chapters: List<ChapterType>
)
fun deleteDownloadedChapters(input: DeleteDownloadedChaptersInput): DeleteDownloadedChaptersPayload {
val (clientMutationId, chapters) = input
Chapter.deleteChapters(chapters)
return DeleteDownloadedChaptersPayload(
clientMutationId = clientMutationId,
chapters = transaction {
ChapterTable.select { ChapterTable.id inList chapters }
.map { ChapterType(it) }
}
)
}
data class DeleteDownloadedChapterInput(
val clientMutationId: String? = null,
val id: Int
)
data class DeleteDownloadedChapterPayload(
val clientMutationId: String?,
val chapters: ChapterType
)
fun deleteDownloadedChapter(input: DeleteDownloadedChapterInput): DeleteDownloadedChapterPayload {
val (clientMutationId, chapter) = input
Chapter.deleteChapters(listOf(chapter))
return DeleteDownloadedChapterPayload(
clientMutationId = clientMutationId,
chapters = transaction {
ChapterType(ChapterTable.select { ChapterTable.id eq chapter }.first())
}
)
}
data class EnqueueChapterDownloadsInput(
val clientMutationId: String? = null,
val ids: List<Int>
)
data class EnqueueChapterDownloadsPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun enqueueChapterDownloads(
input: EnqueueChapterDownloadsInput
): CompletableFuture<EnqueueChapterDownloadsPayload> {
val (clientMutationId, chapters) = input
DownloadManager.enqueue(DownloadManager.EnqueueInput(chapters))
return future {
EnqueueChapterDownloadsPayload(
clientMutationId = clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(DownloadManager.status.first { it.queue.any { it.chapter.id in chapters } })
}
)
}
}
data class EnqueueChapterDownloadInput(
val clientMutationId: String? = null,
val id: Int
)
data class EnqueueChapterDownloadPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun enqueueChapterDownload(
input: EnqueueChapterDownloadInput
): CompletableFuture<EnqueueChapterDownloadPayload> {
val (clientMutationId, chapter) = input
DownloadManager.enqueue(DownloadManager.EnqueueInput(listOf(chapter)))
return future {
EnqueueChapterDownloadPayload(
clientMutationId = clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(DownloadManager.status.first { it.queue.any { it.chapter.id == chapter } })
}
)
}
}
data class DequeueChapterDownloadsInput(
val clientMutationId: String? = null,
val ids: List<Int>
)
data class DequeueChapterDownloadsPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun dequeueChapterDownloads(
input: DequeueChapterDownloadsInput
): CompletableFuture<DequeueChapterDownloadsPayload> {
val (clientMutationId, chapters) = input
DownloadManager.dequeue(DownloadManager.EnqueueInput(chapters))
return future {
DequeueChapterDownloadsPayload(
clientMutationId = clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(DownloadManager.status.first { it.queue.none { it.chapter.id in chapters } })
}
)
}
}
data class DequeueChapterDownloadInput(
val clientMutationId: String? = null,
val id: Int
)
data class DequeueChapterDownloadPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun dequeueChapterDownload(
input: DequeueChapterDownloadInput
): CompletableFuture<DequeueChapterDownloadPayload> {
val (clientMutationId, chapter) = input
DownloadManager.dequeue(DownloadManager.EnqueueInput(listOf(chapter)))
return future {
DequeueChapterDownloadPayload(
clientMutationId = clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(DownloadManager.status.first { it.queue.none { it.chapter.id == chapter } })
}
)
}
}
data class StartDownloaderInput(
val clientMutationId: String? = null
)
data class StartDownloaderPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun startDownloader(input: StartDownloaderInput): CompletableFuture<StartDownloaderPayload> {
DownloadManager.start()
return future {
StartDownloaderPayload(
input.clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(
DownloadManager.status.first { it.status == Status.Started }
)
}
)
}
}
data class StopDownloaderInput(
val clientMutationId: String? = null
)
data class StopDownloaderPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun stopDownloader(input: StopDownloaderInput): CompletableFuture<StopDownloaderPayload> {
return future {
DownloadManager.stop()
StopDownloaderPayload(
input.clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(
DownloadManager.status.first { it.status == Status.Stopped }
)
}
)
}
}
data class ClearDownloaderInput(
val clientMutationId: String? = null
)
data class ClearDownloaderPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun clearDownloader(input: ClearDownloaderInput): CompletableFuture<ClearDownloaderPayload> {
return future {
DownloadManager.clear()
ClearDownloaderPayload(
input.clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(
DownloadManager.status.first { it.status == Status.Stopped && it.queue.isEmpty() }
)
}
)
}
}
data class ReorderChapterDownloadInput(
val clientMutationId: String? = null,
val chapterId: Int,
val to: Int
)
data class ReorderChapterDownloadPayload(
val clientMutationId: String?,
val downloadStatus: DownloadStatus
)
fun reorderChapterDownload(input: ReorderChapterDownloadInput): CompletableFuture<ReorderChapterDownloadPayload> {
val (clientMutationId, chapter, to) = input
DownloadManager.reorder(chapter, to)
return future {
ReorderChapterDownloadPayload(
clientMutationId,
downloadStatus = withTimeout(30.seconds) {
DownloadStatus(
DownloadManager.status.first { it.queue.indexOfFirst { it.chapter.id == chapter } <= to }
)
}
)
}
}
}