diff --git a/package-lock.json b/package-lock.json index 67dec9d..f377f1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.0.0-placeholder", "license": "MIT", "dependencies": { - "@ctrl/shared-torrent": "^4.1.0", + "@ctrl/magnet-link": "^3.1.0", + "@ctrl/shared-torrent": "^4.1.1", "@ctrl/url-join": "^2.0.0", "got": "^12.1.0" }, @@ -50,17 +51,36 @@ "prettier": "^2.6.2" } }, + "node_modules/@ctrl/magnet-link": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@ctrl/magnet-link/-/magnet-link-3.1.0.tgz", + "integrity": "sha512-H+mQmAsP/eW8KtuXnttKIhJLyzlzJe7ZTQKXEaSHuCg/Bj8WduvPOusv6IU0QWbFNGXG6cFju0OMt9r3JFqt1w==", + "dependencies": { + "@ctrl/ts-base32": "^2.1.1" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/@ctrl/shared-torrent": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ctrl/shared-torrent/-/shared-torrent-4.1.0.tgz", - "integrity": "sha512-mMw5ze+G5mk67l7G2WiFNHR5SO7JLsrtqPCknDIiW3fLVcEXLm21nfmDp2ONxiWhK7WKRkCODWCaN3p3vtd+rw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@ctrl/shared-torrent/-/shared-torrent-4.1.1.tgz", + "integrity": "sha512-gDCV02liPbajkOWYxaeFkFDwnv6bmNm/v4OEvGOXrQcwKAZN7HzD4zoGb2Etnp4GO916HUMSMyZQzjRwtUy7tg==", "dependencies": { - "got": "^12.0.1" + "got": "^12.1.0" }, "engines": { "node": ">=14.16" } }, + "node_modules/@ctrl/ts-base32": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@ctrl/ts-base32/-/ts-base32-2.1.1.tgz", + "integrity": "sha512-lQ6Q0hZyhGgzAn/+7h0mseWhMh5d8nS4fxlhjhJrVSc+3U7qvITBvcLRDk2p71OcPgU55ZXVYfTfr2FqjDljGQ==", + "engines": { + "node": ">=14.16" + } + }, "node_modules/@ctrl/url-join": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@ctrl/url-join/-/url-join-2.0.0.tgz", @@ -3237,14 +3257,27 @@ "prettier": "^2.6.2" } }, + "@ctrl/magnet-link": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@ctrl/magnet-link/-/magnet-link-3.1.0.tgz", + "integrity": "sha512-H+mQmAsP/eW8KtuXnttKIhJLyzlzJe7ZTQKXEaSHuCg/Bj8WduvPOusv6IU0QWbFNGXG6cFju0OMt9r3JFqt1w==", + "requires": { + "@ctrl/ts-base32": "^2.1.1" + } + }, "@ctrl/shared-torrent": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ctrl/shared-torrent/-/shared-torrent-4.1.0.tgz", - "integrity": "sha512-mMw5ze+G5mk67l7G2WiFNHR5SO7JLsrtqPCknDIiW3fLVcEXLm21nfmDp2ONxiWhK7WKRkCODWCaN3p3vtd+rw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@ctrl/shared-torrent/-/shared-torrent-4.1.1.tgz", + "integrity": "sha512-gDCV02liPbajkOWYxaeFkFDwnv6bmNm/v4OEvGOXrQcwKAZN7HzD4zoGb2Etnp4GO916HUMSMyZQzjRwtUy7tg==", "requires": { - "got": "^12.0.1" + "got": "^12.1.0" } }, + "@ctrl/ts-base32": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@ctrl/ts-base32/-/ts-base32-2.1.1.tgz", + "integrity": "sha512-lQ6Q0hZyhGgzAn/+7h0mseWhMh5d8nS4fxlhjhJrVSc+3U7qvITBvcLRDk2p71OcPgU55ZXVYfTfr2FqjDljGQ==" + }, "@ctrl/url-join": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@ctrl/url-join/-/url-join-2.0.0.tgz", diff --git a/package.json b/package.json index fa61e78..28313b8 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "test:ci": "vitest run --coverage" }, "dependencies": { - "@ctrl/shared-torrent": "^4.1.0", + "@ctrl/magnet-link": "^3.1.0", + "@ctrl/shared-torrent": "^4.1.1", "@ctrl/url-join": "^2.0.0", "got": "^12.1.0" }, diff --git a/src/transmission.ts b/src/transmission.ts index fad0e79..44e6442 100644 --- a/src/transmission.ts +++ b/src/transmission.ts @@ -2,6 +2,7 @@ import { existsSync, readFileSync } from 'fs'; import got, { Response } from 'got'; +import { magnetDecode } from '@ctrl/magnet-link'; import { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, @@ -223,12 +224,22 @@ export class Transmission implements TorrentClient { torrentOptions.paused = true; } - if (!Buffer.isBuffer(torrent)) { - torrent = Buffer.from(torrent); - } + let torrentHash: string | undefined; + if (typeof torrent === 'string' && torrent.startsWith('magnet:')) { + torrentHash = magnetDecode(torrent).infoHash; + if (!torrentHash) { + throw new Error('Magnet did not contain hash'); + } + + await this.addMagnet(torrent, torrentOptions); + } else { + if (!Buffer.isBuffer(torrent)) { + torrent = Buffer.from(torrent); + } - const res = await this.addTorrent(torrent, torrentOptions); - const torrentHash = [res.arguments['torrent-added'].hashString]; + const res = await this.addTorrent(torrent, torrentOptions); + torrentHash = res.arguments['torrent-added'].hashString; + } if (options.label) { await this.setTorrent(torrentHash, { labels: [options.label] }); diff --git a/test/transmission.spec.ts b/test/transmission.spec.ts index 2eb295e..85f8840 100644 --- a/test/transmission.spec.ts +++ b/test/transmission.spec.ts @@ -50,6 +50,13 @@ describe('Transmission', () => { const res = await client.addMagnet(magnet); expect(res.result).toBe('success'); }); + it('should add normalized magnet link', async () => { + const magnet = + 'magnet:?xt=urn:btih:B0B81206633C42874173D22E564D293DAEFC45E2&dn=Ubuntu+11+10+Alternate+Amd64+Iso&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.open-internet.nl%3A6969%2Fannounce&tr=udp%3A%2F%2Fopen.demonii.si%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Fdenis.stalker.upeer.me%3A6969%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce'; + const client = new Transmission({ baseUrl }); + const res = await client.normalizedAddTorrent(magnet); + expect(res.id).toBeTruthy(); + }); it('should add torrent from file buffer', async () => { const transmission = new Transmission({ baseUrl }); const res = await transmission.addTorrent(fs.readFileSync(torrentFile));