Compare commits

...

42 Commits

Author SHA1 Message Date
sqj
3bb23e4765 updateVersion 2025-08-28 14:41:22 +08:00
sqj
5af7df60e4 fix:歌曲暂停时无法过渡音量的bug 2025-08-28 14:40:30 +08:00
sqj
4280cab090 fix:docs 2025-08-28 13:28:55 +08:00
sqj
7e1111cd33 fix:docs 2025-08-28 05:11:52 +08:00
sqj
194b88519f fix:docs 2025-08-28 04:55:13 +08:00
sqj
7d20b23fb0 fix:docs 2025-08-28 04:20:04 +08:00
sqj
909547ad2e fix:docs 2025-08-28 04:16:38 +08:00
sqj
9779e38140 fix:docs 2025-08-28 03:37:46 +08:00
sqj
0021f32a19 fix:修复因为节流导致软件在后台无法自动切歌的bug 2025-08-28 03:32:25 +08:00
sqj
4784f63ca0 docs 2025-08-28 01:25:43 +08:00
sqj
fb007eaa9c docs 2025-08-28 01:19:51 +08:00
sqj
790530b71f docs 2025-08-28 01:02:31 +08:00
sqj
49bd1c66c0 docs 2025-08-28 00:54:57 +08:00
sqj
1f6dd81e78 docs 2025-08-28 00:53:28 +08:00
sqj
faaf904e9f docs 2025-08-28 00:50:21 +08:00
sqj
faac6273bb docs 2025-08-28 00:47:59 +08:00
sqj
07a9c515a2 docs 2025-08-28 00:34:07 +08:00
sqj
179ff34063 fix(Readme):优化相关声明 2025-08-27 18:27:24 +08:00
sqj
3aff332758 website 2025-08-27 15:01:27 +08:00
sqj
d2b1d69929 new 2025-08-27 14:53:03 +08:00
sqj
67430a25a3 应用更新检测 2025-08-27 14:36:50 +08:00
sqj
7f971f0256 应用更新检测 2025-08-27 14:22:27 +08:00
sqj
a7d4d877a9 website 2025-08-27 14:12:48 +08:00
sqj
0c349bd4d5 website 2025-08-27 14:08:49 +08:00
sqj
a8f7c620d0 website 2025-08-27 14:01:48 +08:00
sqj
8077138609 fix workflow 2025-08-27 13:56:14 +08:00
sqj
9deb6a937b feat:应用更新检测 2025-08-27 13:29:49 +08:00
sqj
1259a6d70d feat:使用文档 2025-08-26 22:20:56 +08:00
sqj
14496d5d0b add(website):更新发布页 2025-08-26 20:01:22 +08:00
sqj
5f042e15eb add(website):更新发布页 2025-08-26 19:52:47 +08:00
sqj
6945c733e9 add(website):更新发布页 2025-08-26 19:32:58 +08:00
sqj
eea157b8d6 fix:gitignore 2025-08-26 18:44:11 +08:00
sqj
0c22eaa212 fix:gitignore 2025-08-26 18:42:28 +08:00
sqj
44542c4d29 feat:updata v1.0.9 2025-08-26 18:38:47 +08:00
sqj
2e398b7874 fix(search,musicSdk):修复下载功能,支持缓存下载&add(setting):支持歌曲缓存支持清除缓存 2025-08-26 18:28:02 +08:00
sqj
d0cd96e1df fix(search,musicSdk):修复下载功能,支持缓存下载&add(setting):支持歌曲缓存支持清除缓存 2025-08-26 18:23:20 +08:00
sqj
89b085381e fix:修复播放列表导入问题 2025-08-25 19:37:16 +08:00
sqj
9830e51fa0 add: 添加了首页热门歌单&支持多平台歌词 2025-08-25 19:04:57 +08:00
sqj
400c97fc31 feat: main.yml 2025-08-22 16:24:26 +08:00
时迁酱
c168e42c8d Update main.yml 2025-08-22 16:14:51 +08:00
时迁酱
e6ea6b11f3 Update main.yml 2025-08-22 16:06:59 +08:00
时迁酱
046ac4edb6 Create main.yml 2025-08-22 15:52:16 +08:00
173 changed files with 15734 additions and 8738 deletions

View File

@@ -1,29 +0,0 @@
{
"title": "音频播放器控件功能完善",
"features": [
"播放列表管理(添加/删除/排序)",
"音量调节控件",
"多种播放模式(顺序/随机/单曲循环)",
"播放列表导出/导入功能",
"播放列表一键清空功能"
],
"tech": { "Web": { "arch": "vue", "component": "tdesign" } },
"design": "现代简约风格深色背景配合高对比度控件主色调为TDesign主题蓝(#0052D9),包含固定底部播放控制区、垂直弹出式音量控制、图标式播放模式选择器和可拖拽排序的播放列表侧边栏。新增导出/导入功能使用TDesign对话框组件提供文件导出/导入和内容复制/粘贴两种方式,所有导出内容进行加密处理。清空功能添加二次确认对话框防止误操作。",
"plan": {
"扩展Pinia状态管理在ControlAudioStore中添加音量控制、播放模式和播放列表相关状态": "holding",
"创建VolumeControl.vue组件实现音量调节滑动条和静音按钮功能": "holding",
"创建PlayModeSelector.vue组件实现三种播放模式的切换功能": "holding",
"创建PlaylistManager.vue组件实现播放列表的基本显示功能": "holding",
"在PlaylistManager组件中实现添加和删除曲目功能": "holding",
"集成拖拽排序功能到PlaylistManager组件": "holding",
"将新组件集成到主播放器界面,调整布局确保合理性": "holding",
"实现播放列表与音频控制的联动,确保播放状态正确反映": "holding",
"添加键盘快捷键支持和状态反馈机制": "holding",
"进行组件间通信测试,确保功能协调工作": "holding",
"创建播放列表加密/解密工具函数": "holding",
"实现播放列表导出功能(文件导出和内容复制)": "holding",
"实现播放列表导入功能(文件导入和内容粘贴)": "holding",
"实现播放列表一键清空功能及二次确认机制": "holding",
"测试导出/导入功能的加密解密正确性": "holding"
}
}

66
.github/workflows/deploydocs.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
# 构建 VitePress 站点并将其部署到 GitHub Pages 的示例工作流程
#
name: Deploy VitePress site to Pages
on:
# 在针对 `main` 分支的推送上运行。如果你
# 使用 `master` 分支作为默认分支,请将其更改为 `master`
push:
branches: [main]
# 允许你从 Actions 选项卡手动运行此工作流程
workflow_dispatch:
# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列
# 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成
concurrency:
group: pages
cancel-in-progress: false
jobs:
# 构建工作
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # 如果未启用 lastUpdated则不需要
- uses: pnpm/action-setup@v3 # 如果使用 pnpm请取消此区域注释
with:
version: 9
# - uses: oven-sh/setup-bun@v1 # 如果使用 Bun请取消注释
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm # 或 pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Install dependencies
run: pnpm add -D vitepress@next # 或 pnpm install / yarn install / bun install
- name: Build with VitePress
run: pnpm run docs:build # 或 pnpm docs:build / yarn docs:build / bun run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist
# 部署工作
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

72
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
name: AutoBuild # 工作流的名称
permissions:
contents: write # 给予写入仓库内容的权限
on:
push:
tags:
- 'v*' # 当推送以v开头的标签时触发此工作流
workflow_dispatch:
jobs:
release:
name: build and release electron app # 任务名称
runs-on: ${{ matrix.os }} # 在matrix.os定义的操作系统上运行
strategy:
fail-fast: false # 如果一个任务失败,其他任务继续运行
matrix:
os: [windows-latest, macos-latest, ubuntu-latest] # 在Windows和macOS上运行任务
steps:
- name: Check out git repository
uses: actions/checkout@v4 # 检出代码仓库
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22 # 安装Node.js 22 这里node环境是能够运行代码的环境
- name: Install Dependencies
run: |
npm i -g yarn
yarn install # 安装项目依赖
- name: Build Electron App for windows
if: matrix.os == 'windows-latest' # 只在Windows上运行
run: yarn run build:win # 构建Windows版应用
- name: Build Electron App for macos
if: matrix.os == 'macos-latest' # 只在macOS上运行
run: |
yarn run build:mac
- name: Build Electron App for linux
if: matrix.os == 'ubuntu-latest' # 只在Linux上运行
run: yarn run build:linux # 构建Linux版应用
- name: Cleanup Artifacts for Windows
if: matrix.os == 'windows-latest'
run: |
npx del-cli "dist/*" "!dist/*.exe" "!dist/*.zip" "!dist/*.yml" # 清理Windows构建产物,只保留特定文件
- name: Cleanup Artifacts for MacOS
if: matrix.os == 'macos-latest'
run: |
npx del-cli "dist/*" "!dist/(*.dmg|*.zip|latest*.yml)" # 清理macOS构建产物,只保留特定文件
- name: Cleanup Artifacts for Linux
if: matrix.os == 'ubuntu-latest'
run: |
npx del-cli "dist/*" "!dist/(*.AppImage|*.deb|*.snap|latest*.yml)" # 清理Linux构建产物,只保留特定文件
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}
path: dist # 上传构建产物作为工作流artifact
- name: release
uses: softprops/action-gh-release@v1
with:
files: 'dist/**' # 将dist目录下所有文件添加到release

8
.gitignore vendored
View File

@@ -10,3 +10,11 @@ build
/download/
/plugin/
/plugins/
temp
temp/log.txt
/.kiro/
/.vscode/
/.codebuddy/
/.idea/
docs/.vitepress/dist
docs/.vitepress/cache

View File

@@ -1,22 +0,0 @@
# 语言设置
## 对话语言
- **主要语言**: 中文(简体中文)
- 与用户对话时请使用中文回复
- 代码注释和文档也应该使用中文
- 变量名和函数名仍使用英文(遵循编程规范)
## 代码规范
- 代码本身使用英文命名
- 注释使用中文说明
- 错误信息和用户界面文本使用中文
- README和文档文件使用中文编写
## 示例
```typescript
// 播放音乐的函数
function playMusic(songId: string): void {
// 开始播放指定的歌曲
console.log('正在播放音乐...')
}
```

View File

@@ -1,16 +0,0 @@
# Product Overview
**Ceru Music** is a free music application built as an Electron desktop app. It provides a cross-platform music experience for Windows, macOS, and Linux users.
## Key Features
- Desktop music player application
- Cross-platform compatibility (Windows, macOS, Linux)
- Modern UI built with Vue.js and TDesign components
- Auto-updating capabilities via electron-updater
## Target Platforms
- Windows (primary build target)
- macOS
- Linux
The application follows Electron's multi-process architecture with separate main, renderer, and preload processes for security and performance.

View File

@@ -1,55 +0,0 @@
# Project Structure
## Root Level Organization
```
├── src/ # Source code
├── resources/ # App resources (icons, etc.)
├── build/ # Build artifacts
├── out/ # Compiled output
└── node_modules/ # Dependencies
```
## Source Code Architecture (`src/`)
### Electron Multi-Process Structure
```
src/
├── main/ # Main process (Node.js)
│ └── index.ts # Entry point for main process
├── preload/ # Preload scripts (security bridge)
│ ├── index.ts # Preload script implementation
│ └── index.d.ts # Type definitions
└── renderer/ # Renderer process (Vue app)
├── src/ # Vue application source
├── index.html # HTML entry point
├── auto-imports.d.ts # Auto-generated import types
└── components.d.ts # Auto-generated component types
```
## Configuration Files
### TypeScript Configuration
- `tsconfig.json`: Root config with project references
- `tsconfig.node.json`: Node.js/Electron main process config
- `tsconfig.web.json`: Web/renderer process config
### Build & Development
- `electron.vite.config.ts`: Vite configuration for Electron
- `electron-builder.yml`: App packaging configuration
- `package.json`: Dependencies and scripts
### Code Quality
- `eslint.config.mjs`: ESLint configuration (flat config)
- `.prettierrc.yaml`: Prettier formatting rules
- `.editorconfig`: Editor configuration
## Key Conventions
- **Renderer alias**: Use `@renderer/*` for renderer source imports
- **Auto-imports**: TDesign components and Vue composables are auto-imported
- **Process separation**: Maintain clear boundaries between main, preload, and renderer
- **TypeScript**: All source files should use TypeScript (.ts/.vue)
## File Naming
- Use kebab-case for component files
- Use camelCase for TypeScript files
- Vue components should be multi-word (ESLint enforced, but disabled)

View File

@@ -1,52 +0,0 @@
# Technology Stack
## Core Technologies
- **Electron**: Desktop app framework (v37.2.3)
- **Vue 3**: Frontend framework with Composition API (v3.5.17)
- **TypeScript**: Primary language for type safety
- **Vite**: Build tool and dev server via electron-vite
- **PNPM**: Package manager (preferred over npm/yarn)
## UI Framework
- **TDesign Vue Next**: Primary UI component library (v1.15.2)
- **SCSS**: Styling preprocessor
- **Auto-import**: Automatic component and composable imports
## State Management & Routing
- **Pinia**: State management (v3.0.3)
- **Vue Router**: Client-side routing (v4.5.1)
## Development Tools
- **ESLint**: Code linting with Electron Toolkit configs
- **Prettier**: Code formatting
- **Vue TSC**: Vue TypeScript checking
## Common Commands
### Development
```bash
pnpm dev # Start development server
pnpm start # Preview built app
```
### Code Quality
```bash
pnpm lint # Run ESLint
pnpm format # Format code with Prettier
pnpm typecheck # Run TypeScript checks
```
### Building
```bash
pnpm build # Build for current platform
pnpm build:win # Build for Windows
pnpm build:mac # Build for macOS
pnpm build:linux # Build for Linux
pnpm build:unpack # Build without packaging
```
## Build System
- **electron-vite**: Vite-based build system for Electron
- **electron-builder**: Application packaging and distribution
- Separate TypeScript configs for Node.js and web contexts
- Auto-updating via electron-updater

View File

@@ -2,4 +2,4 @@ singleQuote: true
semi: false
printWidth: 100
trailingComma: none
endOfLine: "auto"
endOfLine: 'auto'

View File

@@ -1,3 +0,0 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
}

39
.vscode/launch.json vendored
View File

@@ -1,39 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
}
]
}

12
.vscode/settings.json vendored
View File

@@ -1,12 +0,0 @@
{
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"editor.fontSize": 14
}

217
LICENSE
View File

@@ -1,21 +1,204 @@
MIT License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2025 时迁酱
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2025 时迁酱
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

134
README.md
View File

@@ -1,10 +1,14 @@
# Ceru Music
# Ceru Music(澜音)
一个跨平台的音乐播放器应用,支持多来源音乐数据获取与播放。
一个跨平台的音乐播放器应用,支持基于合规插件获取公开音乐信息与播放功能。
## 项目简介
Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器,支持从多个音乐平台获取歌曲信息并播放。该项目结合了现代前端技术和桌面应用开发,提供了流畅的用户体验和灵活的音乐数据源支持
Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器工具,**仅提供插件运行框架与播放功能**,不直接存储、提供任何音乐源文件。用户需通过自行选择、安装合规插件获取音乐相关数据,项目旨在为开发者提供桌面应用技术实践与学习案例,为用户提供合规的音乐播放工具框架
<img src="assets/image-20250827175023917.png" alt="image-20250827175023917" style="zoom: 33%;" /><img src="assets/image-20250827175109430.png" alt="image-20250827175109430" style="zoom:33%;" />
## 技术栈
@@ -13,79 +17,157 @@ Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器,
- **TypeScript**:增强代码可维护性和类型安全
- **Pinia**:状态管理工具
- **Vite**:快速的前端构建工具
- **Meting API**:作为备用音乐数据源
- **CeruPlugins**:音乐插件运行环境(仅提供框架,不包含默认插件)
- **AMLL**:音乐生态辅助模块(仅提供功能接口,不关联具体音乐数据源)
## 主要功能
- 支持从多个音乐平台搜索和播放歌曲
- 获取歌词和专辑信息
- 提供插件加载与管理功能,支持通过合规插件获取公开音乐信息
- 支持通过插件获取歌词、专辑封面等公开元数据
- 支持虚拟滚动列表,优化大量数据渲染性能
- 本地数据存储与播放列表管理
- 本地播放列表管理(仅存储用户手动创建的列表结构,不包含音乐文件)
- **提示**:本地数据仅保存在用户设备本地,未进行云端备份,用户需自行备份以防止数据丢失
- 精美的用户界面与动画效果
- **插件生态框架**(插件需用户自行获取并确保合规性)
## 安装与使用
### 推荐开发环境
- **IDE**: VS Code 或 WebStorm
- **Node.js 版本**: 推荐使用最新稳定版
- **包管理器**: pnpm
- **Node.js 版本**: 22 及以上
- **包管理器**: **yarn**
### 项目设置
1. 安装依赖:
```bash
pnpm install
yarn install
```
2. 启动开发服务器:
```bash
pnpm dev
yarn dev
```
3. 构建应用:
```bash
pnpm build
yarn build
```
### 平台构建指令
- **Windows**:
- Windows
```bash
pnpm build:win
yarn build:win
```
- **macOS**:
- macOS
```bash
pnpm build:mac
yarn build:mac
```
- **Linux**:
- Linux
```bash
pnpm build:linux
yarn build:linux
```
> 提示:构建后的应用仅包含播放器框架,需用户自行配置合规插件方可获取音乐数据。
## 文档与资源
- [API 接口文档](docs/api.md):详细说明了支持的音乐平台和请求格式
- [产品设计文档](docs/design.md):涵盖项目架构、核心功能设计和开发规范
- [产品设计文档](https://www.doubao.com/thread/docs/design.md):涵盖项目架构、核心功能设计和开发规范(不含任何音乐数据源信息)
- [插件开发文档](https://www.doubao.com/thread/docs/CeruMusic插件开发文档.md):仅提供插件开发技术规范,**明确要求插件开发者需遵守数据来源平台的用户协议与版权法**,禁止开发、传播获取非公开数据的插件
## 开源许可
本项目遵循 MIT 许可协议。详情请参阅 [LICENSE](LICENSE) 文件。
本项目源代码遵循 **Apache License 2.0**,仅授权用户对项目框架进行学习、修改与二次开发,不包含任何音乐数据相关授权。详情请参阅 [LICENSE](./LICENSE) 文件,使用前请务必阅读许可条款
## 贡献指南
欢迎贡献代码反馈建议!请遵循 [Git 提交规范](docs/design.md#git提交规范) 并确保代码符合项目风格指南。
欢迎开发者贡献代码反馈建议,贡献内容需符合以下要求:
## 更新日志
请参阅 [更新日志](docs/api.md#更新日志) 了解最新功能和改进
1. 仅涉及播放器框架功能优化、bug 修复、文档完善,不包含任何音乐数据源相关代码。
2. 遵循 [Git 提交规范](https://www.doubao.com/thread/docs/design.md#git提交规范) 并确保代码符合项目风格指南。
3. 贡献的代码需无第三方版权纠纷,且不违反开源许可协议
## 联系方式
如有问题或合作意向,请通过 Gitee 私信联系项目维护者。
如有技术问题或合作意向(仅限技术交流),请通过 Gitee 私信联系项目维护者。
## 项目开发者
- **时迁酱**:产品总体设计与开发
<img src="assets/head.jpg" alt="head.jpg (940×940)" style="zoom:15%;" />
- **无聊的霜霜**:首页设计&Ai助手
<img src="assets/image-20250827181604432.png" alt="image-20250827181604432" style="zoom:25%;" />
- **Star****插件管理**相关功能&部分接口封装
<img src="assets/image-20250827181535681.png" alt="image-20250827181535681" style="zoom:25%;" />
**Tips**: 排名不分先后
# 法律声明与免责条款
**重要提示:使用本项目前,请务必仔细阅读本条款,使用本项目即视为你已充分理解并同意本条款全部内容。**
### 一、定义约定
- “Apache License 2.0”:指 Ceru Music澜音桌面播放器框架及源代码不包含任何第三方插件或音乐数据。
- “**用户**”:指下载、安装、使用本项目的个人或组织。
- “**合规插件**”:指符合数据来源平台用户协议、不侵犯第三方版权、不获取非公开数据的插件。
- “**版权内容**”:指包括但不限于音乐文件、歌词、专辑封面、艺人信息等受著作权法保护的内容。
### 二、数据与内容责任
1. 本项目**不直接获取、存储、传输任何音乐数据或版权内容**,仅提供插件运行框架。用户通过插件获取的所有数据,其合法性、准确性由插件提供者及用户**自行负责**,本项目不承担任何责任。
2. 若用户使用的插件存在获取非公开数据、侵犯第三方版权等违规行为,相关法律责任由用户及插件提供者承担,与本项目无关。
3. 本项目使用的字体、图片等素材,均来自开源社区或已获得合法授权,若存在侵权请联系项目维护者立即移除,本项目将积极配合处理。
### 三、版权合规要求
1. 用户承诺:使用本项目时,仅通过合规插件获取音乐相关信息,且获取、使用版权内容的行为符合**《中华人民共和国著作权法》**及相关法律法规,不侵犯**任何第三方**合法权益。
2. 用户需知晓:任何未经授权下载、传播、使用受版权保护的音乐文件的行为,均可能构成侵权,需自行承担法律后果。
3. 本项目倡导 “尊重版权、支持正版”,提醒用户通过官方音乐平台获取授权音乐服务。
### 四、免责声明
1. 因用户使用非合规插件、违反法律法规或第三方协议导致的任何法律责任(包括但不限于侵权赔偿、行政处罚),均由用户自行承担,本项目不承担任何直接、间接、连带或衍生责任。
2. 因本项目框架本身的 **bug** 导致的用户设备故障、数据丢失,本项目仅承担在合理范围内的技术修复责任,不承担由此产生的间接损失(如商誉损失、业务中断损失等)。
3. 本项目为开源学习项目,不提供商业服务,对用户使用本项目的效果不做任何明示或暗示的保证。
### 五、使用限制
1. 本项目仅允许用于**非商业、纯技术学习目的**,禁止用于任何商业运营、盈利活动,禁止修改后用于侵犯第三方权益的场景。
2. 禁止在违反当地法律法规、本声明或第三方协议的前提下使用本项目,若用户所在地区禁止此类工具的使用,应立即停止使用。
3. 禁止将本项目源代码或构建后的应用,与违规插件捆绑传播,禁止利用本项目从事任何违法违规活动。
### 六、其他
1. 本声明的效力、解释及适用,均适用中华人民共和国法律(不含港澳台地区法律)。
2. 若用户与本项目维护者就本声明产生争议,应首先通过友好协商解决;协商不成的,任何一方均有权向本项目维护者所在地有管辖权的人民法院提起诉讼。
## 赞助
若您认可本项目的技术价值,欢迎通过以下方式支持开发者(仅用于项目技术维护与迭代):
<img src="assets/image-20250827175356006.png" alt="赞助方式1" style="zoom:33%;" /><img src="assets/image-20250827175547444.png" alt="赞助方式2" style="zoom: 33%;" />

BIN
assets/head.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

View File

@@ -1,3 +1,3 @@
provider: generic
url: https://example.com/auto-updates
url: https://update.ceru.shiqianjiang.cn
updaterCacheDirName: ceru-music-updater

View File

@@ -0,0 +1,56 @@
import { defineConfig } from 'vitepress'
// https://vitepress.dev/reference/site-config
export default defineConfig({
lang: 'zh-CN',
title: "Ceru Music",
base: process.env.BASE_URL ?? '/CeruMusic/',
description: "Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器工具,一个跨平台的音乐播放器应用,支持基于合规插件获取公开音乐信息与播放功能。",
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/logo.svg',
nav: [
{ text: '首页', link: '/' },
{ text: '使用文档', link: '/guide/' }
],
sidebar: [
{
text: 'CeruMusic',
items: [
{ text: '使用教程', link: '/guide/' },
{ text: '软件设计文档', link: '/guide/design' }
]
},
{
text: '澜音&插件',
items: [
{ text: '插件类使用', link: '/guide/CeruMusicPluginHost' },
{ text: '澜音插件开发文档(重点)', link: '/guide/CeruMusicPluginDev' }
]
}
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/timeshiftsauce/CeruMusic' },
{ icon: 'gitee', link: 'https://gitee.com/sqjcode/CeruMuisc' },
{ icon: 'qq', link: 'https://qm.qq.com/q/IDpQnbGd06' },
{ icon: 'beatsbydre', link: 'https://shiqianjiang.cn' },
{ icon: 'bilibili', link: 'https://space.bilibili.com/696709986' }
],
footer: {
message: 'Released under the Apache License 2.0 License.',
copyright: `Copyright © 2025-${new Date().getFullYear()} 时迁酱`
},
editLink: {
pattern: 'https://github.com/timeshiftsauce/CeruMusic/edit/main/docs/:path'
},
search: {
provider: 'local'
}
},
lastUpdated: true,
head: [['link', { rel: 'icon', href: (process.env.BASE_URL ?? '/CeruMusic/') + 'logo.svg' }]]
})
// Smooth scrolling functions

View File

@@ -0,0 +1,80 @@
<script setup>
import { useRouter, useData } from 'vitepress'
import { toggleDark } from './dark'
import DefaultTheme from 'vitepress/theme'
import { watch, ref } from 'vue'
const { route } = useRouter()
const isTransitioning = ref(false)
const { Layout } = DefaultTheme
const { isDark } = useData()
toggleDark(isDark)
watch(
() => route.path,
() => {
isTransitioning.value = true
// 动画结束后重置状态
setTimeout(() => {
isTransitioning.value = false
}, 500) // 500ms 要和 CSS 动画时间匹配
}
)
</script>
<template>
<Layout> </Layout>
</template>
<style>
/* .shade {
position: fixed;
width: 100%;
height: 100vh;
background-color: rgb(255, 255, 255);
z-index: 100;
pointer-events: none;
opacity: 0;
transition: transform 0.5s ease-in-out;
}
.shade-active {
opacity: 0;
animation: shadeAnimation 0.5s ease-in-out;
}
@keyframes shadeAnimation {
0% {
opacity: 1;
transform: translateY(0);
}
50% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(100vh);
}
} */
#VPContent.vp-doc > div {
animation:
rises 1s,
looming 0.6s;
}
@keyframes rises {
0% {
transform: translateY(50px);
}
100% {
transform: translateY(0);
}
}
@keyframes looming {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>

View File

@@ -0,0 +1,21 @@
::view-transition-old(*) {
animation: none;
}
::view-transition-new(*) {
animation: globalDark .5s ease-in;
}
@keyframes globalDark {
from {
clip-path: circle(0% at var(--darkX) var(--darkY));
}
to {
clip-path: circle(100% at var(--darkX) var(--darkY));
}
}
.dark img {
filter: brightness(0.8);
}

View File

@@ -0,0 +1,23 @@
import { nextTick, provide } from 'vue'
// 判断是否能使用 startViewTransition
const enableTransitions = () => {
return 'startViewTransition' in document && window.matchMedia('(prefers-reduced-motion: no-preference)').matches
}
// 切换动画
export const toggleDark = (isDark: any) => {
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
//如果不支持动效直接切换
if (!enableTransitions()) {
isDark.value = !isDark.value
return
}
document.documentElement.style.setProperty('--darkX', x + 'px')
document.documentElement.style.setProperty('--darkY', y + 'px')
// 原生的视图转换动画 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/startViewTransition
// pnpm add -D @types/dom-view-transitions 解决 document.startViewTransition 类型错误的问题
await document.startViewTransition(async () => {
isDark.value = !isDark.value
await nextTick()
}).ready
})
}

View File

@@ -0,0 +1,16 @@
import DefaultTheme from 'vitepress/theme'
import './style.css'
import './dark.css'
import MyLayout from './MyLayout.vue';
// history.scrollRestoration = 'manual'
export default {
extends: DefaultTheme,
Layout: MyLayout,
enhanceApp({ app, router, siteData }) {
// ...
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
@import url(./phycat/phycat.light.css);
@import url(./phycat/phycat.dark.css);
/**
* Customize default theme styling by overriding CSS variables:
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
*/
/**
* Colors
*
* Each colors have exact same color scale system with 3 levels of solid
* colors with different brightness, and 1 soft color.
*
* - `XXX-1`: The most solid color used mainly for colored text. It must
* satisfy the contrast ratio against when used on top of `XXX-soft`.
*
* - `XXX-2`: The color used mainly for hover state of the button.
*
* - `XXX-3`: The color for solid background, such as bg color of the button.
* It must satisfy the contrast ratio with pure white (#ffffff) text on
* top of it.
*
* - `XXX-soft`: The color used for subtle background such as custom container
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
* on top of it.
*
* The soft color must be semi transparent alpha channel. This is crucial
* because it allows adding multiple "soft" colors on top of each other
* to create an accent, such as when having inline code block inside
* custom containers.
*
* - `default`: The color used purely for subtle indication without any
* special meanings attached to it such as bg color for menu hover state.
*
* - `brand`: Used for primary brand colors, such as link text, button with
* brand theme, etc.
*
* - `tip`: Used to indicate useful information. The default theme uses the
* brand color for this by default.
*
* - `warning`: Used to indicate warning to the users. Used in custom
* container, badges, etc.
*
* - `danger`: Used to show error, or dangerous message to the users. Used
* in custom container, badges, etc.
* -------------------------------------------------------------------------- */
html.dark #app {
--vp-nav-bg-color: #000000a7 !important;
}
.VPNavBar:not(.VPNavBar.top) {
backdrop-filter: blur(10px);
}
:root {
--vp-c-indigo-1: #14a5c2;
--vp-c-indigo-2: #21b1ce;
--vp-c-indigo-3: #4fcbe4;
--vp-nav-bg-color: #ffffffa7;
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-brand-1: var(--vp-c-indigo-1);
--vp-c-brand-2: var(--vp-c-indigo-2);
--vp-c-brand-3: var(--vp-c-indigo-3);
--vp-c-brand-soft: var(--vp-c-indigo-soft);
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);
--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
}
/**
* Component: Button
* -------------------------------------------------------------------------- */
:root {
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
}
/**
* Component: Home
* -------------------------------------------------------------------------- */
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #5dd6cc 30%, #b8f1cc);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #b8f1cf 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
/**
* Component: Custom Block
* -------------------------------------------------------------------------- */
:root {
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
}
/**
* Component: Algolia
* -------------------------------------------------------------------------- */
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}
:root {
/* 标题后小图标借鉴自思源笔记主题——Savor */
--h1-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.8 29.714v0c-1.371 0-2.514-1.143-2.514-2.514v0c0-1.371 1.143-2.514 2.514-2.514v0c1.371 0 2.514 1.143 2.514 2.514v0c0.114 1.371-1.029 2.514-2.514 2.514z'/></svg>")
no-repeat center;
--h2-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>")
no-repeat center;
--h3-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='28' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>")
no-repeat center;
--h4-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 22.857c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286z'/></svg>")
no-repeat center;
--h5-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 22.857c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286zM4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 11.429c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>")
no-repeat center;
--h6-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 11.429c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 16c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286z'/></svg>")
no-repeat center;
/* 是否开启网格背景1 是0 否 */
--bg-grid: 0;
/* 已完成的代办事项是否显示删除线1 是0 否 */
--check-line: 1;
/* 自动编号格式设置 无需自动编号可全部注释掉或部分注释掉*/
/* --autonum-h1: counter(h1) ". ";
--autonum-h2: counter(h1) "." counter(h2) ". ";
--autonum-h3: counter(h1) "." counter(h2) "." counter(h3) ". ";
--autonum-h4: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) ". ";
--autonum-h5: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". ";
--autonum-h6: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "; */
/* 下面是文章内Toc目录自动编号与上面一样即可 */
/* --autonum-h1toc: counter(h1toc) ". ";
--autonum-h2toc: counter(h1toc) "." counter(h2toc) ". ";
--autonum-h3toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) ". ";
--autonum-h4toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) ". ";
--autonum-h5toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) "." counter(h5toc) ". ";
--autonum-h6toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) "." counter(h5toc) "." counter(h6toc) ". "; */
/* 主题颜色 */
--head-title-color: #3db8bf;
/* 标题主色 */
--head-title-h2-color: #fff;
--head-title-h2-background: linear-gradient(to right, #3db8d3, #80f7c4);
/* 二级标题主色,因为二级标题是背景色的,所以单独设置 */
--element-color: #3db8bf;
/* 元素主色 */
--element-color-deep: #089ba3;
/* 元素深色 */
--element-color-shallow: #7aeaf0;
/* 元素浅色 */
--element-color-so-shallow: #7aeaf077;
/* 元素很浅色 */
--element-color-soo-shallow: #7aeaf018;
/* 元素非常浅色 */
--element-color-linecode: #089ba3;
/* 行内代码文字色 */
--element-color-linecode-background: #7aeaf018;
/* 行内代码背景色 */
/* 程序本体UI */
--appui-color: #3db8bf;
/* 程序UI主题色 */
--appui-color-icon: #3db8bf;
/* 程序UI图标颜色 */
--appui-color-text: #333;
/* 程序UI文字色 */
--primary-color: #3db8bf;
}
* {
scroll-behavior: smooth;
}
/**
* 黑暗模式切换动画
* -------------------------------------------------------------------------- */
#VPContent .vp-doc > div {
animation:
rises 1s,
looming 1s;
}
@keyframes rises {
0% {
transform: translateY(50px);
}
100% {
transform: translateY(0);
}
}
@keyframes looming {
0% {
opacity: 0;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
li {
position: relative;
}
.vp-doc li div[class*='language-'] {
margin: 12px;
}
html.dark .vp-doc div[class*='language-'],
html.dark .vp-doc div[class*='language-'] pre {
background-color: #222222;
}
html .vp-doc div[class*='language-'],
html .vp-doc div[class*='language-'] pre {
background-color: #f8f8f8;
}
#app div[class^='language'] {
border-radius: 1em;
overflow: hidden;
padding: 0.4em;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
docs/assets/head.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

10
docs/assets/logo.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1200" height="1200" rx="379" fill="white"/>
<path d="M957.362 204.197C728.535 260.695 763.039 192.264 634.41 175.368C451.817 151.501 504.125 315.925 504.125 315.925L630.545 673.497C591.211 654.805 544.287 643.928 494.188 643.928C353.275 643.928 239 729.467 239 834.964C239 940.567 353.137 1026 494.188 1026C635.1 1026 749.375 940.461 749.375 834.964C749.375 832.218 749.237 829.473 749.099 826.727C749.513 825.988 749.789 825.143 750.065 824.087C757.932 789.449 634.272 348.345 634.272 348.345C634.272 348.345 764.971 401.886 860.89 351.936C971.163 294.699 964.953 202.402 957.362 204.197Z" fill="url(#paint0_linear_4_16)" stroke="#29293A" stroke-opacity="0.23"/>
<defs>
<linearGradient id="paint0_linear_4_16" x1="678.412" y1="-1151.29" x2="796.511" y2="832.071" gradientUnits="userSpaceOnUse">
<stop offset="0.572115" stop-color="#B8F1ED"/>
<stop offset="0.9999" stop-color="#B8F1CC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,225 +0,0 @@
# 音频发布-订阅模式使用指南
## 概述
这个改进的发布-订阅模式解决了原有实现中无法单个删除订阅者的问题。新的实现提供了以下特性:
- ✅ 支持单个订阅者的精确取消
- ✅ 自动生成唯一订阅ID
- ✅ 类型安全的事件系统
- ✅ 错误处理和日志记录
- ✅ 内存泄漏防护
## 核心特性
### 1. 精确的订阅管理
每个订阅都会返回一个取消订阅函数,调用该函数即可精确取消对应的订阅:
```typescript
// 订阅事件
const unsubscribe = audioStore.subscribe('ended', () => {
console.log('音频播放结束')
})
// 取消订阅
unsubscribe()
```
### 2. 支持的事件类型
- `ended`: 音频播放结束
- `seeked`: 音频拖拽完成
- `timeupdate`: 音频时间更新
- `play`: 音频开始播放
- `pause`: 音频暂停播放
### 3. 类型安全
所有的事件类型和回调函数都有完整的TypeScript类型定义确保编译时类型检查。
## 使用方法
### 基础订阅
```typescript
import { ControlAudioStore } from '@renderer/store/ControlAudio'
const audioStore = ControlAudioStore()
// 订阅播放结束事件
const unsubscribeEnded = audioStore.subscribe('ended', () => {
console.log('音频播放结束了')
})
// 订阅时间更新事件
const unsubscribeTimeUpdate = audioStore.subscribe('timeupdate', () => {
console.log('当前时间:', audioStore.Audio.currentTime)
})
```
### 在Vue组件中使用
```vue
<script setup lang="ts">
import { inject, onMounted, onUnmounted } from 'vue'
import type { AudioSubscribeMethod, UnsubscribeFunction } from '@renderer/types/audio'
// 注入订阅方法
const audioSubscribe = inject<AudioSubscribeMethod>('audioSubscribe')
// 存储取消订阅函数
const unsubscribeFunctions: UnsubscribeFunction[] = []
onMounted(() => {
if (!audioSubscribe) return
// 订阅多个事件
unsubscribeFunctions.push(
audioSubscribe('play', () => console.log('开始播放')),
audioSubscribe('pause', () => console.log('暂停播放')),
audioSubscribe('ended', () => console.log('播放结束'))
)
})
onUnmounted(() => {
// 组件卸载时取消所有订阅
unsubscribeFunctions.forEach((unsubscribe) => unsubscribe())
})
</script>
```
### 条件订阅和取消
```typescript
let endedUnsubscribe: UnsubscribeFunction | null = null
// 条件订阅
const subscribeToEnded = () => {
if (!endedUnsubscribe) {
endedUnsubscribe = audioStore.subscribe('ended', handleAudioEnded)
}
}
// 条件取消订阅
const unsubscribeFromEnded = () => {
if (endedUnsubscribe) {
endedUnsubscribe()
endedUnsubscribe = null
}
}
```
## 高级功能
### 批量管理订阅
```typescript
// 清空特定事件的所有订阅者
audioStore.clearEventSubscribers('ended')
// 清空所有事件的所有订阅者
audioStore.clearAllSubscribers()
```
### 错误处理
系统内置了错误处理机制,如果某个回调函数执行出错,不会影响其他订阅者:
```typescript
audioStore.subscribe('ended', () => {
throw new Error('这个错误不会影响其他订阅者')
})
audioStore.subscribe('ended', () => {
console.log('这个回调仍然会正常执行')
})
```
## 最佳实践
### 1. 及时清理订阅
```typescript
// ✅ 好的做法:组件卸载时清理
onUnmounted(() => {
unsubscribeFunctions.forEach((unsubscribe) => unsubscribe())
})
// ❌ 不好的做法:忘记清理,可能导致内存泄漏
```
### 2. 使用数组管理多个订阅
```typescript
// ✅ 好的做法:统一管理
const unsubscribeFunctions: UnsubscribeFunction[] = []
unsubscribeFunctions.push(
audioStore.subscribe('play', handlePlay),
audioStore.subscribe('pause', handlePause)
)
// 统一清理
unsubscribeFunctions.forEach((fn) => fn())
```
### 3. 避免在高频事件中执行重操作
```typescript
// ❌ 不好的做法在timeupdate中执行重操作
audioStore.subscribe('timeupdate', () => {
// 这会每秒执行多次,影响性能
updateComplexUI()
})
// ✅ 好的做法:使用节流或防抖
let lastUpdate = 0
audioStore.subscribe('timeupdate', () => {
const now = Date.now()
if (now - lastUpdate > 100) {
// 限制更新频率
updateUI()
lastUpdate = now
}
})
```
## 迁移指南
### 从旧版本迁移
旧版本:
```typescript
// 旧的实现方式
provide('setAudioEnd', setEndCallback)
function setEndCallback(fn: Function): void {
endCallback.push(fn)
}
```
新版本:
```typescript
// 新的实现方式
provide('audioSubscribe', audioStore.subscribe)
// 使用时
const unsubscribe = audioSubscribe('ended', () => {
// 处理播放结束
})
// 可以精确取消
unsubscribe()
```
## 性能优化
1. **避免重复订阅**:在订阅前检查是否已经订阅
2. **及时取消订阅**:组件卸载或不再需要时立即取消
3. **合理使用事件**:避免在高频事件中执行重操作
4. **批量操作**:需要清理多个订阅时使用批量清理方法
这个改进的发布-订阅模式为Ceru Music应用提供了更加灵活和可靠的音频事件管理机制。

View File

@@ -1,3 +1,7 @@
---
layout: doc
---
# CeruMusic 插件开发文档
## 概述

View File

@@ -1,3 +1,7 @@
---
layout: doc
---
# CeruMusicPluginHost 使用文档
## 概述
@@ -109,9 +113,7 @@ try {
### 构造函数
```javascript
new CeruMusicPluginHost(pluginCode?)
```
`new CeruMusicPluginHost(pluginCode)`
**参数:**
@@ -125,9 +127,9 @@ new CeruMusicPluginHost(pluginCode?)
**参数:**
- `pluginPath` (string): 插件文件路径
`pluginPath` (string): 插件文件路径
**返回:** Promise<Object> - 插件导出的对象
**返回:** `Promise<Object>` - 插件导出的对象
#### getPluginInfo()
@@ -151,7 +153,7 @@ new CeruMusicPluginHost(pluginCode?)
- `musicInfo` (Object): 歌曲信息对象
- `quality` (string): 音质标识
**返回:** Promise<string> - 音乐播放链接
**返回:** `Promise<string>` - 音乐播放链接
#### getPic(source, musicInfo)
@@ -162,7 +164,7 @@ new CeruMusicPluginHost(pluginCode?)
- `source` (string): 音源标识
- `musicInfo` (Object): 歌曲信息对象
**返回:** Promise<string> - 封面链接
**返回:** `Promise<string>` - 封面链接
#### getLyric(source, musicInfo)
@@ -173,7 +175,7 @@ new CeruMusicPluginHost(pluginCode?)
- `source` (string): 音源标识
- `musicInfo` (Object): 歌曲信息对象
**返回:** Promise<string> - 歌词内容
**返回:** `Promise<string>` - 歌词内容
## 插件环境

View File

@@ -11,7 +11,7 @@ Ceru Music 是一个基于 Electron + Vue 3 的跨平台桌面音乐播放器,
- **前端框架**: Vue 3 + TypeScript + Composition API
- **桌面框架**: Electron (v37.2.3)
- **UI组件库**: TDesign Vue Next (v1.15.2)
- ![image-20250813180317221](D:\code\Ceru-Music\docs\assets\image-20250813180317221.png)
- ![image-20250813180317221](..\assets\image-20250813180317221.png)
- **状态管理**: Pinia (v3.0.3)
- **路由管理**: Vue Router (v4.5.1)
- **构建工具**: Vite + electron-vite
@@ -397,7 +397,7 @@ export const useAppStore = defineStore('app', {
### 欢迎页面设计
![image-20250813180856660](D:\code\Ceru-Music\docs\assets\image-20250813180856660.png)
![image-20250813180856660](..\assets\image-20250813180856660.png)
```vue
<template>
@@ -456,7 +456,7 @@ function skipWelcome() {
##### 界面UI参考
![.\assets\image-20250813180944752.png)
![..\assets\image-20250813180944752.png)
## 页面动画设计

44
docs/guide/index.md Normal file
View File

@@ -0,0 +1,44 @@
# CeruMusic 使用教程
## 1. 软件下载
由于我们团段都是个人开发者原因 暂时无能力部署到 `OSS` 承担高下载量的能力,供大家下载只能通过[Github](https://github.com/timeshiftsauce/CeruMusic)下载安装使用
### Window 安装
由于没有证书原因 **`Window`** 平台可能会出现安装包体误报**危险**。请放心我们的软件都是**开源**在 `Github` 自动化打包的。**具体安装步骤如下**
<img src="../assets/image-20250826214921963.png" alt="image-20250826214921963" style="zoom: 50%;" />如果出现类似图例效果请先点击 **右侧 三个点**
<img src="../assets/image-20250826215101522.png" alt="image-20250826215101522" style="zoom:50%;" />**点击保留**
<img src="../assets/image-20250826215206862.png" alt="image-20250826215206862" style="zoom:50%;" />**点击下拉按钮**
<img src="../assets/image-20250826215251525.png" alt="image-20250826215251525" style="zoom:50%;" />**任然保留**就可以双击打开安装到此教程结束
### Mac OS 系统下载安装
由于同样没有**签名**的原因mac的护栏也会拦截提示安装包损坏
<img src="../assets/3f50d3b838287b4bf1523d0f955fdf37.png" alt="3f50d3b838287b4bf1523d0f955fdf37" style="zoom:50%;" />请不用担心这是典型的签名问题
适用于 macOS 14 Sonoma 及以上版本。
注意:由于我们不提供经过签名的程序包体,因此在安装后首次运行可能会出现 “**澜音** 已损坏” 之类的提示,此时只需打开终端,输入命令
```bash
sudo xattr -r -d com.apple.quarantine /Applications/澜音.app
```
并回车,输入密码再次回车,重新尝试启动程序即可
_要是还有问题可自行在搜索引擎查询由于 。`apple`官方证书需要99刀的价格实在无能为力见谅_ 如果你有能力成为`澜音`的赞助者可联系
- QQ`2115295703`
- 微信:`cl_wj0623`
### 插件安装
首次进入应用需要在软件右上角设置导入**音源**才能使用可查询`Ceru插件`**(目前生态欠缺)** 或现成的**落雪**插件导入使用![image-20250826221438856](../assets/image-20250826221438856.png)
###### 导入完成点击使用![image-20250826221517247](../assets/image-20250826221517247.png)

203
docs/index.md Normal file
View File

@@ -0,0 +1,203 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: 'Ceru Music'
text: '澜音 播放器'
tagline: 澜音是一个跨平台的音乐播放器应用,支持基于合规插件获取公开音乐信息与播放功能。
image:
src: '/logo.svg'
actions:
- theme: brand
text: 下载应用
link: https://ceru.shiqianjiang.cn/#download
target: _blank
- theme: alt
text: 使用文档
link: /guide/
features:
- title: 多平台支持
icon: 🚀
details: 支持网易云音乐、QQ音乐等多个平台搜索
- title: 跨平台支持
icon: 🪟
details: 原生桌面应用,支持 Windows、macOS、Linux 三大操作系统
- title: 歌词显示
icon: 🎼
details: 实时歌词显示,支持专辑信息获取,让音乐体验更丰富
- title: 优雅界面
icon: 💻
details: 现代化设计语言,流畅动画效果,为你带来愉悦的视觉体验
- title: 代码开源
details: 代码完全开源,供给大家使用开发
icon: 👐
link: https://github.com/timeshiftsauce/CeruMusic
---
<div style="margin-top:4rem"></div>
# Ceru Music澜音
一个跨平台的音乐播放器应用,支持基于合规插件获取公开音乐信息与播放功能。
## 项目简介
Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器工具,**仅提供插件运行框架与播放功能**,不直接存储、提供任何音乐源文件。用户需通过自行选择、安装合规插件获取音乐相关数据,项目旨在为开发者提供桌面应用技术实践与学习案例,为用户提供合规的音乐播放工具框架。
<img src="./assets/image-20250827175023917.png" alt="image-20250827175023917" style="zoom: 33%;" /><img src="./assets/image-20250827175109430.png" alt="image-20250827175109430" style="zoom:33%;" />
## 技术栈
- **Electron**:用于构建跨平台桌面应用
- **Vue 3**:前端框架,提供响应式 UI
- **TypeScript**:增强代码可维护性和类型安全
- **Pinia**:状态管理工具
- **Vite**:快速的前端构建工具
- **CeruPlugins**:音乐插件运行环境(仅提供框架,不包含默认插件)
- **AMLL**:音乐生态辅助模块
## 主要功能
- 提供插件加载与管理功能,支持通过合规插件获取公开音乐信息
- 支持通过插件获取歌词、专辑封面等公开元数据
- 支持虚拟滚动列表,优化大量数据渲染性能
- 本地播放列表管理(仅存储用户手动创建的列表结构,不包含音乐文件)
- **提示**:本地数据仅保存在用户设备本地,未进行云端备份,用户需自行备份以防止数据丢失
- 精美的用户界面与动画效果
- **插件生态框架**(插件需用户自行获取并确保合规性)
## 安装与使用
### 推荐开发环境
- **IDE**: VS Code 或 WebStorm
- **Node.js 版本**: 22 及以上
- **包管理器**: **yarn**
### 项目设置
1. 安装依赖:
```bash
yarn install
```
2. 启动开发服务器:
```bash
yarn dev
```
3. 构建应用:
```bash
yarn build
```
### 平台构建指令
- Windows
```bash
yarn build:win
```
- macOS
```bash
yarn build:mac
```
- Linux
```bash
yarn build:linux
```
> 提示:构建后的应用仅包含播放器框架,需用户自行配置合规插件方可获取音乐数据。
## 文档与资源
- [产品设计文档](./guide/design):涵盖项目架构、核心功能设计和开发规范(不含任何音乐数据源信息)。
- [插件开发文档](./guide/CeruMusicPluginDev):仅提供插件开发技术规范,**明确要求插件开发者需遵守数据来源平台的用户协议与版权法**,禁止开发、传播获取非公开数据的插件。
## 开源许可
本项目源代码遵循 **Apache License 2.0**,仅授权用户对项目框架进行学习、修改与二次开发,不包含任何音乐数据相关授权。详情请参阅 [LICENSE](https://github.com/timeshiftsauce/CeruMusic/blob/main/LICENSE) 文件,使用前请务必阅读许可条款。
## 贡献指南
欢迎开发者贡献代码与反馈建议,贡献内容需符合以下要求:
1. 仅涉及播放器框架功能优化、bug 修复、文档完善,不包含任何音乐数据源相关代码。
2. 遵循 [Git 提交规范](./guide/design#git提交规范) 并确保代码符合项目风格指南。
3. 贡献的代码需无第三方版权纠纷,且不违反开源许可协议。
## 联系方式
如有技术问题或合作意向(仅限技术交流),请通过 Gitee 私信联系项目维护者。
## 项目开发者
- **时迁酱**:产品总体设计与开发
<img src="./assets/head.jpg" alt="head.jpg (940×940)" style="zoom:15%;" />
- **无聊的霜霜**:首页设计&Ai助手
<img src="./assets/image-20250827181604432.png" alt="image-20250827181604432" style="zoom:25%;" />
- **Star****插件管理**相关功能&部分接口封装
<img src="./assets/image-20250827181535681.png" alt="image-20250827181535681" style="zoom:25%;" />
**Tips**: 排名不分先后
# 法律声明与免责条款
**重要提示:使用本项目前,请务必仔细阅读本条款,使用本项目即视为你已充分理解并同意本条款全部内容。**
### 一、定义约定
- “Apache License 2.0”:指 Ceru Music澜音桌面播放器框架及源代码不包含任何第三方插件或音乐数据。
- “**用户**”:指下载、安装、使用本项目的个人或组织。
- “**合规插件**”:指符合数据来源平台用户协议、不侵犯第三方版权、不获取非公开数据的插件。
- “**版权内容**”:指包括但不限于音乐文件、歌词、专辑封面、艺人信息等受著作权法保护的内容。
### 二、数据与内容责任
1. 本项目**不直接获取、存储、传输任何音乐数据或版权内容**,仅提供插件运行框架。用户通过插件获取的所有数据,其合法性、准确性由插件提供者及用户**自行负责**,本项目不承担任何责任。
2. 若用户使用的插件存在获取非公开数据、侵犯第三方版权等违规行为,相关法律责任由用户及插件提供者承担,与本项目无关。
3. 本项目使用的字体、图片等素材,均来自开源社区或已获得合法授权,若存在侵权请联系项目维护者立即移除,本项目将积极配合处理。
### 三、版权合规要求
1. 用户承诺:使用本项目时,仅通过合规插件获取音乐相关信息,且获取、使用版权内容的行为符合**《中华人民共和国著作权法》**及相关法律法规,不侵犯**任何第三方**合法权益。
2. 用户需知晓:任何未经授权下载、传播、使用受版权保护的音乐文件的行为,均可能构成侵权,需自行承担法律后果。
3. 本项目倡导 “尊重版权、支持正版”,提醒用户通过官方音乐平台获取授权音乐服务。
### 四、免责声明
1. 因用户使用非合规插件、违反法律法规或第三方协议导致的任何法律责任(包括但不限于侵权赔偿、行政处罚),均由用户自行承担,本项目不承担任何直接、间接、连带或衍生责任。
2. 因本项目框架本身的 **bug** 导致的用户设备故障、数据丢失,本项目仅承担在合理范围内的技术修复责任,不承担由此产生的间接损失(如商誉损失、业务中断损失等)。
3. 本项目为开源学习项目,不提供商业服务,对用户使用本项目的效果不做任何明示或暗示的保证。
### 五、使用限制
1. 本项目仅允许用于**非商业、纯技术学习目的**,禁止用于任何商业运营、盈利活动,禁止修改后用于侵犯第三方权益的场景。
2. 禁止在违反当地法律法规、本声明或第三方协议的前提下使用本项目,若用户所在地区禁止此类工具的使用,应立即停止使用。
3. 禁止将本项目源代码或构建后的应用,与违规插件捆绑传播,禁止利用本项目从事任何违法违规活动。
### 六、其他
1. 本声明的效力、解释及适用,均适用中华人民共和国法律(不含港澳台地区法律)。
2. 若用户与本项目维护者就本声明产生争议,应首先通过友好协商解决;协商不成的,任何一方均有权向本项目维护者所在地有管辖权的人民法院提起诉讼。
## 赞助
若您认可本项目的技术价值,欢迎通过以下方式支持开发者(仅用于项目技术维护与迭代):
<img src="./assets/image-20250827175356006.png" alt="赞助方式1" style="zoom:33%;" /><img src="./assets/image-20250827175547444.png" alt="赞助方式2" style="zoom: 33%;" />
---

10
docs/public/logo.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1200" height="1200" rx="379" fill="white"/>
<path d="M957.362 204.197C728.535 260.695 763.039 192.264 634.41 175.368C451.817 151.501 504.125 315.925 504.125 315.925L630.545 673.497C591.211 654.805 544.287 643.928 494.188 643.928C353.275 643.928 239 729.467 239 834.964C239 940.567 353.137 1026 494.188 1026C635.1 1026 749.375 940.461 749.375 834.964C749.375 832.218 749.237 829.473 749.099 826.727C749.513 825.988 749.789 825.143 750.065 824.087C757.932 789.449 634.272 348.345 634.272 348.345C634.272 348.345 764.971 401.886 860.89 351.936C971.163 294.699 964.953 202.402 957.362 204.197Z" fill="url(#paint0_linear_4_16)" stroke="#29293A" stroke-opacity="0.23"/>
<defs>
<linearGradient id="paint0_linear_4_16" x1="678.412" y1="-1151.29" x2="796.511" y2="832.071" gradientUnits="userSpaceOnUse">
<stop offset="0.572115" stop-color="#B8F1ED"/>
<stop offset="0.9999" stop-color="#B8F1CC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -61,6 +61,6 @@ appImage:
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates
url: https://update.ceru.shiqianjiang.cn
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/

View File

@@ -13,7 +13,7 @@ const baseRule = {
'prefer-const': 'off',
'no-labels': 'off',
'node/no-callback-literal': 'off',
'multiline-ternary': 'off',
'multiline-ternary': 'off'
}
const typescriptRule = {
...baseRule,
@@ -21,58 +21,62 @@ const typescriptRule = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/space-before-function-paren': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/restrict-template-expressions': [1, {
'@typescript-eslint/restrict-template-expressions': [
1,
{
allowBoolean: true,
allowAny: true,
}],
'@typescript-eslint/restrict-plus-operands': [1, {
allowAny: true
}
],
'@typescript-eslint/restrict-plus-operands': [
1,
{
allowBoolean: true,
allowAny: true,
}],
allowAny: true
}
],
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: {
arguments: false,
attributes: false,
},
},
attributes: false
}
}
],
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/return-await': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/comma-dangle': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-argument': 'off'
}
const vueRule = {
...typescriptRule,
'vue/multi-word-component-names': 'off',
'vue/max-attributes-per-line': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/use-v-on-exact': 'off',
'vue/use-v-on-exact': 'off'
}
exports.base = {
export const base = {
extends: ['standard'],
rules: baseRule,
parser: '@babel/eslint-parser',
parser: '@babel/eslint-parser'
}
exports.html = {
export const html = {
files: ['*.html'],
plugins: ['html'],
plugins: ['html']
}
exports.typescript = {
export const typescript = {
files: ['*.ts'],
rules: typescriptRule,
parser: '@typescript-eslint/parser',
extends: [
'standard-with-typescript',
],
extends: ['standard-with-typescript']
}
exports.vue = {
export const vue = {
files: ['*.vue'],
rules: vueRule,
parser: 'vue-eslint-parser',
@@ -82,7 +86,7 @@ exports.vue = {
'plugin:vue/vue3-recommended',
'plugin:vue-pug/vue3-recommended',
// "plugin:vue/strongly-recommended"
'standard-with-typescript',
'standard-with-typescript'
],
parserOptions: {
sourceType: 'module',
@@ -91,8 +95,8 @@ exports.vue = {
js: '@typescript-eslint/parser',
// Script parser for `<script lang="ts">`
ts: '@typescript-eslint/parser',
},
extraFileExtensions: ['.vue'],
ts: '@typescript-eslint/parser'
},
extraFileExtensions: ['.vue']
}
}

View File

@@ -1,28 +1,31 @@
{
"name": "ceru-music",
"version": "1.0.0",
"version": "1.1.6",
"description": "一款简洁优雅的音乐播放器",
"main": "./out/main/index.js",
"author": "sqj,wldss,star",
"license": "MIT",
"license": "Apache-2.0",
"homepage": "https://electron-vite.org",
"scripts": {
"format": "prettier --write .",
"lint": "eslint --cache . --fix",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"typecheck": "yarn run typecheck:node && yarn run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev --watch",
"build": "npm run typecheck && electron-vite build",
"build": "yarn run typecheck && electron-vite build",
"onlybuild": "electron-vite build && electron-builder --win --x64",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win --x64 --config --publish never",
"build:mac": "npm run build && electron-builder --mac --config --publish never",
"build:linux": "npm run build && electron-builder --linux --publish never",
"build:deps": "electron-builder install-app-deps && npm run build && electron-builder --win --x64 --config",
"buildico": "electron-icon-builder --input=./resources/logo.png --output=resources --flatten"
"build:unpack": "yarn run build && electron-builder --dir",
"build:win": "yarn run build && electron-builder --win --x64 --config --publish never",
"build:mac": "yarn run build && electron-builder --mac --config --publish never",
"build:linux": "yarn run build && electron-builder --linux --config --publish never",
"build:deps": "electron-builder install-app-deps && yarn run build && electron-builder --win --x64 --config",
"buildico": "electron-icon-builder --input=./resources/logo.png --output=resources --flatten",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
"dependencies": {
"@applemusic-like-lyrics/lyric": "^0.2.4",
@@ -48,9 +51,11 @@
"dompurify": "^3.2.6",
"electron-log": "^5.4.3",
"electron-updater": "^6.3.9",
"hpagent": "^1.2.0",
"iconv-lite": "^0.7.0",
"jss": "^10.10.0",
"jss-preset-default": "^10.10.0",
"lodash": "^4.17.21",
"marked": "^16.1.2",
"mitt": "^3.0.1",
"needle": "^3.3.1",

File diff suppressed because it is too large Load Diff

View File

@@ -1,145 +0,0 @@
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 请求响应状态: 200"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
error "[ceru 音乐插件] Error: 歌曲不存在"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2645500113,\"name\":\"跳楼机\",\"artist\":\"LBI利比\",\"album\":\"跳楼机\",\"pic_id\":\"109951170507596121\",\"url_id\":2645500113,\"lyric_id\":2645500113,\"source\":\"netease\",\"lyric\":\"[00:00.00] 作..."log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/1135545898"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/1135545898"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/1139605559"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/1139605559"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2003594562"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2003594562"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[CeruMusic] 响应不是JSON格式内容: ..."
error "[ceru 音乐插件] Error: 歌曲不存在"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: ..."
log "[CeruMusic] 请求响应内容: [object Object]"
error "[ceru 音乐插件] Error: 歌曲不存在"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2645500113,\"name\":\"跳楼机\",\"artist\":\"LBI利比\",\"album\":\"跳楼机\",\"pic_id\":\"109951170507596121\",\"url_id\":2645500113,\"lyric_id\":2645500113,\"source\":\"netease\",\"lyric\":\"[00:00.00] 作..."
error "[ceru 音乐插件] Error: 歌曲不存在"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2645500113,\"name\":\"跳楼机\",\"artist\":\"LBI利比\",\"album\":\"跳楼机\",\"pic_id\":\"109951170507596121\",\"url_id\":2645500113,\"lyric_id\":2645500113,\"source\":\"netease\",\"lyric\":\"[00:00.00] 作..."
log "[CeruMusic] 请求响应内容: [object Object]"
error "[ceru 音乐插件] Error: 歌曲不存在"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2149456401,\"name\":\"alone.\",\"artist\":\"DLSS\",\"album\":\"alone.\",\"pic_id\":\"109951169530908047\",\"url_id\":2149456401,\"lyric_id\":2149456401,\"source\":\"netease\",\"lyric\":\"[00:00...."
log "[CeruMusic] 请求响应内容: [object Object]"
error "[ceru 音乐插件] Error: 歌曲不存在"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2003594562,\"name\":\"天晴\",\"artist\":\"是二智呀\",\"album\":\"天晴\",\"pic_id\":\"109951168114308737\",\"url_id\":2003594562,\"lyric_id\":2003594562,\"source\":\"netease\",\"lyric\":\"[00:00.06]作词:陈澈..."
error "[ceru 音乐插件] Error: 歌曲不存在"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[ceru 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2645500113"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/254574
log [CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/254574
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"status":true,"song_data":{"id":254574,"name":"后来","artist":"刘若英","album":"我等你","pic_id":"109951163351825356","url_id":254574,"lyric_id":254574,"source":"netease","lyric":"[00:00.000] 作词 : 施人诚\n[00:01.000] 作曲 : 玉城千春\n[00:02.000] 编曲 : 王继康\n[00:03.000] 制作人 : 光良\n[00:12.571]后来 我总算学会了如何去爱\n[00:19.303]可惜你 早已远去 消失在人海\n[00:25.238]后来 终于在眼泪中明白\n[00:32.064]有些人 一旦错过就不在\n[00:39.800]栀子花 白花瓣\n[00:46.027]落在我蓝色百褶裙上\n[00:51.763]爱你 你轻声说\n[00:58.844]我低下头 闻见一阵芬芳\n[01:05.371]那个永恒的夜晚\n[01:09.341]十七岁仲夏\n[01:12.104]你吻我的那个夜晚\n[01:18.232]让我往后的时光\n[01:21.749]每当有感叹\n[01:24.862]总想起当天的星光\n[01:30.992]那时候的爱情\n[01:37.422]为什么就能那样简单\n[01:42.493]而又是为什么 人年少时\n[01:50.179]一定要让深爱的人受伤\n[01:56.301]在这相似的深夜里\n[02:00.566]你是否一样 也在静静追悔感伤\n[02:09.350]如果当时我们能\n[02:13.015]不那么倔强\n[02:16.079]现在也 不那么遗憾\n[02:21.053]你都如何回忆我\n[02:24.014]带着笑或是很沉默\n[02:27.231]这些年来\n[02:28.837]有没有人能让你不寂寞\n[02:33.455]后来 我总算学会了如何去爱\n[02:40.238]可惜你 早已远去 消失在人海\n[02:46.318]后来 终于在眼泪中明白\n[02:53.042]有些人 一旦错过就不在\n[03:25.379]你都如何回忆我\n[03:28.132]带着笑或是很沉默\n[03:31.296]这些年来\n[03:32.953]有没有人能让你不寂寞\n[03:37.523]后来\n[03:39.530]我总算学会了如何去爱\n[03:44.301]可惜你 早已远去 消失在人海\n[03:50.174]后来 终于在眼泪中明白\n[03:57.104]有些人 一旦错过就不在\n[04:03.136]后来 我总算学会了如何去爱\n[02:59.120]\n[04:09.965]可惜你 早已远去 消失在人海\n[04:15.937]后来 终于在眼泪中明白\n[04:22.771]有些人 一旦错过就不在\n[04:29.598]永远不会再重来\n[04:35.510]有一个男孩爱着那个女孩\n[05:02.681]录音工程师 : 周建平 & Peter Chong (MAL)\n[05:03.781]混音工程师 : 王晋溢\n[05:04.881]录音室 : 捷奏 & Synchrosound (MAL)\n[05:05.981]混音室 : 白金录音室\n[05:06.111]吉他 : Jamie Wilson\n[05:07.222]和声编写 : 光良\n[05:08.333]和声 : 梁静茹\n[05:09.444]OP : Victor Music Publishing Co., Ltd.\n[05:10.555]ISRC TW-A45-99-62502\n","pic":"https://p3.music.126.net/eBF7bHnJYBUfOFrJ_7SUfw==/109951163351825356.jpg?param=300y300","url":"https://m701.music.126.net/20250822145154/db9d934a5c833fe5bbe68e21bfd4720f/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/14783185971/f717/93d1/d743/037c337c4123b835758717a3e2e9286b.mp3","size":13658950,"br":320}}
log [ceru 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/254574
log [CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/254574
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"status":true,"song_data":{"id":254574,"name":"后来","artist":"刘若英","album":"我等你","pic_id":"109951163351825356","url_id":254574,"lyric_id":254574,"source":"netease","lyric":"[00:00.000] 作词 : 施人诚\n[00:01.000] 作曲 : 玉城千春\n[00:02.000] 编曲 : 王继康\n[00:03.000] 制作人 : 光良\n[00:12.571]后来 我总算学会了如何去爱\n[00:19.303]可惜你 早已远去 消失在人海\n[00:25.238]后来 终于在眼泪中明白\n[00:32.064]有些人 一旦错过就不在\n[00:39.800]栀子花 白花瓣\n[00:46.027]落在我蓝色百褶裙上\n[00:51.763]爱你 你轻声说\n[00:58.844]我低下头 闻见一阵芬芳\n[01:05.371]那个永恒的夜晚\n[01:09.341]十七岁仲夏\n[01:12.104]你吻我的那个夜晚\n[01:18.232]让我往后的时光\n[01:21.749]每当有感叹\n[01:24.862]总想起当天的星光\n[01:30.992]那时候的爱情\n[01:37.422]为什么就能那样简单\n[01:42.493]而又是为什么 人年少时\n[01:50.179]一定要让深爱的人受伤\n[01:56.301]在这相似的深夜里\n[02:00.566]你是否一样 也在静静追悔感伤\n[02:09.350]如果当时我们能\n[02:13.015]不那么倔强\n[02:16.079]现在也 不那么遗憾\n[02:21.053]你都如何回忆我\n[02:24.014]带着笑或是很沉默\n[02:27.231]这些年来\n[02:28.837]有没有人能让你不寂寞\n[02:33.455]后来 我总算学会了如何去爱\n[02:40.238]可惜你 早已远去 消失在人海\n[02:46.318]后来 终于在眼泪中明白\n[02:53.042]有些人 一旦错过就不在\n[03:25.379]你都如何回忆我\n[03:28.132]带着笑或是很沉默\n[03:31.296]这些年来\n[03:32.953]有没有人能让你不寂寞\n[03:37.523]后来\n[03:39.530]我总算学会了如何去爱\n[03:44.301]可惜你 早已远去 消失在人海\n[03:50.174]后来 终于在眼泪中明白\n[03:57.104]有些人 一旦错过就不在\n[04:03.136]后来 我总算学会了如何去爱\n[02:59.120]\n[04:09.965]可惜你 早已远去 消失在人海\n[04:15.937]后来 终于在眼泪中明白\n[04:22.771]有些人 一旦错过就不在\n[04:29.598]永远不会再重来\n[04:35.510]有一个男孩爱着那个女孩\n[05:02.681]录音工程师 : 周建平 & Peter Chong (MAL)\n[05:03.781]混音工程师 : 王晋溢\n[05:04.881]录音室 : 捷奏 & Synchrosound (MAL)\n[05:05.981]混音室 : 白金录音室\n[05:06.111]吉他 : Jamie Wilson\n[05:07.222]和声编写 : 光良\n[05:08.333]和声 : 梁静茹\n[05:09.444]OP : Victor Music Publishing Co., Ltd.\n[05:10.555]ISRC TW-A45-99-62502\n","pic":"https://p3.music.126.net/eBF7bHnJYBUfOFrJ_7SUfw==/109951163351825356.jpg?param=300y300","url":"https://m701.music.126.net/20250822145155/4f1e01f33ad960791480b07624819f2a/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/14783185971/f717/93d1/d743/037c337c4123b835758717a3e2e9286b.mp3","size":13658950,"br":320}}
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.
log [CeruMusic] Plugin "ceru 音乐插件" loaded successfully.

View File

@@ -1,100 +0,0 @@
log [CeruMusic] Plugin "未知插件" loaded successfully.log [插件] 注册事件监听器: request
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/urlinfo/1.0.0
log [CeruMusic] 事件驱动插件初始化成功
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 503
log [CeruMusic] 请求响应内容: [object Object]
log [插件] 音源注册完成: kw,wy,mg,tx,kg
log [插件] 发送事件: inited [object Object]
error [CeruMusic] Request failed: Expected JSON response but got: text/html
log [CeruMusic] 响应不是JSON格式内容: <html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>
...
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应状态: 404
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应状态: 404
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/254574/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 kw 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/kw/2061973302/320k
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 请求响应内容: [object Object]

View File

@@ -1,28 +0,0 @@
log "[CeruMusic] Plugin \"LiHouse 音乐插件\" loaded successfully."log "[LiHouse 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/1135545898"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/1135545898"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[LiHouse 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2003594562"
log "[LiHouse 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2003594562"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: ..."
log "[CeruMusic] 请求响应内容: [object Object]"
error "[LiHouse 音乐插件] 请求失败: 歌曲不存在"
error "[LiHouse 音乐插件] Error: 歌曲不存在"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2149456401,\"name\":\"alone.\",\"artist\":\"DLSS\",\"album\":\"alone.\",\"pic_id\":\"109951169530908047\",\"url_id\":2149456401,\"lyric_id\":2149456401,\"source\":\"netease\",\"lyric\":\"[00:00...."
error "[LiHouse 音乐插件] Error: 歌曲不存在"
error "[LiHouse 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[LiHouse 音乐插件] 请求失败: 歌曲不存在"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2003594562,\"name\":\"天晴\",\"artist\":\"是二智呀\",\"album\":\"天晴\",\"pic_id\":\"109951168114308737\",\"url_id\":2003594562,\"lyric_id\":2003594562,\"source\":\"netease\",\"lyric\":\"[00:00.06]作词:陈澈..."
error "[LiHouse 音乐插件] Error: 歌曲不存在"
log "[CeruMusic] 发起请求: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[LiHouse 音乐插件] 请求音乐链接: https://www.lihouse.xyz/coco_widget/music_resource/id/2149456401"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 响应不是JSON格式内容: {\"status\":true,\"song_data\":{\"id\":2149456401,\"name\":\"alone.\",\"artist\":\"DLSS\",\"album\":\"alone.\",\"pic_id\":\"109951169530908047\",\"url_id\":2149456401,\"lyric_id\":2149456401,\"source\":\"netease\",\"lyric\":\"[00:00...."
log "[CeruMusic] 请求响应内容: [object Object]"
error "[LiHouse 音乐插件] Error: 歌曲不存在"
error "[LiHouse 音乐插件] 请求失败: 歌曲不存在"

View File

@@ -1,200 +0,0 @@
end
log handleGetMusicUrl(kg_178240, hires) failed: Key失效/鉴权失败
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
start Handle Action(musicUrl)
log musicInfo {"name":"后来","singer":"刘若英","source":"kw","songmid":"96765035","albumId":"13825074","interval":"05:09","albumName":"2020 刘若英陪你 献上录音专辑","lrc":null,"img":"http://img1.kwcdn.kuwo.cn/star/albumcover/500/s4s68/34/3776980601.jpg","otherSource":null,"types":[{"type":"128k","size":"4.72Mb"},{"type":"320k","size":"11.80Mb"},{"type":"flac","size":"60.23Mb"},{"type":"flac24bit","size":"60.23Mb"}],"_types":{"flac24bit":{"size":"60.23MB"},"flac":{"size":"60.23MB"},"320k":{"size":"11.80MB"},"128k":{"size":"4.72MB"}},"typeUrl":{},"url":"http://cu.sycdn.kuwo.cn/226d5ab974a1d2ca5b5643e2354e7696/68a73db3/resource/s2/87/81/730236710.flac"}
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log quality hires
log source kw
log --- start --- https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log [CeruMusic] 请求响应状态: 200
log API Response: {"body":{"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":false,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:30:35 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["583"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.12571569811552763"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":false,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
end
log handleGetMusicUrl(kw_96765035, hires) success, URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac
log [ikun音源] Got URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flaclog 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 注册事件监听器: request
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:32:16 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0007874071598052979"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log checkUpdate success
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
start Handle Action(musicUrl)
log quality hires
log musicInfo {"name":"后来","singer":"刘若英","source":"kw","songmid":"96765035","albumId":"13825074","interval":"05:09","albumName":"2020 刘若英陪你 献上录音专辑","lrc":null,"img":"http://img1.kwcdn.kuwo.cn/star/albumcover/500/s4s68/34/3776980601.jpg","otherSource":null,"types":[{"type":"128k","size":"4.72Mb"},{"type":"320k","size":"11.80Mb"},{"type":"flac","size":"60.23Mb"},{"type":"flac24bit","size":"60.23Mb"}],"_types":{"flac24bit":{"size":"60.23MB"},"flac":{"size":"60.23MB"},"320k":{"size":"11.80MB"},"128k":{"size":"4.72MB"}},"typeUrl":{},"url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac"}
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log source kw
log --- start --- https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:32:17 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["582"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0030085640028119087"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
end
log handleGetMusicUrl(kw_96765035, hires) success, URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac
log [ikun音源] Got URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log [ikun音源 by Ceru插件] 注册事件监听器: request
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [CeruMusic] 事件驱动插件初始化成功
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:32:58 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0008850144222378731"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log checkUpdate success
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
error [ikun音源] Error: args.map is not a function
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [ikun音源 by Ceru插件] 注册事件监听器: request
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:33:02 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0008127372711896896"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log checkUpdate success
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
error [ikun音源] Error: args.map is not a function
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 注册事件监听器: request
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:33:30 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0008348245173692703"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log checkUpdate success
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
error [ikun音源] Error: args.map is not a function
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [ikun音源 by Ceru插件] 注册事件监听器: request
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 请求响应状态: 200
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:34:27 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0008898386731743813"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log checkUpdate success
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
error [ikun音源] Error: args.map is not a functionlog [ikun音源] 使用事件驱动方式获取 kw 音源链接
error [ikun音源] Error: args.map is not a function
error [ikun音源] Error: args.map is not a function
log [ikun音源] 使用事件驱动方式获取 kg 音源链接
log [ikun音源] 使用事件驱动方式获取 kg 音源链接
error [ikun音源] Error: args.map is not a function
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 注册事件监听器: request
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","data":{"updateMsg":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:35:51 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["370"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0008251480758190155"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log [ikun音源 by Ceru插件] 发送事件: updateAlert {"log":"⚠️ 重要更新\n更新地址:\nhttps://api.ikunshare.com/script\n日志\n更换域名\nQQ群: https://qm.qq.com/q/okMS3ubs0E","updateUrl":"https://api.ikunshare.com/script"}
log checkUpdate success
log [ikun音源] 使用事件驱动方式获取 kg 音源链接
log quality hires
start groupStart--------- Handle Action(musicUrl)
log musicInfo {"singer":"周杰伦","name":"半岛铁盒","albumName":"八度空间","albumId":"961807","songmid":178240,"source":"kg","interval":"05:19","_interval":319,"img":"http://imge.kugou.com/stdmusic/480/20250221/20250221180703846658.jpg","lrc":null,"otherSource":null,"hash":"67BA8A4A0681F2078BC423CB13B904B7","types":[{"type":"128k","size":"4.88 MB","hash":"67BA8A4A0681F2078BC423CB13B904B7"},{"type":"320k","size":"12.19 MB","hash":"68DEA6329FB28534271943B3F97599DC"},{"type":"flac","size":"34.93 MB","hash":"9F0F140F8A9C3A0E639A9BF8680E80E9"},{"type":"flac24bit","size":"61.72 MB","hash":"2CCC7683F50BE90A0C407D6FF0F973D9"}],"_types":{"128k":{"size":"4.88 MB","hash":"67BA8A4A0681F2078BC423CB13B904B7"},"320k":{"size":"12.19 MB","hash":"68DEA6329FB28534271943B3F97599DC"},"flac":{"size":"34.93 MB","hash":"9F0F140F8A9C3A0E639A9BF8680E80E9"},"flac24bit":{"size":"61.72 MB","hash":"2CCC7683F50BE90A0C407D6FF0F973D9"}},"typeUrl":{}}
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=kg&songId=67BA8A4A0681F2078BC423CB13B904B7&quality=hires
log --- start --- https://api.ikunshare.com/url?source=kg&songId=67BA8A4A0681F2078BC423CB13B904B7&quality=hires
log source kg
log [CeruMusic] 请求响应状态: 403
log API Response: {"body":{"code":403,"message":"你还没给我上供","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":403,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:35:51 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["138"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.00015995558351278305"]}}
log [CeruMusic] 请求响应内容: {"code":403,"message":"你还没给我上供","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log handleGetMusicUrl(kg_178240, hires) failed: Key失效/鉴权失败
error [ikun音源] Error: Key失效/鉴权失败
end log [ikun音源] 使用事件驱动方式获取 kg 音源链接
start groupStart--------- Handle Action(musicUrl)
log source kg
log musicInfo {"singer":"周杰伦","name":"半岛铁盒","albumName":"八度空间","albumId":"961807","songmid":178240,"source":"kg","interval":"05:19","_interval":319,"img":"http://imge.kugou.com/stdmusic/480/20250221/20250221180703846658.jpg","lrc":null,"otherSource":null,"hash":"67BA8A4A0681F2078BC423CB13B904B7","types":[{"type":"128k","size":"4.88 MB","hash":"67BA8A4A0681F2078BC423CB13B904B7"},{"type":"320k","size":"12.19 MB","hash":"68DEA6329FB28534271943B3F97599DC"},{"type":"flac","size":"34.93 MB","hash":"9F0F140F8A9C3A0E639A9BF8680E80E9"},{"type":"flac24bit","size":"61.72 MB","hash":"2CCC7683F50BE90A0C407D6FF0F973D9"}],"_types":{"128k":{"size":"4.88 MB","hash":"67BA8A4A0681F2078BC423CB13B904B7"},"320k":{"size":"12.19 MB","hash":"68DEA6329FB28534271943B3F97599DC"},"flac":{"size":"34.93 MB","hash":"9F0F140F8A9C3A0E639A9BF8680E80E9"},"flac24bit":{"size":"61.72 MB","hash":"2CCC7683F50BE90A0C407D6FF0F973D9"}},"typeUrl":{}}
log --- start --- https://api.ikunshare.com/url?source=kg&songId=67BA8A4A0681F2078BC423CB13B904B7&quality=hires
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=kg&songId=67BA8A4A0681F2078BC423CB13B904B7&quality=hires
log quality hires
log [CeruMusic] 请求响应状态: 403
log API Response: {"body":{"code":403,"message":"你还没给我上供","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":403,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:36:55 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["138"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["8.029583841562271e-05"]}}
log handleGetMusicUrl(kg_178240, hires) failed: Key失效/鉴权失败
error [ikun音源] Error: Key失效/鉴权失败
end
log [CeruMusic] 请求响应内容: {"code":403,"message":"你还没给我上供","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log [ikun音源] 使用事件驱动方式获取 kw 音源链接
log source kw
log musicInfo {"name":"后来","singer":"刘若英","source":"kw","songmid":"96765035","albumId":"13825074","interval":"05:09","albumName":"2020 刘若英陪你 献上录音专辑","lrc":null,"img":"http://img1.kwcdn.kuwo.cn/star/albumcover/500/s4s68/34/3776980601.jpg","otherSource":null,"types":[{"type":"128k","size":"4.72Mb"},{"type":"320k","size":"11.80Mb"},{"type":"flac","size":"60.23Mb"},{"type":"flac24bit","size":"60.23Mb"}],"_types":{"flac24bit":{"size":"60.23MB"},"flac":{"size":"60.23MB"},"320k":{"size":"11.80MB"},"128k":{"size":"4.72MB"}},"typeUrl":{},"url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac"}
log --- start --- https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=kw&songId=96765035&quality=hires
log quality hires
start groupStart--------- Handle Action(musicUrl)
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","url":"http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac","info":{"id":"96765035","name":"后来","album":"2020 刘若英陪你 献上录音专辑","artist":"刘若英"},"ekey":null,"cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 12:15:35","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:36:56 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["582"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.002598297782242298"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log handleGetMusicUrl(kw_96765035, hires) success, URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac
end
log [ikun音源] Got URL: http://cu.sycdn.kuwo.cn/f9678d8cdc643bcd8ff61bc61099540d/68a7e45b/resource/s2/87/81/730236710.flac
log [ikun音源] 使用事件驱动方式获取 mg 音源链接
log source mg
start groupStart--------- Handle Action(musicUrl)
log musicInfo {"singer":"音阙诗听","name":"红昭愿 (伴奏)","albumName":"诗","albumId":"1140686463","songmid":"1135545898","copyrightId":"69069801208","source":"mg","interval":"02:53","img":"http://d.musicapp.migu.cn/data/oss/resource/00/4g/u6/5fa3dbc0f6584fa88ba2c073f52d7330.webp","lrc":null,"lrcUrl":"https://d.musicapp.migu.cn/data/oss/resource/00/4s/oi/6972a559ab2d4162b649ac12646c9678","types":[{"type":"128k","size":"2.62 MB"},{"type":"320k","size":"6.56 MB"}],"_types":{"128k":{"size":"2.62 MB"},"320k":{"size":"6.56 MB"}},"typeUrl":{},"url":"http://freetyst.nf.migu.cn/public/product9th/product47/2025/03/1216/2025%E5%B9%B401%E6%9C%8820%E6%97%A514%E7%82%B940%E5%88%86%E7%B4%A7%E6%80%A5%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E6%88%90%E9%83%BD%E8%B0%A6%E4%BF%AE%E6%88%90%E6%9C%AC502%E9%A6%96015401/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/69069801208160124.mp3"}
log quality hires
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=mg&songId=1135545898&quality=hires
log --- start --- https://api.ikunshare.com/url?source=mg&songId=1135545898&quality=hires
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","url":"http://freetyst.nf.migu.cn/public/product9th/product47/2025/03/1216/2025%E5%B9%B401%E6%9C%8820%E6%97%A514%E7%82%B940%E5%88%86%E7%B4%A7%E6%80%A5%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E6%88%90%E9%83%BD%E8%B0%A6%E4%BF%AE%E6%88%90%E6%9C%AC502%E9%A6%96015401/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/69069801208160124.mp3","info":{"id":"1135545898","name":"红昭愿 (伴奏)","album":"诗","artist":"音阙诗听"},"ekey":"","cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":null,"canExpire":false},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","url":"http://freetyst.nf.migu.cn/public/product9th/product47/2025/03/1216/2025%E5%B9%B401%E6%9C%8820%E6%97%A514%E7%82%B940%E5%88%86%E7%B4%A7%E6%80%A5%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E6%88%90%E9%83%BD%E8%B0%A6%E4%BF%AE%E6%88%90%E6%9C%AC502%E9%A6%96015401/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/69069801208160124.mp3","info":{"id":"1135545898","name":"红昭愿 (伴奏)","album":"诗","artist":"音阙诗听"},"ekey":"","cache":true,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":null,"canExpire":false},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:37:05 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["761"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.004381708800792694"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
end
log [ikun音源] Got URL: http://freetyst.nf.migu.cn/public/product9th/product47/2025/03/1216/2025%E5%B9%B401%E6%9C%8820%E6%97%A514%E7%82%B940%E5%88%86%E7%B4%A7%E6%80%A5%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E6%88%90%E9%83%BD%E8%B0%A6%E4%BF%AE%E6%88%90%E6%9C%AC502%E9%A6%96015401/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/69069801208160124.mp3
log handleGetMusicUrl(mg_1135545898, hires) success, URL: http://freetyst.nf.migu.cn/public/product9th/product47/2025/03/1216/2025%E5%B9%B401%E6%9C%8820%E6%97%A514%E7%82%B940%E5%88%86%E7%B4%A7%E6%80%A5%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E6%88%90%E9%83%BD%E8%B0%A6%E4%BF%AE%E6%88%90%E6%9C%AC502%E9%A6%96015401/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/69069801208160124.mp3
log [ikun音源] 使用事件驱动方式获取 wy 音源链接
start groupStart--------- Handle Action(musicUrl)
log musicInfo {"singer":"DLSS","name":"alone.","albumName":"alone.","albumId":193463408,"source":"wy","interval":"02:25","songmid":2149456401,"img":"http://p2.music.126.net/I-pKOLxJENNTkZp1nbY2VA==/109951169530908047.jpg","lrc":null,"types":[{"type":"128k","size":"2.21 MB"},{"type":"320k","size":"5.54 MB"},{"type":"flac","size":"16.91 MB"},{"type":"flac24bit","size":"30.14 MB"}],"_types":{"flac24bit":{"size":"30.14 MB"},"flac":{"size":"16.91 MB"},"320k":{"size":"5.54 MB"},"128k":{"size":"2.21 MB"}},"typeUrl":{},"url":"http://m701.music.126.net/20250822111746/88562bac7e992f3433e465b0d8b57883/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506990299/de4f/d537/7094/a86a0c894b20f627e58f4e037d4c395d.flac"}
log source wy
log --- start --- https://api.ikunshare.com/url?source=wy&songId=2149456401&quality=hires
log quality hires
log [CeruMusic] 发起请求: https://api.ikunshare.com/url?source=wy&songId=2149456401&quality=hires
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","url":"http://m701.music.126.net/20250822120208/2d51054583249a7c26ad5fb98b6cd10c/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506990299/de4f/d537/7094/a86a0c894b20f627e58f4e037d4c395d.flac","info":{"id":"2149456401","name":"无","album":"无","artist":"无"},"ekey":"","cache":false,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 11:46:08","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","url":"http://m701.music.126.net/20250822120208/2d51054583249a7c26ad5fb98b6cd10c/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506990299/de4f/d537/7094/a86a0c894b20f627e58f4e037d4c395d.flac","info":{"id":"2149456401","name":"无","album":"无","artist":"无"},"ekey":"","cache":false,"quality":{"target":"无损音质 24Bit","result":"无损音质 24Bit"},"expire":{"ExpireAt":"2025-08-22 11:46:08","canExpire":true},"yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:37:08 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["573"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.05814129579812288"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log handleGetMusicUrl(wy_2149456401, hires) success, URL: http://m701.music.126.net/20250822120208/2d51054583249a7c26ad5fb98b6cd10c/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506990299/de4f/d537/7094/a86a0c894b20f627e58f4e037d4c395d.flac
end
log [ikun音源] Got URL: http://m701.music.126.net/20250822120208/2d51054583249a7c26ad5fb98b6cd10c/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506990299/de4f/d537/7094/a86a0c894b20f627e58f4e037d4c395d.flac

View File

@@ -1,611 +0,0 @@
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 wy 音源链接"
log "[CeruMusic] 发起请求: https://api.cenguigui.cn/api/netease/music_v1.php?id=2149456401&type=json&level=standard"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[聚合API接口 (by lerd)] Got URL: https://m801.music.126.net/20250822114001/b2afa538a9bd71a275090423ddb61b8b/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506991358/9262/9bfa/0e3d/8c4de2e46cb45b5913ac027c12634562.mp3?vuutv=W9gkRY5/Xlj5zcDzyIP7t0xycVF+bFPqM0yESnLJxymoNNC8Qe5OOEOlRo53aqLkZnFkBT8oxO2ITbyyaDwgkp+EtrWk+EReVTFmLEMt874=&cdntag=bWFyaz1vc193ZWIscXVhbGl0eV9zdGFuZGFyZA"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[CeruMusic] 请求响应状态: 200"log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 wy 音源链接"
log "[CeruMusic] 发起请求: https://api.cenguigui.cn/api/netease/music_v1.php?id=2149456401&type=json&level=standard"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[聚合API接口 (by lerd)] Got URL: https://m701.music.126.net/20250822114056/2d8aa51da3c2074cb50a36f4bf348786/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/35506991358/9262/9bfa/0e3d/8c4de2e46cb45b5913ac027c12634562.mp3?vuutv=AsMvTRDjrKksRSVj9wEKkCeAiu88u1zgQsfaYBeFQEw2J4cS1rQojrSdnZMXbu7OdwCJztt32zRefQ6ptoNL0+xYMJarqVgOT1jJWCTrJgc=&cdntag=bWFyaz1vc193ZWIscXVhbGl0eV9zdGFuZGFyZA"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[CeruMusic] 事件驱动插件初始化成功"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[CeruMusic] 请求响应状态: 200"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request"
log "[聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]"
log "[聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mg"
log "[CeruMusic] 事件驱动插件初始化成功"
log "[CeruMusic] Plugin \"聚合API接口 (by lerd)\" loaded successfully."
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
error "[聚合API接口 (by lerd)] Error: get url error"
log "[CeruMusic] 请求响应内容: [object Object]"
log "[聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接"
log "[CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128"
log "[CeruMusic] 请求响应状态: 200"
log "[CeruMusic] 请求响应内容: [object Object]"
error "[聚合API接口 (by lerd)] Error: get url error"log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接
log [CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":-2,"msg":"酷狗hash解析暂未公开开放,如需请付费使用或购买源码使用"}
error [聚合API接口 (by lerd)] Error: get url error
log [聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接
log [CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":-2,"msg":"酷狗hash解析暂未公开开放,如需请付费使用或购买源码使用"}
error [聚合API接口 (by lerd)] Error: get url errorlog [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接
log [CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":-2,"msg":"酷狗hash解析暂未公开开放,如需请付费使用或购买源码使用"}
error [聚合API接口 (by lerd)] Error: get url error
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd)] 使用事件驱动方式获取 kg 音源链接
log [CeruMusic] 发起请求: https://www.hhlqilongzhu.cn/api/dg_kugouSQ.php?type=json&hash=67BA8A4A0681F2078BC423CB13B904B7&quality=128
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":-2,"msg":"酷狗hash解析暂未公开开放,如需请付费使用或购买源码使用"}
error [聚合API接口 (by lerd)] Error: get url error
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: request
log [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"tx":{"name":"tx","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kg":{"name":"kg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit"]},"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["320k","flac"]}}}
log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac"]},"kg":{"name":"酷狗音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"tx":{"name":"QQ音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["320k","flac"]}}
log [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.
log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: ["tx","wy","kg","kw","mg"]
log [CeruMusic] 事件驱动插件初始化成功

File diff suppressed because it is too large Load Diff

View File

@@ -1,83 +0,0 @@
log [未知插件 by Ceru插件] 注册事件监听器: request
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/urlinfo/1.0.0
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "未知插件" loaded successfully.
log [CeruMusic] 请求响应状态: 503
log [CeruMusic] 响应不是JSON格式内容: <html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>
...
log [CeruMusic] 请求响应内容: [object Object]
error [CeruMusic] Request failed: Expected JSON response but got: text/html
log [未知插件 by Ceru插件] 发送事件: inited [object Object]
log [未知插件 by Ceru插件] 动态音源信息已更新: [object Object]
log [未知插件 by Ceru插件] 音源注册完成: kw,wy,mg,tx,kglog [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1895330088/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/38576323/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1808492017/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/502043537/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1887139866/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1365898499/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1363948882/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 请求响应内容: [object Object]
log [CeruMusic] 响应不是JSON格式内容: Not Found...
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8
log [未知插件 by Ceru插件] 注册事件监听器: request
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/urlinfo/1.0.0
log [CeruMusic] Plugin "未知插件" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] 请求响应状态: 503
log [CeruMusic] 响应不是JSON格式内容: <html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>
...
log [未知插件 by Ceru插件] 发送事件: inited [object Object]
error [CeruMusic] Request failed: Expected JSON response but got: text/html
log [未知插件 by Ceru插件] 动态音源信息已更新: [object Object]
log [未知插件 by Ceru插件] 音源注册完成: kw,wy,mg,tx,kg
log [CeruMusic] 请求响应内容: [object Object]
log [未知插件] 使用事件驱动方式获取 tx 音源链接
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/url/tx/1363948882/master
log [CeruMusic] 请求响应状态: 404
log [CeruMusic] 响应不是JSON格式内容: Not Found...
log [CeruMusic] 请求响应内容: [object Object]
error [未知插件] Error: Expected JSON response but got: text/plain; charset=utf-8

View File

@@ -1,52 +0,0 @@
log [CeruMusic] Plugin "ikun音源" loaded successfully.log [聚合API接口 (by lerd) by Ceru插件] 注册事件监听器: requestlog [聚合API接口 (by lerd) by Ceru插件] 发送事件: inited [object Object]log [聚合API接口 (by lerd) by Ceru插件] 动态音源信息已更新: [object Object]log [聚合API接口 (by lerd) by Ceru插件] 音源注册完成: tx,wy,kg,kw,mglog [CeruMusic] Plugin "聚合API接口 (by lerd)" loaded successfully.log [CeruMusic] 事件驱动插件初始化成功log [未知插件 by Ceru插件] 注册事件监听器: request
log [CeruMusic] 发起请求: http://flower.tempmusics.tk/v1/urlinfo/1.0.0
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] Plugin "未知插件" loaded successfully.
log [CeruMusic] 请求响应状态: 503
log [CeruMusic] 响应不是JSON格式内容: <html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>
...
log [未知插件 by Ceru插件] 发送事件: inited [object Object]
log [未知插件 by Ceru插件] 音源注册完成: kw,wy,mg,tx,kg
log [未知插件 by Ceru插件] 动态音源信息已更新: [object Object]
log [CeruMusic] 请求响应内容: [object Object]
error [CeruMusic] Request failed: Expected JSON response but got: text/html
log [CeruMusic] Plugin "未知插件" loaded successfully.
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: [object Object]
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log 解析后的 MUSIC_QUALITY 数据: [object Object]
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=6c72d109ed7db5cf037b3bbf1dfccb53
log [ikun音源 by Ceru插件] 注册事件监听器: request
log [ikun音源 by Ceru插件] 发送事件: inited [object Object]
log [ikun音源 by Ceru插件] 动态音源信息已更新: [object Object]
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [ikun音源 by Ceru插件] 音源注册完成: kw,wy,mg
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: [object Object]
log checkUpdate success
log API Response: [object Object]
log [ikun音源 by Ceru插件] 发送事件: updateAlert [object Object]
log "[CeruMusic] Plugin \"LiHouse 音乐插件\" loaded successfully."
log "[CeruMusic] Plugin \"ceru 音乐插件\" loaded successfully."
log 解析后的 MUSIC_QUALITY 数据: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取到的 MUSIC_QUALITY 字符串: {"kw":["128k","320k","flac","flac24bit","hires"],"wy":["128k","320k","flac","flac24bit","hires","atmos","master"],"mg":["128k","320k","flac","flac24bit","hires"]}
log 提取的音源配置: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log --- start --- https://api.ikunshare.com/script?key=&checkUpdate=5917eb1e565bf906fb0433bb1a3b00b5
log [ikun音源 by Ceru插件] 注册事件监听器: request
log [CeruMusic] 发起请求: https://api.ikunshare.com/script?key=&checkUpdate=5917eb1e565bf906fb0433bb1a3b00b5
log [ikun音源 by Ceru插件] 发送事件: inited {"status":true,"openDevTools":false,"sources":{"kw":{"name":"kw","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"wy","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"mg","type":"music","actions":["musicUrl"],"qualitys":["128k","320k","flac","flac24bit","hires"]}}}
log [ikun音源 by Ceru插件] 音源注册完成: ["kw","wy","mg"]
log [ikun音源 by Ceru插件] 动态音源信息已更新: {"kw":{"name":"酷我音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]},"wy":{"name":"网易云音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires","atmos","master"]},"mg":{"name":"咪咕音乐","type":"music","qualitys":["128k","320k","flac","flac24bit","hires"]}}
log [CeruMusic] Plugin "ikun音源" loaded successfully.
log [CeruMusic] 事件驱动插件初始化成功
log [CeruMusic] 请求响应状态: 200
log [CeruMusic] 请求响应内容: {"code":200,"message":"成功","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}}
log API Response: {"body":{"code":200,"message":"成功","yourinfo":{"ip":"183.251.97.29","ua":"lx-music-nodejs/1.0.0"}},"statusCode":200,"headers":{"server":["openresty"],"date":["Fri, 22 Aug 2025 03:44:41 GMT"],"content-type":["application/json; charset=utf-8"],"content-length":["108"],"connection":["keep-alive"],"access-control-allow-origin":["*"],"x-process-time":["0.0007938602939248085"],"cache-control":["no-cache"],"alt-svc":["h3=\":443\"; ma=2592000"]}}
log checkUpdate success

View File

@@ -1,75 +0,0 @@
/**
* LiHouse 音乐插件
* @author CodeBuddy
* @version 1.0.0
*/
// 基础 URL
const baseTwoUrl = 'https://www.lihouse.xyz/coco_widget';
// 1. 插件信息
const pluginInfo = {
name: 'ceru 音乐插件',
version: '1.0.0',
author: '时迁酱',
description: '提供 网易云 音乐资源的访问'
}
// 2. 支持的音源配置
const sources = {
wy: {
name: '网易云',
type: 'music',
qualitys: ['320k'] // 假设支持这些音质
}
}
// 3. 获取音乐URL的核心函数
async function musicUrl(source, musicInfo, quality) {
// 从 cerumusic 对象获取 API
const { request, env, version } = cerumusic
// 构建请求参数
const songId = musicInfo.songmid || musicInfo.hash;
if (!songId) {
throw new Error('无效的歌曲ID');
}
const apiUrl = `${baseTwoUrl}/music_resource/id/${songId}`;
console.log(`[${pluginInfo.name}] 请求音乐链接: ${apiUrl}`);
try {
// 发起网络请求
const { body, statusCode } = await request(apiUrl, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'User-Agent': `cerumusic-${env}/${version}`
}
});
// 处理响应
if (statusCode !== 200 || !body.status) {
const errorMessage = body.message || '歌曲不存在';
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
// 根据请求的音质选择对应的链接
// 假设 song_data 中包含不同音质的链接
const songData = body.song_data;
return songData.url
throw new Error('无效的响应格式');
} catch (error) {
console.error(`[${pluginInfo.name}] 请求失败:`, error.message);
throw new Error(`获取音乐链接失败: ${error.message}`);
}
}
// 导出插件
module.exports = {
pluginInfo,
sources,
musicUrl,
}

File diff suppressed because one or more lines are too long

View File

@@ -1,284 +0,0 @@
/**
* 由 CeruMusic 插件转换器转换 - @author sqj
* @name ikun音源
* @author ikunshare
* @version v14
* @description 反馈群951962664
*/
const pluginInfo = {
name: "ikun音源",
version: "v14",
author: "ikunshare",
description: "反馈群951962664"
};
// 原始插件代码
const originalPluginCode = "/*!\n * @name ikun音源\n * @description 反馈群951962664\n * @version v14\n * @author ikunshare\n */\n\nconst DEV_ENABLE = false\nconst UPDATE_ENABLE = true\nconst API_URL = \"https://api.ikunshare.com\"\nconst API_KEY = ``\nconst MUSIC_QUALITY = JSON.parse('{\"kw\":[\"128k\",\"320k\",\"flac\",\"flac24bit\",\"hires\"],\"wy\":[\"128k\",\"320k\",\"flac\",\"flac24bit\",\"hires\",\"atmos\",\"master\"],\"mg\":[\"128k\",\"320k\",\"flac\",\"flac24bit\",\"hires\"]}');\nconst MUSIC_SOURCE = Object.keys(MUSIC_QUALITY);\n\nconst { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx;\n\nconst SCRIPT_MD5 = \"5917eb1e565bf906fb0433bb1a3b00b5\";\n\nconst httpFetch = (url, options = { method: \"GET\" }) => {\n return new Promise((resolve, reject) => {\n console.log(\"--- start --- \" + url);\n request(url, options, (err, resp) => {\n if (err) return reject(err);\n console.log(\"API Response: \", resp);\n resolve(resp);\n });\n });\n};\n\nconst handleGetMusicUrl = async (source, musicInfo, quality) => {\n const songId = musicInfo.hash ?? musicInfo.songmid;\n const request = await httpFetch(\n `${API_URL}/url?source=${source}&songId=${songId}&quality=${quality}`,\n {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": `${\n env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`\n }`,\n \"X-Request-Key\": API_KEY,\n },\n follow_max: 5,\n }\n );\n const { body } = request;\n if (!body || isNaN(Number(body.code))) throw new Error(\"unknow error\");\n if (env != \"mobile\") console.groupEnd();\n switch (body.code) {\n case 200:\n console.log(\n `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.url}`\n );\n return body.url;\n case 403:\n console.log(\n `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: Key失效/鉴权失败`\n );\n throw new Error(\"Key失效/鉴权失败\");\n case 500:\n console.log(\n `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`\n );\n throw new Error(`获取URL失败, ${body.msg ?? \"未知错误\"}`);\n case 429:\n console.log(\n `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`\n );\n throw new Error(\"请求过速\");\n default:\n console.log(\n `handleGetMusicUrl(${source}_${\n musicInfo.songmid\n }, ${quality}) failed, ${body.msg ? body.msg : \"未知错误\"}`\n );\n throw new Error(body.msg ?? \"未知错误\");\n }\n};\n\nconst checkUpdate = async () => {\n const request = await httpFetch(\n `${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`,\n {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": `${\n env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`\n }`,\n },\n }\n );\n const { body } = request;\n\n if (!body || body.code !== 200) console.log(\"checkUpdate failed\");\n else {\n console.log(\"checkUpdate success\");\n if (body.data != null) {\n globalThis.lx.send(lx.EVENT_NAMES.updateAlert, {\n log: body.data.updateMsg,\n updateUrl: body.data.updateUrl,\n });\n }\n }\n};\n\nconst musicSources = {};\nMUSIC_SOURCE.forEach((item) => {\n musicSources[item] = {\n name: item,\n type: \"music\",\n actions: [\"musicUrl\"],\n qualitys: MUSIC_QUALITY[item],\n };\n});\n\non(EVENT_NAMES.request, ({ action, source, info }) => {\n switch (action) {\n case \"musicUrl\":\n if (env != \"mobile\") {\n console.group(`Handle Action(musicUrl)`);\n console.log(\"source\", source);\n console.log(\"quality\", info.type);\n console.log(\"musicInfo\", info.musicInfo);\n } else {\n console.log(`Handle Action(musicUrl)`);\n console.log(\"source\", source);\n console.log(\"quality\", info.type);\n console.log(\"musicInfo\", info.musicInfo);\n }\n return handleGetMusicUrl(source, info.musicInfo, info.type)\n .then((data) => Promise.resolve(data))\n .catch((err) => Promise.reject(err));\n default:\n console.error(`action(${action}) not support`);\n return Promise.reject(\"action not support\");\n }\n});\n\nif (UPDATE_ENABLE) checkUpdate();\n\nsend(EVENT_NAMES.inited, {\n status: true,\n openDevTools: DEV_ENABLE,\n sources: musicSources,\n});\n";
// 音源信息将通过插件的 send 调用动态获取
let sources = {};
function getSourceName(sourceId) {
const nameMap = {
'kw': '酷我音乐',
'kg': '酷狗音乐',
'tx': 'QQ音乐',
'wy': '网易云音乐',
'mg': '咪咕音乐'
};
return nameMap[sourceId] || sourceId.toUpperCase() + '音乐';
}
// 提取默认音源配置作为备用
function extractDefaultSources() {
// 尝试从 MUSIC_QUALITY 常量中提取音源信息
const qualityMatch = originalPluginCode.match(/const\s+MUSIC_QUALITY\s*=\s*JSON\.parse\(([^)]+)\)/);
if (qualityMatch) {
try {
// 处理字符串,移除外层引号并正确解析
let qualityStr = qualityMatch[1].trim();
if (qualityStr.startsWith("'") && qualityStr.endsWith("'")) {
qualityStr = qualityStr.slice(1, -1);
} else if (qualityStr.startsWith('"') && qualityStr.endsWith('"')) {
qualityStr = qualityStr.slice(1, -1);
}
console.log('提取到的 MUSIC_QUALITY 字符串:', qualityStr);
const qualityData = JSON.parse(qualityStr);
console.log('解析后的 MUSIC_QUALITY 数据:', qualityData);
const extractedSources = {};
Object.keys(qualityData).forEach(sourceId => {
extractedSources[sourceId] = {
name: getSourceName(sourceId),
type: 'music',
qualitys: qualityData[sourceId] || ['128k', '320k']
};
});
console.log('提取的音源配置:', extractedSources);
return extractedSources;
} catch (e) {
console.log('解析 MUSIC_QUALITY 失败:', e.message);
}
}
// 默认音源配置
return {
kw: { name: "酷我音乐", type: "music", qualitys: ['128k', '320k', 'flac', 'flac24bit', 'hires', 'atmos', 'master'] },
kg: { name: "酷狗音乐", type: "music", qualitys: ['128k', '320k', 'flac', 'flac24bit', 'hires', 'atmos', 'master'] },
tx: { name: "QQ音乐", type: "music", qualitys: ['128k', '320k', 'flac', 'flac24bit', 'hires', 'atmos', 'master'] },
wy: { name: "网易云音乐", type: "music", qualitys: ['128k', '320k', 'flac', 'flac24bit', 'hires', 'atmos', 'master'] },
mg: { name: "咪咕音乐", type: "music", qualitys: ['128k', '320k', 'flac', 'flac24bit', 'hires', 'atmos', 'master'] }
};
}
// 初始化默认音源
sources = extractDefaultSources();
// 插件状态
let isInitialized = false;
let pluginSources = {};
let requestHandler = null;
initializePlugin()
function initializePlugin() {
if (isInitialized) return;
const { request, utils } = cerumusic;
// 创建完整的 lx 模拟环境
const mockLx = {
EVENT_NAMES: {
request: 'request',
inited: 'inited',
updateAlert: 'updateAlert'
},
on: (event, handler) => {
console.log(`[ikun音源 by Ceru插件] 注册事件监听器: ${event}`);
if (event === 'request') {
requestHandler = handler;
}
},
send: (event, data) => {
console.log(`[ikun音源 by Ceru插件] 发送事件: ${event}`, data);
if (event === 'inited' && data.sources) {
// 动态更新音源信息,保持原始的音质配置
pluginSources = data.sources;
// 将插件发送的音源信息转换为正确格式并同步到导出的 sources
Object.keys(pluginSources).forEach(sourceId => {
const sourceInfo = pluginSources[sourceId];
// 保留原始音质配置,如果存在的话
const originalQualitys = sources[sourceId] && sources[sourceId].qualitys;
sources[sourceId] = {
name: getSourceName(sourceId),
type: sourceInfo.type || 'music',
// 优先使用插件发送的音质配置,其次使用原始解析的配置,最后使用默认配置
qualitys: sourceInfo.qualitys || originalQualitys || ['128k', '320k']
};
});
console.log('[ikun音源 by Ceru插件] 音源注册完成:', Object.keys(pluginSources));
console.log('[ikun音源 by Ceru插件] 动态音源信息已更新:', sources);
}
},
request: request,
utils: {
buffer: utils.buffer,
crypto: {
aesEncrypt: (data, mode, key, iv) => {
// 简化的 AES 加密实现
try {
return utils.crypto ? utils.crypto.aesEncrypt(data, mode, key, iv) : data;
} catch (e) {
return data;
}
},
md5: (str) => {
try {
return utils.crypto ? utils.crypto.md5(str) : str;
} catch (e) {
return str;
}
},
randomBytes: (size) => {
try {
return utils.crypto ? utils.crypto.randomBytes(size) : Buffer.alloc(size);
} catch (e) {
return Buffer.alloc(size);
}
},
rsaEncrypt: (data, key) => {
try {
return utils.crypto ? utils.crypto.rsaEncrypt(data, key) : data;
} catch (e) {
return data;
}
}
}
},
version: '1.0.0',
currentScriptInfo: {
rawScript: originalPluginCode,
name: 'ikun音源',
version: 'v14',
author: 'ikunshare',
description: '反馈群951962664'
},
env: 'nodejs' // 添加环境信息
};
// 创建全局环境
const globalThis = {
lx: mockLx
};
// 创建沙箱环境
const sandbox = {
globalThis: globalThis,
lx: mockLx,
console: console,
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
Buffer: Buffer,
JSON: JSON,
require: () => ({}),
module: { exports: {} },
exports: {},
process: { env: { NODE_ENV: 'production' } }
};
try {
// 使用 Function 构造器执行插件代码
const pluginFunction = new Function(
'globalThis', 'lx', 'console', 'setTimeout', 'clearTimeout',
'setInterval', 'clearInterval', 'Buffer', 'JSON', 'require',
'module', 'exports', 'process',
originalPluginCode
);
pluginFunction(
globalThis, mockLx, console, setTimeout, clearTimeout,
setInterval, clearInterval, Buffer, JSON, () => ({}),
{ exports: {} }, {}, { env: { NODE_ENV: 'production' } }
);
isInitialized = true;
console.log(`[CeruMusic] 事件驱动插件初始化成功`);
} catch (error) {
console.log(`[CeruMusic] 插件初始化完成: ${error.message}`);
isInitialized = true;
}
}
async function musicUrl(source, musicInfo, quality) {
// 确保插件已初始化
initializePlugin();
// 等待一小段时间让插件完全初始化
await new Promise(resolve => setTimeout(resolve, 100));
if (!requestHandler) {
const errorMessage = '插件请求处理器未初始化';
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
console.log(`[${pluginInfo.name}] 使用事件驱动方式获取 ${source} 音源链接`);
try {
// 调用插件的请求处理器
const result = await requestHandler({
source: source,
action: 'musicUrl',
info: {
musicInfo: musicInfo,
type: quality
}
});
// 检查结果是否有效
if (!result) {
const errorMessage = `获取 ${source} 音源链接失败: 返回结果为空`;
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
// 如果结果是对象且包含错误信息
if (typeof result === 'object' && result.error) {
const errorMessage = result.error || `获取 ${source} 音源链接失败`;
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
// 如果结果是对象且包含状态码
if (typeof result === 'object' && result.code && result.code !== 200) {
const errorMessage = result.msg || `接口错误 (Code: ${result.code})`;
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
console.log(`[${pluginInfo.name}] Got URL: ${typeof result === 'string' ? result : result.url || result}`);
return result;
} catch (error) {
// 确保错误信息格式与 example-plugin.js 一致
const errorMessage = error.message || `获取 ${source} 音源链接时发生未知错误`;
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
}
}
module.exports = {
pluginInfo,
sources,
musicUrl
};

View File

@@ -6,7 +6,6 @@ const enc_key = Buffer.from(
[0x40, 0x47, 0x61, 0x77, 0x5e, 0x32, 0x74, 0x47, 0x51, 0x36, 0x31, 0x2d, 0xce, 0xd2, 0x6e, 0x69],
'binary'
)
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const decodeLyric = (str) =>
new Promise((resolve, reject) => {
if (!str.length) return
@@ -22,7 +21,6 @@ const decodeLyric = (str) =>
const headExp = /^.*\[id:\$\w+\]\n/
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const parseLyric = (str) => {
str = str.replace(/\r/g, '')
if (headExp.test(str)) str = str.replace(headExp, '')
@@ -45,9 +43,10 @@ const parseLyric = (str) => {
}
}
let i = 0
let lxlyric = str.replace(/\[((\d+),\d+)\].*/g, (str) => {
let crlyric = str.replace(/\[((\d+),\d+)\].*/g, (str) => {
let result = str.match(/\[((\d+),\d+)\].*/)
let time = parseInt(result[2])
let lineStartTime = parseInt(result[2]) // 行开始时间
let time = lineStartTime
let ms = time % 1000
time /= 1000
let m = parseInt(time / 60)
@@ -59,24 +58,31 @@ const parseLyric = (str) => {
if (rlyric) rlyric[i] = `[${time}]${rlyric[i]?.join('') ?? ''}`
if (tlyric) tlyric[i] = `[${time}]${tlyric[i]?.join('') ?? ''}`
i++
return str.replace(result[1], time)
// 保持原始的 [start,duration] 格式,将相对时间戳转换为绝对时间戳
let processedStr = str.replace(/<(\d+),(\d+),(\d+)>/g, (match, start, duration, param) => {
const absoluteStart = lineStartTime + parseInt(start)
return `(${absoluteStart},${duration},${param})`
})
return processedStr
})
rlyric = rlyric ? rlyric.join('\n') : ''
tlyric = tlyric ? tlyric.join('\n') : ''
lxlyric = lxlyric.replace(/<(\d+,\d+),\d+>/g, '<$1>')
lxlyric = decodeName(lxlyric)
lyric = lxlyric.replace(/<\d+,\d+>/g, '')
// 保留完整的时间戳格式 (startTime,duration,param)
crlyric = crlyric.replace(/<(\d+,\d+,\d+)>/g, '($1)')
crlyric = decodeName(crlyric)
lyric = crlyric.replace(/\(\d+,\d+,\d+\)/g, '')
rlyric = decodeName(rlyric)
tlyric = decodeName(tlyric)
return {
lyric,
tlyric,
rlyric,
lxlyric
crlyric
}
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const decodeKrc = async (data) => {
return decodeLyric(data).then(parseLyric)
}

View File

@@ -1,5 +1,7 @@
// 业务工具方法
import { LX } from "../../types/global"
export const toNewMusicInfo = (oldMusicInfo: any): LX.Music.MusicInfo => {
const meta: Record<string, any> = {
songId: oldMusicInfo.songmid, // 歌曲IDlocal为文件路径

262
src/main/autoUpdate.ts Normal file
View File

@@ -0,0 +1,262 @@
import { BrowserWindow, app, shell } from 'electron';
import axios from 'axios';
import fs from 'fs';
import path from 'node:path';
let mainWindow: BrowserWindow | null = null;
let currentUpdateInfo: UpdateInfo | null = null;
let downloadProgress = { percent: 0, transferred: 0, total: 0 };
// 更新信息接口
interface UpdateInfo {
url: string;
name: string;
notes: string;
pub_date: string;
}
// 更新服务器配置
const UPDATE_SERVER = 'https://update.ceru.shiqianjiang.cn';
const UPDATE_API_URL = `${UPDATE_SERVER}/update/${process.platform}/${app.getVersion()}`;
// 初始化自动更新器
export function initAutoUpdater(window: BrowserWindow) {
mainWindow = window;
console.log('Auto updater initialized');
}
// 检查更新
export async function checkForUpdates(window?: BrowserWindow) {
if (window) {
mainWindow = window;
}
try {
console.log('Checking for updates...');
mainWindow?.webContents.send('auto-updater:checking-for-update');
const updateInfo = await fetchUpdateInfo();
if (updateInfo && isNewerVersion(updateInfo.name, app.getVersion())) {
console.log('Update available:', updateInfo);
currentUpdateInfo = updateInfo;
mainWindow?.webContents.send('auto-updater:update-available', updateInfo);
} else {
console.log('No update available');
mainWindow?.webContents.send('auto-updater:update-not-available');
}
} catch (error) {
console.error('Error checking for updates:', error);
mainWindow?.webContents.send('auto-updater:error', (error as Error).message);
}
}
// 获取更新信息
async function fetchUpdateInfo(): Promise<UpdateInfo | null> {
try {
const response = await axios.get(UPDATE_API_URL, {
timeout: 10000, // 10秒超时
validateStatus: (status) => status === 200 || status === 204 // 允许 200 和 204 状态码
});
if (response.status === 200) {
return response.data as UpdateInfo;
} else if (response.status === 204) {
// 204 表示没有更新
return null;
}
return null;
} catch (error: any) {
if (error.response) {
// 服务器响应了错误状态码
throw new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
} else if (error.request) {
// 请求已发出但没有收到响应
throw new Error('Network error: No response received');
} else {
// 其他错误
throw new Error(`Request failed: ${error.message}`);
}
}
}
// 比较版本号
function isNewerVersion(remoteVersion: string, currentVersion: string): boolean {
const parseVersion = (version: string) => {
return version.replace(/^v/, '').split('.').map(num => parseInt(num, 10));
};
const remote = parseVersion(remoteVersion);
const current = parseVersion(currentVersion);
for (let i = 0; i < Math.max(remote.length, current.length); i++) {
const r = remote[i] || 0;
const c = current[i] || 0;
if (r > c) return true;
if (r < c) return false;
}
return false;
}
// 下载更新
export async function downloadUpdate() {
if (!currentUpdateInfo) {
throw new Error('No update info available');
}
try {
console.log('Starting download:', currentUpdateInfo.url);
// 通知渲染进程开始下载
mainWindow?.webContents.send('auto-updater:download-started', currentUpdateInfo);
const downloadPath = await downloadFile(currentUpdateInfo.url);
console.log('Download completed:', downloadPath);
mainWindow?.webContents.send('auto-updater:update-downloaded', {
downloadPath,
updateInfo: currentUpdateInfo
});
} catch (error) {
console.error('Download failed:', error);
mainWindow?.webContents.send('auto-updater:error', (error as Error).message);
}
}
// 下载文件
async function downloadFile(url: string): Promise<string> {
const fileName = path.basename(url);
const downloadPath = path.join(app.getPath('temp'), fileName);
// 进度节流变量
let lastProgressSent = 0;
let lastProgressTime = 0;
const PROGRESS_THROTTLE_INTERVAL = 500; // 500ms 发送一次进度
const PROGRESS_THRESHOLD = 1; // 进度变化超过1%才发送
try {
const response = await axios({
method: 'GET',
url: url,
responseType: 'stream',
timeout: 30000, // 30秒超时
onDownloadProgress: (progressEvent) => {
const { loaded, total } = progressEvent;
const percent = total ? (loaded / total) * 100 : 0;
const currentTime = Date.now();
// 节流逻辑:只在进度变化显著或时间间隔足够时发送
const progressDiff = Math.abs(percent - lastProgressSent);
const timeDiff = currentTime - lastProgressTime;
if (progressDiff >= PROGRESS_THRESHOLD || timeDiff >= PROGRESS_THROTTLE_INTERVAL) {
downloadProgress = {
percent,
transferred: loaded,
total: total || 0
};
mainWindow?.webContents.send('auto-updater:download-progress', downloadProgress);
lastProgressSent = percent;
lastProgressTime = currentTime;
}
}
});
// 发送初始进度
const totalSize = parseInt(response.headers['content-length'] || '0', 10);
mainWindow?.webContents.send('auto-updater:download-progress', {
percent: 0,
transferred: 0,
total: totalSize
});
// 创建写入流
const writer = fs.createWriteStream(downloadPath);
// 将响应数据流写入文件
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', () => {
// 发送最终进度
mainWindow?.webContents.send('auto-updater:download-progress', {
percent: 100,
transferred: totalSize,
total: totalSize
});
console.log('File download completed:', downloadPath);
resolve(downloadPath);
});
writer.on('error', (error) => {
// 删除部分下载的文件
fs.unlink(downloadPath, () => {});
reject(error);
});
response.data.on('error', (error: Error) => {
writer.destroy();
fs.unlink(downloadPath, () => {});
reject(error);
});
});
} catch (error: any) {
// 删除可能创建的文件
if (fs.existsSync(downloadPath)) {
fs.unlink(downloadPath, () => {});
}
if (error.response) {
throw new Error(`Download failed: HTTP ${error.response.status} ${error.response.statusText}`);
} else if (error.request) {
throw new Error('Download failed: Network error');
} else {
throw new Error(`Download failed: ${error.message}`);
}
}
}
// 退出并安装
export function quitAndInstall() {
if (!currentUpdateInfo) {
console.error('No update info available for installation');
return;
}
// 对于不同平台,处理方式不同
if (process.platform === 'win32') {
// Windows: 打开安装程序
const fileName = path.basename(currentUpdateInfo.url);
const downloadPath = path.join(app.getPath('temp'), fileName);
if (fs.existsSync(downloadPath)) {
shell.openPath(downloadPath).then(() => {
app.quit();
});
} else {
console.error('Downloaded file not found:', downloadPath);
}
} else if (process.platform === 'darwin') {
// macOS: 打开 dmg 或 zip 文件
const fileName = path.basename(currentUpdateInfo.url);
const downloadPath = path.join(app.getPath('temp'), fileName);
if (fs.existsSync(downloadPath)) {
shell.openPath(downloadPath).then(() => {
app.quit();
});
} else {
console.error('Downloaded file not found:', downloadPath);
}
} else {
// Linux: 打开下载文件夹
shell.showItemInFolder(path.join(app.getPath('temp'), path.basename(currentUpdateInfo.url)));
}
}

View File

@@ -0,0 +1,28 @@
import { ipcMain, BrowserWindow } from 'electron';
import { initAutoUpdater, checkForUpdates, downloadUpdate, quitAndInstall } from '../autoUpdate';
// 注册自动更新相关的IPC事件
export function registerAutoUpdateEvents() {
// 检查更新
ipcMain.handle('auto-updater:check-for-updates', (event) => {
const window = BrowserWindow.fromWebContents(event.sender);
if (window) {
checkForUpdates(window);
}
});
// 下载更新
ipcMain.handle('auto-updater:download-update', () => {
downloadUpdate();
});
// 安装更新
ipcMain.handle('auto-updater:quit-and-install', () => {
quitAndInstall();
});
}
// 初始化自动更新(在主窗口创建后调用)
export function initAutoUpdateForWindow(window: BrowserWindow) {
initAutoUpdater(window);
}

View File

@@ -0,0 +1,33 @@
import { ipcMain } from 'electron'
import { musicCacheService } from '../services/musicCache'
// 获取缓存信息
ipcMain.handle('music-cache:get-info', async () => {
try {
return await musicCacheService.getCacheInfo()
} catch (error) {
console.error('获取缓存信息失败:', error)
return { count: 0, size: 0, sizeFormatted: '0 B' }
}
})
// 清空缓存
ipcMain.handle('music-cache:clear', async () => {
try {
await musicCacheService.clearCache()
return { success: true, message: '缓存已清空' }
} catch (error) {
console.error('清空缓存失败:', error)
return { success: false, message: '清空缓存失败' }
}
})
// 获取缓存大小
ipcMain.handle('music-cache:get-size', async () => {
try {
return await musicCacheService.getCacheSize()
} catch (error) {
console.error('获取缓存大小失败:', error)
return 0
}
})

View File

@@ -91,8 +91,10 @@ function createWindow(): void {
sandbox: false,
webSecurity: false,
nodeIntegration: true,
contextIsolation: false
contextIsolation: false,
backgroundThrottling: false
}
})
if (process.platform == 'darwin') mainWindow.setWindowButtonVisibility(false)
@@ -190,8 +192,9 @@ ipcMain.handle('service-music-request', async (_, api, args) => {
return await musicService.request(api, args)
})
aiEvents(mainWindow)
import './events/musicCache'
import { registerAutoUpdateEvents, initAutoUpdateForWindow } from './events/autoUpdate'
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
@@ -216,9 +219,6 @@ app.whenReady().then(async () => {
optimizer.watchWindowShortcuts(window)
})
// IPC test
ipcMain.on('ping', () => console.log('pong'))
// 窗口控制 IPC 处理
ipcMain.on('window-minimize', () => {
const window = BrowserWindow.getFocusedWindow()
@@ -277,6 +277,21 @@ app.whenReady().then(async () => {
createWindow()
createTray()
// 注册自动更新事件
registerAutoUpdateEvents()
ipcMain.on('startPing', () => {
if (ping) clearInterval(ping)
console.log('start-----开始')
startPing()
})
ipcMain.on('stopPing', () => {
clearInterval(ping)
})
// 初始化自动更新器
if (mainWindow) {
initAutoUpdateForWindow(mainWindow)
}
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
@@ -297,3 +312,60 @@ app.on('before-quit', () => {
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
let ping: NodeJS.Timeout
function startPing() {
let interval = 3000
ping = setInterval(() => {
if (mainWindow) {
mainWindow.webContents
.executeJavaScript(
`
(function() {
const audio = document.getElementById("globaAudio");
if(!audio) return { playing:false, ended: false };
if(audio.ended) return { playing:false, ended: true };
return { playing: !audio.paused, ended: false, currentTime: audio.currentTime, duration: audio.duration };
})()
`
)
.then((res) => {
console.log(res)
if (res.duration - res.currentTime <= 20) {
clearInterval(ping)
interval = 500
ping = setInterval(() => {
if (mainWindow) {
mainWindow.webContents
.executeJavaScript(
`
(function() {
const audio = document.getElementById("globaAudio");
if(!audio) return { playing:false, ended: false };
if(audio.ended) return { playing:false, ended: true };
return { playing: !audio.paused, ended: false, currentTime: audio.currentTime, duration: audio.duration };
})()
`
)
.then((res) => {
console.log(res)
if (res && res.ended) {
mainWindow?.webContents.send('song-ended')
console.log('next song')
clearInterval(ping)
}
})
.catch((err) => console.warn(err))
}
}, interval)
}
})
.catch((err) => console.warn(err))
}
}, interval)
}

View File

@@ -154,7 +154,7 @@ export const netEaseService: MusicServiceBase = {
// 对于多个ID并行获取详情
const promises = ids.map((id) => sourceModule.musicInfo.getMusicInfo(id))
const results = await Promise.all(promises)
return results.filter((result :any) => result) // 过滤掉失败的结果
return results.filter((result: any) => result) // 过滤掉失败的结果
} else {
throw new Error(`不支持的音乐源: ${source}`)
}

View File

@@ -0,0 +1,189 @@
import { app } from 'electron'
import * as path from 'path'
import * as fs from 'fs/promises'
import * as crypto from 'crypto'
import axios from 'axios'
export class MusicCacheService {
private cacheDir: string
private cacheIndex: Map<string, string> = new Map()
private indexFilePath: string
constructor() {
this.cacheDir = path.join(app.getPath('userData'), 'music-cache')
this.indexFilePath = path.join(this.cacheDir, 'cache-index.json')
this.initCache()
}
private async initCache() {
try {
// 确保缓存目录存在
await fs.mkdir(this.cacheDir, { recursive: true })
// 加载缓存索引
await this.loadCacheIndex()
} catch (error) {
console.error('初始化音乐缓存失败:', error)
}
}
private async loadCacheIndex() {
try {
const indexData = await fs.readFile(this.indexFilePath, 'utf-8')
const index = JSON.parse(indexData)
this.cacheIndex = new Map(Object.entries(index))
} catch (error) {
// 索引文件不存在或损坏,创建新的
this.cacheIndex = new Map()
await this.saveCacheIndex()
}
}
private async saveCacheIndex() {
try {
const indexObj = Object.fromEntries(this.cacheIndex)
await fs.writeFile(this.indexFilePath, JSON.stringify(indexObj, null, 2))
} catch (error) {
console.error('保存缓存索引失败:', error)
}
}
private generateCacheKey(songId: string): string {
return crypto.createHash('md5').update(`${songId}`).digest('hex')
}
private getCacheFilePath(cacheKey: string, url: string): string {
const ext = path.extname(new URL(url).pathname) || '.mp3'
return path.join(this.cacheDir, `${cacheKey}${ext}`)
}
async getCachedMusicUrl(songId: string, originalUrlPromise: Promise<string>): Promise<string> {
const cacheKey = this.generateCacheKey(songId)
console.log('hash',cacheKey)
// 检查是否已缓存
if (this.cacheIndex.has(cacheKey)) {
const cachedFilePath = this.cacheIndex.get(cacheKey)!
try {
// 验证文件是否存在
await fs.access(cachedFilePath)
console.log(`使用缓存文件: ${cachedFilePath}`)
return `file://${cachedFilePath}`
} catch (error) {
// 文件不存在,从缓存索引中移除
this.cacheIndex.delete(cacheKey)
await this.saveCacheIndex()
}
}
// 下载并缓存文件 先返回源链接不等待结果优化体验
this.downloadAndCache(songId, await originalUrlPromise, cacheKey)
return await originalUrlPromise
}
private async downloadAndCache(songId: string, url: string, cacheKey: string): Promise<string> {
try {
console.log(`开始下载歌曲: ${songId}`)
const response = await axios({
method: 'GET',
url: url,
responseType: 'stream',
timeout: 30000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
})
const cacheFilePath = this.getCacheFilePath(cacheKey, url)
const writer = require('fs').createWriteStream(cacheFilePath)
response.data.pipe(writer)
return new Promise((resolve, reject) => {
writer.on('finish', async () => {
try {
// 更新缓存索引
this.cacheIndex.set(cacheKey, cacheFilePath)
await this.saveCacheIndex()
console.log(`歌曲缓存完成: ${cacheFilePath}`)
resolve(`file://${cacheFilePath}`)
} catch (error) {
reject(error)
}
})
writer.on('error', (error: Error) => {
console.error(`下载歌曲失败: ${songId}`, error)
// 清理失败的文件
fs.unlink(cacheFilePath).catch(() => {})
reject(error)
})
})
} catch (error) {
console.error(`下载歌曲失败: ${songId}`, error)
throw error
}
}
async clearCache(): Promise<void> {
try {
// 删除所有缓存文件
for (const filePath of this.cacheIndex.values()) {
try {
await fs.unlink(filePath)
} catch (error) {
// 忽略文件不存在的错误
}
}
// 清空缓存索引
this.cacheIndex.clear()
await this.saveCacheIndex()
console.log('音乐缓存已清空')
} catch (error) {
console.error('清空缓存失败:', error)
}
}
async getCacheSize(): Promise<number> {
let totalSize = 0
for (const filePath of this.cacheIndex.values()) {
try {
const stats = await fs.stat(filePath)
totalSize += stats.size
} catch (error) {
// 文件不存在,忽略
}
}
return totalSize
}
async getCacheInfo(): Promise<{ count: number; size: number; sizeFormatted: string }> {
const size = await this.getCacheSize()
const count = this.cacheIndex.size
const formatSize = (bytes: number): string => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
return {
count,
size,
sizeFormatted: formatSize(size)
}
}
}
// 单例实例
export const musicCacheService = new MusicCacheService()

View File

@@ -1,20 +1,26 @@
import main from './service'
import { ipcMain } from 'electron';
export type MainApi = ReturnType<typeof main>;
export type MethodParams<T extends keyof MainApi> =
MainApi[T] extends (...args: any[]) => any
import { ipcMain } from 'electron'
export type MainApi = ReturnType<typeof main>
export type MethodParams<T extends keyof MainApi> = MainApi[T] extends (...args: any[]) => any
? Parameters<MainApi[T]>[0]
: never;
export function request<T extends keyof MainApi>(_: any, method: T,
: never
export function request<T extends keyof MainApi>(
_: any,
method: T,
options: {
source: any;
} & (MethodParams<T> extends object ? MethodParams<T> : { [key: string]: any })): ReturnType<MainApi[T]> {
const { source, ...args } = options;
source: any
} & (MethodParams<T> extends object ? MethodParams<T> : { [key: string]: any })
): ReturnType<MainApi[T]> {
try {
const { source, ...args } = options
if (!source) throw new Error('请配置音源')
const Api = main(source);
const Api = main(source)
if (Api.hasOwnProperty(method)) {
return (Api[method] as (args: any) => any)(args);
return (Api[method] as (args: any) => any)(args)
}
throw new Error(`未知的方法: ${method}`)
}catch (error:any){
throw new Error(error.message)
}
throw new Error(`未知的方法: ${method}`);
}
ipcMain.handle('service-music-sdk-request', request)

View File

@@ -1,19 +1,56 @@
import { SearchSongArg, SearchResult, GetMusicUrlArg, GetMusicPicArg } from './type'
import {
SearchSongArg,
SearchResult,
GetMusicUrlArg,
GetMusicPicArg,
GetLyricArg,
PlaylistResult,
GetSongListDetailsArg,
PlaylistDetailResult,
DownloadSingleSongArgs
} from './type'
import pluginService from '../plugin/index'
import musicSdk from '../../utils/musicSdk/index'
import { getAppDirPath } from '../../utils/path'
import { musicCacheService } from '../musicCache'
import path from 'node:path'
import fs from 'fs'
import fsPromise from 'fs/promises'
import axios from 'axios'
import { pipeline } from 'node:stream/promises'
import { fileURLToPath } from 'url'
const fileLock: Record<string, boolean> = {}
function main(source: string) {
const Api = musicSdk[source]
Api.songList
return {
async search({ keyword, page = 1, limit = 30 }: SearchSongArg) {
return await Api.musicSearch.search(keyword, page, limit) as Promise<SearchResult>
return (await Api.musicSearch.search(keyword, page, limit)) as Promise<SearchResult>
},
async getMusicUrl({ pluginId, songInfo, quality }: GetMusicUrlArg) {
try {
const usePlugin = pluginService.getPluginById(pluginId)
if (!pluginId || !usePlugin) return { error: '请配置音源来播放歌曲' }
return await usePlugin.getMusicUrl(source, songInfo , quality)
// 获取原始URL
const originalUrlPromise = usePlugin.getMusicUrl(source, songInfo, quality)
// 生成歌曲唯一标识
const songId = `${songInfo.name}-${songInfo.singer}-${source}-${quality}`
// 尝试获取缓存的URL
try {
const cachedUrl = await musicCacheService.getCachedMusicUrl(songId, originalUrlPromise)
return cachedUrl
} catch (cacheError) {
console.warn('缓存获取失败使用原始URL:', cacheError)
const originalUrl = await originalUrlPromise
return originalUrl
}
} catch (e: any) {
return {
error: '获取歌曲失败 ' + e.error || e
@@ -21,7 +58,7 @@ function main(source: string) {
}
},
async getPic({songInfo}: GetMusicPicArg) {
async getPic({ songInfo }: GetMusicPicArg) {
try {
return await Api.getPic(songInfo)
} catch (e: any) {
@@ -29,6 +66,101 @@ function main(source: string) {
error: '获取歌曲失败 ' + e.error || e
}
}
},
async getLyric({ songInfo }: GetLyricArg) {
try {
const res = await Api.getLyric(songInfo).promise
return res
} catch (e: any) {
return {
error: '获取歌词失败 ' + (e.error || e.message || e)
}
}
},
async getHotSonglist() {
return (await Api.songList.getList(Api.songList.sortList[0].id, '', 1)) as PlaylistResult
},
async getPlaylistDetail({ id, page }: GetSongListDetailsArg) {
return (await Api.songList.getListDetail(id, page)) as PlaylistDetailResult
},
async downloadSingleSong({ pluginId, songInfo, quality }: DownloadSingleSongArgs) {
const url = await this.getMusicUrl({ pluginId, songInfo, quality })
if (typeof url === 'object') throw new Error('无法获取歌曲链接')
// 从URL中提取文件扩展名如果没有则默认为mp3
const getFileExtension = (url: string): string => {
try {
const urlObj = new URL(url)
const pathname = urlObj.pathname
const lastDotIndex = pathname.lastIndexOf('.')
if (lastDotIndex !== -1 && lastDotIndex < pathname.length - 1) {
const extension = pathname.substring(lastDotIndex + 1).toLowerCase()
// 验证是否为常见的音频格式
const validExtensions = ['mp3', 'flac', 'wav', 'aac', 'm4a', 'ogg', 'wma']
if (validExtensions.includes(extension)) {
return extension
}
}
} catch (error) {
console.warn('解析URL失败使用默认扩展名:', error)
}
return 'mp3' // 默认扩展名
}
const fileExtension = getFileExtension(url)
const songPath = path.join(
getAppDirPath('music'),
'CeruMusic',
'songs',
`${songInfo.name}-${songInfo.singer}-${source}.${fileExtension}`
.replace(/[/\\:*?"<>|]/g, '')
.replace(/^\.+/, '')
.replace(/\.+$/, '')
.trim()
)
if (fileLock[songPath]) {
throw new Error('歌曲正在下载中')
} else {
fileLock[songPath] = true
}
try {
if (fs.existsSync(songPath)) {
return {
message: '歌曲已存在'
}
}
await fsPromise.mkdir(path.dirname(songPath), { recursive: true })
if (url.startsWith('file://')) {
const filePath = fileURLToPath(url)
const readStream = fs.createReadStream(filePath)
const writeStream = fs.createWriteStream(songPath)
await pipeline(readStream, writeStream)
} else {
const songDataRes = await axios({
method: 'GET',
url: url,
responseType: 'stream'
})
await pipeline(songDataRes.data, fs.createWriteStream(songPath))
}
} finally {
delete fileLock[songPath]
}
return {
message: '下载成功',
path: songPath
}
}
}
}

View File

@@ -1,6 +1,6 @@
export interface sdkArg {
source: string
[key:string]: any
[key: string]: any
}
export interface SearchSongArg {
@@ -8,7 +8,6 @@ export interface SearchSongArg {
page: number
limit: number
}
// 可以添加到 src/main/services/music/service-base.ts 文件中
// 单首歌曲的类型定义
export interface MusicItem {
@@ -49,3 +48,48 @@ export interface GetMusicPicArg {
export interface GetLyricArg {
songInfo: MusicItem
}
interface Playlist {
play_count: string // 播放次数,如 "1.8万"
id: string // 歌单ID
author: string // 创建者/作者
name: string // 歌单名称
time: string // 创建时间,格式为 "YYYY-MM-DD"
img: string // 封面图片URL
grade?: string // 评分可能为undefined
total: number // 歌曲总数
desc: string // 歌单描述
source: string // 音乐来源,如 "wy" 表示网易云音乐
}
export interface PlaylistResult {
list: Playlist[]
total: number
page: number
source: string
}
export interface GetSongListDetailsArg {
id: string
page: number
}
// 歌单详情信息
export interface PlaylistInfo {
name: string
img: string
desc: string
}
// 歌单详情结果
export interface PlaylistDetailResult {
list: MusicItem[]
page: number
limit: number
total: number
source: string
info: PlaylistInfo
}
export interface DownloadSingleSongArgs extends GetMusicUrlArg {
path?: string
}

View File

@@ -101,7 +101,7 @@ const pluginService = {
}
},
getPluginById(pluginId: string): CeruMusicPluginHost | null{
getPluginById(pluginId: string): CeruMusicPluginHost | null {
if (!Object.hasOwn(loadedPlugins, pluginId)) {
return null
}

View File

@@ -5,7 +5,7 @@ import { getAppDirPath } from '../../utils/path'
import { remove_empty_strings } from '../../utils/array'
function getLogPath(pluginId: string): string {
return path.join(getAppDirPath(), 'plugin', 'logs', `${pluginId}.txt`)
return path.join(getAppDirPath(), 'plugins', 'logs', `${pluginId}.txt`)
}
const fileLock: Record<string, Promise<any> | undefined> = {}
@@ -94,14 +94,16 @@ class Logger {
}
}
function parseArgs(args){
return args.map(arg=>{
if(typeof arg==='object'){
function parseArgs(args) {
return args
.map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg)
}
return arg
}).join(' ')
})
.join(' ')
}
async function getLog(pluginId: string) {

View File

@@ -1,7 +1,7 @@
import * as vm from 'vm'
import fetch from 'node-fetch'
import * as fs from 'fs'
import {MusicItem} from '../../musicSdk/type'
import { MusicItem } from '../../musicSdk/type'
// 定义插件结构接口
export interface PluginInfo {
@@ -26,7 +26,7 @@ interface CeruMusicPlugin {
getLyric?: (source: string, musicInfo: MusicInfo) => Promise<string>
}
interface MusicInfo extends MusicItem{
interface MusicInfo extends MusicItem {
id?: string
}
@@ -197,7 +197,9 @@ class CeruMusicPluginHost {
}
if (callback) {
makeRequest().catch(() => {}) // 错误已在makeRequest中处理
makeRequest().catch((error) => {
console.error(`[CeruMusic] Unhandled request error in callback mode: ${error.message}`)
}) // 确保错误被正确处理
return undefined
} else {
return makeRequest()
@@ -407,7 +409,9 @@ class CeruMusicPluginHost {
}
if (callback) {
makeRequest().catch(() => {}) // 错误已在makeRequest中处理
makeRequest().catch((error) => {
console.error(`[CeruMusic] Unhandled request error in callback mode: ${error.message}`)
}) // 确保错误被正确处理
return undefined
} else {
return makeRequest()

View File

@@ -92,7 +92,7 @@ export default {
lyric: Buffer.from(body.content, 'base64').toString('utf-8'),
tlyric: '',
rlyric: '',
lxlyric: ''
crlyric: ''
}
default:
return Promise.reject(new Error(`未知歌词格式: ${body.fmt}`))

View File

@@ -1,119 +0,0 @@
import { decodeName, formatPlayTime, sizeFormate } from '../../index'
import { signatureParams, createHttpFetch } from './util'
import { formatSingerName } from '../../utils'
export default {
limit: 30,
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page, limit) {
const sign = signatureParams(
`userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&keyword=${str}&dfid=-&clientver=11409&platform=AndroidFilter&tag=`,
3
)
return createHttpFetch(
`https://gateway.kugou.com/complexsearch/v3/search/song?userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&dfid=-&clientver=11409&platform=AndroidFilter&tag=&keyword=${encodeURIComponent(str)}&signature=${sign}`,
{
headers: {
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
referer: 'https://kugou.com'
}
}
).then((body) => body)
},
filterList(raw) {
let ids = new Set()
const list = []
raw.forEach((item) => {
if (ids.has(item.Audioid)) return
ids.add(item.Audioid)
const types = []
const _types = {}
if (item.FileSize !== 0) {
let size = sizeFormate(item.FileSize)
types.push({ type: '128k', size, hash: item.FileHash })
_types['128k'] = {
size,
hash: item.FileHash
}
}
if (item.HQ != undefined) {
let size = sizeFormate(item.HQ.FileSize)
types.push({ type: '320k', size, hash: item.HQ.Hash })
_types['320k'] = {
size,
hash: item.HQ.Hash
}
}
if (item.SQ != undefined) {
let size = sizeFormate(item.SQ.FileSize)
types.push({ type: 'flac', size, hash: item.SQ.Hash })
_types.flac = {
size,
hash: item.SQ.Hash
}
}
if (item.Res != undefined) {
let size = sizeFormate(item.Res.FileSize)
types.push({ type: 'flac24bit', size, hash: item.Res.Hash })
_types.flac24bit = {
size,
hash: item.Res.Hash
}
}
list.push({
singer: decodeName(formatSingerName(item.Singers)),
name: decodeName(item.SongName),
albumName: decodeName(item.AlbumName),
albumId: item.AlbumID,
songmid: item.Audioid,
source: 'kg',
interval: formatPlayTime(item.Duration),
_interval: item.Duration,
img: null,
lrc: null,
otherSource: null,
hash: item.FileHash,
types,
_types,
typeUrl: {}
})
})
return list
},
handleResult(rawData) {
const rawList = []
rawData.forEach((item) => {
rawList.push(item)
item.Grp.forEach((e) => rawList.push(e))
})
return this.filterList(rawList)
},
search(str, page = 1, limit, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit == null) limit = this.limit
return this.musicSearch(str, page, limit).then((data) => {
let list = this.handleResult(data.lists)
if (!list) return this.search(str, page, limit, retryNum)
this.total = data.total
this.page = page
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit,
total: this.total,
source: 'kg'
})
})
}
}

View File

@@ -1,915 +0,0 @@
import { httpFetch } from '../../../request'
import { formatSingerName } from '../../utils'
import {
decodeName,
formatPlayTime,
sizeFormate,
dateFormat,
formatPlayCount
} from '../../../index'
import { signatureParams, createHttpFetch } from './../util'
import { getMusicInfosByList } from '../musicInfo'
import album from '../album'
export default {
_requestObj_tags: null,
_requestObj_listInfo: null,
_requestObj_list: null,
_requestObj_listRecommend: null,
listDetailLimit: 10000,
currentTagInfo: {
id: undefined,
info: undefined
},
sortList: [
{
name: '推荐',
id: '5'
},
{
name: '最热',
id: '6'
},
{
name: '最新',
id: '7'
},
{
name: '热藏',
id: '3'
},
{
name: '飙升',
id: '8'
}
],
cache: new Map(),
collectionIdListInfoCache: new Map(),
regExps: {
listData: /global\.data = (\[.+\]);/,
listInfo: /global = {[\s\S]+?name: "(.+)"[\s\S]+?pic: "(.+)"[\s\S]+?};/,
// https://www.kugou.com/yy/special/single/1067062.html
listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/
},
/**
* 获取歌曲列表内的音乐
* @param {*} id
* @param {*} page
*/
async getListDetail(id, page) {
id = id.toString()
if (id.includes('special/single/')) id = id.replace(this.regExps.listDetailLink, '$1')
// fix https://www.kugou.com/songlist/xxx/?uid=xxx&chl=qq_client&cover=http%3A%2F%2Fimge.kugou.com%xxx.jpg&iszlist=1
if (/https?:/.test(id)) {
if (id.includes('#')) id = id.replace(/#.*$/, '')
if (id.includes('global_collection_id'))
return this.getUserListDetailByCollectionId(
id.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'),
page
)
if (id.includes('chain='))
return this.getUserListDetail3(id.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
if (id.includes('.html')) {
if (id.includes('zlist.html')) {
id = id.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
if (id.includes('pagesize')) {
id = id
.replace('pagesize=30', 'pagesize=' + this.listDetailLimit)
.replace('page=1', 'page=' + page)
} else {
id += `&pagesize=${this.listDetailLimit}&page=${page}`
}
} else if (!id.includes('song.html'))
return this.getUserListDetail3(
id.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'),
page
)
}
return this.getUserListDetail(id.replace(/^.*?http/, 'http'), page)
}
if (/^\d+$/.test(id)) return this.getUserListDetailByCode(id, page)
if (id.startsWith('gid_'))
return this.getUserListDetailByCollectionId(id.replace('gid_', ''), page)
if (id.startsWith('id_')) return this.getUserListDetailBySpecialId(id.replace('id_', ''), page)
return new Error('Failed.')
},
/**
* 获取SpecialId歌单
* @param {*} id
*/
async getUserListDetailBySpecialId(id, page, tryNum = 0) {
if (tryNum > 2) throw new Error('try max num')
const { body } = await httpFetch(this.getSongListDetailUrl(id)).promise
let listData = body.match(this.regExps.listData)
let listInfo = body.match(this.regExps.listInfo)
if (!listData) return this.getListDetailBySpecialId(id, page, ++tryNum)
let list = await getMusicInfosByList(JSON.parse(listData[1]))
let name
let pic
if (listInfo) {
name = listInfo[1]
pic = listInfo[2]
}
let desc = this.parseHtmlDesc(body)
return {
list,
page: 1,
limit: 10000,
total: list.length,
source: 'kg',
info: {
name,
img: pic,
desc
// author: body.result.info.userinfo.username,
// play_count: formatPlayCount(body.result.listen_num),
}
}
},
parseHtmlDesc(html) {
const prefix = '<div class="pc_specail_text pc_singer_tab_content" id="specailIntroduceWrap">'
let index = html.indexOf(prefix)
if (index < 0) return null
const afterStr = html.substring(index + prefix.length)
index = afterStr.indexOf('</div>')
if (index < 0) return null
return decodeName(afterStr.substring(0, index))
},
/**
* 使用SpecialId获取CollectionId
* @param {*} specialId
*/
async getCollectionIdBySpecialId(specialId) {
return httpFetch(`http://mobilecdnbj.kugou.com/api/v5/special/info?specialid=${specialId}`, {
headers: {
'User-Agent':
'Mozilla/5.0 (Linux; Android 10; HLK-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Mobile Safari/537.36 EdgA/104.0.1293.70'
}
}).promise.then(({ body }) => {
// console.log('getCollectionIdBySpecialId', body)
if (!body.data.global_specialid)
return Promise.reject(new Error('Failed to get global collection id.'))
return body.data.global_specialid
})
},
/**
* 获取歌单URL
* @param {*} sortId
* @param {*} tagId
* @param {*} page
*/
getSongListUrl(sortId, tagId, page) {
if (tagId == null) tagId = ''
return `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_ajax=1&cdn=cdn&t=${sortId}&c=${tagId}&p=${page}`
},
getInfoUrl(tagId) {
return tagId
? `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&cdn=cdn&t=5&c=${tagId}`
: 'http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&'
},
getSongListDetailUrl(id) {
return `http://www2.kugou.kugou.com/yueku/v9/special/single/${id}-5-9999.html`
},
filterInfoHotTag(rawData) {
const result = []
if (rawData.status !== 1) return result
for (const key of Object.keys(rawData.data)) {
let tag = rawData.data[key]
result.push({
id: tag.special_id,
name: tag.special_name,
source: 'kg'
})
}
return result
},
filterTagInfo(rawData) {
const result = []
for (const name of Object.keys(rawData)) {
result.push({
name,
list: rawData[name].data.map((tag) => ({
parent_id: tag.parent_id,
parent_name: tag.pname,
id: tag.id,
name: tag.name,
source: 'kg'
}))
})
}
return result
},
filterSongList(rawData) {
return rawData.map((item) => ({
play_count: item.total_play_count || formatPlayCount(item.play_count),
id: 'id_' + item.specialid,
author: item.nickname,
name: item.specialname,
time: dateFormat(item.publish_time || item.publishtime, 'Y-M-D'),
img: item.img || item.imgurl,
total: item.songcount,
grade: item.grade,
desc: item.intro,
source: 'kg'
}))
},
getSongList(sortId, tagId, page, tryNum = 0) {
if (this._requestObj_list) this._requestObj_list.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
this._requestObj_list = httpFetch(this.getSongListUrl(sortId, tagId, page))
return this._requestObj_list.promise.then(({ body }) => {
if (!body || body.status !== 1) return this.getSongList(sortId, tagId, page, ++tryNum)
return this.filterSongList(body.special_db)
})
},
getSongListRecommend(tryNum = 0) {
if (this._requestObj_listRecommend) this._requestObj_listRecommend.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
this._requestObj_listRecommend = httpFetch(
'http://everydayrec.service.kugou.com/guess_special_recommend',
{
method: 'post',
headers: {
'User-Agent': 'KuGou2012-8275-web_browser_event_handler'
},
body: {
appid: 1001,
clienttime: 1566798337219,
clientver: 8275,
key: 'f1f93580115bb106680d2375f8032d96',
mid: '21511157a05844bd085308bc76ef3343',
platform: 'pc',
userid: '262643156',
return_min: 6,
return_max: 15
}
}
)
return this._requestObj_listRecommend.promise.then(({ body }) => {
if (body.status !== 1) return this.getSongListRecommend(++tryNum)
return this.filterSongList(body.data.special_list)
})
},
/**
* 通过CollectionId获取歌单详情
* @param {*} id
*/
async getUserListInfoByCollectionId(id) {
if (!id || id.length > 1000) return Promise.reject(new Error('get list error'))
if (this.collectionIdListInfoCache.has(id)) return this.collectionIdListInfoCache.get(id)
const params = `appid=1058&specialid=0&global_specialid=${id}&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-`
return createHttpFetch(
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`,
{
headers: {
mid: '1586163242519',
Referer: 'https://m3ws.kugou.com/share/index.php',
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
dfid: '-',
clienttime: '1586163242519'
}
}
).then((body) => {
let info = {
type: body.type,
userName: body.nickname,
userAvatar: body.user_avatar,
imageUrl: body.imgurl,
desc: body.intro,
name: body.specialname,
globalSpecialid: body.global_specialid,
total: body.songcount,
playCount: body.playcount
}
this.collectionIdListInfoCache.set(id, info)
return info
})
},
/**
* 通过SpecialId获取歌单
* @param {*} id
*/
// async getUserListDetailBySpecialId(id, page = 1, limit = 300) {
// if (!id || id.length > 1000) return Promise.reject(new Error('get list error.'))
// const listInfo = await this.getListInfoBySpecialId(id)
// const params = `specialid=${id}&need_sort=1&module=CloudMusic&clientver=11589&pagesize=${limit}&userid=0&page=${page}&type=0&area_code=1&appid=1005`
// return createHttpFetch(`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 2)}`, {
// headers: {
// 'User-Agent': 'Android10-AndroidPhone-11589-201-0-playlist-wifi',
// },
// }).then(body => {
// if (!body.info) return Promise.reject(new Error('Get list failed.'))
// const songList = this.filterListByCollectionId(body.info)
// return {
// list: songList || [],
// page,
// limit,
// total: body.count,
// source: 'kg',
// info: {
// name: listInfo.name,
// img: listInfo.image,
// desc: listInfo.desc,
// // author: listInfo.userName,
// // play_count: formatPlayCount(listInfo.playCount),
// },
// }
// })
// },
/**
* 通过CollectionId获取歌单
* @param {*} id
*/
async getUserListDetailByCollectionId(id, page = 1, limit = 300) {
if (!id || id.length > 1000) return Promise.reject(new Error('ID error.'))
const listInfo = await this.getUserListInfoByCollectionId(id)
const params = `need_sort=1&module=CloudMusic&clientver=11589&pagesize=${limit}&global_collection_id=${id}&userid=0&page=${page}&type=0&area_code=1&appid=1005`
return createHttpFetch(
`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 'android')}`,
{
headers: {
'User-Agent': 'Android10-AndroidPhone-11589-201-0-playlist-wifi'
}
}
).then((body) => {
if (!body.info) return Promise.reject(new Error('Get list failed.'))
const songList = this.filterListByCollectionId(body.info)
return {
list: songList || [],
page,
limit,
total: listInfo.total,
source: 'kg',
info: {
name: listInfo.name,
img: listInfo.imageUrl && listInfo.imageUrl.replace('{size}', 240),
desc: listInfo.desc,
author: listInfo.userName,
play_count: formatPlayCount(listInfo.playCount)
}
}
})
},
/**
* 过滤GlobalSpecialId歌单数据
* @param {*} rawData
*/
filterListByCollectionId(rawData) {
let ids = new Set()
let list = []
rawData.forEach((item) => {
if (!item) return
if (ids.has(item.hash)) return
ids.add(item.hash)
const types = []
const _types = {}
item.relate_goods.forEach((data) => {
let size = sizeFormate(data.size)
switch (data.level) {
case 2:
types.push({ type: '128k', size, hash: data.hash })
_types['128k'] = {
size,
hash: data.hash
}
break
case 4:
types.push({ type: '320k', size, hash: data.hash })
_types['320k'] = {
size,
hash: data.hash
}
break
case 5:
types.push({ type: 'flac', size, hash: data.hash })
_types.flac = {
size,
hash: data.hash
}
break
case 6:
types.push({ type: 'flac24bit', size, hash: data.hash })
_types.flac24bit = {
size,
hash: data.hash
}
break
}
})
list.push({
singer:
formatSingerName(item.singerinfo, 'name') ||
decodeName(item.name).split(' - ')[0].replace(/&/g, '、'),
name: decodeName(item.name).split(' - ')[1],
albumName: decodeName(item.albuminfo.name),
albumId: item.albuminfo.id,
songmid: item.audio_id,
source: 'kg',
interval: formatPlayTime(parseInt(item.timelen) / 1000),
img: null,
lrc: null,
hash: item.hash,
otherSource: null,
types,
_types,
typeUrl: {}
})
})
return list
},
/**
* 通过酷狗码获取歌单
* @param {*} id
* @param {*} page
*/
async getUserListDetailByCode(id, page = 1) {
// type 1单曲2歌单3电台4酷狗码5别人的播放队列
const codeData = await createHttpFetch('http://t.kugou.com/command/', {
method: 'POST',
headers: {
'KG-RC': 1,
'KG-THash': 'network_super_call.cpp:3676261689:379',
'User-Agent': ''
},
body: {
appid: 1001,
clientver: 9020,
mid: '21511157a05844bd085308bc76ef3343',
clienttime: 640612895,
key: '36164c4015e704673c588ee202b9ecb8',
data: id
}
})
if (!codeData) return Promise.reject(new Error('Get list failed.'))
const codeInfo = codeData.info
switch (codeInfo.type) {
case 2:
if (!codeInfo.global_collection_id)
return this.getUserListDetailBySpecialId(codeInfo.id, page)
break
case 3:
return album.getAlbumDetail(codeInfo.id, page)
}
if (codeInfo.global_collection_id)
return this.getUserListDetailByCollectionId(codeInfo.global_collection_id, page)
if (codeInfo.userid != null) {
const songList = await createHttpFetch(
'http://www2.kugou.kugou.com/apps/kucodeAndShare/app/',
{
method: 'POST',
headers: {
'KG-RC': 1,
'KG-THash': 'network_super_call.cpp:3676261689:379',
'User-Agent': ''
},
body: {
appid: 1001,
clientver: 9020,
mid: '21511157a05844bd085308bc76ef3343',
clienttime: 640612895,
key: '36164c4015e704673c588ee202b9ecb8',
data: {
id: codeInfo.id,
type: 3,
userid: codeInfo.userid,
collect_type: 0,
page: 1,
pagesize: codeInfo.count
}
}
}
)
// console.log(songList)
let list = await getMusicInfosByList(songList || codeInfo.list)
return {
list,
page: 1,
limit: codeInfo.count,
total: list.length,
source: 'kg',
info: {
name: codeInfo.name,
img: (codeInfo.img_size && codeInfo.img_size.replace('{size}', 240)) || codeInfo.img,
// desc: body.result.info.list_desc,
author: codeInfo.username
// play_count: formatPlayCount(info.count),
}
}
}
},
async getUserListDetail3(chain, page) {
const songInfo = await createHttpFetch(
`http://m.kugou.com/schain/transfer?pagesize=${this.listDetailLimit}&chain=${chain}&su=1&page=${page}&n=0.7928855356604456`,
{
headers: {
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
}
}
)
if (!songInfo.list) {
if (songInfo.global_collection_id)
return this.getUserListDetailByCollectionId(songInfo.global_collection_id, page)
else
return this.getUserListDetail4(songInfo, chain, page).catch(() =>
this.getUserListDetail5(chain)
)
}
let list = await getMusicInfosByList(songInfo.list)
// console.log(info, songInfo)
return {
list,
page: 1,
limit: this.listDetailLimit,
total: list.length,
source: 'kg',
info: {
name: songInfo.info.name,
img: songInfo.info.img,
// desc: body.result.info.list_desc,
author: songInfo.info.username
// play_count: formatPlayCount(info.count),
}
}
},
async getUserListDetailByLink({ info }, link) {
let listInfo = info['0']
let total = listInfo.count
let tasks = []
let page = 0
while (total) {
const limit = total > 90 ? 90 : total
total -= limit
page += 1
tasks.push(
createHttpFetch(
link.replace(/pagesize=\d+/, 'pagesize=' + limit).replace(/page=\d+/, 'page=' + page),
{
headers: {
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
Referer: link
}
}
).then((data) => data.list.info)
)
}
let result = await Promise.all(tasks).then(([...datas]) => datas.flat())
result = await getMusicInfosByList(result)
// console.log(result)
return {
list: result,
page,
limit: this.listDetailLimit,
total: result.length,
source: 'kg',
info: {
name: listInfo.name,
img: listInfo.pic && listInfo.pic.replace('{size}', 240),
// desc: body.result.info.list_desc,
author: listInfo.list_create_username
// play_count: formatPlayCount(listInfo.count),
}
}
},
createGetListDetail2Task(id, total) {
let tasks = []
let page = 0
while (total) {
const limit = total > 300 ? 300 : total
total -= limit
page += 1
const params =
'appid=1058&global_specialid=' +
id +
'&specialid=0&plat=0&version=8000&page=' +
page +
'&pagesize=' +
limit +
'&srcappid=2919&clientver=20000&clienttime=1586163263991&mid=1586163263991&uuid=1586163263991&dfid=-'
tasks.push(
createHttpFetch(
`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 'web')}`,
{
headers: {
mid: '1586163263991',
Referer: 'https://m3ws.kugou.com/share/index.php',
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
dfid: '-',
clienttime: '1586163263991'
}
}
).then((data) => data.info)
)
}
return Promise.all(tasks).then(([...datas]) => datas.flat())
},
async getUserListDetail2(global_collection_id) {
let id = global_collection_id
if (id.length > 1000) throw new Error('get list error')
const params =
'appid=1058&specialid=0&global_specialid=' +
id +
'&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-'
let info = await createHttpFetch(
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`,
{
headers: {
mid: '1586163242519',
Referer: 'https://m3ws.kugou.com/share/index.php',
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
dfid: '-',
clienttime: '1586163242519'
}
}
)
const songInfo = await this.createGetListDetail2Task(id, info.songcount)
let list = await getMusicInfosByList(songInfo)
// console.log(info, songInfo, list)
return {
list,
page: 1,
limit: this.listDetailLimit,
total: list.length,
source: 'kg',
info: {
name: info.specialname,
img: info.imgurl && info.imgurl.replace('{size}', 240),
desc: info.intro,
author: info.nickname,
play_count: formatPlayCount(info.playcount)
}
}
},
async getListInfoByChain(chain) {
if (this.cache.has(chain)) return this.cache.get(chain)
const { body } = await httpFetch(`https://m.kugou.com/share/?chain=${chain}&id=${chain}`, {
headers: {
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
}
}).promise
// console.log(body)
let result = body.match(/var\sphpParam\s=\s({.+?});/)
if (result) result = JSON.parse(result[1])
this.cache.set(chain, result)
return result
},
async getUserListDetailByPcChain(chain) {
let key = `${chain}_pc_list`
if (this.cache.has(key)) return this.cache.get(key)
const { body } = await httpFetch(`http://www.kugou.com/share/${chain}.html`, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
}).promise
let result = body.match(/var\sdataFromSmarty\s=\s(\[.+?\])/)
if (result) result = JSON.parse(result[1])
this.cache.set(chain, result)
result = await getMusicInfosByList(result)
// console.log(info, songInfo)
return result
},
async getUserListDetail4(songInfo, chain, page) {
const limit = 100
const [listInfo, list] = await Promise.all([
this.getListInfoByChain(chain),
this.getUserListDetailBySpecialId(songInfo.id, page, limit)
])
return {
list: list || [],
page,
limit,
total: list.length ?? 0,
source: 'kg',
info: {
name: listInfo.specialname,
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
// desc: body.result.info.list_desc,
author: listInfo.nickname
// play_count: formatPlayCount(info.count),
}
}
},
async getUserListDetail5(chain) {
const [listInfo, list] = await Promise.all([
this.getListInfoByChain(chain),
this.getUserListDetailByPcChain(chain)
])
return {
list: list || [],
page: 1,
limit: this.listDetailLimit,
total: list.length ?? 0,
source: 'kg',
info: {
name: listInfo.specialname,
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
// desc: body.result.info.list_desc,
author: listInfo.nickname
// play_count: formatPlayCount(info.count),
}
}
},
async getUserListDetail(link, page, retryNum = 0) {
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
const requestLink = httpFetch(link, {
headers: {
'User-Agent':
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
Referer: link
},
follow_max: 2
})
const {
headers: { location },
statusCode,
body
} = await requestLink.promise
// console.log(body, location, statusCode)
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
if (typeof body == 'string') {
if (body.includes('"global_collection_id":'))
return this.getUserListDetailByCollectionId(
body.replace(/^[\s\S]+?"global_collection_id":"(\w+)"[\s\S]+?$/, '$1'),
page
)
if (body.includes('"albumid":'))
return album.getAlbumDetail(body.replace(/^[\s\S]+?"albumid":(\w+)[\s\S]+?$/, '$1'), page)
if (body.includes('"album_id":') && link.includes('album/info'))
return album.getAlbumDetail(body.replace(/^[\s\S]+?"album_id":(\w+)[\s\S]+?$/, '$1'), page)
if (body.includes('list_id = "') && link.includes('album/info'))
return album.getAlbumDetail(body.replace(/^[\s\S]+?list_id = "(\w+)"[\s\S]+?$/, '$1'), page)
}
if (location) {
// 概念版分享链接 https://t1.kugou.com/xxx
if (location.includes('global_specialid'))
return this.getUserListDetailByCollectionId(
location.replace(/^.*?global_specialid=(\w+)(?:&.*$|#.*$|$)/, '$1'),
page
)
if (location.includes('global_collection_id'))
return this.getUserListDetailByCollectionId(
location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'),
page
)
if (location.includes('chain='))
return this.getUserListDetail3(
location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'),
page
)
if (location.includes('.html')) {
if (location.includes('zlist.html')) {
let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
if (link.includes('pagesize')) {
link = link
.replace('pagesize=30', 'pagesize=' + this.listDetailLimit)
.replace('page=1', 'page=' + page)
} else {
link += `&pagesize=${this.listDetailLimit}&page=${page}`
}
return this.getUserListDetail(link, page, ++retryNum)
} else
return this.getUserListDetail3(
location.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'),
page
)
}
return this.getUserListDetail(location, page, ++retryNum)
}
if (body.errcode !== 0) return this.getUserListDetail(link, page, ++retryNum)
return this.getUserListDetailByLink(body, link)
},
// 获取列表信息
getListInfo(tagId, tryNum = 0) {
if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
this._requestObj_listInfo = httpFetch(this.getInfoUrl(tagId))
return this._requestObj_listInfo.promise.then(({ body }) => {
if (body.status !== 1) return this.getListInfo(tagId, ++tryNum)
return {
limit: body.data.params.pagesize,
page: body.data.params.p,
total: body.data.params.total,
source: 'kg'
}
})
},
// 获取列表数据
getList(sortId, tagId, page) {
let tasks = [this.getSongList(sortId, tagId, page)]
tasks.push(
this.currentTagInfo.id === tagId
? Promise.resolve(this.currentTagInfo.info)
: this.getListInfo(tagId).then((info) => {
this.currentTagInfo.id = tagId
this.currentTagInfo.info = Object.assign({}, info)
return info
})
)
if (!tagId && page === 1 && sortId === this.sortList[0].id)
tasks.push(this.getSongListRecommend()) // 如果是所有类别,则顺便获取推荐列表
return Promise.all(tasks).then(([list, info, recommendList]) => {
if (recommendList) list.unshift(...recommendList)
return {
list,
...info
}
})
},
// 获取标签
getTags(tryNum = 0) {
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
this._requestObj_tags = httpFetch(this.getInfoUrl())
return this._requestObj_tags.promise.then(({ body }) => {
if (body.status !== 1) return this.getTags(++tryNum)
return {
hotTag: this.filterInfoHotTag(body.data.hotTag),
tags: this.filterTagInfo(body.data.tagids),
source: 'kg'
}
})
},
getDetailPageUrl(id) {
if (typeof id == 'string') {
if (/^https?:\/\//.test(id)) return id
id = id.replace('id_', '')
}
return `https://www.kugou.com/yy/special/single/${id}.html`
},
search(text, page, limit = 20) {
const params = `userid=1384394652&req_custom=1&appid=1005&req_multi=1&version=11589&page=${page}&filter=0&pagesize=${limit}&order=0&clienttime=1681779443&iscorrection=1&searchsong=0&keyword=${text}&mid=288799920684148686226285199951543865551&dfid=3eSBsO1u97EY1zeIZd40hH4p&clientver=11589&platform=AndroidFilter`
const url = encodeURI(
`http://complexsearchretry.kugou.com/v1/search/special?${params}&signature=${signatureParams(params, 'android')}`
)
return createHttpFetch(url).then((body) => {
// console.log(body)
return {
list: body.lists.map((item) => {
return {
play_count: formatPlayCount(item.total_play_count),
id: item.gid ? `gid_${item.gid}` : `id_${item.specialid}`,
author: item.nickname,
name: item.specialname,
time: dateFormat(item.publish_time, 'Y-M-D'),
img: item.img,
grade: item.grade,
desc: item.intro,
total: item.song_count,
source: 'kg'
}
}),
limit,
total: body.total,
source: 'kg'
}
})
// http://msearchretry.kugou.com/api/v3/search/special?version=9209&keyword=%E5%91%A8%E6%9D%B0%E4%BC%A6&pagesize=20&filter=0&page=1&sver=2&with_res_tag=0
// http://ioscdn.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&correct=1&sver=5
// http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2
}
}
// getList
// getTags
// getListDetail

View File

@@ -183,7 +183,11 @@ export default {
lrcT
}
},
transformLrc(tags, lrclist) {
transformLrc(tags, lrclist, keepOriginalTime = false) {
if (keepOriginalTime) {
// 保持原始时间格式用于逐字歌词
return `${tags.join('\n')}\n${lrclist ? lrclist.map((l) => `${l.text}\n`).join('') : '暂无歌词'}`
}
return `${tags.join('\n')}\n${lrclist ? lrclist.map((l) => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}`
},
parseLrc(lrc) {
@@ -224,10 +228,10 @@ export default {
// return Promise.reject(new Error('Get lyric failed'))
// }
// if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
// lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
// lrcInfo.crlyric = lrcTools.parse(lrcInfo.lyric)
// // console.log(lrcInfo.lyric)
// // console.log(lrcInfo.tlyric)
// // console.log(lrcInfo.lxlyric)
// // console.log(lrcInfo.crlyric)
// // console.log(JSON.stringify(lrcInfo))
// })
// })
@@ -257,9 +261,9 @@ export default {
// console.log(lrcInfo)
if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
try {
lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
lrcInfo.crlyric = lrcTools.parse(lrcInfo.lyric)
} catch {
lrcInfo.lxlyric = ''
lrcInfo.crlyric = ''
}
lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '')
if (!existTimeExp.test(lrcInfo.lyric)) return Promise.reject(new Error('Get lyric failed'))

View File

@@ -65,8 +65,14 @@ export const matchToken = (headers) => {
// })
// })
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const decodeLyric = (base64Data) => kwdecode(base64Data, false)
export const decodeLyric = (options) => {
if (typeof options === 'string') {
// 兼容旧的调用方式
return kwdecode(options, false)
}
// 新的调用方式,传递对象
return kwdecode(options.lrcBase64, options.isGetLyricx || false)
}
// export const tokenRequest = async(url, options = {}) => {
// let token = kw_token.token
@@ -101,26 +107,32 @@ export const lrcTools = {
isOK: false,
lines: [],
tags: [],
getWordInfo(str, str2, prevWord) {
getWordInfo(str, str2, prevWord, lineStartTime = 0) {
// 使用原始的酷我音乐时间计算逻辑,但输出绝对时间戳
const offset = parseInt(str)
const offset2 = parseInt(str2)
let startTime = Math.abs((offset + offset2) / (this.offset * 2))
let endTime = Math.abs((offset - offset2) / (this.offset2 * 2)) + startTime
if (prevWord) {
if (startTime < prevWord.endTime) {
prevWord.endTime = startTime
if (prevWord.startTime > prevWord.endTime) {
prevWord.startTime = prevWord.endTime
}
let duration = Math.abs((offset - offset2) / (this.offset2 * 2))
prevWord.newTimeStr = `<${prevWord.startTime},${prevWord.endTime - prevWord.startTime}>`
// console.log(prevWord)
// 转换为基于行开始时间的绝对时间戳
const absoluteStartTime = lineStartTime + startTime
const endTime = absoluteStartTime + duration
if (prevWord) {
if (absoluteStartTime < prevWord.endTime) {
prevWord.endTime = absoluteStartTime
if (prevWord.absoluteStartTime > prevWord.endTime) {
prevWord.absoluteStartTime = prevWord.endTime
}
prevWord.newTimeStr = `(${prevWord.absoluteStartTime},${prevWord.endTime - prevWord.absoluteStartTime},0)`
}
}
return {
startTime,
absoluteStartTime,
endTime,
timeStr: `<${startTime},${endTime - startTime}>`
duration,
timeStr: `(${absoluteStartTime},${duration},0)`
}
},
parseLine(line) {
@@ -134,17 +146,35 @@ export const lrcTools = {
}
const wordTimes = words.match(this.rxps.wordTimeAll)
if (!wordTimes) return
// console.log(wordTimes)
// 提取原始时间戳信息 [start,duration]
const timeMatch = time.match(/\[(\d+):(\d+)\.(\d+)\]/)
let lineStartTime = 0
let lineDuration = 0
if (timeMatch) {
const minutes = parseInt(timeMatch[1])
const seconds = parseInt(timeMatch[2])
const milliseconds = parseInt(timeMatch[3])
lineStartTime = minutes * 60000 + seconds * 1000 + milliseconds
// 计算行持续时间(这里需要根据实际情况调整)
lineDuration = 5000 // 默认5秒实际应该根据下一行时间计算
}
let preTimeInfo
for (const timeStr of wordTimes) {
const result = this.rxps.wordTime.exec(timeStr)
const wordInfo = this.getWordInfo(result[1], result[2], preTimeInfo)
words = words.replace(timeStr, wordInfo.timeStr)
const wordInfo = this.getWordInfo(result[1], result[2], preTimeInfo, lineStartTime)
const newTimeStr = `(${wordInfo.absoluteStartTime},${wordInfo.duration},0)`
words = words.replace(timeStr, newTimeStr)
if (preTimeInfo?.newTimeStr)
words = words.replace(preTimeInfo.timeStr, preTimeInfo.newTimeStr)
preTimeInfo = wordInfo
preTimeInfo.timeStr = newTimeStr
}
this.lines.push(time + words)
// 使用 [start,duration] 格式而不是标准时间格式
const originalTimeTag = `[${lineStartTime},${lineDuration}]`
this.lines.push(originalTimeTag + words)
return
}
result = this.rxps.tagLine.exec(line)

View File

@@ -46,7 +46,7 @@ const mrcTools = {
}
return {
lyric: lrcLines.join('\n'),
lxlyric: lxlrcLines.join('\n')
crlyric: lxlrcLines.join('\n')
}
},
getText(url, tryNum = 0) {
@@ -70,7 +70,7 @@ const mrcTools = {
})
},
getLrc(url) {
return this.getText(url).then((text) => ({ lxlyric: '', lyric: text }))
return this.getText(url).then((text) => ({ crlyric: '', lyric: text }))
},
getTrc(url) {
if (!url) return Promise.resolve('')

View File

@@ -1,196 +0,0 @@
import { httpFetch } from '../../../request'
import { formatPlayTime } from '../../../index'
// import { sizeFormate } from '../../index'
// const boardList = [{ id: 'mg__27553319', name: '咪咕尖叫新歌榜', bangid: '27553319' }, { id: 'mg__27186466', name: '咪咕尖叫热歌榜', bangid: '27186466' }, { id: 'mg__27553408', name: '咪咕尖叫原创榜', bangid: '27553408' }, { id: 'mg__23189800', name: '咪咕港台榜', bangid: '23189800' }, { id: 'mg__23189399', name: '咪咕内地榜', bangid: '23189399' }, { id: 'mg__19190036', name: '咪咕欧美榜', bangid: '19190036' }, { id: 'mg__23189813', name: '咪咕日韩榜', bangid: '23189813' }, { id: 'mg__23190126', name: '咪咕彩铃榜', bangid: '23190126' }, { id: 'mg__15140045', name: '咪咕KTV榜', bangid: '15140045' }, { id: 'mg__15140034', name: '咪咕网络榜', bangid: '15140034' }, { id: 'mg__23217754', name: 'MV榜', bangid: '23217754' }, { id: 'mg__23218151', name: '新专辑榜', bangid: '23218151' }, { id: 'mg__21958042', name: 'iTunes榜', bangid: '21958042' }, { id: 'mg__21975570', name: 'billboard榜', bangid: '21975570' }, { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815' }, { id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' }, { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943' }, { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437' }]
const boardList = [
{ id: 'mg__27553319', name: '尖叫新歌榜', bangid: '27553319', webId: 'jianjiao_newsong' },
{ id: 'mg__27186466', name: '尖叫热歌榜', bangid: '27186466', webId: 'jianjiao_hotsong' },
{ id: 'mg__27553408', name: '尖叫原创榜', bangid: '27553408', webId: 'jianjiao_original' },
{ id: 'mg__migumusic', name: '音乐榜', bangid: 'migumusic', webId: 'migumusic' },
{ id: 'mg__movies', name: '影视榜', bangid: 'movies', webId: 'movies' },
{ id: 'mg__23189800', name: '港台榜', bangid: '23189800', webId: 'hktw' },
{ id: 'mg__23189399', name: '内地榜', bangid: '23189399', webId: 'mainland' },
{ id: 'mg__19190036', name: '欧美榜', bangid: '19190036', webId: 'eur_usa' },
{ id: 'mg__23189813', name: '日韩榜', bangid: '23189813', webId: 'jpn_kor' },
{ id: 'mg__23190126', name: '彩铃榜', bangid: '23190126', webId: 'coloring' },
{ id: 'mg__15140045', name: 'KTV榜', bangid: '15140045', webId: 'ktv' },
{ id: 'mg__15140034', name: '网络榜', bangid: '15140034', webId: 'network' },
{ id: 'mg__23217754', name: 'MV榜', bangid: '23217754', webId: 'mv' },
{ id: 'mg__23218151', name: '新专辑榜', bangid: '23218151', webId: 'newalbum' },
{ id: 'mg__21958042', name: '美国iTunes榜', bangid: '21958042', webId: 'itunes' },
{ id: 'mg__21975570', name: '美国billboard榜', bangid: '21975570', webId: 'billboard' },
{ id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815', webId: 'hito' },
{ id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' },
{ id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943', webId: 'mnet' },
{ id: 'mg__22273437', name: '英国UK榜', bangid: '22273437', webId: 'uk' }
]
// const boardList = [
// { id: 'mg__jianjiao_newsong', bangid: 'jianjiao_newsong', name: '尖叫新歌榜' },
// { id: 'mg__jianjiao_hotsong', bangid: 'jianjiao_hotsong', name: '尖叫热歌榜' },
// { id: 'mg__jianjiao_original', bangid: 'jianjiao_original', name: '尖叫原创榜' },
// { id: 'mg__migumusic', bangid: 'migumusic', name: '音乐榜' },
// { id: 'mg__movies', bangid: 'movies', name: '影视榜' },
// { id: 'mg__mainland', bangid: 'mainland', name: '内地榜' },
// { id: 'mg__hktw', bangid: 'hktw', name: '港台榜' },
// { id: 'mg__eur_usa', bangid: 'eur_usa', name: '欧美榜' },
// { id: 'mg__jpn_kor', bangid: 'jpn_kor', name: '日韩榜' },
// { id: 'mg__coloring', bangid: 'coloring', name: '彩铃榜' },
// { id: 'mg__ktv', bangid: 'ktv', name: 'KTV榜' },
// { id: 'mg__network', bangid: 'network', name: '网络榜' },
// { id: 'mg__newalbum', bangid: 'newalbum', name: '新专辑榜' },
// { id: 'mg__mv', bangid: 'mv', name: 'MV榜' },
// { id: 'mg__itunes', bangid: 'itunes', name: '美国iTunes榜' },
// { id: 'mg__billboard', bangid: 'billboard', name: '美国billboard榜' },
// { id: 'mg__hito', bangid: 'hito', name: 'Hito中文榜' },
// { id: 'mg__mnet', bangid: 'mnet', name: '韩国Melon榜' },
// { id: 'mg__uk', bangid: 'uk', name: '英国UK榜' },
// ]
export default {
limit: 10000,
getUrl(id, page) {
const targetBoard = boardList.find((board) => board.bangid == id)
return `https://music.migu.cn/v3/music/top/${targetBoard.webId}`
// return `http://m.music.migu.cn/migu/remoting/cms_list_tag?nid=${id}&pageSize=${this.limit}&pageNo=${page - 1}`
},
successCode: '000000',
requestBoardsObj: null,
regExps: {
listData: /var listData = (\{.+\})<\/script>/
},
getData(url) {
const requestObj = httpFetch(url)
return requestObj.promise
},
getSinger(singers) {
let arr = []
singers.forEach((singer) => {
arr.push(singer.name)
})
return arr.join('、')
},
getIntv(interval) {
if (!interval) return 0
let intvArr = interval.split(':')
let intv = 0
let unit = 1
while (intvArr.length) {
intv += intvArr.pop() * unit
unit *= 60
}
return parseInt(intv)
},
formateIntv() {},
filterData(rawData) {
// console.log(JSON.stringify(rawData))
// console.log(rawData)
let ids = new Set()
const list = []
rawData.forEach((item) => {
if (ids.has(item.copyrightId)) return
ids.add(item.copyrightId)
const types = []
const _types = {}
const size = null
types.push({ type: '128k', size })
_types['128k'] = { size }
if (item.hq) {
const size = null
types.push({ type: '320k', size })
_types['320k'] = { size }
}
if (item.sq) {
const size = null
types.push({ type: 'flac', size })
_types.flac = { size }
}
list.push({
singer: this.getSinger(item.singers),
name: item.name,
albumName: item.album && item.album.albumName,
albumId: item.album && item.album.albumId,
songmid: item.id,
copyrightId: item.copyrightId,
source: 'mg',
interval: item.duration ? formatPlayTime(this.getIntv(item.duration)) : null,
img: item.mediumPic ? `https:${item.mediumPic}` : null,
lrc: null,
// lrcUrl: item.lrcUrl,
otherSource: null,
types,
_types,
typeUrl: {}
})
})
return list
},
filterBoardsData(rawList) {
// console.log(rawList)
let list = []
for (const board of rawList) {
if (board.template != 'group1') continue
for (const item of board.itemList) {
if (
(item.template != 'row1' && item.template != 'grid1' && !item.actionUrl) ||
!item.actionUrl.includes('rank-info')
)
continue
let data = item.displayLogId.param
list.push({
id: 'mg__' + data.rankId,
name: data.rankName,
bangid: String(data.rankId)
})
}
}
return list
},
async getBoards(retryNum = 0) {
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
// let response
// try {
// response = await this.getBoardsData()
// } catch (error) {
// return this.getBoards(retryNum)
// }
// // console.log(response.body.data.contentItemList)
// if (response.statusCode !== 200 || response.body.code !== this.successCode) return this.getBoards(retryNum)
// const list = this.filterBoardsData(response.body.data.contentItemList)
// // console.log(list)
// // console.log(JSON.stringify(list))
// this.list = list
// return {
// list,
// source: 'mg',
// }
this.list = boardList
return {
list: boardList,
source: 'mg'
}
},
getList(bangid, page, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
return this.getData(this.getUrl(bangid, page)).then(({ statusCode, body }) => {
if (statusCode !== 200) return this.getList(bangid, page, retryNum)
let listData = body.match(this.regExps.listData)
if (!listData) return this.getList(bangid, page, retryNum)
const datas = JSON.parse(RegExp.$1)
// console.log(datas)
listData = this.filterData(datas.songs.items)
return {
total: datas.songs.itemTotal,
list: this.filterData(datas.songs.items),
limit: this.limit,
page,
source: 'mg'
}
})
}
}

View File

@@ -7,7 +7,7 @@ import { eapi } from './utils/crypto'
// str = str.replace(/\r/g, '')
// let lxlyric = str.replace(/\[((\d+),\d+)\].*/g, str => {
// let crlyric = str.replace(/\[((\d+),\d+)\].*/g, str => {
// let result = str.match(/\[((\d+),\d+)\].*/)
// let time = parseInt(result[2])
// let ms = time % 1000
@@ -30,8 +30,8 @@ import { eapi } from './utils/crypto'
// return str
// })
// lxlyric = decodeName(lxlyric)
// return lxlyric.trim()
// crlyric = decodeName(crlyric)
// return crlyric.trim()
// }
const eapiRequest = (url, data) => {
@@ -96,20 +96,13 @@ const parseTools = {
lrcLines.push(`${startTimeStr}${words.replace(this.rxps.wordTimeAll, '')}`)
let times = words.match(this.rxps.wordTimeAll)
if (!times) continue
times = times.map((time) => {
const result = /\((\d+),(\d+),\d+\)/.exec(time)
return `<${Math.max(parseInt(result[1]) - startMsTime, 0)},${result[2]}>`
})
const wordArr = words.split(this.rxps.wordTime)
wordArr.shift()
const newWords = times.map((time, index) => `${time}${wordArr[index]}`).join('')
lxlrcLines.push(`${startTimeStr}${newWords}`)
// 保持网易云音乐逐字歌词的原始格式 [start,duration](start,duration)xxx
const originalTimeTag = result[0] // 保持原始的 [start,duration] 格式
lxlrcLines.push(`${originalTimeTag}${words}`)
}
return {
lyric: lrcLines.join('\n'),
lxlyric: lxlrcLines.join('\n')
crlyric: lxlrcLines.join('\n')
}
},
parseHeaderInfo(str) {
@@ -172,7 +165,7 @@ const parseTools = {
lyric: '',
tlyric: '',
rlyric: '',
lxlyric: ''
crlyric: ''
}
if (ylrc) {
let lines = this.parseHeaderInfo(ylrc)
@@ -198,7 +191,7 @@ const parseTools = {
const timeRxp = /^\[[\d:.]+\]/
const headers = lines.filter((l) => timeRxp.test(l)).join('\n')
info.lyric = `${headers}\n${result.lyric}`
info.lxlyric = result.lxlyric
info.crlyric = result.crlyric
return info
}
}
@@ -243,7 +236,7 @@ const parseTools = {
// lyric: body.lrc.lyric,
// tlyric: body.tlyric?.lyric ?? '',
// rlyric: body.romalrc?.lyric ?? '',
// // lxlyric: parseLyric(body.klyric.lyric),
// // crlyric: parseLyric(body.klyric.lyric),
// }
// })
// return requestObj

View File

@@ -36,7 +36,7 @@ export default {
headers: { location },
statusCode
} = await requestObj_listDetailLink.promise
// console.log(headers)
// console.log(statusCode)
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
const url = location == null ? link : location
return this.regExps.listDetailLink.test(url)
@@ -153,14 +153,14 @@ export default {
_types.flac = {
size
}
// eslint-disable-next-line no-fallthrough
case 320000:
size = item.h ? sizeFormate(item.h.size) : null
types.push({ type: '320k', size })
_types['320k'] = {
size
}
// eslint-disable-next-line no-fallthrough
case 192000:
case 128000:
size = item.l ? sizeFormate(item.l.size) : null

View File

@@ -1,11 +1,23 @@
import electron from 'electron'
import path from 'path'
function getAppDirPath() {
let dirPath: string = electron.app.getAppPath()
if (dirPath.endsWith('.asar')) {
dirPath = path.join(path.dirname(dirPath), '../')
}
function getAppDirPath(name?: "home"
| "appData"
| "assets"
| "userData"
| "sessionData"
| "temp"
| "exe"
| "module"
| "desktop"
| "documents"
| "downloads"
| "music"
| "pictures"
| "videos"
| "recent"
| "logs"
| "crashDumps") {
let dirPath: string = electron.app.getPath(name ?? 'userData')
return dirPath
}

View File

@@ -1,12 +1,12 @@
import needle from 'needle'
import axios from 'axios'
import { bHh } from './musicSdk/options'
import { deflateRaw } from 'zlib'
import { httpOverHttp, httpsOverHttp } from 'tunnel'
import { HttpsProxyAgent, HttpProxyAgent } from 'hpagent'
// 常量定义
const DEFAULT_TIMEOUT = 15000
const DEFAULT_USER_AGENT =
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Mobile Safari/537.36'
const debugRequest = false
const httpsRxp = /^https:/
@@ -56,58 +56,20 @@ export const clearProxy = () => {
* @param {string} url - 请求URL
*/
const getRequestAgent = (url) => {
let options
let proxyUrl
if (proxy.enable && proxy.host) {
options = {
proxy: {
host: proxy.host,
port: proxy.port
}
}
// 如果有用户名和密码,添加认证
if (proxy.username && proxy.password) {
options.proxy.proxyAuth = `${proxy.username}:${proxy.password}`
}
const auth = proxy.username && proxy.password ? `${proxy.username}:${proxy.password}@` : ''
proxyUrl = `http://${auth}${proxy.host}:${proxy.port}`
} else if (proxy.envProxy) {
options = {
proxy: {
host: proxy.envProxy.host,
port: proxy.envProxy.port
proxyUrl = `http://${proxy.envProxy.host}:${proxy.envProxy.port}`
}
}
}
return options ? (httpsRxp.test(url) ? httpsOverHttp : httpOverHttp)(options) : undefined
}
/**
* 核心请求函数
* @param {string} url - 请求URL
* @param {Object} options - 请求选项
* @param {Function} callback - 回调函数
*/
const request = (url, options, callback) => {
let data
if (options.body) {
data = options.body
} else if (options.form) {
data = options.form
options.json = false
} else if (options.formData) {
data = options.formData
options.json = false
if (proxyUrl) {
return httpsRxp.test(url)
? new HttpsProxyAgent({ proxy: proxyUrl })
: new HttpProxyAgent({ proxy: proxyUrl })
}
options.response_timeout = options.timeout
return needle.request(options.method || 'get', url, data, options, (err, resp, body) => {
if (!err) {
body = resp.body = resp.raw.toString()
try {
resp.body = JSON.parse(resp.body)
} catch (_) {}
body = resp.body
}
callback(err, resp, body)
}).request
return undefined
}
/**
@@ -125,30 +87,31 @@ const defaultHeaders = {
const buildHttpPromise = (url, options) => {
let obj = {
isCancelled: false,
cancelToken: axios.CancelToken.source(),
cancelHttp: () => {
if (!obj.requestObj) return (obj.isCancelled = true)
cancelHttp(obj.requestObj)
obj.requestObj = null
obj.promise = obj.cancelHttp = null
obj.cancelFn(new Error('已取消'))
obj.cancelFn = null
if (obj.isCancelled) return
obj.isCancelled = true
obj.cancelToken.cancel('已取消')
}
}
obj.promise = new Promise((resolve, reject) => {
obj.cancelFn = reject
obj.promise = new Promise(async (resolve, reject) => {
try {
debugRequest && console.log(`\n---send request------${url}------------`)
fetchData(url, options.method, options, (err, resp, body) => {
const response = await fetchData(url, options.method, {
...options,
cancelToken: obj.cancelToken.token
})
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(body)
obj.requestObj = null
obj.cancelFn = null
if (err) return reject(err)
resolve(resp)
}).then((ro) => {
obj.requestObj = ro
if (obj.isCancelled) obj.cancelHttp()
})
debugRequest && console.log(response.data)
resolve(response)
} catch (err) {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(err.message)
reject(err)
}
})
return obj
}
@@ -160,18 +123,19 @@ const buildHttpPromise = (url, options) => {
export const httpFetch = (url, options = { method: 'get' }) => {
const requestObj = buildHttpPromise(url, options)
requestObj.promise = requestObj.promise.catch((err) => {
if (axios.isCancel(err)) {
return Promise.reject(new Error('已取消'))
}
if (err.code === 'ECONNABORTED' || err.message.includes('timeout')) {
return Promise.reject(new Error('超时'))
}
if (err.code === 'ENOTFOUND') {
return Promise.reject(new Error('未连接'))
}
if (err.message === 'socket hang up') {
return Promise.reject(new Error('无法请求'))
}
switch (err.code) {
case 'ETIMEDOUT':
case 'ESOCKETTIMEDOUT':
return Promise.reject(new Error('超时'))
case 'ENOTFOUND':
return Promise.reject(new Error('未连接'))
default:
return Promise.reject(err)
}
})
return requestObj
}
@@ -181,8 +145,8 @@ export const httpFetch = (url, options = { method: 'get' }) => {
* @param {Object} requestObj - 请求对象
*/
export const cancelHttp = (requestObj) => {
if (!requestObj || !requestObj.abort) return
requestObj.abort()
if (!requestObj || !requestObj.cancelHttp) return
requestObj.cancelHttp()
}
/**
@@ -202,14 +166,23 @@ const handleDeflateRaw = (data) =>
* @param {string} url - 请求URL
* @param {string} method - 请求方法
* @param {Object} options - 请求选项
* @param {Function} callback - 回调函数
*/
const fetchData = async (url, method, options, callback) => {
const { headers = {}, format = 'json', timeout = DEFAULT_TIMEOUT, ...restOptions } = options
const fetchData = async (url, method = 'get', options = {}) => {
const {
headers = {},
format = 'json',
timeout = DEFAULT_TIMEOUT,
data,
body,
form,
formData,
cancelToken,
...restOptions
} = options
console.log('---start---', url)
const requestHeaders = Object.assign({}, headers)
const requestHeaders = Object.assign({}, defaultHeaders, headers)
// 处理特殊头部
if (requestHeaders[bHh]) {
@@ -229,21 +202,90 @@ const fetchData = async (url, method, options, callback) => {
delete requestHeaders[bHh]
}
return request(
url,
{
...restOptions,
method,
headers: Object.assign({}, defaultHeaders, requestHeaders),
timeout,
agent: getRequestAgent(url),
json: format === 'json'
},
(err, resp, body) => {
if (err) return callback(err, null)
callback(null, resp, body)
// 处理请求数据
let requestData = data || body || form || formData
// 处理表单数据
if (form || formData) {
if (form) {
requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded'
if (typeof form === 'object') {
requestData = new URLSearchParams(form).toString()
}
}
}
const axiosConfig = {
method: method.toLowerCase(),
url,
headers: requestHeaders,
timeout,
httpsAgent: getRequestAgent(url),
httpAgent: getRequestAgent(url),
...restOptions
}
// 添加取消令牌
if (cancelToken) {
axiosConfig.cancelToken = cancelToken
}
// 根据方法添加数据
if (['post', 'put', 'patch'].includes(method.toLowerCase()) && requestData) {
axiosConfig.data = requestData
} else if (['get', 'delete'].includes(method.toLowerCase()) && requestData) {
axiosConfig.params = requestData
}
// 处理响应格式
if (format !== 'json') {
axiosConfig.responseType = format === 'script' ? 'text' : format
} else {
// 对于可能需要原始数据的请求,使用 arraybuffer
if (url.includes('newlyric.kuwo.cn')) {
axiosConfig.responseType = 'arraybuffer'
}
}
try {
const response = await axios(axiosConfig)
// 处理不同类型的响应数据
let bodyData = response.data
let rawData
if (axiosConfig.responseType === 'arraybuffer') {
rawData = Buffer.from(response.data)
// 尝试解析为 JSON如果失败则保持原始数据
try {
bodyData = JSON.parse(rawData.toString())
} catch {
bodyData = rawData.toString()
}
} else {
rawData = Buffer.isBuffer(response.data)
? response.data
: Buffer.from(
typeof response.data === 'string' ? response.data : JSON.stringify(response.data)
)
}
return {
statusCode: response.status,
headers: response.headers,
body: bodyData,
data: bodyData,
raw: rawData
}
} catch (error) {
if (axios.isAxiosError(error)) {
const err = new Error(error.message)
err.code = error.code
err.response = error.response
throw err
}
throw error
}
}
/**
@@ -261,13 +303,17 @@ export const http = (url, options, cb) => {
if (options.method == null) options.method = 'get'
debugRequest && console.log(`\n---send request------${url}------------`)
return fetchData(url, options.method, options, (err, resp, body) => {
fetchData(url, options.method, options)
.then((resp) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(resp.body)
cb(null, resp, resp.body)
})
.catch((err) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(body)
if (err) {
debugRequest && console.log(JSON.stringify(err))
}
cb(err, resp, body)
cb(err, null, null)
})
}
@@ -284,13 +330,17 @@ export const httpGet = (url, options, callback) => {
}
debugRequest && console.log(`\n---send request-------${url}------------`)
return fetchData(url, 'get', options, function (err, resp, body) {
fetchData(url, 'get', options)
.then((resp) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(resp.body)
callback(null, resp, resp.body)
})
.catch((err) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(body)
if (err) {
debugRequest && console.log(JSON.stringify(err))
}
callback(err, resp, body)
callback(err, null, null)
})
}
@@ -309,13 +359,17 @@ export const httpPost = (url, data, options, callback) => {
options.data = data
debugRequest && console.log(`\n---send request-------${url}------------`)
return fetchData(url, 'post', options, function (err, resp, body) {
fetchData(url, 'post', options)
.then((resp) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(resp.body)
callback(null, resp, resp.body)
})
.catch((err) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(body)
if (err) {
debugRequest && console.log(JSON.stringify(err))
}
callback(err, resp, body)
callback(err, null, null)
})
}
@@ -335,19 +389,27 @@ export const http_jsonp = (url, options, callback) => {
if (url.indexOf('?') < 0) url += '?'
url += `&${options.jsonpCallback}=${jsonpCallback}`
options.format = 'script'
options.format = 'text'
debugRequest && console.log(`\n---send request-------${url}------------`)
return fetchData(url, 'get', options, function (err, resp, body) {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(body)
if (err) {
debugRequest && console.log(JSON.stringify(err))
} else {
body = JSON.parse(body.replace(new RegExp(`^${jsonpCallback}\\(({.*})\\)$`), '$1'))
}
callback(err, resp, body)
fetchData(url, 'get', options)
.then((resp) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(resp.body)
try {
const body = JSON.parse(
resp.body.replace(new RegExp(`^${jsonpCallback}\\(({.*})\\)$`), '$1')
)
callback(null, resp, body)
} catch (err) {
callback(err, resp, null)
}
})
.catch((err) => {
debugRequest && console.log(`\n---response------${url}------------`)
debugRequest && console.log(JSON.stringify(err))
callback(err, null, null)
})
}
@@ -358,13 +420,16 @@ export const http_jsonp = (url, options, callback) => {
*/
export const checkUrl = (url, options = {}) => {
return new Promise((resolve, reject) => {
fetchData(url, 'head', options, (err, resp) => {
if (err) return reject(err)
fetchData(url, 'head', options)
.then((resp) => {
if (resp.statusCode === 200) {
resolve()
} else {
reject(new Error(resp.statusCode))
}
})
.catch((err) => {
reject(err)
})
})
}

View File

@@ -1,7 +1,8 @@
import { ElectronAPI } from '@electron-toolkit/preload'
import {MainApi,MethodParams} from '../main/services/musicSdk/index'
import { MainApi, MethodParams } from '../main/services/musicSdk/index'
// 自定义 API 接口
interface CustomAPI {
autoUpdater: any
minimize: () => void
maximize: () => void
close: () => void
@@ -11,11 +12,20 @@ interface CustomAPI {
music: {
request: (api: string, args: any) => Promise<any>
requestSdk:<T extends keyof MainApi>(method: T, args: {
source: any;
} & (MethodParams<T> extends object ? MethodParams<T> : { [key: string]: any })) => ReturnType<MainApi[T]>
requestSdk: <T extends keyof MainApi>(
method: T,
args: {
source: any
} & (MethodParams<T> extends object ? MethodParams<T> : { [key: string]: any })
) => ReturnType<MainApi[T]>
}
musicCache: {
getInfo: () => Promise<any>
clear: () => Promise
getSize: () => Promise<string>
},
ai: {
ask: (prompt: string) => Promise<any>
askStream: (prompt: string, streamId: string) => Promise<any>
@@ -34,7 +44,11 @@ interface CustomAPI {
loadAllPlugins: () => Promise<any>
getPluginLog: (pluginId: string) => Promise<any>
}
ping: (callback: Function<any>) => undefined
pingService: {
start: () => undefined,
stop: () => undefined
}
// 用户配置API
getUserConfig: () => Promise<any>
}

View File

@@ -26,7 +26,8 @@ const api = {
music: {
request: (api: string, args: any) => ipcRenderer.invoke('service-music-request', api, args),
requestSdk:(api: string, args: any) => ipcRenderer.invoke('service-music-sdk-request', api, args)
requestSdk: (api: string, args: any) =>
ipcRenderer.invoke('service-music-sdk-request', api, args)
},
plugins: {
selectAndAddPlugin: (type: 'lx' | 'cr') =>
@@ -60,7 +61,59 @@ const api = {
}
},
getUserConfig: () => ipcRenderer.invoke('get-user-config')
musicCache: {
getInfo: () => ipcRenderer.invoke('music-cache:get-info'),
clear: () => ipcRenderer.invoke('music-cache:clear'),
getSize: () => ipcRenderer.invoke('music-cache:get-size')
},
getUserConfig: () => ipcRenderer.invoke('get-user-config'),
// 自动更新相关
autoUpdater: {
checkForUpdates: () => ipcRenderer.invoke('auto-updater:check-for-updates'),
downloadUpdate: () => ipcRenderer.invoke('auto-updater:download-update'),
quitAndInstall: () => ipcRenderer.invoke('auto-updater:quit-and-install'),
// 监听更新事件
onCheckingForUpdate: (callback: () => void) => {
ipcRenderer.on('auto-updater:checking-for-update', callback);
},
onUpdateAvailable: (callback: () => void) => {
ipcRenderer.on('auto-updater:update-available', callback);
},
onUpdateNotAvailable: (callback: () => void) => {
ipcRenderer.on('auto-updater:update-not-available', callback);
},
onDownloadProgress: (callback: (progress: any) => void) => {
ipcRenderer.on('auto-updater:download-progress', (_, progress) => callback(progress));
},
onUpdateDownloaded: (callback: () => void) => {
ipcRenderer.on('auto-updater:update-downloaded', callback);
},
onError: (callback: (error: string) => void) => {
ipcRenderer.on('auto-updater:error', (_, error) => callback(error));
},
onDownloadStarted: (callback: (updateInfo: any) => void) => {
ipcRenderer.on('auto-updater:download-started', (_, updateInfo) => callback(updateInfo));
},
// 移除所有监听器
removeAllListeners: () => {
ipcRenderer.removeAllListeners('auto-updater:checking-for-update');
ipcRenderer.removeAllListeners('auto-updater:update-available');
ipcRenderer.removeAllListeners('auto-updater:update-not-available');
ipcRenderer.removeAllListeners('auto-updater:download-started');
ipcRenderer.removeAllListeners('auto-updater:download-progress');
ipcRenderer.removeAllListeners('auto-updater:update-downloaded');
ipcRenderer.removeAllListeners('auto-updater:error');
}
},
ping: (callbaack: Function) => ipcRenderer.on('song-ended', () => callbaack()),
pingService: {
start: () => { ipcRenderer.send('startPing'); console.log('eventStart') },
stop: () => { ipcRenderer.send('stopPing') }
}
}
// Use `contextBridge` APIs to expose Electron APIs to

Some files were not shown because too many files have changed in this diff Show More