qbittorrent-api-client
Version:
JavaScript client for qBittorrent api
483 lines (478 loc) • 15.8 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
ErrorType: () => ErrorType,
QBittorrentClient: () => QBittorrentClient,
QBittorrentClientError: () => QBittorrentClientError,
QBittorrentTorrentContentPriority: () => QBittorrentTorrentContentPriority,
QBittorrentTorrentTrackerStatus: () => QBittorrentTorrentTrackerStatus,
default: () => QBittorrentClient
});
module.exports = __toCommonJS(src_exports);
// src/classes/QBittorrentClient.ts
var import_axios = __toESM(require("axios"), 1);
// src/utils/QBittorrentClientError.ts
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
ErrorType2["FORBIDDEN"] = "FORBIDDEN";
ErrorType2["IP_BANNED"] = "IP_BANNED";
ErrorType2["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
ErrorType2["OPERATION_FAILED"] = "OPERATION_FAILED";
return ErrorType2;
})(ErrorType || {});
var QBittorrentClientError = class extends Error {
name = "QBittorrentClientError";
type;
constructor(message, context) {
super(message ?? "qBittorrent client error");
this.type = context?.type;
}
};
// src/classes/QBittorrentClient.ts
var import_form_data = __toESM(require("form-data"), 1);
var QBittorrentClient = class {
constructor(options) {
this.options = options;
this.httpClient.defaults.baseURL = this.baseUrl;
this.httpClient.interceptors.response.use((response) => response, (error) => {
if (error.response.status === 403) {
throw new QBittorrentClientError("Authentication needed", {
type: "FORBIDDEN" /* FORBIDDEN */
});
}
throw error;
});
}
httpClient = import_axios.default.create();
sessionCookie;
get baseUrl() {
return this.options.baseUrl + "/api/v2";
}
async authenticate(username, password) {
return this.login(username, password).then((sessionCookie) => {
if (!sessionCookie) {
throw new Error("No session cookie");
}
this.sessionCookie = sessionCookie;
this.httpClient.defaults.headers.common["Cookie"] = sessionCookie;
});
}
async login(username, password) {
const params = new URLSearchParams();
if (username)
params.append("username", username);
if (password)
params.append("password", password);
return this.httpClient("auth/login", {
method: "POST",
data: params,
withCredentials: true
}).then(
async (response) => {
if (response.status === 403) {
throw new QBittorrentClientError("Too many failed attempts, your IP is banned", {
type: "IP_BANNED" /* IP_BANNED */
});
}
if (response.data === "Fails.") {
throw new QBittorrentClientError("Invalid credentials", {
type: "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */
});
}
const cookies = response.headers["set-cookie"];
if (Array.isArray(cookies)) {
return cookies.find((cookie) => cookie.startsWith("SID="))?.split(";")[0];
}
return void 0;
},
(error) => {
if (error.response.status === 403) {
throw new QBittorrentClientError("Too many failed attempts, your IP is banned", {
type: "IP_BANNED" /* IP_BANNED */
});
}
throw error;
}
);
}
async logout() {
await this.httpClient("/auth/logout", {
method: "POST",
withCredentials: true
});
}
async version() {
return this.httpClient.get("app/version").then((response) => response.data);
}
async getAppPreferences() {
return this.httpClient.get(`app/preferences`).then((res) => res.data);
}
async setAppPreferences(preferences) {
await this.httpClient.post(`app/setPreferences`, `json=${JSON.stringify(preferences)}`);
}
async getTorrentInfos() {
return this.httpClient.get("torrents/info").then((res) => res.data);
}
async getTorrentContents(hash) {
return this.httpClient.get(`torrents/files`, {
params: {
hash: hash.toLowerCase()
}
}).then((res) => res.data);
}
async getTorrentProperties(hash) {
return this.httpClient.get(`torrents/properties`, {
params: {
hash: hash.toLowerCase()
}
}).then((res) => res.data);
}
async getTorrentTrackers(hash) {
return this.httpClient.get(`torrents/trackers`, {
params: {
hash: hash.toLowerCase()
}
}).then((res) => res.data);
}
async getTransferInfo() {
return this.httpClient.get(`transfer/info`, {}).then((res) => res.data);
}
// async syncMainData(): Promise<QBittorrentMainData> {
// const headers = await this.getRequestHeaders()
//
// if (this.isMainDataPending == false) {
// this.isMainDataPending = true
// this.syncRids.mainData = this.syncRids.mainData.then((rid) =>
// this.client
// .get<QBittorrentSyncMainData>(`sync/maindata`, {
// params: {
// rid,
// },
// headers,
// })
// .then(({ data }) => {
// const {
// rid: newRid = 0,
// full_update = false,
// categories = {},
// categories_removed = [],
// server_state = EMPTY_SERVER_STATE,
// tags = [],
// tags_removed = [],
// torrents = {},
// torrents_removed = [],
// trackers = {},
// trackers_removed = [],
// } = data
//
// if (full_update) {
// this.syncStates.mainData = {
// categories,
// server_state,
// tags,
// torrents,
// trackers,
// }
// } else {
// // categories
// Object.keys(categories).forEach((category) => {
// this.syncStates.mainData.categories[category] = {
// ...this.syncStates.mainData.categories[category],
// ...categories[category],
// }
// })
//
// categories_removed.forEach((category) => {
// delete this.syncStates.mainData.categories[category]
// })
//
// // tags
// this.syncStates.mainData.tags.push(...tags)
// this.syncStates.mainData.tags = this.syncStates.mainData.tags.filter(
// (tag) => !tags_removed.includes(tag),
// )
//
// // torrents
// Object.keys(torrents).forEach((torrent) => {
// this.syncStates.mainData.torrents[torrent] = {
// ...this.syncStates.mainData.torrents[torrent],
// ...torrents[torrent],
// }
// })
//
// torrents_removed.forEach((torrent) => {
// delete this.syncStates.mainData.torrents[torrent]
// })
//
// // trackers
// Object.keys(trackers).forEach((tracker) => {
// this.syncStates.mainData.trackers[tracker] = {
// ...this.syncStates.mainData.trackers[tracker],
// ...trackers[tracker],
// }
// })
//
// trackers_removed.forEach((tracker) => {
// delete this.syncStates.mainData.trackers[tracker]
// })
// }
//
// return newRid
// })
// .finally(() => {
// this.isMainDataPending = false
// }),
// )
// }
//
// try {
// await this.syncRids.mainData
// } catch (e) {
// this.syncRids.mainData = Promise.resolve(0)
// throw e
// }
//
// return this.syncStates.mainData
// }
async syncTorrentPeers(hash) {
return this.httpClient.get(`sync/torrentPeers`, {
params: {
hash: hash.toLowerCase(),
rid: 0
}
}).then(({ data }) => data.peers);
}
async torrentsPause(hashes) {
return this.httpClient.get(`torrents/pause`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
async torrentsResume(hashes) {
return this.httpClient.get(`torrents/resume`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
async torrentsDelete(hashes, deleteFiles) {
return this.httpClient.get(`torrents/delete`, {
params: {
hashes: hashes.join("|").toLowerCase(),
deleteFiles: deleteFiles ? "true" : "false"
}
}).then(() => {
});
}
async torrentsRecheck(hashes) {
return this.httpClient.get(`torrents/recheck`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
async torrentsSetLocation(hashes, location) {
return this.httpClient.get(`torrents/setLocation`, {
params: {
hashes: hashes.join("|").toLowerCase(),
location
}
}).then(() => {
});
}
async torrentsSetTopPrio(hashes) {
return this.httpClient.get(`torrents/topPrio`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
async torrentsSetBottomPrio(hashes) {
return this.httpClient.get(`torrents/bottomPrio`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
async torrentsAddFiles(files, options) {
const form = new import_form_data.default();
files.forEach((file, index) => {
form.append("torrents", file, {
filename: `${index}.torrent`,
contentType: "application/x-bittorrent"
});
});
Object.keys(options).forEach((key) => {
const property = key;
form.append(property, `${options[property]}`);
});
const headers = form.getHeaders({
Cookie: this.sessionCookie,
"Content-Length": form.getLengthSync()
});
return this.httpClient.post(`torrents/add`, form, {
headers
}).then((response) => {
if (response.data === "Fails.") {
throw new QBittorrentClientError("Can not add torrent file", {
type: "OPERATION_FAILED" /* OPERATION_FAILED */
});
}
});
}
async torrentsAddURLs(urls, options) {
const form = new import_form_data.default();
form.append("urls", urls.join("\n"));
Object.keys(options).forEach((key) => {
const property = key;
form.append(property, `${options[property]}`);
});
const headers = form.getHeaders({
Cookie: this.sessionCookie,
"Content-Length": form.getLengthSync()
});
return this.httpClient.post(`torrents/add`, form, {
headers
}).then(() => {
});
}
async torrentsAddTags(hashes, tags) {
return this.httpClient.get(`torrents/addTags`, {
params: {
hashes: hashes.join("|").toLowerCase(),
tags: tags.join(",")
}
}).then(() => {
});
}
async torrentsRemoveTags(hashes, tags) {
return this.httpClient.get(`torrents/removeTags`, {
params: {
hashes: hashes.join("|").toLowerCase(),
tags: tags?.join(",")
}
}).then(() => {
});
}
async torrentsAddTrackers(hash, urls) {
if (urls.length > 0) {
return this.httpClient.get(`torrents/addTrackers`, {
params: {
hash: hash.toLowerCase(),
urls: urls.join("\n")
}
}).then(() => {
});
}
}
async torrentsReannounce(hashes) {
if (hashes.length > 0) {
return this.httpClient.get(`torrents/reannounce`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
}
async torrentsRemoveTrackers(hash, urls) {
if (urls.length > 0) {
return this.httpClient.get(`torrents/removeTrackers`, {
params: {
hash: hash.toLowerCase(),
urls: urls.join("|")
}
}).then(() => {
});
}
}
async torrentsSetSuperSeeding(hashes, value) {
if (hashes.length > 0) {
return this.httpClient.get(`torrents/setSuperSeeding`, {
params: {
hashes: hashes.join("|").toLowerCase(),
value: value ? "true" : "false"
}
}).then(() => {
});
}
}
async torrentsToggleSequentialDownload(hashes) {
if (hashes.length > 0) {
return this.httpClient.get(`torrents/toggleSequentialDownload`, {
params: {
hashes: hashes.join("|").toLowerCase()
}
}).then(() => {
});
}
}
async torrentsFilePrio(hash, ids, priority) {
return this.httpClient.get(`torrents/filePrio`, {
params: {
hash: hash.toLowerCase(),
id: ids.join("|"),
priority
}
}).then(() => {
});
}
};
// src/types/QBittorrentTorrentsMethods.ts
var QBittorrentTorrentContentPriority = /* @__PURE__ */ ((QBittorrentTorrentContentPriority2) => {
QBittorrentTorrentContentPriority2[QBittorrentTorrentContentPriority2["DO_NOT_DOWNLOAD"] = 0] = "DO_NOT_DOWNLOAD";
QBittorrentTorrentContentPriority2[QBittorrentTorrentContentPriority2["NORMAL"] = 1] = "NORMAL";
QBittorrentTorrentContentPriority2[QBittorrentTorrentContentPriority2["HIGH"] = 6] = "HIGH";
QBittorrentTorrentContentPriority2[QBittorrentTorrentContentPriority2["MAXIMUM"] = 7] = "MAXIMUM";
return QBittorrentTorrentContentPriority2;
})(QBittorrentTorrentContentPriority || {});
var QBittorrentTorrentTrackerStatus = /* @__PURE__ */ ((QBittorrentTorrentTrackerStatus2) => {
QBittorrentTorrentTrackerStatus2[QBittorrentTorrentTrackerStatus2["DISABLED"] = 0] = "DISABLED";
QBittorrentTorrentTrackerStatus2[QBittorrentTorrentTrackerStatus2["NOT_CONTACTED"] = 1] = "NOT_CONTACTED";
QBittorrentTorrentTrackerStatus2[QBittorrentTorrentTrackerStatus2["CONTACTED"] = 2] = "CONTACTED";
QBittorrentTorrentTrackerStatus2[QBittorrentTorrentTrackerStatus2["UPDATING"] = 3] = "UPDATING";
QBittorrentTorrentTrackerStatus2[QBittorrentTorrentTrackerStatus2["ERROR"] = 4] = "ERROR";
return QBittorrentTorrentTrackerStatus2;
})(QBittorrentTorrentTrackerStatus || {});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ErrorType,
QBittorrentClient,
QBittorrentClientError,
QBittorrentTorrentContentPriority,
QBittorrentTorrentTrackerStatus
});
//# sourceMappingURL=index.cjs.map