UNPKG

netease-music-downloader

Version:
181 lines (180 loc) 8.55 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.downloadSong = downloadSong; const axios_1 = __importDefault(require("axios")); const fs = __importStar(require("fs")); const netease_1 = require("../services/netease"); const proxy_1 = require("../services/proxy"); const file_1 = require("../utils/file"); const progress_1 = require("../utils/progress"); async function downloadImage(url) { try { const response = await (0, axios_1.default)({ method: 'get', url, responseType: 'arraybuffer' }); return Buffer.from(response.data); } catch (error) { console.error('下载封面图片失败 Failed to download cover image:', error instanceof Error ? error.message : 'Unknown error'); return null; } } async function downloadSong(id, progressBar, options) { const MAX_STALL_TIME = 10000; // 10 seconds const MAX_RETRIES = 3; let retryCount = 0; async function attemptDownload() { try { let song; try { song = await (0, netease_1.getSongInfo)(id); } catch (error) { console.error(`\n获取歌曲信息失败,跳过下载 Failed to get song info, skipping download (ID: ${id})`); return false; } const songName = song.name; const artistName = song.artists?.[0]?.name || '未知歌手 Unknown Artist'; console.log(`\n歌曲信息 Song info: ${artistName}-${songName}`); const availability = await (0, netease_1.checkSongAvailabilityWithRetry)(id, options?.autoProxy); if (!availability.available || !availability.url) { console.log(`歌曲已下架或无版权,跳过下载\nSong is unavailable or no copyright, skipping download`); return false; } // 获取文件格式 const fileExtension = availability.type || availability.url.split('.').pop()?.split('?')[0] || 'mp3'; console.log(`获取到音质 Quality: ${availability.quality || 'unknown'}, 比特率 Bitrate: ${availability.bitrate || 'unknown'}kbps, 格式 Format: ${fileExtension}`); const sanitizedSongName = (0, file_1.sanitizeFileName)(songName); const sanitizedArtistName = (0, file_1.sanitizeFileName)(artistName); const fileName = `${sanitizedArtistName}-${sanitizedSongName}.${fileExtension}`; const filePath = (0, file_1.getDownloadPath)('single', fileName); const lrcPath = (0, file_1.getDownloadPath)('single', `${sanitizedArtistName}-${sanitizedSongName}.lrc`); // 下载歌词 const lyrics = await (0, netease_1.getLyrics)(id); if (lyrics) { fs.writeFileSync(lrcPath, lyrics, 'utf8'); console.log('歌词下载完成 Lyrics downloaded'); console.log('网页链接 Web URL:', `https://music.163.com/#/song?id=${id}`); } if (fs.existsSync(filePath)) { console.log(`文件已存在,跳过下载 File exists, skipping download: ${fileName}`); return true; } console.log(`开始下载 Start downloading: ${artistName}-${songName}`); const response = await (0, axios_1.default)({ method: 'get', url: availability.url, responseType: 'stream', ...(availability.needProxy ? netease_1.proxyConfig : {}) }); const totalLength = parseInt(response.headers['content-length'], 10); const bar = (0, progress_1.createSingleBar)(); bar.start(Math.round(totalLength / 1024), 0); const writer = fs.createWriteStream(filePath); let downloadedBytes = 0; let lastProgressTime = Date.now(); response.data.on('data', (chunk) => { downloadedBytes += chunk.length; bar.update(Math.round(downloadedBytes / 1024)); lastProgressTime = Date.now(); }); response.data.pipe(writer); return new Promise((resolve, reject) => { const checkProgress = setInterval(() => { if (Date.now() - lastProgressTime > MAX_STALL_TIME) { clearInterval(checkProgress); writer.end(); writer.on('close', () => { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); // 删除未完成的文件 } bar.stop(); console.log('\n下载停滞,准备重试 Download stalled, preparing to retry...'); resolve(false); }); } }, 1000); writer.on('finish', async () => { clearInterval(checkProgress); bar.stop(); if (downloadedBytes >= totalLength * 0.99) { // 允许1%的误差 console.log(`\n下载完成 Download completed: ${fileName}`); resolve(true); } else { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); // 删除不完整的文件 } console.log('\n下载不完整,准备重试 Incomplete download, preparing to retry...'); resolve(false); } }); writer.on('error', (error) => { clearInterval(checkProgress); bar.stop(); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); // 删除错误的文件 } console.error('\n下载出错,准备重试 Download error, preparing to retry:', error.message); resolve(false); }); }); } catch (error) { console.error('\n下载出错,准备重试 Download error, preparing to retry:', error instanceof Error ? error.message : 'Unknown error'); return false; } } while (retryCount < MAX_RETRIES) { const success = await attemptDownload(); if (success) return; retryCount++; if (retryCount < MAX_RETRIES) { console.log(`\n第 ${retryCount}/${MAX_RETRIES} 次重试 Retry ${retryCount}/${MAX_RETRIES}`); if (options?.autoProxy) { console.log('重新获取代理列表 Updating proxy list...'); await (0, proxy_1.getAutoProxy)(true); // 强制更新代理列表 } } } console.error('\n达到最大重试次数,下载失败 Maximum retries reached, download failed'); }