# -*- coding: utf-8 -*- """命令行入口(python -m music_downloader)。""" from __future__ import annotations import asyncio import sys from dataclasses import asdict from .downloader import ( MusicDownloader, ) from .models import ( DownloadException, ) # ============ CLI 入口 ============ def _print_usage() -> None: """无参数时打印模块信息与用法。""" print("网易云音乐下载器") print("支持的音质: standard / exhigh / lossless / hires / sky / jyeffect / jymaster / dolby") print("支持的功能: 单曲/批量下载、标签与封面写入(mutagen 纯 Python)") print() print("用法:") print(" python -m music_downloader [quality] # 仅打印信息") print(" python -m music_downloader [quality] --download # 打印并下载") print() print("示例:") print(" python -m music_downloader 123456") print(" python -m music_downloader 123456 lossless") print(" python -m music_downloader 123456 hires --download") async def _main(argv: list[str]) -> int: """CLI 主体(下载链路是协程,故整体在 asyncio.run 里跑)。返回进程退出码。""" downloader = MusicDownloader() if len(argv) < 2: _print_usage() return 0 try: music_id = int(argv[1]) except ValueError: print(f"错误: music_id 必须是整数,收到: {argv[1]!r}") return 1 quality = argv[2] if len(argv) > 2 and not argv[2].startswith("--") else "lossless" do_download = "--download" in argv try: info = await downloader.get_music_info(music_id, quality) except DownloadException as e: print(f"获取音乐信息失败: {e}") return 1 print() print("=" * 70) print(f"音乐信息 (ID={info.id}, quality={info.quality})") print("=" * 70) info_dict = asdict(info) for key, value in info_dict.items(): # 歌词太长,只显示行数 if key in ("lyric", "tlyric"): lines = [ln for ln in (value or "").splitlines() if ln.strip()] preview = " | ".join(lines[:2])[:80] if lines else "(空)" print(f" {key:<14}: {len(lines)} 行 预览: {preview}{'...' if len(lines) > 2 else ''}") continue # URL 类字段:完整展示(如果终端窄可换行) if key in ("download_url", "pic_url"): print(f" {key:<14}: {value}") continue print(f" {key:<14}: {value}") print("=" * 70) if do_download: print() print("开始下载...") result = await downloader.download_music_file(music_id, quality) if result.success: print(f"下载完成: {result.file_path} ({result.file_size} 字节)") else: print(f"下载失败: {result.error_message}") return 1 return 0 if __name__ == "__main__": sys.exit(asyncio.run(_main(sys.argv)))