download_c411_torrent
Download .torrent files from c411.org using infoHash and save them to a specified directory for torrent management.
Instructions
Download a .torrent file from c411.org by its infoHash and save it to disk.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| infoHash | Yes | The 40-character hex infoHash of the torrent | |
| outputDir | No | Directory where the .torrent file should be saved. Defaults to /tmp. |
Output Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| error | No | ||
| success | Yes | ||
| filename | No | ||
| savedPath | No |
Implementation Reference
- src/c411-client.ts:428-517 (handler)The `downloadTorrent` method in `C411Client` handles the actual logic for downloading a .torrent file from the c411 API and saving it to the specified output directory.
async downloadTorrent(infoHash: string, outputDir = '/tmp'): Promise<DownloadResult> { if (!infoHash || !/^[a-fA-F0-9]{40}$/.test(infoHash)) { return { success: false, error: 'Invalid infoHash. Must be a 40-character hex string.' }; } try { return await this.withAuthentication<DownloadResult>(async () => { const response = await this.client.get<ArrayBuffer>(`/api/torrents/${infoHash}/download`, { responseType: 'arraybuffer', headers: { 'Accept': 'application/x-bittorrent, application/octet-stream, */*', 'Referer': `${this.baseUrl}/torrents/${infoHash}`, }, }); const contentType = getContentType(response.headers as Record<string, unknown>); const responseUrl = getResponseUrl(response.request); if (isMaintenanceResponse(response.status, response.data, contentType)) { throw new MaintenanceError(); } if (isAuthenticationFailureResponse(response.status, response.data, contentType, responseUrl)) { return { type: 'reauth' }; } if (response.status === 404) { return { type: 'success', value: { success: false, error: 'Torrent not found.' } }; } if (response.status >= 400) { const errorMessage = getErrorMessageFromResponse( response.data, contentType ) || `HTTP ${response.status}`; return { type: 'success', value: { success: false, error: `Download failed - ${errorMessage}` } }; } const buffer = Buffer.isBuffer(response.data) ? response.data : Buffer.from(response.data); if (!this.isValidTorrentFile(buffer)) { const errorMessage = getErrorMessageFromResponse(response.data, contentType); const responseDescription = errorMessage ? `Unexpected download response: ${errorMessage}` : `Unexpected download response with content type ${contentType ?? 'unknown'}`; return { type: 'success', value: { success: false, error: `${responseDescription}. The payload does not look like a valid .torrent file.`, }, }; } const contentDisposition = typeof response.headers['content-disposition'] === 'string' ? response.headers['content-disposition'] : undefined; let filename = `${infoHash}.torrent`; if (contentDisposition) { const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (match && match[1]) { filename = match[1].replace(/['"]/g, '').trim(); } } const safeFilename = path.basename(filename) || `${infoHash}.torrent`; const resolvedOutputDir = path.resolve(outputDir); const savedPath = path.join(resolvedOutputDir, safeFilename); await mkdir(resolvedOutputDir, { recursive: true }); await writeFile(savedPath, buffer); return { type: 'success', value: { success: true, filename: safeFilename, savedPath, }, }; }, 'Unable to authenticate. Check C411_USERNAME and C411_PASSWORD environment variables.'); } catch (error) { const message = getSafeErrorMessage(error, this.requestTimeoutMs); console.error(`Error downloading torrent: ${message}`); return { success: false, error: message }; } } - src/register-tools.ts:33-51 (registration)Registration of the 'download_c411_torrent' tool, which maps the MCP tool request to the `client.downloadTorrent` implementation.
server.registerTool('download_c411_torrent', { description: 'Download a .torrent file from c411.org by its infoHash and save it to disk.', inputSchema: downloadToolSchema, outputSchema: downloadToolOutputSchema, }, async (args) => { const result = await client.downloadTorrent(args.infoHash, args.outputDir ?? '/tmp'); return result.success ? textWithStructuredContent(result.savedPath || `Saved ${result.filename}`, { success: true, filename: result.filename || `${args.infoHash}.torrent`, savedPath: result.savedPath || `Saved ${result.filename}`, }) : errorContent(result.error || 'Download failed', { success: false, ...(result.filename ? { filename: result.filename } : {}), ...(result.savedPath ? { savedPath: result.savedPath } : {}), error: result.error || 'Download failed', }); });