UNPKG

andrade-soulseek-downloader

Version:

Simple, safe Soulseek download library with built-in rate limiting to prevent bans

187 lines 7.24 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.downloadPeerFile = void 0; const net = __importStar(require("net")); const fs = __importStar(require("fs")); const events_1 = require("events"); const message_factory_1 = require("../message-factory"); const stack_1 = __importDefault(require("../stack")); const debug = (msg) => { if (process.env.DEBUG?.includes('slsk:peer:file')) { console.log(`[slsk:peer:file] ${msg}`); } }; const downloadPeerFile = (host, port, token, user, noPierce) => { const emitter = new events_1.EventEmitter(); debug(`downloadPeerFile ${user}`); const conn = net.createConnection({ host, port }, () => { if (noPierce) { debug(`noPierce ${user} connected`); conn.write(message_factory_1.MessageFactory.to.peer .peerInit(stack_1.default.currentLogin, 'F', token) .getBuff()); setTimeout(() => { debug('noPierce sending 8* 00'); if (conn.destroyed) { debug('socket closed'); return; } conn.write(Buffer.from('00000000' + '00000000', 'hex')); }, 1000); } else { conn.write(message_factory_1.MessageFactory.to.peer.pierceFw(token).getBuff()); } }); let received = false; let requestToken = noPierce ? token : undefined; let buf = Buffer.alloc(0); let tok; let down; let i = 0; let writeStream = null; let totalBytesReceived = 0; conn.on('data', data => { if (!noPierce && !received) { requestToken = data.toString('hex', 0, 4); conn.write(Buffer.from('00000000' + '00000000', 'hex')); received = true; } else { debug('file data'); // Get download info if not already fetched if (!tok) { tok = stack_1.default.downloadTokens[requestToken]; if (tok) { down = stack_1.default.download[tok.user + '_' + tok.file]; debug(`Got download info for ${tok.user} - ${tok.file}, size: ${tok.size}`); // Create write stream for progressive writing if (down && down.path && !writeStream) { debug(`Creating write stream for ${down.path}`); writeStream = fs.createWriteStream(down.path); emitter.emit('start', { size: tok.size, file: tok.file }); } } else { debug(`Warning: No download token found for ${requestToken}`); } } // Write data progressively to file if (writeStream) { writeStream.write(data); } // Also buffer data for compatibility buf = Buffer.concat([buf, data]); totalBytesReceived += data.length; // Emit progress event if (tok && tok.size) { const percentage = (totalBytesReceived / tok.size) * 100; if (i % 10 === 0 || percentage >= 100) { debug(`Progress: ${totalBytesReceived}/${tok.size} (${percentage.toFixed(1)}%)`); } emitter.emit('progress', { received: totalBytesReceived, total: tok.size, percentage: percentage }); } if (down && down.stream) { debug('push to stream'); down.stream.push(data); } } if (tok) { if (i % 10 === 0) { debug(`buf: ${buf.length} size: ${tok.size}`); } i++; } if (tok && buf.length >= tok.size) { debug(`disconnect, buf: ${buf.length} size: ${tok.size}`); conn.end(); } }); conn.on('close', () => { debug(`file socket close ${user}`); if (tok && down) { if (down.stream) down.stream.push(null); // Close write stream if used if (writeStream) { writeStream.end(() => { down.buffer = buf; emitter.emit('complete', { path: down.path, size: totalBytesReceived }); if (typeof down.cb === 'function') down.cb(null, down); }); } else { // Fallback to original behavior if no write stream const filePath = down.path || getFilePathName(tok.user, tok.file); fs.writeFile(filePath, buf, () => { down.path = filePath; down.buffer = buf; emitter.emit('complete', { path: filePath, size: totalBytesReceived }); if (typeof down.cb === 'function') down.cb(null, down); }); } } else { fs.writeFile(`${user}-${token}.mp3`, buf, () => { }); debug(`ERROR: token ${token} not exist`); emitter.emit('error', new Error(`Token ${token} not found`)); } }); conn.on('error', (err) => { debug(`file socket error ${user}, destroying`); emitter.emit('error', err); conn.destroy(); }); return emitter; }; exports.downloadPeerFile = downloadPeerFile; function getFilePathName(user, file) { const parts = file.split('\\'); return `/tmp/slsk/${user}_${parts[parts.length - 1]}`; } //# sourceMappingURL=download-peer-file.js.map