Created
January 5, 2025 14:33
-
-
Save WeslyG/ad40494c0be8788eeff57ed602350ecb to your computer and use it in GitHub Desktop.
SYNO.DownloadStation2.Task upload torrent nodejs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// yarn add axios form-data | |
import { createReadStream } from "fs"; | |
import { version } from "os"; | |
import axios, { AxiosInstance } from "axios"; | |
import FormData from "form-data"; | |
interface SynologyAuthResponse { | |
data: { | |
sid: string; | |
}; | |
success: boolean; | |
} | |
interface SynologyTaskResponse { | |
data: { | |
list: Array<{ | |
id: string; | |
status: string; | |
}>; | |
}; | |
success: boolean; | |
} | |
interface SynologyErrorResponse { | |
error: { | |
code: number; | |
message: string; | |
}; | |
success: boolean; | |
} | |
class SynologyDownloadStation { | |
private baseURL: string; | |
private username: string; | |
private password: string; | |
private sid: string | null = null; | |
private client: AxiosInstance; | |
constructor(baseURL: string, username: string, password: string) { | |
this.baseURL = baseURL; | |
this.username = username; | |
this.password = password; | |
this.client = axios.create({ | |
baseURL: this.baseURL, | |
validateStatus: () => true, | |
}); | |
} | |
private async login(): Promise<void> { | |
try { | |
const response = await this.client.get<SynologyAuthResponse>( | |
"/webapi/auth.cgi", | |
{ | |
params: { | |
api: "SYNO.API.Auth", | |
version: "3", | |
method: "login", | |
account: this.username, | |
passwd: this.password, | |
session: "DownloadStation", | |
format: "sid", | |
}, | |
} | |
); | |
if (!response.data.success) { | |
throw new Error("Login failed"); | |
} | |
this.sid = response.data.data.sid; | |
} catch (error) { | |
throw new Error(`Authentication failed: ${error.message}`); | |
} | |
} | |
private async ensureAuthenticated(): Promise<void> { | |
if (!this.sid) { | |
await this.login(); | |
} | |
} | |
async uploadTorrent( | |
torrentPath: string, | |
destination?: string | |
): Promise<string> { | |
try { | |
await this.ensureAuthenticated(); | |
const formData = new FormData(); | |
// sequence is a key! | |
formData.append("api", "SYNO.DownloadStation2.Task"); | |
formData.append("method", "create"); | |
formData.append("version", "2"); | |
formData.append("type", `"file"`); | |
formData.append("file", `["torrent"]`); | |
if (destination) { | |
formData.append("destination", `"${destination}"`); | |
} | |
formData.append("create_list", "false"); | |
formData.append("torrent", createReadStream(torrentPath)); | |
const response = await this.client.post< | |
SynologyTaskResponse | SynologyErrorResponse | |
>(`/webapi/entry.cgi?_sid=${this.sid}`, formData, { | |
headers: { | |
...formData.getHeaders(), | |
Accept: "*/*", | |
}, | |
}); | |
console.log(response.data); | |
if ("error" in response.data) { | |
throw new Error( | |
`API Error: ${response.data.error.message} (Code: ${response.data.error.code})` | |
); | |
} | |
if (!response.data.success) { | |
throw new Error("Failed to create download task"); | |
} | |
const taskId = response.data.data.task_id[0]; | |
if (!taskId) { | |
throw new Error("No task ID returned"); | |
} | |
return taskId; | |
} catch (error) { | |
throw new Error(`Failed to upload torrent: ${error.message}`); | |
} | |
} | |
async getTaskStatus(taskId: string): Promise<string> { | |
try { | |
await this.ensureAuthenticated(); | |
const bodyUrlEncoded = new URLSearchParams(); | |
bodyUrlEncoded.append("api", "SYNO.DownloadStation2.Task"); | |
bodyUrlEncoded.append("version", "2"); | |
bodyUrlEncoded.append("method", "get"); | |
bodyUrlEncoded.append("id", `["${taskId}"]`); | |
bodyUrlEncoded.append("additional", `["detail", "transfer"]`); | |
const response = await this.client<SynologyTaskResponse>({ | |
method: "post", | |
url: `${this.baseURL}/webapi/entry.cgi?_sid=${this.sid}`, | |
headers: { "Content-Type": "application/x-www-form-urlencoded" }, | |
data: bodyUrlEncoded, | |
}); | |
if (!response.data.success) { | |
throw new Error("Failed to get task status"); | |
} | |
const task = response.data.data.task[0]; | |
console.log(task); | |
if (!task) { | |
throw new Error("Task not found"); | |
} | |
return task.status; | |
} catch (error) { | |
throw new Error(`Failed to get task status: ${error.message}`); | |
} | |
} | |
} | |
// Example usage: | |
async function main() { | |
const synology = new SynologyDownloadStation( | |
"http://IP_ADD:5000", | |
"username", | |
"password" | |
); | |
try { | |
// Upload torrent file | |
const taskId = await synology.uploadTorrent( | |
"2068935.torrent", | |
"media/films" // Optional destination path | |
); | |
console.log(`Torrent upload successful. Task ID: ${taskId}`); | |
// Get task status | |
const status = await synology.getTaskStatus(taskId); | |
console.log(`Task status: ${status}`); | |
} catch (error) { | |
console.error("Error:", error.message); | |
} | |
} | |
main(); | |
// export default SynologyDownloadStation; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment