Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ctrl/qbittorrent

Package Overview
Dependencies
Maintainers
0
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ctrl/qbittorrent - npm Package Compare versions

Comparing version 9.1.0 to 9.2.0

34

dist/src/qbittorrent.d.ts

@@ -1,14 +0,32 @@

import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
import type { Jsonify } from 'type-fest';
import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentClientConfig, TorrentClientState } from '@ctrl/shared-torrent';
import type { AddMagnetOptions, AddTorrentOptions, BuildInfo, Preferences, Torrent, TorrentCategories, TorrentFile, TorrentFilePriority, TorrentFilters, TorrentPeersResponse, TorrentPieceState, TorrentProperties, TorrentTrackers, WebSeed } from './types.js';
interface QBittorrentState extends TorrentClientState {
auth?: {
/**
* auth cookie
*/
sid: string;
/**
* cookie expiration
*/
expires: Date;
};
version?: {
version: string;
isVersion5OrHigher: boolean;
};
}
export declare class QBittorrent implements TorrentClient {
config: TorrentSettings;
/**
* auth cookie
* Create a new QBittorrent client from a state
*/
private _sid?;
static createFromState(config: Readonly<TorrentClientConfig>, state: Readonly<Jsonify<QBittorrentState>>): QBittorrent;
config: TorrentClientConfig;
state: QBittorrentState;
constructor(options?: Partial<TorrentClientConfig>);
/**
* cookie expiration
* Export the state of the client as JSON
*/
private _exp?;
constructor(options?: Partial<TorrentSettings>);
exportState(): Jsonify<QBittorrentState>;
/**

@@ -215,2 +233,4 @@ * @deprecated

request<T>(path: string, method: 'GET' | 'POST', params?: Record<string, string | number>, body?: URLSearchParams | FormData, headers?: Record<string, string>, isJson?: boolean): Promise<T>;
private checkVersion;
}
export {};

@@ -17,11 +17,15 @@ import { parse as cookieParse } from 'cookie';

export class QBittorrent {
config;
/**
* auth cookie
* Create a new QBittorrent client from a state
*/
_sid;
/**
* cookie expiration
*/
_exp;
static createFromState(config, state) {
const client = new QBittorrent(config);
client.state = {
...state,
auth: state.auth ? { ...state.auth, expires: new Date(state.auth.expires) } : undefined,
};
return client;
}
config;
state = {};
constructor(options = {}) {

@@ -31,2 +35,8 @@ this.config = { ...defaults, ...options };

/**
* Export the state of the client as JSON
*/
exportState() {
return JSON.parse(JSON.stringify(this.state));
}
/**
* @deprecated

@@ -312,4 +322,5 @@ */

async pauseTorrent(hashes) {
const endpoint = this.state.version?.isVersion5OrHigher ? '/torrents/stop' : '/torrents/pause';
const data = { hashes: normalizeHashes(hashes) };
await this.request('/torrents/pause', 'POST', undefined, objToUrlSearchParams(data));
await this.request(endpoint, 'POST', undefined, objToUrlSearchParams(data));
return true;

@@ -321,4 +332,7 @@ }

async resumeTorrent(hashes) {
const endpoint = this.state.version?.isVersion5OrHigher
? '/torrents/start'
: '/torrents/resume';
const data = { hashes: normalizeHashes(hashes) };
await this.request('/torrents/resume', 'POST', undefined, objToUrlSearchParams(data));
await this.request(endpoint, 'POST', undefined, objToUrlSearchParams(data));
return true;

@@ -369,2 +383,7 @@ }

if (options) {
// Handle version-specific paused/stopped parameter
if (this.state.version?.isVersion5OrHigher && 'paused' in options) {
form.append('stopped', options.paused);
delete options.paused;
}
// disable savepath when autoTMM is defined

@@ -444,2 +463,7 @@ if (options.useAutoTMM === 'true') {

if (options) {
// Handle version-specific paused/stopped parameter
if (this.state.version?.isVersion5OrHigher && 'paused' in options) {
form.append('stopped', options.paused);
delete options.paused;
}
// disable savepath when autoTMM is defined

@@ -535,3 +559,3 @@ if (options.useAutoTMM === 'true') {

async login() {
const url = joinURL(this.config.baseUrl, this.config.path, '/auth/login');
const url = joinURL(this.config.baseUrl, this.config.path ?? '', '/auth/login');
const res = await ofetch.raw(url, {

@@ -554,22 +578,22 @@ method: 'POST',

}
const cookie = cookieParse(res.headers.get('set-cookie'));
const cookie = cookieParse(res.headers.get('set-cookie') ?? '');
if (!cookie.SID) {
throw new Error('Invalid cookie');
}
this._sid = cookie.SID;
// Not sure if it might be lowercase
const expires = cookie.Expires ?? cookie.expires;
// Assumed to be in seconds
const maxAge = cookie['Max-Age'] ?? cookie['max-age'];
this._exp = expires
? new Date(expires)
: maxAge
? new Date(Number(maxAge) * 1000)
: // Default expiration 1 hour
new Date(Date.now() + 3600000);
this.state.auth = {
sid: cookie.SID,
expires: expires
? new Date(expires)
: maxAge
? new Date(Number(maxAge) * 1000)
: new Date(Date.now() + 3600000),
};
// Check version after successful login
await this.checkVersion();
return true;
}
logout() {
this._sid = undefined;
this._exp = undefined;
delete this.state.auth;
return true;

@@ -579,3 +603,5 @@ }

async request(path, method, params, body, headers = {}, isJson = true) {
if (!this._sid || !this._exp || this._exp.getTime() < new Date().getTime()) {
if (!this.state.auth?.sid ||
!this.state.auth.expires ||
this.state.auth.expires.getTime() < new Date().getTime()) {
const authed = await this.login();

@@ -586,7 +612,7 @@ if (!authed) {

}
const url = joinURL(this.config.baseUrl, this.config.path, path);
const url = joinURL(this.config.baseUrl, this.config.path ?? '', path);
const res = await ofetch(url, {
method,
headers: {
Cookie: `SID=${this._sid ?? ''}`,
Cookie: `SID=${this.state.auth.sid ?? ''}`,
...headers,

@@ -605,2 +631,13 @@ },

}
async checkVersion() {
if (!this.state.version?.version) {
const newVersion = await this.getAppVersion();
// Remove potential 'v' prefix and any extra info after version number
const cleanVersion = newVersion.replace(/^v/, '').split('-')[0];
this.state.version = {
version: newVersion,
isVersion5OrHigher: cleanVersion === '5.0.0' || isGreater(cleanVersion, '5.0.0'),
};
}
}
}

@@ -624,1 +661,4 @@ /**

}
function isGreater(a, b) {
return a.localeCompare(b, undefined, { numeric: true }) === 1;
}

@@ -552,3 +552,4 @@ export interface BuildInfo {

*/
paused: TrueFalseStr;
paused?: TrueFalseStr;
stopped?: TrueFalseStr;
/**

@@ -610,3 +611,4 @@ * Control filesystem structure for content (added in Web API v2.7)

*/
paused: TrueFalseStr;
paused?: TrueFalseStr;
stopped?: TrueFalseStr;
/**

@@ -613,0 +615,0 @@ * Create the root folder. Possible values are true, false, unset (default)

{
"name": "@ctrl/qbittorrent",
"version": "9.1.0",
"version": "9.2.0",
"description": "TypeScript api wrapper for qbittorrent using got",

@@ -40,7 +40,8 @@ "author": "Scott Cooper <scttcper@gmail.com>",

"@ctrl/magnet-link": "^4.0.2",
"@ctrl/shared-torrent": "^6.1.0",
"@ctrl/shared-torrent": "^6.2.1",
"@ctrl/torrent-file": "^4.1.0",
"cookie": "^1.0.1",
"cookie": "^1.0.2",
"node-fetch-native": "^1.6.4",
"ofetch": "^1.4.1",
"type-fest": "^4.30.2",
"ufo": "^1.5.4",

@@ -51,12 +52,12 @@ "uint8array-extras": "^1.4.0"

"@biomejs/biome": "1.9.4",
"@ctrl/eslint-config-biome": "4.2.11",
"@eslint/compat": "^1.2.2",
"@sindresorhus/tsconfig": "6.0.0",
"@ctrl/eslint-config-biome": "4.3.1",
"@eslint/compat": "^1.2.4",
"@sindresorhus/tsconfig": "7.0.0",
"@types/cookie": "1.0.0",
"@types/node": "22.9.0",
"@vitest/coverage-v8": "2.1.4",
"@types/node": "22.10.2",
"@vitest/coverage-v8": "2.1.8",
"p-wait-for": "5.0.2",
"typedoc": "0.26.11",
"typescript": "5.6.3",
"vitest": "2.1.4"
"typedoc": "0.27.5",
"typescript": "5.7.2",
"vitest": "2.1.8"
},

@@ -63,0 +64,0 @@ "release": {

@@ -101,2 +101,11 @@ # qBittorrent [![npm](https://badgen.net/npm/v/@ctrl/qbittorrent)](https://www.npmjs.com/package/@ctrl/qbittorrent) [![coverage](https://badgen.net/codecov/c/github/scttcper/qbittorrent)](https://codecov.io/gh/scttcper/qbittorrent)

##### export and create from state
If you're shutting down the server often (serverless?) you can export the state
```ts
const state = client.exportState()
const client = QBittorrent.createFromState(config, state);
```
### See Also

@@ -103,0 +112,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc