UNPKG

andrade-soulseek-downloader

Version:

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

147 lines 4.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Track = void 0; /** * Domain entity representing a music track available on Soulseek. * Encapsulates track metadata and quality scoring business logic. */ class Track { id; artist; title; bitrate; fileSize; filePath; user; slots; speed; matchScore; /** * Creates a new Track entity. * @param id - Unique identifier for the track * @param artist - Artist name * @param title - Track title * @param bitrate - Audio bitrate value object * @param fileSize - File size in bytes * @param filePath - Path to file on remote user's system * @param user - Soulseek username of the file owner * @param slots - Whether user has available download slots * @param speed - User's upload speed in bytes/second * @param matchScore - Search relevance score (0-1) * @throws {Error} If validation fails */ constructor(id, artist, title, bitrate, fileSize, filePath, user, slots, speed, matchScore) { this.id = id; this.artist = artist; this.title = title; this.bitrate = bitrate; this.fileSize = fileSize; this.filePath = filePath; this.user = user; this.slots = slots; this.speed = speed; this.matchScore = matchScore; this.validateTrack(); } /** Validates track invariants */ validateTrack() { if (!this.artist || !this.title) { throw new Error('Track must have artist and title'); } if (this.fileSize <= 0) { throw new Error('File size must be positive'); } if (this.matchScore < 0 || this.matchScore > 1) { throw new Error('Match score must be between 0 and 1'); } } /** @returns Track unique identifier */ getId() { return this.id; } /** @returns Artist name */ getArtist() { return this.artist; } /** @returns Track title */ getTitle() { return this.title; } /** @returns Bitrate value object */ getBitrate() { return this.bitrate; } /** @returns File size in bytes */ getFileSize() { return this.fileSize; } /** @returns Remote file path */ getFilePath() { return this.filePath; } /** @returns Soulseek username */ getUser() { return this.user; } /** @returns Whether user has download slots available */ hasAvailableSlots() { return this.slots; } /** @returns Upload speed in bytes/second */ getSpeed() { return this.speed; } /** @returns Search relevance score (0-1) */ getMatchScore() { return this.matchScore; } /** * Calculates quality score based on bitrate, availability, speed, and match. * Core business logic for track prioritization. * @returns Quality score from 0-100 (higher is better) */ calculateQualityScore() { let score = 0; // Bitrate is the most important (50 points) score += this.bitrate.toQualityPoints(); // Slot availability (25 points) if (this.slots) { score += 25; } // Connection speed (15 points) const speedScore = Math.min(15, (this.speed / 5000000) * 15); score += speedScore; // Match accuracy (10 points) score += this.matchScore * 10; return score; } /** * Compares quality against another track. * @param other - Track to compare against * @returns True if this track has higher quality score */ isBetterThan(other) { return this.calculateQualityScore() > other.calculateQualityScore(); } /** * Serializes track to JSON representation. * @returns Plain object with all track properties */ toJSON() { return { id: this.id.getValue(), artist: this.artist, title: this.title, bitrate: this.bitrate.getValue(), fileSize: this.fileSize, filePath: this.filePath, user: this.user, slots: this.slots, speed: this.speed, matchScore: this.matchScore, qualityScore: this.calculateQualityScore() }; } } exports.Track = Track; //# sourceMappingURL=track.js.map