# 音搜 **Repository Path**: deepin20/NetMusicPlayer ## Basic Information - **Project Name**: 音搜 - **Description**: 音搜-音乐播放器:一款基于 PyQt5 和 python-vlc 开发的跨平台音乐播放器,专为统信 UOS 优化,支持在线搜索、本地播放、主题切换等丰富功能。 - **Primary Language**: Python - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-22 - **Last Updated**: 2026-10-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 🎵 音搜 **一款基于 PyQt5 和 python-vlc 开发的跨平台音乐播放器,专为统信 UOS 优化,支持在线搜索、本地播放、主题切换等丰富功能。** ![软件截图](https://gitee.com/deepin20/NetMusicPlayer/blob/master/netmusicplayer.png) --- ## ✨ 主要功能 | 功能模块 | 说明 | |---------|------| | **在线搜索** | 通过网易云音乐 API 搜索歌曲、歌手、专辑,支持中文/英文关键词 | | **本地播放** | 支持 `.mp3` / `.flac` / `.wav` / `.m4a` 等常见音频格式 | | **播放列表** | 支持右键删除、清空列表,可添加本地文件或在线歌曲 | | **内嵌歌词** | 主窗口内显示当前歌曲的 LRC 格式歌词(网易云源) | | **播放控制** | 播放/暂停、上一首/下一首、音量调节、进度拖拽 | | **主题切换** | 浅色/深色两套主题 | | **单实例** | 只允许一个播放器进程运行 | | **高 DPI 适配** | 自动适配高分屏,界面清晰 | | **爬虫支持** | 可爬取 33ve 音乐网站歌手和歌曲(实验性) | | **下载管理** | 批量下载歌曲文件,支持暂停/续传 | | **聚合下载后端** | 内置 go-music-dl(music-dl)sidecar:本机代理多源直链解析,自动降级回退自部署 API | > **注**:桌面歌词、播放模式切换(顺序/单曲/随机)、拖拽排序、全局快捷键等功能目前为 **计划中**,将在后续版本中实现。 ### 聚合下载后端(go-music-dl sidecar) 检测到 `music-dl` 可执行文件(`/usr/bin/music-dl` 或项目 `bin/music-dl`,可在设置中手动指定)后, 程序会按需拉起 `music-dl web` 子进程(默认 `127.0.0.1:27183`,端口被占用时自动顺延): - **下载**网易云歌曲时优先走其 `/music/download` 代理(Range 透传,断点续传不受影响); - 代理无法解析(如未配置音源 Cookie)时**自动回退**自部署 NeteaseCloudMusicApi,功能不残废; - 播放地址获取失败时也会尝试代理兜底; - music-dl 的 SQLite/Cookie 数据定向到 `~/.music_search_data/gomusicdl/`,不污染全局配置; - 关闭窗口时子进程随之退出;程序崩溃残留的实例会在下次启动时被复用。 上游项目:guohuiyuan/go-music-dl(AGPL-3.0,独立进程原样调用,未修改其源码)。 上游源码随项目存放于 `third_party/go-music-dl/`(快照,无 .git;`build/` 编译缓存未纳入)。 可执行文件优先级:设置指定路径 > `/usr/bin/music-dl` > 项目 `bin/music-dl`(随包副本,已就位)。 --- ## 📱 Android 客户端 仓库里的 `android/` 是一份独立的 Jetpack Compose 客户端(`cn.tuxnav.yinsou`), 与桌面版**共用同一套音源定义与交互约定**,但不是同一份代码: | 能力 | 说明 | |------|------| | **内置网易源** | 免登录公开接口,装上就能搜歌、看歌词、播无版权限制的曲目(实验性) | | **自建服务** | 设置里填电脑/NAS 上 music-dl Web 版地址,解锁聚合搜索、排行榜、每日推荐 | | **后台播放** | Media3 `MediaSessionService`:通知栏、锁屏、蓝牙耳机按键、音频焦点 | | **逐字歌词** | 主屏滚动歌词 + 可拖动的**悬浮歌词**(需要「显示在其他应用上层」权限) | | **批量下载** | SAF 目录授权,把歌单/榜单整批存成 mp3,不申请存储权限 | | **本地音乐** | 读系统媒体库,下载下来的歌直接能播 | | **收藏 / 最近** | 本地持久化,与桌面版同为「收藏 + 最近」两栏 | 播放模式(顺序 / 单曲 / 随机)取值与桌面版一一对应,配置里写的是同一组数字。 构建方式见 [`android/README.md`](android/README.md)。 --- ## 🚀 快速开始 ### 环境要求 - 统信 UOS 20+ / Deepin 20+ / Ubuntu 18.04+ - Python 3.7+ - VLC 媒体播放器(用于音频解码) ### 安装步骤 1. **安装系统依赖**(如果使用系统包): ```bash sudo apt update sudo apt install vlc python3-pyqt5 python3-vlc python3-requests ``` 2. **下载软件包**: - 从官方仓库或发布页下载 `.deb` 安装包(或直接运行源码)。 - 解压后进入目录:`cd NetMusicPlayer1.2/opt/apps/com.yourcompany.netmusicplayer/files/bin` 3. **启动 API 服务**(首次使用): ```bash cd /path/to/NeteaseCloudMusicApi node app.js & ``` 建议使用 `systemd` 或 `pm2` 设置为开机自启。 4. **运行程序**: ```bash python3 main.py ``` ### 首次配置 - 默认 API 地址为 `http://localhost:3000`(自部署服务)。如果使用公共代理,可在“工具”→“设置 API 地址”中修改。 - 如无法搜索或播放,请检查 API 服务是否运行。 --- ## 🎮 使用指南 ### 搜索与播放 1. 在顶部搜索框输入歌曲名、歌手或专辑。 2. 点击 **“搜索”** 按钮,下方列表显示结果。 3. 双击任意歌曲即可播放。 4. 也可点击 **“明星”** 按钮,从预置列表中选择歌手一键搜索(需先切换到 33ve 源)。 ### 播放控制 - **底部控制栏**:上一首、播放/暂停、下一首、音量滑块。 - **播放列表**:双击播放列表中的歌曲直接播放;右键菜单可删除选中或清空列表。 - **播放模式**:当前仅支持顺序播放,循环/随机模式计划中。 ### 歌词显示 - **内嵌歌词**:播放歌曲时自动从网络获取 LRC 歌词,显示在主窗口中部。 - **桌面歌词**:目前为占位按钮,独立悬浮窗口功能计划中。 ### 本地文件播放 - 点击“文件”→“打开本地文件”,选择音频文件后自动添加到播放列表并播放。 ### 主题与视图 - **切换主题**:“视图”→“主题”→浅色/深色。 - **显示/隐藏组件**:“视图”菜单中可控制播放列表和内嵌歌词的显示/隐藏。 ### 自定义 API 地址 - 若自行部署了 NeteaseCloudMusicApi,可在“工具”→“设置 API 地址”中填写 `http://your-server:port`。 --- ## ⌨️ 快捷键 当前支持控件点击操作,全局快捷键(空格、方向键等)为计划中功能。 --- ## 🐛 常见问题 ### 1. 搜索无结果或提示“网络连接错误” - **原因**:API 服务未启动或地址错误。 - **解决**:启动本地 API(`node app.js &`),或在“工具”中修改 API 地址为 `http://localhost:3000`。 ### 2. 无法播放某些歌曲(无声音或报错) - **原因**:部分歌曲版权限制或 API 返回的 URL 无效。 - **解决**:尝试播放其他歌曲;自部署最新版 NeteaseCloudMusicApi 可提高成功率。 ### 3. 搜索框打不出中文 / 中文关键词搜不到 - **原因**:Qt 程序能不能打中文,取决于「运行时的 Qt 版本」和「输入法前端插件的 Qt 版本」是否一致。 例如 pip 安装的 PyQt5 自带 Qt 5.15,而系统里的 fcitx 前端(`libfcitxplatforminputcontextplugin.so`) 是按系统 Qt 5.11 编译的 —— 两者版本不一致时,插件要么加载不上(打不出中文), 要么强行加载后 Qt 直接报 `Cannot mix incompatible Qt library (5.11.3) with this library (5.15.19)` 并崩溃。 - **解决**:程序启动时会自动比对版本并处理(见 `common/im_env.py`): 若当前 PyQt5 与系统输入法前端版本不匹配,会自动把 `PyQt5`/`sip` 定向切换到 deb 依赖的那份系统 PyQt5(只动这两个包,不影响 requests / vlc 等依赖), 并设置好 `QT_IM_MODULE` / `XMODIFIERS`。 自查命令: ```bash python3 main.py --check-ime ``` 输出里会写明运行时 Qt 版本、检测到的输入法前端及其 Qt 版本、最终选用的 `QT_IM_MODULE`。 如果显示「没有与运行时 Qt 兼容的输入法前端」,按提示安装对应前端包 (如 `sudo apt install fcitx-frontend-qt5`)。 - **补充**:另外两点也已处理 —— 输入法组合中按回车不会被当成「搜索」提前触发; 关键词里的全角空格(`U+3000`)、全角字母数字和零宽字符会自动规范化。 - **临时关闭自动配置**:`export NETMUSICPLAYER_NO_IME=1` ### 4. 点击歌手后提示「爬取失败: No module named 'cloudscraper'」或「获取 0 首歌曲」 - **原因**:这个现象背后叠了三层问题,任何一层没处理都拿不到数据: 1. **依赖缺失**:`cloudscraper` 以前既没装在环境里、也没写进 `requirements.txt`, 导入爬虫模块时直接抛 `ModuleNotFoundError`;同类漏装的还有 `fake-useragent`、`tqdm`。 2. **站点加了人机验证**:33ve 在页面之前插了一层「安全人机验证」(带 `csrf_token` 的复选框表单)。 它**不是 Cloudflare**,没有 JS 挑战,所以 cloudscraper 的绕过能力对它完全无效; 真正需要的是「同一个 Session 先 GET 拿 token、再 POST 提交」。 3. **解析函数是空实现**:`crawler/crawl_songs.py` 里的 `parse_songs_from_singer_page()` 与 `find_max_page_for_singer()` 原本只有占位注释和 `return 1`,即使前两层都过了也只会返回 0 首。 - **解决**:三点已一并修复,并新增 `crawler/site_session.py` 作为统一会话网关: - 自动识别并提交人机验证,验证状态按 Cookie 缓存(约 1 小时),后续点击不再重复验证; - cloudscraper 缺失时自动降级为 `requests.Session`,不会再让 `ModuleNotFoundError` 冒到状态栏; - 分页改为「逐页抓取 + 遇到空页即停 + 按 id 去重」(站点分页区会显示比实际更大的页码,不可信); - 爬取结果自动并入本地歌曲库(`~/.music_search_data/songs_33ve.json`), 否则爬到的歌只在当次列表里,回到搜索框依然搜不到; - 只有真抓到歌曲才写 `last_crawl`,避免一次失败在 28 天缓存期内被当成「已爬过」而永久跳过。 - **装依赖**: ```bash pip3 install --user -r requirements.txt ``` ### 5. 歌曲能列出来,但点播放没声音 / 提示「无法获取播放地址」 - **原因**:库里存的是下载入口 `https://www.33ve.com/plug/down.php?ac=music&id=...`。 该入口同样受人机验证保护——裸请求返回 **403**;通过验证后才会 **302** 跳到酷狗的真实音频直链 (`sharefs.tx.kugou.com/...`)。直接把入口 URL 交给 VLC 是拿不到声音的。 - **解决**:播放/下载前会用已验证的会话实时换取直链(见 `CrawlerSource.resolve_play_url()`)。 目标直链带时效签名、数小时后失效,因此只用于播放、不写回数据库;但会做 **5 分钟**的短时复用 (见 `CrawlerSource.DIRECT_URL_TTL_SECONDS`),暂停后继续、切回上一首都不会再请求站点。 ### 5b. 提示「站点下载次数已达上限,请稍后重试」 - **原因**:33ve 对 `down.php` 有**按 IP 的下载限次**。实测(2026-09-22): - 连续解析 **3~4 条不同歌曲**就会触发; - 超限时站点**不返回 403/429**,而是回 **HTTP 200 + 一段 JS**: `alert('您的下载次数已用完!')` —— 只看状态码完全识别不出来; - 限次按 **IP** 计,与 Cookie 无关(清空 Cookie 换新会话照样被拦); - 恢复窗口**很长且反复请求会续期**:连续探测 8 分钟仍未恢复, 完全静默约 13 分钟后才解除。 - **解决**: - 程序会准确识别这类页面(`site_session.is_quota_page()`)并单独上报 `DownloadQuotaExceeded`,提示你「稍后重试」——而不再是一句与真实原因无关的 「无法获取播放地址」; - 判定顺序上**配额优先于 403**,避免被当成「未验证」白跑一轮验证; - 配合上面的 5 分钟直链复用,重复播放不会消耗配额。 - **建议**:出现该提示后**停手十几分钟**再试(实测:静默 7 分钟仍被限, 且限次只锁 `down.php` 这一个接口——同一时间站点首页仍可正常访问,说明不是整站封 IP)。 越是反复点击,恢复得越慢。 ### 6. 桌面歌词窗口关闭后无法再打开 - **说明**:桌面歌词功能尚未实现,此按钮仅为预留占位。 ### 7. 单实例检测导致无法启动第二个窗口 - **说明**:本程序设计为单实例,如需多开,请注释 `main.py` 中的 `single_instance_check()` 调用。 ### 8. 高 DPI 下界面文字模糊 - **解决**:`main.py` 已启用高 DPI 支持 (`AA_EnableHighDpiScaling`)。如果仍模糊,请调整系统缩放设置。 --- ## 🛠️ 开发者信息 - **编程语言**:Python 3 - **GUI 框架**:PyQt5 - **音频后端**:python-vlc (VLC media player) - **音乐 API**:Binaryify/NeteaseCloudMusicApi - **开源协议**:GPL-3.0 - **作者**:温暖断章 - **联系方式**:`1802272181@.com`(请替换为真实邮箱) --- ## 📦 打包与发布 本软件遵循统信 UOS 应用打包规范,目录结构如下: ``` /opt/apps/com.yourcompany.netmusicplayer/ ├── info ├── entries/ │ ├── applications/ │ └── icons/ └── files/bin/ ├── main.py ├── ui_main.py ├── player.py ├── api.py ├── lyric_window.py ├── widget_playlist.py └── utils.py ``` 构建 `.deb` 包命令: ```bash dpkg-deb --build netmusicplayer-package ``` --- ## 📄 许可证 本程序是自由软件,遵循 GNU 通用公共许可证第 3 版(GPL-3.0)。您可以自由使用、修改和分发,但必须保留版权声明和许可证声明。 --- **感谢使用 UOS 网络音乐播放器!** 如有问题或建议,请通过“帮助”→“反馈问题”联系我们。 --- ## 🔒 安全提示 ### 代理使用风险 - 本项目默认**禁用**代理功能(`CRAWLER_ENABLE_PROXY = False`)。 - 如手动启用代理,请务必使用**可信的代理服务器**,避免使用来源不明的公共代理。 - 公共代理可能记录您的请求数据,存在隐私泄露风险;同时可能违反目标网站的服务条款。 ### 缓存隐私 - 程序会在 `~/.music_search_data/` 目录下缓存搜索记录和爬取信息(如 `crawl_cache.json`)。 - 这些缓存文件**未加密**,包含您的搜索历史,请妥善保管。 - 您可以通过“设置”→“清理过期缓存”定期清理,或手动删除缓存目录。 ### 法律免责 - 本程序仅供学习研究使用,请勿用于商业用途。 - 用户应遵守相关法律法规及目标网站的服务条款,并自行承担使用风险。