Skip to content

Commit

Permalink
feat: Switch to using hash as the normalized id (#98)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: uses the torrent hash as the normalized id. Will automatically convert a single hash to an array of hashes as required by the api.
  • Loading branch information
scttcper authored Feb 4, 2022
1 parent 1d75d06 commit 1c19d0f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 34 deletions.
73 changes: 44 additions & 29 deletions src/transmission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DefaultResponse,
FreeSpaceResponse,
GetTorrentRepsonse,
NormalizedTorrentIds,
RenamePathOptions,
SessionArguments,
SessionResponse,
Expand All @@ -35,12 +36,6 @@ const defaults: TorrentSettings = {
timeout: 5000,
};

/**
* TODO: remove when hash is available on normalized torrent
* @deprecated
*/
export type TransmissionNormalizedTorrent = NormalizedTorrent & { hash: string };

export class Transmission implements TorrentClient {
config: TorrentSettings;

Expand All @@ -60,22 +55,26 @@ export class Transmission implements TorrentClient {
return res.body;
}

async queueTop(ids: TorrentIds): Promise<DefaultResponse> {
async queueTop(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('queue-move-top', { ids });
return res.body;
}

async queueBottom(ids: TorrentIds): Promise<DefaultResponse> {
async queueBottom(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('queue-move-bottom', { ids });
return res.body;
}

async queueUp(ids: TorrentIds): Promise<DefaultResponse> {
async queueUp(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('queue-move-up', { ids });
return res.body;
}

async queueDown(ids: TorrentIds): Promise<DefaultResponse> {
async queueDown(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('queue-move-down', { ids });
return res.body;
}
Expand All @@ -85,30 +84,35 @@ export class Transmission implements TorrentClient {
return res.body;
}

async pauseTorrent(ids: TorrentIds): Promise<DefaultResponse> {
async pauseTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('torrent-stop', { ids });
return res.body;
}

async resumeTorrent(ids: TorrentIds): Promise<DefaultResponse> {
async resumeTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('torrent-start', { ids });
return res.body;
}

async verifyTorrent(ids: TorrentIds): Promise<DefaultResponse> {
async verifyTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('torrent-verify', { ids });
return res.body;
}

/**
* ask tracker for more peers
*/
async reannounceTorrent(ids: TorrentIds): Promise<DefaultResponse> {
async reannounceTorrent(id: NormalizedTorrentIds): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('torrent-reannounce', { ids });
return res.body;
}

async moveTorrent(ids: TorrentIds, location: string): Promise<DefaultResponse> {
async moveTorrent(id: NormalizedTorrentIds, location: string): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<DefaultResponse>('torrent-set-location', {
ids,
move: true,
Expand All @@ -121,9 +125,10 @@ export class Transmission implements TorrentClient {
* Torrent Mutators
*/
async setTorrent(
ids: TorrentIds,
id: NormalizedTorrentIds,
options: Partial<SetTorrentOptions> = {},
): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
options.ids = ids;
const res = await this.request<DefaultResponse>('torrent-set', options);
return res.body;
Expand All @@ -133,9 +138,10 @@ export class Transmission implements TorrentClient {
* Renaming a Torrent's Path
*/
async renamePath(
ids: TorrentIds,
id: NormalizedTorrentIds,
options: Partial<RenamePathOptions> = {},
): Promise<DefaultResponse> {
const ids = this._handleNormalizedIds(id);
options.ids = ids;
const res = await this.request<DefaultResponse>('torrent-rename-path', options);
return res.body;
Expand All @@ -144,7 +150,8 @@ export class Transmission implements TorrentClient {
/**
* Removing a Torrent
*/
async removeTorrent(ids: TorrentIds, removeData = true): Promise<AddTorrentResponse> {
async removeTorrent(id: NormalizedTorrentIds, removeData = true): Promise<AddTorrentResponse> {
const ids = this._handleNormalizedIds(id);
const res = await this.request<AddTorrentResponse>('torrent-remove', {
ids,
'delete-local-data': removeData,
Expand Down Expand Up @@ -210,7 +217,7 @@ export class Transmission implements TorrentClient {
async normalizedAddTorrent(
torrent: string | Buffer,
options: Partial<NormalizedAddTorrentOptions> = {},
): Promise<TransmissionNormalizedTorrent> {
): Promise<NormalizedTorrent> {
const torrentOptions: Partial<AddTorrentOptions> = {};
if (options.startPaused) {
torrentOptions.paused = true;
Expand All @@ -221,16 +228,16 @@ export class Transmission implements TorrentClient {
}

const res = await this.addTorrent(torrent, torrentOptions);
const torrentId = res.arguments['torrent-added'].id;
const torrentHash = [res.arguments['torrent-added'].hashString];

if (options.label) {
await this.setTorrent(torrentId, { labels: [options.label] });
await this.setTorrent(torrentHash, { labels: [options.label] });
}

return this.getTorrent(torrentId);
return this.getTorrent(torrentHash);
}

async getTorrent(id: TorrentIds): Promise<TransmissionNormalizedTorrent> {
async getTorrent(id: NormalizedTorrentIds): Promise<NormalizedTorrent> {
const result = await this.listTorrents(id);
if (!result.arguments.torrents || result.arguments.torrents.length === 0) {
throw new Error('Torrent not found');
Expand Down Expand Up @@ -265,7 +272,7 @@ export class Transmission implements TorrentClient {
}

async listTorrents(
ids?: TorrentIds,
id?: NormalizedTorrentIds,
additionalFields: string[] = [],
): Promise<GetTorrentRepsonse> {
const fields = [
Expand Down Expand Up @@ -329,8 +336,9 @@ export class Transmission implements TorrentClient {
'webseeds',
...additionalFields,
];
const args: Record<string, string[] | TorrentIds> = { fields };
if (ids) {
const args: Record<string, string[] | NormalizedTorrentIds> = { fields };
if (id) {
const ids = this._handleNormalizedIds(id);
args.ids = ids;
}

Expand Down Expand Up @@ -380,7 +388,15 @@ export class Transmission implements TorrentClient {
}
}

private _normalizeTorrentData(torrent: Torrent): TransmissionNormalizedTorrent {
private _handleNormalizedIds(ids: NormalizedTorrentIds): TorrentIds {
if (typeof ids === 'string' && ids !== 'recently-active') {
return [ids];
}

return ids;
}

private _normalizeTorrentData(torrent: Torrent): NormalizedTorrent {
const dateAdded = new Date(torrent.addedDate * 1000).toISOString();
const dateCompleted = new Date(torrent.doneDate * 1000).toISOString();

Expand All @@ -400,8 +416,7 @@ export class Transmission implements TorrentClient {
}

return {
id: torrent.id,
hash: torrent.hashString,
id: torrent.hashString,
name: torrent.name,
state,
isCompleted: torrent.leftUntilDone < 1,
Expand Down
12 changes: 9 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,19 @@ export interface FreeSpaceResponse extends DefaultResponse {
/**
* "ids", which specifies which torrents to use.
* All torrents are used if the "ids" argument is omitted.
*
* "ids" should be one of the following:
* (1) an integer referring to a torrent id
* (2) a list of torrent id numbers, sha1 hash strings, or both
* (3) a string, "recently-active", for recently-active torrents
* 1. an integer referring to a torrent id
* 2. a list of torrent id numbers, sha1 hash strings, or both
* 3. a string, "recently-active", for recently-active torrents
*/
export type TorrentIds = number | 'recently-active' | Array<number | string>;

/**
* Allows the user to pass a single hash, this will be converted to an array
*/
export type NormalizedTorrentIds = TorrentIds | string;

export interface GetTorrentRepsonse extends DefaultResponse {
arguments: {
removed: Torrent[];
Expand Down
4 changes: 2 additions & 2 deletions test/transmission.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const baseUrl = 'http://localhost:9091/';
const torrentName = 'ubuntu-18.04.1-desktop-amd64.iso';
const torrentFile = path.join(__dirname, '/ubuntu-18.04.1-desktop-amd64.iso.torrent');

async function setupTorrent(transmission: Transmission) {
async function setupTorrent(transmission: Transmission): Promise<string> {
const res = await transmission.addTorrent(torrentFile);
await pWaitFor(
async () => {
Expand All @@ -21,7 +21,7 @@ async function setupTorrent(transmission: Transmission) {
},
{ timeout: 10000, interval: 200 },
);
return res.arguments['torrent-added'].id;
return res.arguments['torrent-added'].hashString;
}

describe('Transmission', () => {
Expand Down

0 comments on commit 1c19d0f

Please sign in to comment.