Rest API to add downloads (#331)

* feat: rest api to add silent downloads
This commit is contained in:
Talha Ahmed 2025-01-05 11:33:39 +05:00 committed by GitHub
parent b23cfcc672
commit 3f7824dab8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 185 additions and 3 deletions

View File

@ -125,6 +125,7 @@ follow these steps.
1. Clone the project 1. Clone the project
2. Install the [JBR](https://github.com/JetBrains/JetBrainsRuntime/releases) 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 3. cd into the project, open your terminal and execute the following commands
4. select which way you want to compile the app 4. select which way you want to compile the app
<details> <details>

100
REST-API.yml Normal file
View File

@ -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

View File

@ -1,14 +1,24 @@
package com.abdownloadmanager.desktop.integration package com.abdownloadmanager.desktop.integration
import com.abdownloadmanager.integration.IntegrationHandler
import com.abdownloadmanager.desktop.AppComponent 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.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.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
class IntegrationHandlerImp: IntegrationHandler,KoinComponent{ class IntegrationHandlerImp: IntegrationHandler,KoinComponent{
val appComponent by inject<AppComponent>() val appComponent by inject<AppComponent>()
val downloadSystem by inject<DownloadSystem>()
val queueManager by inject<QueueManager>()
val appSettings by inject<AppRepository>()
override suspend fun addDownload(list: List<NewDownloadInfoFromIntegration>) { override suspend fun addDownload(list: List<NewDownloadInfoFromIntegration>) {
appComponent.externalCredentialComingIntoApp(list.map { appComponent.externalCredentialComingIntoApp(list.map {
DownloadCredentials( DownloadCredentials(
@ -18,4 +28,34 @@ class IntegrationHandlerImp: IntegrationHandler,KoinComponent{
) )
}) })
} }
} override fun listQueues(): List<ApiQueueModel> {
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)
}
}
}

View File

@ -0,0 +1,9 @@
package com.abdownloadmanager.integration
import kotlinx.serialization.Serializable
@Serializable
data class ApiQueueModel(
val id: Long,
val name: String,
)

View File

@ -4,6 +4,7 @@ import com.abdownloadmanager.integration.http4k.MyHttp4KServer
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.builtins.ListSerializer
//val scope = CoroutineScope(SupervisorJob()) //val scope = CoroutineScope(SupervisorJob())
@ -114,6 +115,24 @@ class Integration(
} }
MyResponse.Text("OK") 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<NewDownloadTask>(message)
}
itemsToAdd.onFailure { it.printStackTrace() }
integrationHandler.addDownloadTask(itemsToAdd.getOrThrow())
}
MyResponse.Text("OK")
}
post("/ping") { post("/ping") {
MyResponse.Text("pong") MyResponse.Text("pong")
} }

View File

@ -4,4 +4,6 @@ interface IntegrationHandler{
suspend fun addDownload( suspend fun addDownload(
list: List<NewDownloadInfoFromIntegration> list: List<NewDownloadInfoFromIntegration>
) )
fun listQueues(): List<ApiQueueModel>
suspend fun addDownloadTask(task: NewDownloadTask)
} }

View File

@ -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,
)