From 3f7824dab8003d13169f6970dc4ac18552f371c2 Mon Sep 17 00:00:00 2001 From: Talha Ahmed Date: Sun, 5 Jan 2025 11:33:39 +0500 Subject: [PATCH] Rest API to add downloads (#331) * feat: rest api to add silent downloads --- README.md | 1 + REST-API.yml | 100 ++++++++++++++++++ .../integration/IntegrationHandlerImp.kt | 46 +++++++- .../integration/ApiQueueModel.kt | 9 ++ .../integration/Integration.kt | 19 ++++ .../integration/IntegrationHandler.kt | 2 + .../integration/NewDownloadTask.kt | 11 ++ 7 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 REST-API.yml create mode 100644 integration/server/src/main/kotlin/com/abdownloadmanager/integration/ApiQueueModel.kt create mode 100644 integration/server/src/main/kotlin/com/abdownloadmanager/integration/NewDownloadTask.kt diff --git a/README.md b/README.md index 3f9657f..86a4ac7 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ follow these steps. 1. Clone the project 2. Install the [JBR](https://github.com/JetBrains/JetBrainsRuntime/releases) + 1. If you extract it to your home directory and don't want to modify global `JAVA_HOME` environment variable you can set `JAVA_HOME` to the extracted directory e.g. `export JAVA_HOME=~/jbrsdk_jcef-21.0.4-linux-x64-b620.4` for linux or `$env:JAVA_HOME="C:\path\to\jbr"` on Windows 3. cd into the project, open your terminal and execute the following commands 4. select which way you want to compile the app
diff --git a/REST-API.yml b/REST-API.yml new file mode 100644 index 0000000..8e4f980 --- /dev/null +++ b/REST-API.yml @@ -0,0 +1,100 @@ +openapi: 3.0.0 +info: + title: Download Service API + version: 1.0.0 + description: API for managing download tasks and queues. +servers: + - url: http://localhost:15151 + description: Default server running on port 15151 + +paths: + /add: + post: + summary: Add a new download source + requestBody: + description: Data for adding a download source + content: + application/json: + schema: + type: object + properties: + link: + type: string + description: The link to the download source + headers: + type: object + additionalProperties: + type: string + description: Optional headers for the request + downloadPage: + type: string + description: Optional download page URL + responses: + "200": + description: Successfully added the download + content: + plain/text: + schema: + type: string + description: OK on success + + /queues: + get: + summary: Get list of download queues + responses: + "200": + description: List of download queues + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + description: The unique ID of the queue + name: + type: string + description: The name of the queue + /start-headless-download: + post: + summary: Add a new download task + requestBody: + description: Data for adding a download task + content: + application/json: + schema: + type: object + properties: + downloadSource: + type: object + properties: + link: + type: string + description: The link to the download source + headers: + type: object + additionalProperties: + type: string + description: Optional headers for the request + downloadPage: + type: string + description: Optional download page URL + folder: + type: string + description: Optional folder to save the download (Unix style path) + name: + type: string + description: Optional name for the download task + queueId: + type: integer + description: Optional queue ID to associate the task with + responses: + "200": + description: Successfully added the download task + content: + plain/text: + schema: + type: string + description: OK on success diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/integration/IntegrationHandlerImp.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/integration/IntegrationHandlerImp.kt index 12f0e4d..3e59474 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/integration/IntegrationHandlerImp.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/integration/IntegrationHandlerImp.kt @@ -1,14 +1,24 @@ package com.abdownloadmanager.desktop.integration -import com.abdownloadmanager.integration.IntegrationHandler import com.abdownloadmanager.desktop.AppComponent -import ir.amirab.downloader.downloaditem.DownloadCredentials +import com.abdownloadmanager.desktop.repository.AppRepository +import com.abdownloadmanager.utils.DownloadSystem +import com.abdownloadmanager.integration.IntegrationHandler import com.abdownloadmanager.integration.NewDownloadInfoFromIntegration +import com.abdownloadmanager.integration.NewDownloadTask +import com.abdownloadmanager.integration.ApiQueueModel +import ir.amirab.downloader.downloaditem.DownloadCredentials +import ir.amirab.downloader.downloaditem.DownloadItem +import ir.amirab.downloader.queue.QueueManager +import ir.amirab.downloader.utils.OnDuplicateStrategy import org.koin.core.component.KoinComponent import org.koin.core.component.inject class IntegrationHandlerImp: IntegrationHandler,KoinComponent{ val appComponent by inject() + val downloadSystem by inject() + val queueManager by inject() + val appSettings by inject() override suspend fun addDownload(list: List) { appComponent.externalCredentialComingIntoApp(list.map { DownloadCredentials( @@ -18,4 +28,34 @@ class IntegrationHandlerImp: IntegrationHandler,KoinComponent{ ) }) } -} \ No newline at end of file + override fun listQueues(): List { + return queueManager.getAll().map { downloadQueue -> + val queueModel = downloadQueue.getQueueModel() + ApiQueueModel(id = queueModel.id, name = queueModel.name) + } + } + override suspend fun addDownloadTask(task: NewDownloadTask) { + val downloadItem = + DownloadItem( + link = task.downloadSource.link, + headers = task.downloadSource.headers, + downloadPage = task.downloadSource.downloadPage, + folder = task.folder ?: appSettings.saveLocation.value, + id = -1, + name = task.name ?: task.downloadSource.link.substringAfterLast("/"), + ) + val id = + downloadSystem.addDownload( + downloadItem = downloadItem, + onDuplicateStrategy = OnDuplicateStrategy.default(), + queueId = task.queueId, + categoryId = null + ) + if (task.queueId != null) { + val queue = queueManager.getQueue(task.queueId!!) + queue.start() + } else { + downloadSystem.manualResume(id) + } + } +} diff --git a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/ApiQueueModel.kt b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/ApiQueueModel.kt new file mode 100644 index 0000000..900cf1d --- /dev/null +++ b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/ApiQueueModel.kt @@ -0,0 +1,9 @@ +package com.abdownloadmanager.integration + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiQueueModel( + val id: Long, + val name: String, +) diff --git a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/Integration.kt b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/Integration.kt index d2cd9ea..6b23e74 100644 --- a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/Integration.kt +++ b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/Integration.kt @@ -4,6 +4,7 @@ import com.abdownloadmanager.integration.http4k.MyHttp4KServer import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlinx.serialization.json.Json +import kotlinx.serialization.builtins.ListSerializer //val scope = CoroutineScope(SupervisorJob()) @@ -114,6 +115,24 @@ class Integration( } MyResponse.Text("OK") } + get("/queues") { + runBlocking { + val queues = integrationHandler.listQueues() + val jsonResponse = customJson.encodeToString(ListSerializer(ApiQueueModel.serializer()), queues) + MyResponse.Text(jsonResponse) + } + } + post("/start-headless-download") { + runBlocking { + val itemsToAdd = kotlin.runCatching { + val message = it.getBody().orEmpty() + customJson.decodeFromString(message) + } + itemsToAdd.onFailure { it.printStackTrace() } + integrationHandler.addDownloadTask(itemsToAdd.getOrThrow()) + } + MyResponse.Text("OK") + } post("/ping") { MyResponse.Text("pong") } diff --git a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/IntegrationHandler.kt b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/IntegrationHandler.kt index 7217f2a..3af4cec 100644 --- a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/IntegrationHandler.kt +++ b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/IntegrationHandler.kt @@ -4,4 +4,6 @@ interface IntegrationHandler{ suspend fun addDownload( list: List ) + fun listQueues(): List + suspend fun addDownloadTask(task: NewDownloadTask) } \ No newline at end of file diff --git a/integration/server/src/main/kotlin/com/abdownloadmanager/integration/NewDownloadTask.kt b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/NewDownloadTask.kt new file mode 100644 index 0000000..addb614 --- /dev/null +++ b/integration/server/src/main/kotlin/com/abdownloadmanager/integration/NewDownloadTask.kt @@ -0,0 +1,11 @@ +package com.abdownloadmanager.integration + +import kotlinx.serialization.Serializable + +@Serializable +data class NewDownloadTask( + val downloadSource: NewDownloadInfoFromIntegration, + var folder: String? = null, + var name: String? = null, + var queueId: Long? = null, +)