mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 11:29:42 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44542c4d29 | ||
|
|
2e398b7874 | ||
|
|
d0cd96e1df | ||
|
|
89b085381e | ||
|
|
9830e51fa0 | ||
|
|
400c97fc31 | ||
|
|
c168e42c8d | ||
|
|
e6ea6b11f3 | ||
|
|
046ac4edb6 | ||
|
|
6d14cda0a7 |
63
.github/workflows/main.yml
vendored
Normal file
63
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
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] # 在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: 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: 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
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@ build
|
||||
/download/
|
||||
/plugin/
|
||||
/plugins/
|
||||
temp
|
||||
temp/log.txt
|
||||
|
||||
@@ -2,4 +2,4 @@ singleQuote: true
|
||||
semi: false
|
||||
printWidth: 100
|
||||
trailingComma: none
|
||||
endOfLine: "auto"
|
||||
endOfLine: 'auto'
|
||||
|
||||
14
README.md
14
README.md
@@ -29,25 +29,25 @@ Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器,
|
||||
|
||||
- **IDE**: VS Code 或 WebStorm
|
||||
- **Node.js 版本**: 推荐使用最新稳定版
|
||||
- **包管理器**: pnpm
|
||||
- **包管理器**: yarn
|
||||
|
||||
### 项目设置
|
||||
|
||||
1. 安装依赖:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
yarn install
|
||||
```
|
||||
|
||||
2. 启动开发服务器:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
yarn dev
|
||||
```
|
||||
|
||||
3. 构建应用:
|
||||
```bash
|
||||
pnpm build
|
||||
yarn build
|
||||
```
|
||||
|
||||
### 平台构建指令
|
||||
@@ -55,18 +55,18 @@ Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器,
|
||||
- **Windows**:
|
||||
|
||||
```bash
|
||||
pnpm build:win
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
- **macOS**:
|
||||
|
||||
```bash
|
||||
pnpm build:mac
|
||||
yarn build:mac
|
||||
```
|
||||
|
||||
- **Linux**:
|
||||
```bash
|
||||
pnpm build:linux
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## 文档与资源
|
||||
|
||||
@@ -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, {
|
||||
allowBoolean: true,
|
||||
allowAny: true,
|
||||
}],
|
||||
'@typescript-eslint/restrict-plus-operands': [1, {
|
||||
allowBoolean: true,
|
||||
allowAny: true,
|
||||
}],
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
1,
|
||||
{
|
||||
allowBoolean: true,
|
||||
allowAny: true
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/restrict-plus-operands': [
|
||||
1,
|
||||
{
|
||||
allowBoolean: 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',
|
||||
ts: '@typescript-eslint/parser'
|
||||
},
|
||||
extraFileExtensions: ['.vue'],
|
||||
},
|
||||
extraFileExtensions: ['.vue']
|
||||
}
|
||||
}
|
||||
|
||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ceru-music",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.9",
|
||||
"description": "一款简洁优雅的音乐播放器",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "sqj,wldss,star",
|
||||
@@ -11,17 +11,17 @@
|
||||
"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": "pnpm run typecheck:node && pnpm run typecheck:web",
|
||||
"typecheck": "yarn run typecheck:node && yarn run typecheck:web",
|
||||
"start": "electron-vite preview",
|
||||
"dev": "electron-vite dev --watch",
|
||||
"build": "pnpm 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": "pnpm run build && electron-builder --dir",
|
||||
"build:win": "pnpm run build && electron-builder --win --x64 --config",
|
||||
"build:mac": "pnpm run build && electron-builder --mac",
|
||||
"build:linux": "pnpm run build && electron-builder --linux",
|
||||
"build:deps": "electron-builder install-app-deps && pnpm run build && electron-builder --win --x64 --config",
|
||||
"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 --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"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -48,9 +48,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
@@ -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.
|
||||
@@ -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]
|
||||
@@ -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 音乐插件] 请求失败: 歌曲不存在"
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
};
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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, // 歌曲ID,local为文件路径
|
||||
|
||||
33
src/main/events/musicCache.ts
Normal file
33
src/main/events/musicCache.ts
Normal 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
|
||||
}
|
||||
})
|
||||
@@ -190,8 +190,8 @@ ipcMain.handle('service-music-request', async (_, api, args) => {
|
||||
return await musicService.request(api, args)
|
||||
})
|
||||
|
||||
|
||||
aiEvents(mainWindow)
|
||||
import './events/musicCache'
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
|
||||
@@ -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}`)
|
||||
}
|
||||
|
||||
189
src/main/services/musicCache/index.ts
Normal file
189
src/main/services/musicCache/index.ts
Normal 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()
|
||||
@@ -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;
|
||||
if (!source) throw new Error('请配置音源')
|
||||
const Api = main(source);
|
||||
if (Api.hasOwnProperty(method)) {
|
||||
return (Api[method] as (args: any) => any)(args);
|
||||
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)
|
||||
if (Api.hasOwnProperty(method)) {
|
||||
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)
|
||||
ipcMain.handle('service-music-sdk-request', request)
|
||||
|
||||
@@ -1,27 +1,64 @@
|
||||
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)
|
||||
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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getPic({songInfo}: GetMusicPicArg) {
|
||||
|
||||
async getPic({ songInfo }: GetMusicPicArg) {
|
||||
try {
|
||||
return await Api.getPic(songInfo)
|
||||
} catch (e: any) {
|
||||
@@ -29,7 +66,102 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default main
|
||||
export default main
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
export interface sdkArg {
|
||||
source: string
|
||||
[key:string]: any
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface SearchSongArg {
|
||||
keyword: string
|
||||
page: number
|
||||
limit: number
|
||||
}
|
||||
// 可以添加到 src/main/services/music/service-base.ts 文件中
|
||||
}
|
||||
|
||||
// 单首歌曲的类型定义
|
||||
export interface MusicItem {
|
||||
@@ -48,4 +47,49 @@ 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
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const pluginService = {
|
||||
}
|
||||
},
|
||||
|
||||
getPluginById(pluginId: string): CeruMusicPluginHost | null{
|
||||
getPluginById(pluginId: string): CeruMusicPluginHost | null {
|
||||
if (!Object.hasOwn(loadedPlugins, pluginId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -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> = {}
|
||||
@@ -80,7 +80,7 @@ class Logger {
|
||||
error(...args: any[]): void {
|
||||
this.write(`error ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
|
||||
group(...args: any[]): void {
|
||||
args.unshift('groupStart---------')
|
||||
this.write(`start ${parseArgs(args)}\n`)
|
||||
@@ -88,20 +88,22 @@ class Logger {
|
||||
groupEnd(...args: any[]): void {
|
||||
this.write(`end ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
|
||||
private write(msg: string): void {
|
||||
writeLog(this.logFilePath, msg, WriteMode.APPEND).then()
|
||||
}
|
||||
}
|
||||
|
||||
function parseArgs(args){
|
||||
return args.map(arg=>{
|
||||
if(typeof arg==='object'){
|
||||
return JSON.stringify(arg)
|
||||
}
|
||||
function parseArgs(args) {
|
||||
return args
|
||||
.map((arg) => {
|
||||
if (typeof arg === 'object') {
|
||||
return JSON.stringify(arg)
|
||||
}
|
||||
|
||||
return arg
|
||||
}).join(' ')
|
||||
return arg
|
||||
})
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
async function getLog(pluginId: string) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`))
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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('')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
debugRequest && console.log(`\n---send request------${url}------------`)
|
||||
fetchData(url, options.method, options, (err, resp, body) => {
|
||||
|
||||
obj.promise = new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
debugRequest && console.log(`\n---send request------${url}------------`)
|
||||
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 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,14 +303,18 @@ 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) => {
|
||||
debugRequest && console.log(`\n---response------${url}------------`)
|
||||
debugRequest && console.log(body)
|
||||
if (err) {
|
||||
|
||||
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(JSON.stringify(err))
|
||||
}
|
||||
cb(err, resp, body)
|
||||
})
|
||||
cb(err, null, null)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,14 +330,18 @@ export const httpGet = (url, options, callback) => {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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(JSON.stringify(err))
|
||||
}
|
||||
callback(err, resp, body)
|
||||
})
|
||||
callback(err, null, null)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,14 +359,18 @@ 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) {
|
||||
debugRequest && console.log(`\n---response------${url}------------`)
|
||||
debugRequest && console.log(body)
|
||||
if (err) {
|
||||
|
||||
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(JSON.stringify(err))
|
||||
}
|
||||
callback(err, resp, body)
|
||||
})
|
||||
callback(err, null, null)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,20 +389,28 @@ 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)
|
||||
if (resp.statusCode === 200) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(resp.statusCode))
|
||||
}
|
||||
})
|
||||
fetchData(url, 'head', options)
|
||||
.then((resp) => {
|
||||
if (resp.statusCode === 200) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(resp.statusCode))
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
17
src/preload/index.d.ts
vendored
17
src/preload/index.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
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 {
|
||||
minimize: () => void
|
||||
@@ -11,11 +11,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>
|
||||
|
||||
@@ -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,6 +61,12 @@ const api = {
|
||||
}
|
||||
},
|
||||
|
||||
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')
|
||||
}
|
||||
|
||||
|
||||
5
src/renderer/components.d.ts
vendored
5
src/renderer/components.d.ts
vendored
@@ -11,6 +11,7 @@ declare module 'vue' {
|
||||
FloatBall: typeof import('./src/components/AI/FloatBall.vue')['default']
|
||||
FullPlay: typeof import('./src/components/Play/FullPlay.vue')['default']
|
||||
GlobalAudio: typeof import('./src/components/Play/GlobalAudio.vue')['default']
|
||||
MusicCache: typeof import('./src/components/Settings/MusicCache.vue')['default']
|
||||
PlaylistActions: typeof import('./src/components/Play/PlaylistActions.vue')['default']
|
||||
PlaylistSettings: typeof import('./src/components/Settings/PlaylistSettings.vue')['default']
|
||||
PlayMusic: typeof import('./src/components/Play/PlayMusic.vue')['default']
|
||||
@@ -18,11 +19,15 @@ declare module 'vue' {
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SearchComponent: typeof import('./src/components/Search/SearchComponent.vue')['default']
|
||||
ShaderBackground: typeof import('./src/components/Play/ShaderBackground.vue')['default']
|
||||
SongVirtualList: typeof import('./src/components/Music/SongVirtualList.vue')['default']
|
||||
TAlert: typeof import('tdesign-vue-next')['Alert']
|
||||
TAside: typeof import('tdesign-vue-next')['Aside']
|
||||
TButton: typeof import('tdesign-vue-next')['Button']
|
||||
TCard: typeof import('tdesign-vue-next')['Card']
|
||||
TContent: typeof import('tdesign-vue-next')['Content']
|
||||
TDialog: typeof import('tdesign-vue-next')['Dialog']
|
||||
ThemeDemo: typeof import('./src/components/ThemeDemo.vue')['default']
|
||||
ThemeSelector: typeof import('./src/components/ThemeSelector.vue')['default']
|
||||
TIcon: typeof import('tdesign-vue-next')['Icon']
|
||||
TImage: typeof import('tdesign-vue-next')['Image']
|
||||
TInput: typeof import('tdesign-vue-next')['Input']
|
||||
|
||||
@@ -4,11 +4,47 @@ import GlobalAudio from './components/Play/GlobalAudio.vue'
|
||||
import FloatBall from './components/AI/FloatBall.vue'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
const userInfo = LocalUserDetailStore()
|
||||
|
||||
import './assets/main.css'
|
||||
import './assets/theme/blue.css'
|
||||
import './assets/theme/pink.css'
|
||||
import './assets/theme/orange.css'
|
||||
import './assets/theme/cyan.css'
|
||||
onMounted(() => {
|
||||
userInfo.init()
|
||||
// 设置测试音频URL
|
||||
loadSavedTheme()
|
||||
})
|
||||
|
||||
// 基于现有主题文件的配置
|
||||
const themes = [
|
||||
{ name: 'default', label: '默认', color: '#2ba55b' },
|
||||
{ name: 'pink', label: '粉色', color: '#fc5e7e' },
|
||||
{ name: 'blue', label: '蓝色', color: '#57b4ff' },
|
||||
{ name: 'cyan', label: '青色', color: '#3ac2b8' },
|
||||
{ name: 'orange', label: '橙色', color: '#fb9458' }
|
||||
]
|
||||
|
||||
const loadSavedTheme = () => {
|
||||
const savedTheme = localStorage.getItem('selected-theme')
|
||||
if (savedTheme && themes.some(t => t.name === savedTheme)) {
|
||||
applyTheme(savedTheme)
|
||||
}
|
||||
}
|
||||
|
||||
const applyTheme = (themeName) => {
|
||||
const documentElement = document.documentElement
|
||||
|
||||
// 移除之前的主题
|
||||
documentElement.removeAttribute('theme-mode')
|
||||
|
||||
// 应用新主题(如果不是默认主题)
|
||||
if (themeName !== 'default') {
|
||||
documentElement.setAttribute('theme-mode', themeName)
|
||||
}
|
||||
|
||||
// 保存到本地存储
|
||||
localStorage.setItem('selected-theme', themeName)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
|
||||
:root,
|
||||
:root[theme-mode='light'] {
|
||||
--td-brand-color-1: #e2fae2;
|
||||
--td-brand-color-2: #c5f4cb;
|
||||
--td-brand-color-3: #91dca1;
|
||||
--td-brand-color-4: #55c277;
|
||||
--td-brand-color-5: #2ba55b;
|
||||
--td-brand-color-6: #008942;
|
||||
--td-brand-color-7: #006d33;
|
||||
--td-brand-color-8: #005426;
|
||||
--td-brand-color-9: #003c19;
|
||||
--td-brand-color-10: #00260d;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-3);
|
||||
--td-brand-color: var(--td-brand-color-4);
|
||||
--td-brand-color-active: var(--td-brand-color-5);
|
||||
--td-warning-color-1: #fef3e6;
|
||||
--td-warning-color-2: #f9e0c7;
|
||||
--td-warning-color-3: #f7c797;
|
||||
--td-warning-color-4: #f2995f;
|
||||
--td-warning-color-5: #ed7b2f;
|
||||
--td-warning-color-6: #d35a21;
|
||||
--td-warning-color-7: #ba431b;
|
||||
--td-warning-color-8: #9e3610;
|
||||
--td-warning-color-9: #842b0b;
|
||||
--td-warning-color-10: #5a1907;
|
||||
--td-warning-color: var(--td-warning-color-5);
|
||||
--td-warning-color-hover: var(--td-warning-color-4);
|
||||
--td-warning-color-focus: var(--td-warning-color-2);
|
||||
--td-warning-color-active: var(--td-warning-color-6);
|
||||
--td-warning-color-disabled: var(--td-warning-color-3);
|
||||
--td-warning-color-light: var(--td-warning-color-1);
|
||||
--td-error-color-1: #fdecee;
|
||||
--td-error-color-2: #f9d7d9;
|
||||
--td-error-color-3: #f8b9be;
|
||||
--td-error-color-4: #f78d94;
|
||||
--td-error-color-5: #f36d78;
|
||||
--td-error-color-6: #e34d59;
|
||||
--td-error-color-7: #c9353f;
|
||||
--td-error-color-8: #b11f26;
|
||||
--td-error-color-9: #951114;
|
||||
--td-error-color-10: #680506;
|
||||
--td-error-color: var(--td-error-color-6);
|
||||
--td-error-color-hover: var(--td-error-color-5);
|
||||
--td-error-color-focus: var(--td-error-color-2);
|
||||
--td-error-color-active: var(--td-error-color-7);
|
||||
--td-error-color-disabled: var(--td-error-color-3);
|
||||
--td-error-color-light: var(--td-error-color-1);
|
||||
--td-success-color-1: #e8f8f2;
|
||||
--td-success-color-2: #bcebdc;
|
||||
--td-success-color-3: #85dbbe;
|
||||
--td-success-color-4: #48c79c;
|
||||
--td-success-color-5: #00a870;
|
||||
--td-success-color-6: #078d5c;
|
||||
--td-success-color-7: #067945;
|
||||
--td-success-color-8: #056334;
|
||||
--td-success-color-9: #044f2a;
|
||||
--td-success-color-10: #033017;
|
||||
--td-success-color: var(--td-success-color-5);
|
||||
--td-success-color-hover: var(--td-success-color-4);
|
||||
--td-success-color-focus: var(--td-success-color-2);
|
||||
--td-success-color-active: var(--td-success-color-6);
|
||||
--td-success-color-disabled: var(--td-success-color-3);
|
||||
--td-success-color-light: var(--td-success-color-1);
|
||||
--td-gray-color-1: #f0f4f1;
|
||||
--td-gray-color-2: #e9efeb;
|
||||
--td-gray-color-3: #e1eae4;
|
||||
--td-gray-color-4: #d4dfd8;
|
||||
--td-gray-color-5: #bdc8c1;
|
||||
--td-gray-color-6: #9ca8a1;
|
||||
--td-gray-color-7: #808d86;
|
||||
--td-gray-color-8: #6d7873;
|
||||
--td-gray-color-9: #565f5b;
|
||||
--td-gray-color-10: #454c48;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-container: #fff;
|
||||
--td-bg-color-container-select: #fff;
|
||||
--td-bg-color-page: var(--td-gray-color-2);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-1);
|
||||
--td-bg-color-container-active: var(--td-gray-color-3);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-1);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-2);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-4);
|
||||
--td-bg-color-component: var(--td-gray-color-3);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-4);
|
||||
--td-bg-color-component-active: var(--td-gray-color-6);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-2);
|
||||
--td-component-stroke: var(--td-gray-color-3);
|
||||
--td-component-border: var(--td-gray-color-4);
|
||||
--td-font-white-1: #ffffff;
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-gray-1);
|
||||
--td-text-color-secondary: var(--td-font-gray-2);
|
||||
--td-text-color-placeholder: var(--td-font-gray-3);
|
||||
--td-text-color-disabled: var(--td-font-gray-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-brand-color-light-hover: var(--td-brand-color-2);
|
||||
--td-warning-color-light-hover: var(--td-warning-color-2);
|
||||
--td-error-color-light-hover: var(--td-error-color-2);
|
||||
--td-success-color-light-hover: var(--td-success-color-2);
|
||||
--td-bg-color-secondarycomponent: var(--td-gray-color-4);
|
||||
--td-bg-color-secondarycomponent-hover: var(--td-gray-color-5);
|
||||
--td-bg-color-secondarycomponent-active: var(--td-gray-color-6);
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 8%);
|
||||
--td-scrollbar-color: rgba(0, 0, 0, 10%);
|
||||
--td-scrollbar-hover-color: rgba(0, 0, 0, 30%);
|
||||
--td-scroll-track-color: #fff;
|
||||
--td-bg-color-specialcomponent: #fff;
|
||||
--td-border-level-1-color: var(--td-gray-color-3);
|
||||
--td-border-level-2-color: var(--td-gray-color-4);
|
||||
--td-shadow-1:
|
||||
0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
--td-shadow-2:
|
||||
0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%),
|
||||
0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
--td-shadow-3:
|
||||
0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%),
|
||||
0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
|
||||
--td-mask-active: rgba(0, 0, 0, 0.6);
|
||||
--td-mask-disabled: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
:root[theme-mode='dark'] {
|
||||
--td-brand-color-1: #2ba55b20;
|
||||
--td-brand-color-2: #003c19;
|
||||
--td-brand-color-3: #005426;
|
||||
--td-brand-color-4: #006d33;
|
||||
--td-brand-color-5: #008942;
|
||||
--td-brand-color-6: #2ba55b;
|
||||
--td-brand-color-7: #4cd47c;
|
||||
--td-brand-color-8: #91dca1;
|
||||
--td-brand-color-9: #c5f4cb;
|
||||
--td-brand-color-10: #e2fae2;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-5);
|
||||
--td-brand-color: var(--td-brand-color-6);
|
||||
--td-brand-color-active: var(--td-brand-color-7);
|
||||
--td-warning-color-1: #4f2a1d;
|
||||
--td-warning-color-2: #582f21;
|
||||
--td-warning-color-3: #733c23;
|
||||
--td-warning-color-4: #a75d2b;
|
||||
--td-warning-color-5: #cf6e2d;
|
||||
--td-warning-color-6: #dc7633;
|
||||
--td-warning-color-7: #e8935c;
|
||||
--td-warning-color-8: #ecbf91;
|
||||
--td-warning-color-9: #eed7bf;
|
||||
--td-warning-color-10: #f3e9dc;
|
||||
--td-error-color-1: #472324;
|
||||
--td-error-color-2: #5e2a2d;
|
||||
--td-error-color-3: #703439;
|
||||
--td-error-color-4: #83383e;
|
||||
--td-error-color-5: #a03f46;
|
||||
--td-error-color-6: #c64751;
|
||||
--td-error-color-7: #de6670;
|
||||
--td-error-color-8: #ec888e;
|
||||
--td-error-color-9: #edb1b6;
|
||||
--td-error-color-10: #eeced0;
|
||||
--td-success-color-1: #193a2a;
|
||||
--td-success-color-2: #1a4230;
|
||||
--td-success-color-3: #17533d;
|
||||
--td-success-color-4: #0d7a55;
|
||||
--td-success-color-5: #059465;
|
||||
--td-success-color-6: #43af8a;
|
||||
--td-success-color-7: #46bf96;
|
||||
--td-success-color-8: #80d2b6;
|
||||
--td-success-color-9: #b4e1d3;
|
||||
--td-success-color-10: #deede8;
|
||||
--td-gray-color-1: #f0f4f1;
|
||||
--td-gray-color-2: #e9efeb;
|
||||
--td-gray-color-3: #e1eae4;
|
||||
--td-gray-color-4: #d4dfd8;
|
||||
--td-gray-color-5: #bdc8c1;
|
||||
--td-gray-color-6: #9ca8a1;
|
||||
--td-gray-color-7: #808d86;
|
||||
--td-gray-color-8: #6d7873;
|
||||
--td-gray-color-9: #565f5b;
|
||||
--td-gray-color-10: #454c48;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-page: var(--td-gray-color-14);
|
||||
--td-bg-color-container: var(--td-gray-color-13);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-12);
|
||||
--td-bg-color-container-active: var(--td-gray-color-10);
|
||||
--td-bg-color-container-select: var(--td-gray-color-9);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-12);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-11);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component: var(--td-gray-color-11);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-10);
|
||||
--td-bg-color-component-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-12);
|
||||
--td-component-stroke: var(--td-gray-color-11);
|
||||
--td-component-border: var(--td-gray-color-9);
|
||||
--td-font-white-1: rgba(255, 255, 255, 0.9);
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-white-1);
|
||||
--td-text-color-secondary: var(--td-font-white-2);
|
||||
--td-text-color-placeholder: var(--td-font-white-3);
|
||||
--td-text-color-disabled: var(--td-font-white-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-shadow-1:
|
||||
0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
--td-shadow-2:
|
||||
0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.1), 0 5px 5px rgba(0, 0, 0, 0.16);
|
||||
--td-shadow-3:
|
||||
0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.2);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #5e5e5e;
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 55%);
|
||||
--td-scrollbar-color: rgba(255, 255, 255, 10%);
|
||||
--td-scrollbar-hover-color: rgba(255, 255, 255, 30%);
|
||||
--td-scroll-track-color: #333;
|
||||
--td-bg-color-specialcomponent: transparent;
|
||||
--td-border-level-1-color: var(--td-gray-color-11);
|
||||
--td-border-level-2-color: var(--td-gray-color-9);
|
||||
--td-mask-active: rgba(0, 0, 0, 0.4);
|
||||
--td-mask-disabled: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
:root {
|
||||
--td-font-family: pingfang sc, microsoft yahei, arial regular;
|
||||
--td-font-family-medium: pingfang sc, microsoft yahei, arial medium;
|
||||
--td-font-size-link-small: 12px;
|
||||
--td-font-size-link-medium: 14px;
|
||||
--td-font-size-link-large: 16px;
|
||||
--td-font-size-mark-small: 12px;
|
||||
--td-font-size-mark-medium: 14px;
|
||||
--td-font-size-body-small: 12px;
|
||||
--td-font-size-body-medium: 14px;
|
||||
--td-font-size-body-large: 16px;
|
||||
--td-font-size-title-small: 14px;
|
||||
--td-font-size-title-medium: 16px;
|
||||
--td-font-size-title-large: 20px;
|
||||
--td-font-size-headline-small: 24px;
|
||||
--td-font-size-headline-medium: 28px;
|
||||
--td-font-size-headline-large: 36px;
|
||||
--td-font-size-display-medium: 48px;
|
||||
--td-font-size-display-large: 64px;
|
||||
--td-line-height-link-small: 20px;
|
||||
--td-line-height-link-medium: 22px;
|
||||
--td-line-height-link-large: 24px;
|
||||
--td-line-height-mark-small: 20px;
|
||||
--td-line-height-mark-medium: 22px;
|
||||
--td-line-height-body-small: 20px;
|
||||
--td-line-height-body-medium: 22px;
|
||||
--td-line-height-body-large: 24px;
|
||||
--td-line-height-title-small: 22px;
|
||||
--td-line-height-title-medium: 24px;
|
||||
--td-line-height-title-large: 28px;
|
||||
--td-line-height-headline-small: 32px;
|
||||
--td-line-height-headline-medium: 36px;
|
||||
--td-line-height-headline-large: 44px;
|
||||
--td-line-height-display-medium: 56px;
|
||||
--td-line-height-display-large: 72px;
|
||||
--td-font-link-small: var(--td-font-size-link-small) / var(--td-line-height-link-small)
|
||||
var(--td-font-family);
|
||||
--td-font-link-medium: var(--td-font-size-link-medium) / var(--td-line-height-link-medium)
|
||||
var(--td-font-family);
|
||||
--td-font-link-large: var(--td-font-size-link-large) / var(--td-line-height-link-large)
|
||||
var(--td-font-family);
|
||||
--td-font-mark-small: 600 var(--td-font-size-mark-small) / var(--td-line-height-mark-small)
|
||||
var(--td-font-family);
|
||||
--td-font-mark-medium: 600 var(--td-font-size-mark-medium) / var(--td-line-height-mark-medium)
|
||||
var(--td-font-family);
|
||||
--td-font-body-small: var(--td-font-size-body-small) / var(--td-line-height-body-small)
|
||||
var(--td-font-family);
|
||||
--td-font-body-medium: var(--td-font-size-body-medium) / var(--td-line-height-body-medium)
|
||||
var(--td-font-family);
|
||||
--td-font-body-large: var(--td-font-size-body-large) / var(--td-line-height-body-large)
|
||||
var(--td-font-family);
|
||||
--td-font-title-small: 600 var(--td-font-size-title-small) / var(--td-line-height-title-small)
|
||||
var(--td-font-family);
|
||||
--td-font-title-medium: 600 var(--td-font-size-title-medium) / var(--td-line-height-title-medium)
|
||||
var(--td-font-family);
|
||||
--td-font-title-large: 600 var(--td-font-size-title-large) / var(--td-line-height-title-large)
|
||||
var(--td-font-family);
|
||||
--td-font-headline-small: 600 var(--td-font-size-headline-small) /
|
||||
var(--td-line-height-headline-small) var(--td-font-family);
|
||||
--td-font-headline-medium: 600 var(--td-font-size-headline-medium) /
|
||||
var(--td-line-height-headline-medium) var(--td-font-family);
|
||||
--td-font-headline-large: 600 var(--td-font-size-headline-large) /
|
||||
var(--td-line-height-headline-large) var(--td-font-family);
|
||||
--td-font-display-medium: 600 var(--td-font-size-display-medium) /
|
||||
var(--td-line-height-display-medium) var(--td-font-family);
|
||||
--td-font-display-large: 600 var(--td-font-size-display-large) /
|
||||
var(--td-line-height-display-large) var(--td-font-family);
|
||||
--td-radius-small: 2px;
|
||||
--td-radius-default: 3px;
|
||||
--td-radius-medium: 6px;
|
||||
--td-radius-large: 9px;
|
||||
--td-radius-extraLarge: 12px;
|
||||
--td-radius-round: 999px;
|
||||
--td-radius-circle: 50%;
|
||||
--td-size-1: 2px;
|
||||
--td-size-2: 4px;
|
||||
--td-size-3: 6px;
|
||||
--td-size-4: 8px;
|
||||
--td-size-5: 12px;
|
||||
--td-size-6: 16px;
|
||||
--td-size-7: 20px;
|
||||
--td-size-8: 24px;
|
||||
--td-size-9: 28px;
|
||||
--td-size-10: 32px;
|
||||
--td-size-11: 36px;
|
||||
--td-size-12: 40px;
|
||||
--td-size-13: 48px;
|
||||
--td-size-14: 56px;
|
||||
--td-size-15: 64px;
|
||||
--td-size-16: 72px;
|
||||
--td-comp-size-xxxs: var(--td-size-6);
|
||||
--td-comp-size-xxs: var(--td-size-7);
|
||||
--td-comp-size-xs: var(--td-size-8);
|
||||
--td-comp-size-s: var(--td-size-9);
|
||||
--td-comp-size-m: var(--td-size-10);
|
||||
--td-comp-size-l: var(--td-size-11);
|
||||
--td-comp-size-xl: var(--td-size-12);
|
||||
--td-comp-size-xxl: var(--td-size-13);
|
||||
--td-comp-size-xxxl: var(--td-size-14);
|
||||
--td-comp-size-xxxxl: var(--td-size-15);
|
||||
--td-comp-size-xxxxxl: var(--td-size-16);
|
||||
--td-pop-padding-s: var(--td-size-2);
|
||||
--td-pop-padding-m: var(--td-size-3);
|
||||
--td-pop-padding-l: var(--td-size-4);
|
||||
--td-pop-padding-xl: var(--td-size-5);
|
||||
--td-pop-padding-xxl: var(--td-size-6);
|
||||
--td-comp-paddingLR-xxs: var(--td-size-1);
|
||||
--td-comp-paddingLR-xs: var(--td-size-2);
|
||||
--td-comp-paddingLR-s: var(--td-size-4);
|
||||
--td-comp-paddingLR-m: var(--td-size-5);
|
||||
--td-comp-paddingLR-l: var(--td-size-6);
|
||||
--td-comp-paddingLR-xl: var(--td-size-8);
|
||||
--td-comp-paddingLR-xxl: var(--td-size-10);
|
||||
--td-comp-paddingTB-xxs: var(--td-size-1);
|
||||
--td-comp-paddingTB-xs: var(--td-size-2);
|
||||
--td-comp-paddingTB-s: var(--td-size-4);
|
||||
--td-comp-paddingTB-m: var(--td-size-5);
|
||||
--td-comp-paddingTB-l: var(--td-size-6);
|
||||
--td-comp-paddingTB-xl: var(--td-size-8);
|
||||
--td-comp-paddingTB-xxl: var(--td-size-10);
|
||||
--td-comp-margin-xxs: var(--td-size-1);
|
||||
--td-comp-margin-xs: var(--td-size-2);
|
||||
--td-comp-margin-s: var(--td-size-4);
|
||||
--td-comp-margin-m: var(--td-size-5);
|
||||
--td-comp-margin-l: var(--td-size-6);
|
||||
--td-comp-margin-xl: var(--td-size-7);
|
||||
--td-comp-margin-xxl: var(--td-size-8);
|
||||
--td-comp-margin-xxxl: var(--td-size-10);
|
||||
--td-comp-margin-xxxxl: var(--td-size-12);
|
||||
}
|
||||
|
||||
355
src/renderer/src/assets/theme/blue.css
Normal file
355
src/renderer/src/assets/theme/blue.css
Normal file
@@ -0,0 +1,355 @@
|
||||
:root[theme-mode="blue"] {
|
||||
--td-brand-color-1: #ecf4ff;
|
||||
--td-brand-color-2: #cde5ff;
|
||||
--td-brand-color-3: #9aceff;
|
||||
--td-brand-color-4: #57b4ff;
|
||||
--td-brand-color-5: #3198e2;
|
||||
--td-brand-color-6: #007dc5;
|
||||
--td-brand-color-7: #00629c;
|
||||
--td-brand-color-8: #004a77;
|
||||
--td-brand-color-9: #003355;
|
||||
--td-brand-color-10: #00213a;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-3);
|
||||
--td-brand-color: var(--td-brand-color-4);
|
||||
--td-brand-color-active: var(--td-brand-color-5);
|
||||
--td-warning-color-1: #fef3e6;
|
||||
--td-warning-color-2: #f9e0c7;
|
||||
--td-warning-color-3: #f7c797;
|
||||
--td-warning-color-4: #f2995f;
|
||||
--td-warning-color-5: #ed7b2f;
|
||||
--td-warning-color-6: #d35a21;
|
||||
--td-warning-color-7: #ba431b;
|
||||
--td-warning-color-8: #9e3610;
|
||||
--td-warning-color-9: #842b0b;
|
||||
--td-warning-color-10: #5a1907;
|
||||
--td-warning-color: var(--td-warning-color-5);
|
||||
--td-warning-color-hover: var(--td-warning-color-4);
|
||||
--td-warning-color-focus: var(--td-warning-color-2);
|
||||
--td-warning-color-active: var(--td-warning-color-6);
|
||||
--td-warning-color-disabled: var(--td-warning-color-3);
|
||||
--td-warning-color-light: var(--td-warning-color-1);
|
||||
--td-error-color-1: #fdecee;
|
||||
--td-error-color-2: #f9d7d9;
|
||||
--td-error-color-3: #f8b9be;
|
||||
--td-error-color-4: #f78d94;
|
||||
--td-error-color-5: #f36d78;
|
||||
--td-error-color-6: #e34d59;
|
||||
--td-error-color-7: #c9353f;
|
||||
--td-error-color-8: #b11f26;
|
||||
--td-error-color-9: #951114;
|
||||
--td-error-color-10: #680506;
|
||||
--td-error-color: var(--td-error-color-6);
|
||||
--td-error-color-hover: var(--td-error-color-5);
|
||||
--td-error-color-focus: var(--td-error-color-2);
|
||||
--td-error-color-active: var(--td-error-color-7);
|
||||
--td-error-color-disabled: var(--td-error-color-3);
|
||||
--td-error-color-light: var(--td-error-color-1);
|
||||
--td-success-color-1: #e8f8f2;
|
||||
--td-success-color-2: #bcebdc;
|
||||
--td-success-color-3: #85dbbe;
|
||||
--td-success-color-4: #48c79c;
|
||||
--td-success-color-5: #00a870;
|
||||
--td-success-color-6: #078d5c;
|
||||
--td-success-color-7: #067945;
|
||||
--td-success-color-8: #056334;
|
||||
--td-success-color-9: #044f2a;
|
||||
--td-success-color-10: #033017;
|
||||
--td-success-color: var(--td-success-color-5);
|
||||
--td-success-color-hover: var(--td-success-color-4);
|
||||
--td-success-color-focus: var(--td-success-color-2);
|
||||
--td-success-color-active: var(--td-success-color-6);
|
||||
--td-success-color-disabled: var(--td-success-color-3);
|
||||
--td-success-color-light: var(--td-success-color-1);
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-container: #fff;
|
||||
--td-bg-color-container-select: #fff;
|
||||
--td-bg-color-page: var(--td-gray-color-2);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-1);
|
||||
--td-bg-color-container-active: var(--td-gray-color-3);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-1);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-2);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-4);
|
||||
--td-bg-color-component: var(--td-gray-color-3);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-4);
|
||||
--td-bg-color-component-active: var(--td-gray-color-6);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-2);
|
||||
--td-component-stroke: var(--td-gray-color-3);
|
||||
--td-component-border: var(--td-gray-color-4);
|
||||
--td-font-white-1: #ffffff;
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-gray-1);
|
||||
--td-text-color-secondary: var(--td-font-gray-2);
|
||||
--td-text-color-placeholder: var(--td-font-gray-3);
|
||||
--td-text-color-disabled: var(--td-font-gray-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-brand-color-light-hover: var(--td-brand-color-2);
|
||||
--td-warning-color-light-hover: var(--td-warning-color-2);
|
||||
--td-error-color-light-hover: var(--td-error-color-2);
|
||||
--td-success-color-light-hover: var(--td-success-color-2);
|
||||
--td-bg-color-secondarycomponent: var(--td-gray-color-4);
|
||||
--td-bg-color-secondarycomponent-hover: var(--td-gray-color-5);
|
||||
--td-bg-color-secondarycomponent-active: var(--td-gray-color-6);
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 8%);
|
||||
--td-scrollbar-color: rgba(0, 0, 0, 10%);
|
||||
--td-scrollbar-hover-color: rgba(0, 0, 0, 30%);
|
||||
--td-scroll-track-color: #fff;
|
||||
--td-bg-color-specialcomponent: #fff;
|
||||
--td-border-level-1-color: var(--td-gray-color-3);
|
||||
--td-border-level-2-color: var(--td-gray-color-4);
|
||||
--td-shadow-1: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
--td-shadow-2: 0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
--td-shadow-3: 0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
|
||||
--td-mask-active: rgba(0, 0, 0, 0.6);
|
||||
--td-mask-disabled: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
:root[theme-mode="dark"] {
|
||||
--td-brand-color-1: #3198e220;
|
||||
--td-brand-color-2: #003355;
|
||||
--td-brand-color-3: #004a77;
|
||||
--td-brand-color-4: #00629c;
|
||||
--td-brand-color-5: #007dc5;
|
||||
--td-brand-color-6: #3198e2;
|
||||
--td-brand-color-7: #53b1fd;
|
||||
--td-brand-color-8: #9aceff;
|
||||
--td-brand-color-9: #cde5ff;
|
||||
--td-brand-color-10: #ecf4ff;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-5);
|
||||
--td-brand-color: var(--td-brand-color-6);
|
||||
--td-brand-color-active: var(--td-brand-color-7);
|
||||
--td-warning-color-1: #4f2a1d;
|
||||
--td-warning-color-2: #582f21;
|
||||
--td-warning-color-3: #733c23;
|
||||
--td-warning-color-4: #a75d2b;
|
||||
--td-warning-color-5: #cf6e2d;
|
||||
--td-warning-color-6: #dc7633;
|
||||
--td-warning-color-7: #e8935c;
|
||||
--td-warning-color-8: #ecbf91;
|
||||
--td-warning-color-9: #eed7bf;
|
||||
--td-warning-color-10: #f3e9dc;
|
||||
--td-error-color-1: #472324;
|
||||
--td-error-color-2: #5e2a2d;
|
||||
--td-error-color-3: #703439;
|
||||
--td-error-color-4: #83383e;
|
||||
--td-error-color-5: #a03f46;
|
||||
--td-error-color-6: #c64751;
|
||||
--td-error-color-7: #de6670;
|
||||
--td-error-color-8: #ec888e;
|
||||
--td-error-color-9: #edb1b6;
|
||||
--td-error-color-10: #eeced0;
|
||||
--td-success-color-1: #193a2a;
|
||||
--td-success-color-2: #1a4230;
|
||||
--td-success-color-3: #17533d;
|
||||
--td-success-color-4: #0d7a55;
|
||||
--td-success-color-5: #059465;
|
||||
--td-success-color-6: #43af8a;
|
||||
--td-success-color-7: #46bf96;
|
||||
--td-success-color-8: #80d2b6;
|
||||
--td-success-color-9: #b4e1d3;
|
||||
--td-success-color-10: #deede8;
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-page: var(--td-gray-color-14);
|
||||
--td-bg-color-container: var(--td-gray-color-13);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-12);
|
||||
--td-bg-color-container-active: var(--td-gray-color-10);
|
||||
--td-bg-color-container-select: var(--td-gray-color-9);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-12);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-11);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component: var(--td-gray-color-11);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-10);
|
||||
--td-bg-color-component-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-12);
|
||||
--td-component-stroke: var(--td-gray-color-11);
|
||||
--td-component-border: var(--td-gray-color-9);
|
||||
--td-font-white-1: rgba(255, 255, 255, 0.9);
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-white-1);
|
||||
--td-text-color-secondary: var(--td-font-white-2);
|
||||
--td-text-color-placeholder: var(--td-font-white-3);
|
||||
--td-text-color-disabled: var(--td-font-white-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-shadow-1: 0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
--td-shadow-2: 0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.10), 0 5px 5px rgba(0, 0, 0, 0.16);
|
||||
--td-shadow-3: 0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.20);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #5e5e5e;
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 55%);
|
||||
--td-scrollbar-color: rgba(255, 255, 255, 10%);
|
||||
--td-scrollbar-hover-color: rgba(255, 255, 255, 30%);
|
||||
--td-scroll-track-color: #333;
|
||||
--td-bg-color-specialcomponent: transparent;
|
||||
--td-border-level-1-color: var(--td-gray-color-11);
|
||||
--td-border-level-2-color: var(--td-gray-color-9);
|
||||
--td-mask-active: rgba(0, 0, 0, 0.4);
|
||||
--td-mask-disabled: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
:root {
|
||||
--td-font-family: pingfang sc, microsoft yahei, arial regular;
|
||||
--td-font-family-medium: pingfang sc, microsoft yahei, arial medium;
|
||||
--td-font-size-link-small: 12px;
|
||||
--td-font-size-link-medium: 14px;
|
||||
--td-font-size-link-large: 16px;
|
||||
--td-font-size-mark-small: 12px;
|
||||
--td-font-size-mark-medium: 14px;
|
||||
--td-font-size-body-small: 12px;
|
||||
--td-font-size-body-medium: 14px;
|
||||
--td-font-size-body-large: 16px;
|
||||
--td-font-size-title-small: 14px;
|
||||
--td-font-size-title-medium: 16px;
|
||||
--td-font-size-title-large: 20px;
|
||||
--td-font-size-headline-small: 24px;
|
||||
--td-font-size-headline-medium: 28px;
|
||||
--td-font-size-headline-large: 36px;
|
||||
--td-font-size-display-medium: 48px;
|
||||
--td-font-size-display-large: 64px;
|
||||
--td-line-height-link-small: 20px;
|
||||
--td-line-height-link-medium: 22px;
|
||||
--td-line-height-link-large: 24px;
|
||||
--td-line-height-mark-small: 20px;
|
||||
--td-line-height-mark-medium: 22px;
|
||||
--td-line-height-body-small: 20px;
|
||||
--td-line-height-body-medium: 22px;
|
||||
--td-line-height-body-large: 24px;
|
||||
--td-line-height-title-small: 22px;
|
||||
--td-line-height-title-medium: 24px;
|
||||
--td-line-height-title-large: 28px;
|
||||
--td-line-height-headline-small: 32px;
|
||||
--td-line-height-headline-medium: 36px;
|
||||
--td-line-height-headline-large: 44px;
|
||||
--td-line-height-display-medium: 56px;
|
||||
--td-line-height-display-large: 72px;
|
||||
--td-font-link-small: var(--td-font-size-link-small) / var(--td-line-height-link-small) var(--td-font-family);
|
||||
--td-font-link-medium: var(--td-font-size-link-medium) / var(--td-line-height-link-medium) var(--td-font-family);
|
||||
--td-font-link-large: var(--td-font-size-link-large) / var(--td-line-height-link-large) var(--td-font-family);
|
||||
--td-font-mark-small: 600 var(--td-font-size-mark-small) / var(--td-line-height-mark-small) var(--td-font-family);
|
||||
--td-font-mark-medium: 600 var(--td-font-size-mark-medium) / var(--td-line-height-mark-medium) var(--td-font-family);
|
||||
--td-font-body-small: var(--td-font-size-body-small) / var(--td-line-height-body-small) var(--td-font-family);
|
||||
--td-font-body-medium: var(--td-font-size-body-medium) / var(--td-line-height-body-medium) var(--td-font-family);
|
||||
--td-font-body-large: var(--td-font-size-body-large) / var(--td-line-height-body-large) var(--td-font-family);
|
||||
--td-font-title-small: 600 var(--td-font-size-title-small) / var(--td-line-height-title-small) var(--td-font-family);
|
||||
--td-font-title-medium: 600 var(--td-font-size-title-medium) / var(--td-line-height-title-medium) var(--td-font-family);
|
||||
--td-font-title-large: 600 var(--td-font-size-title-large) / var(--td-line-height-title-large) var(--td-font-family);
|
||||
--td-font-headline-small: 600 var(--td-font-size-headline-small) / var(--td-line-height-headline-small) var(--td-font-family);
|
||||
--td-font-headline-medium: 600 var(--td-font-size-headline-medium) / var(--td-line-height-headline-medium) var(--td-font-family);
|
||||
--td-font-headline-large: 600 var(--td-font-size-headline-large) / var(--td-line-height-headline-large) var(--td-font-family);
|
||||
--td-font-display-medium: 600 var(--td-font-size-display-medium) / var(--td-line-height-display-medium) var(--td-font-family);
|
||||
--td-font-display-large: 600 var(--td-font-size-display-large) / var(--td-line-height-display-large) var(--td-font-family);
|
||||
--td-radius-small: 2px;
|
||||
--td-radius-default: 3px;
|
||||
--td-radius-medium: 6px;
|
||||
--td-radius-large: 9px;
|
||||
--td-radius-extraLarge: 12px;
|
||||
--td-radius-round: 999px;
|
||||
--td-radius-circle: 50%;
|
||||
--td-size-1: 2px;
|
||||
--td-size-2: 4px;
|
||||
--td-size-3: 6px;
|
||||
--td-size-4: 8px;
|
||||
--td-size-5: 12px;
|
||||
--td-size-6: 16px;
|
||||
--td-size-7: 20px;
|
||||
--td-size-8: 24px;
|
||||
--td-size-9: 28px;
|
||||
--td-size-10: 32px;
|
||||
--td-size-11: 36px;
|
||||
--td-size-12: 40px;
|
||||
--td-size-13: 48px;
|
||||
--td-size-14: 56px;
|
||||
--td-size-15: 64px;
|
||||
--td-size-16: 72px;
|
||||
--td-comp-size-xxxs: var(--td-size-6);
|
||||
--td-comp-size-xxs: var(--td-size-7);
|
||||
--td-comp-size-xs: var(--td-size-8);
|
||||
--td-comp-size-s: var(--td-size-9);
|
||||
--td-comp-size-m: var(--td-size-10);
|
||||
--td-comp-size-l: var(--td-size-11);
|
||||
--td-comp-size-xl: var(--td-size-12);
|
||||
--td-comp-size-xxl: var(--td-size-13);
|
||||
--td-comp-size-xxxl: var(--td-size-14);
|
||||
--td-comp-size-xxxxl: var(--td-size-15);
|
||||
--td-comp-size-xxxxxl: var(--td-size-16);
|
||||
--td-pop-padding-s: var(--td-size-2);
|
||||
--td-pop-padding-m: var(--td-size-3);
|
||||
--td-pop-padding-l: var(--td-size-4);
|
||||
--td-pop-padding-xl: var(--td-size-5);
|
||||
--td-pop-padding-xxl: var(--td-size-6);
|
||||
--td-comp-paddingLR-xxs: var(--td-size-1);
|
||||
--td-comp-paddingLR-xs: var(--td-size-2);
|
||||
--td-comp-paddingLR-s: var(--td-size-4);
|
||||
--td-comp-paddingLR-m: var(--td-size-5);
|
||||
--td-comp-paddingLR-l: var(--td-size-6);
|
||||
--td-comp-paddingLR-xl: var(--td-size-8);
|
||||
--td-comp-paddingLR-xxl: var(--td-size-10);
|
||||
--td-comp-paddingTB-xxs: var(--td-size-1);
|
||||
--td-comp-paddingTB-xs: var(--td-size-2);
|
||||
--td-comp-paddingTB-s: var(--td-size-4);
|
||||
--td-comp-paddingTB-m: var(--td-size-5);
|
||||
--td-comp-paddingTB-l: var(--td-size-6);
|
||||
--td-comp-paddingTB-xl: var(--td-size-8);
|
||||
--td-comp-paddingTB-xxl: var(--td-size-10);
|
||||
--td-comp-margin-xxs: var(--td-size-1);
|
||||
--td-comp-margin-xs: var(--td-size-2);
|
||||
--td-comp-margin-s: var(--td-size-4);
|
||||
--td-comp-margin-m: var(--td-size-5);
|
||||
--td-comp-margin-l: var(--td-size-6);
|
||||
--td-comp-margin-xl: var(--td-size-7);
|
||||
--td-comp-margin-xxl: var(--td-size-8);
|
||||
--td-comp-margin-xxxl: var(--td-size-10);
|
||||
--td-comp-margin-xxxxl: var(--td-size-12);
|
||||
}
|
||||
355
src/renderer/src/assets/theme/cyan.css
Normal file
355
src/renderer/src/assets/theme/cyan.css
Normal file
@@ -0,0 +1,355 @@
|
||||
:root[theme-mode="cyan"] {
|
||||
--td-brand-color-1: #e3fcf8;
|
||||
--td-brand-color-2: #beefe9;
|
||||
--td-brand-color-3: #86dad1;
|
||||
--td-brand-color-4: #3ac2b8;
|
||||
--td-brand-color-5: #00a59b;
|
||||
--td-brand-color-6: #00877e;
|
||||
--td-brand-color-7: #006b64;
|
||||
--td-brand-color-8: #00524c;
|
||||
--td-brand-color-9: #003b36;
|
||||
--td-brand-color-10: #002724;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-3);
|
||||
--td-brand-color: var(--td-brand-color-4);
|
||||
--td-brand-color-active: var(--td-brand-color-5);
|
||||
--td-warning-color-1: #fef3e6;
|
||||
--td-warning-color-2: #f9e0c7;
|
||||
--td-warning-color-3: #f7c797;
|
||||
--td-warning-color-4: #f2995f;
|
||||
--td-warning-color-5: #ed7b2f;
|
||||
--td-warning-color-6: #d35a21;
|
||||
--td-warning-color-7: #ba431b;
|
||||
--td-warning-color-8: #9e3610;
|
||||
--td-warning-color-9: #842b0b;
|
||||
--td-warning-color-10: #5a1907;
|
||||
--td-warning-color: var(--td-warning-color-5);
|
||||
--td-warning-color-hover: var(--td-warning-color-4);
|
||||
--td-warning-color-focus: var(--td-warning-color-2);
|
||||
--td-warning-color-active: var(--td-warning-color-6);
|
||||
--td-warning-color-disabled: var(--td-warning-color-3);
|
||||
--td-warning-color-light: var(--td-warning-color-1);
|
||||
--td-error-color-1: #fdecee;
|
||||
--td-error-color-2: #f9d7d9;
|
||||
--td-error-color-3: #f8b9be;
|
||||
--td-error-color-4: #f78d94;
|
||||
--td-error-color-5: #f36d78;
|
||||
--td-error-color-6: #e34d59;
|
||||
--td-error-color-7: #c9353f;
|
||||
--td-error-color-8: #b11f26;
|
||||
--td-error-color-9: #951114;
|
||||
--td-error-color-10: #680506;
|
||||
--td-error-color: var(--td-error-color-6);
|
||||
--td-error-color-hover: var(--td-error-color-5);
|
||||
--td-error-color-focus: var(--td-error-color-2);
|
||||
--td-error-color-active: var(--td-error-color-7);
|
||||
--td-error-color-disabled: var(--td-error-color-3);
|
||||
--td-error-color-light: var(--td-error-color-1);
|
||||
--td-success-color-1: #e8f8f2;
|
||||
--td-success-color-2: #bcebdc;
|
||||
--td-success-color-3: #85dbbe;
|
||||
--td-success-color-4: #48c79c;
|
||||
--td-success-color-5: #00a870;
|
||||
--td-success-color-6: #078d5c;
|
||||
--td-success-color-7: #067945;
|
||||
--td-success-color-8: #056334;
|
||||
--td-success-color-9: #044f2a;
|
||||
--td-success-color-10: #033017;
|
||||
--td-success-color: var(--td-success-color-5);
|
||||
--td-success-color-hover: var(--td-success-color-4);
|
||||
--td-success-color-focus: var(--td-success-color-2);
|
||||
--td-success-color-active: var(--td-success-color-6);
|
||||
--td-success-color-disabled: var(--td-success-color-3);
|
||||
--td-success-color-light: var(--td-success-color-1);
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-container: #fff;
|
||||
--td-bg-color-container-select: #fff;
|
||||
--td-bg-color-page: var(--td-gray-color-2);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-1);
|
||||
--td-bg-color-container-active: var(--td-gray-color-3);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-1);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-2);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-4);
|
||||
--td-bg-color-component: var(--td-gray-color-3);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-4);
|
||||
--td-bg-color-component-active: var(--td-gray-color-6);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-2);
|
||||
--td-component-stroke: var(--td-gray-color-3);
|
||||
--td-component-border: var(--td-gray-color-4);
|
||||
--td-font-white-1: #ffffff;
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-gray-1);
|
||||
--td-text-color-secondary: var(--td-font-gray-2);
|
||||
--td-text-color-placeholder: var(--td-font-gray-3);
|
||||
--td-text-color-disabled: var(--td-font-gray-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-brand-color-light-hover: var(--td-brand-color-2);
|
||||
--td-warning-color-light-hover: var(--td-warning-color-2);
|
||||
--td-error-color-light-hover: var(--td-error-color-2);
|
||||
--td-success-color-light-hover: var(--td-success-color-2);
|
||||
--td-bg-color-secondarycomponent: var(--td-gray-color-4);
|
||||
--td-bg-color-secondarycomponent-hover: var(--td-gray-color-5);
|
||||
--td-bg-color-secondarycomponent-active: var(--td-gray-color-6);
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 8%);
|
||||
--td-scrollbar-color: rgba(0, 0, 0, 10%);
|
||||
--td-scrollbar-hover-color: rgba(0, 0, 0, 30%);
|
||||
--td-scroll-track-color: #fff;
|
||||
--td-bg-color-specialcomponent: #fff;
|
||||
--td-border-level-1-color: var(--td-gray-color-3);
|
||||
--td-border-level-2-color: var(--td-gray-color-4);
|
||||
--td-shadow-1: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
--td-shadow-2: 0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
--td-shadow-3: 0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
|
||||
--td-mask-active: rgba(0, 0, 0, 0.6);
|
||||
--td-mask-disabled: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
:root[theme-mode="dark"] {
|
||||
--td-brand-color-1: #00a59b20;
|
||||
--td-brand-color-2: #003b36;
|
||||
--td-brand-color-3: #00524c;
|
||||
--td-brand-color-4: #006b64;
|
||||
--td-brand-color-5: #00877e;
|
||||
--td-brand-color-6: #00a59b;
|
||||
--td-brand-color-7: #0ed6ca;
|
||||
--td-brand-color-8: #86dad1;
|
||||
--td-brand-color-9: #beefe9;
|
||||
--td-brand-color-10: #e3fcf8;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-5);
|
||||
--td-brand-color: var(--td-brand-color-6);
|
||||
--td-brand-color-active: var(--td-brand-color-7);
|
||||
--td-warning-color-1: #4f2a1d;
|
||||
--td-warning-color-2: #582f21;
|
||||
--td-warning-color-3: #733c23;
|
||||
--td-warning-color-4: #a75d2b;
|
||||
--td-warning-color-5: #cf6e2d;
|
||||
--td-warning-color-6: #dc7633;
|
||||
--td-warning-color-7: #e8935c;
|
||||
--td-warning-color-8: #ecbf91;
|
||||
--td-warning-color-9: #eed7bf;
|
||||
--td-warning-color-10: #f3e9dc;
|
||||
--td-error-color-1: #472324;
|
||||
--td-error-color-2: #5e2a2d;
|
||||
--td-error-color-3: #703439;
|
||||
--td-error-color-4: #83383e;
|
||||
--td-error-color-5: #a03f46;
|
||||
--td-error-color-6: #c64751;
|
||||
--td-error-color-7: #de6670;
|
||||
--td-error-color-8: #ec888e;
|
||||
--td-error-color-9: #edb1b6;
|
||||
--td-error-color-10: #eeced0;
|
||||
--td-success-color-1: #193a2a;
|
||||
--td-success-color-2: #1a4230;
|
||||
--td-success-color-3: #17533d;
|
||||
--td-success-color-4: #0d7a55;
|
||||
--td-success-color-5: #059465;
|
||||
--td-success-color-6: #43af8a;
|
||||
--td-success-color-7: #46bf96;
|
||||
--td-success-color-8: #80d2b6;
|
||||
--td-success-color-9: #b4e1d3;
|
||||
--td-success-color-10: #deede8;
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-page: var(--td-gray-color-14);
|
||||
--td-bg-color-container: var(--td-gray-color-13);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-12);
|
||||
--td-bg-color-container-active: var(--td-gray-color-10);
|
||||
--td-bg-color-container-select: var(--td-gray-color-9);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-12);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-11);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component: var(--td-gray-color-11);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-10);
|
||||
--td-bg-color-component-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-12);
|
||||
--td-component-stroke: var(--td-gray-color-11);
|
||||
--td-component-border: var(--td-gray-color-9);
|
||||
--td-font-white-1: rgba(255, 255, 255, 0.9);
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-white-1);
|
||||
--td-text-color-secondary: var(--td-font-white-2);
|
||||
--td-text-color-placeholder: var(--td-font-white-3);
|
||||
--td-text-color-disabled: var(--td-font-white-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-shadow-1: 0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
--td-shadow-2: 0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.10), 0 5px 5px rgba(0, 0, 0, 0.16);
|
||||
--td-shadow-3: 0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.20);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #5e5e5e;
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 55%);
|
||||
--td-scrollbar-color: rgba(255, 255, 255, 10%);
|
||||
--td-scrollbar-hover-color: rgba(255, 255, 255, 30%);
|
||||
--td-scroll-track-color: #333;
|
||||
--td-bg-color-specialcomponent: transparent;
|
||||
--td-border-level-1-color: var(--td-gray-color-11);
|
||||
--td-border-level-2-color: var(--td-gray-color-9);
|
||||
--td-mask-active: rgba(0, 0, 0, 0.4);
|
||||
--td-mask-disabled: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
:root {
|
||||
--td-font-family: pingfang sc, microsoft yahei, arial regular;
|
||||
--td-font-family-medium: pingfang sc, microsoft yahei, arial medium;
|
||||
--td-font-size-link-small: 12px;
|
||||
--td-font-size-link-medium: 14px;
|
||||
--td-font-size-link-large: 16px;
|
||||
--td-font-size-mark-small: 12px;
|
||||
--td-font-size-mark-medium: 14px;
|
||||
--td-font-size-body-small: 12px;
|
||||
--td-font-size-body-medium: 14px;
|
||||
--td-font-size-body-large: 16px;
|
||||
--td-font-size-title-small: 14px;
|
||||
--td-font-size-title-medium: 16px;
|
||||
--td-font-size-title-large: 20px;
|
||||
--td-font-size-headline-small: 24px;
|
||||
--td-font-size-headline-medium: 28px;
|
||||
--td-font-size-headline-large: 36px;
|
||||
--td-font-size-display-medium: 48px;
|
||||
--td-font-size-display-large: 64px;
|
||||
--td-line-height-link-small: 20px;
|
||||
--td-line-height-link-medium: 22px;
|
||||
--td-line-height-link-large: 24px;
|
||||
--td-line-height-mark-small: 20px;
|
||||
--td-line-height-mark-medium: 22px;
|
||||
--td-line-height-body-small: 20px;
|
||||
--td-line-height-body-medium: 22px;
|
||||
--td-line-height-body-large: 24px;
|
||||
--td-line-height-title-small: 22px;
|
||||
--td-line-height-title-medium: 24px;
|
||||
--td-line-height-title-large: 28px;
|
||||
--td-line-height-headline-small: 32px;
|
||||
--td-line-height-headline-medium: 36px;
|
||||
--td-line-height-headline-large: 44px;
|
||||
--td-line-height-display-medium: 56px;
|
||||
--td-line-height-display-large: 72px;
|
||||
--td-font-link-small: var(--td-font-size-link-small) / var(--td-line-height-link-small) var(--td-font-family);
|
||||
--td-font-link-medium: var(--td-font-size-link-medium) / var(--td-line-height-link-medium) var(--td-font-family);
|
||||
--td-font-link-large: var(--td-font-size-link-large) / var(--td-line-height-link-large) var(--td-font-family);
|
||||
--td-font-mark-small: 600 var(--td-font-size-mark-small) / var(--td-line-height-mark-small) var(--td-font-family);
|
||||
--td-font-mark-medium: 600 var(--td-font-size-mark-medium) / var(--td-line-height-mark-medium) var(--td-font-family);
|
||||
--td-font-body-small: var(--td-font-size-body-small) / var(--td-line-height-body-small) var(--td-font-family);
|
||||
--td-font-body-medium: var(--td-font-size-body-medium) / var(--td-line-height-body-medium) var(--td-font-family);
|
||||
--td-font-body-large: var(--td-font-size-body-large) / var(--td-line-height-body-large) var(--td-font-family);
|
||||
--td-font-title-small: 600 var(--td-font-size-title-small) / var(--td-line-height-title-small) var(--td-font-family);
|
||||
--td-font-title-medium: 600 var(--td-font-size-title-medium) / var(--td-line-height-title-medium) var(--td-font-family);
|
||||
--td-font-title-large: 600 var(--td-font-size-title-large) / var(--td-line-height-title-large) var(--td-font-family);
|
||||
--td-font-headline-small: 600 var(--td-font-size-headline-small) / var(--td-line-height-headline-small) var(--td-font-family);
|
||||
--td-font-headline-medium: 600 var(--td-font-size-headline-medium) / var(--td-line-height-headline-medium) var(--td-font-family);
|
||||
--td-font-headline-large: 600 var(--td-font-size-headline-large) / var(--td-line-height-headline-large) var(--td-font-family);
|
||||
--td-font-display-medium: 600 var(--td-font-size-display-medium) / var(--td-line-height-display-medium) var(--td-font-family);
|
||||
--td-font-display-large: 600 var(--td-font-size-display-large) / var(--td-line-height-display-large) var(--td-font-family);
|
||||
--td-radius-small: 2px;
|
||||
--td-radius-default: 3px;
|
||||
--td-radius-medium: 6px;
|
||||
--td-radius-large: 9px;
|
||||
--td-radius-extraLarge: 12px;
|
||||
--td-radius-round: 999px;
|
||||
--td-radius-circle: 50%;
|
||||
--td-size-1: 2px;
|
||||
--td-size-2: 4px;
|
||||
--td-size-3: 6px;
|
||||
--td-size-4: 8px;
|
||||
--td-size-5: 12px;
|
||||
--td-size-6: 16px;
|
||||
--td-size-7: 20px;
|
||||
--td-size-8: 24px;
|
||||
--td-size-9: 28px;
|
||||
--td-size-10: 32px;
|
||||
--td-size-11: 36px;
|
||||
--td-size-12: 40px;
|
||||
--td-size-13: 48px;
|
||||
--td-size-14: 56px;
|
||||
--td-size-15: 64px;
|
||||
--td-size-16: 72px;
|
||||
--td-comp-size-xxxs: var(--td-size-6);
|
||||
--td-comp-size-xxs: var(--td-size-7);
|
||||
--td-comp-size-xs: var(--td-size-8);
|
||||
--td-comp-size-s: var(--td-size-9);
|
||||
--td-comp-size-m: var(--td-size-10);
|
||||
--td-comp-size-l: var(--td-size-11);
|
||||
--td-comp-size-xl: var(--td-size-12);
|
||||
--td-comp-size-xxl: var(--td-size-13);
|
||||
--td-comp-size-xxxl: var(--td-size-14);
|
||||
--td-comp-size-xxxxl: var(--td-size-15);
|
||||
--td-comp-size-xxxxxl: var(--td-size-16);
|
||||
--td-pop-padding-s: var(--td-size-2);
|
||||
--td-pop-padding-m: var(--td-size-3);
|
||||
--td-pop-padding-l: var(--td-size-4);
|
||||
--td-pop-padding-xl: var(--td-size-5);
|
||||
--td-pop-padding-xxl: var(--td-size-6);
|
||||
--td-comp-paddingLR-xxs: var(--td-size-1);
|
||||
--td-comp-paddingLR-xs: var(--td-size-2);
|
||||
--td-comp-paddingLR-s: var(--td-size-4);
|
||||
--td-comp-paddingLR-m: var(--td-size-5);
|
||||
--td-comp-paddingLR-l: var(--td-size-6);
|
||||
--td-comp-paddingLR-xl: var(--td-size-8);
|
||||
--td-comp-paddingLR-xxl: var(--td-size-10);
|
||||
--td-comp-paddingTB-xxs: var(--td-size-1);
|
||||
--td-comp-paddingTB-xs: var(--td-size-2);
|
||||
--td-comp-paddingTB-s: var(--td-size-4);
|
||||
--td-comp-paddingTB-m: var(--td-size-5);
|
||||
--td-comp-paddingTB-l: var(--td-size-6);
|
||||
--td-comp-paddingTB-xl: var(--td-size-8);
|
||||
--td-comp-paddingTB-xxl: var(--td-size-10);
|
||||
--td-comp-margin-xxs: var(--td-size-1);
|
||||
--td-comp-margin-xs: var(--td-size-2);
|
||||
--td-comp-margin-s: var(--td-size-4);
|
||||
--td-comp-margin-m: var(--td-size-5);
|
||||
--td-comp-margin-l: var(--td-size-6);
|
||||
--td-comp-margin-xl: var(--td-size-7);
|
||||
--td-comp-margin-xxl: var(--td-size-8);
|
||||
--td-comp-margin-xxxl: var(--td-size-10);
|
||||
--td-comp-margin-xxxxl: var(--td-size-12);
|
||||
}
|
||||
355
src/renderer/src/assets/theme/orange.css
Normal file
355
src/renderer/src/assets/theme/orange.css
Normal file
@@ -0,0 +1,355 @@
|
||||
:root[theme-mode="orange"] {
|
||||
--td-brand-color-1: #fff1ea;
|
||||
--td-brand-color-2: #ffd9c5;
|
||||
--td-brand-color-3: #ffb991;
|
||||
--td-brand-color-4: #fb9458;
|
||||
--td-brand-color-5: #e47228;
|
||||
--td-brand-color-6: #c05708;
|
||||
--td-brand-color-7: #9a4200;
|
||||
--td-brand-color-8: #753000;
|
||||
--td-brand-color-9: #552100;
|
||||
--td-brand-color-10: #3d1600;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-3);
|
||||
--td-brand-color: var(--td-brand-color-4);
|
||||
--td-brand-color-active: var(--td-brand-color-5);
|
||||
--td-warning-color-1: #fef3e6;
|
||||
--td-warning-color-2: #f9e0c7;
|
||||
--td-warning-color-3: #f7c797;
|
||||
--td-warning-color-4: #f2995f;
|
||||
--td-warning-color-5: #ed7b2f;
|
||||
--td-warning-color-6: #d35a21;
|
||||
--td-warning-color-7: #ba431b;
|
||||
--td-warning-color-8: #9e3610;
|
||||
--td-warning-color-9: #842b0b;
|
||||
--td-warning-color-10: #5a1907;
|
||||
--td-warning-color: var(--td-warning-color-5);
|
||||
--td-warning-color-hover: var(--td-warning-color-4);
|
||||
--td-warning-color-focus: var(--td-warning-color-2);
|
||||
--td-warning-color-active: var(--td-warning-color-6);
|
||||
--td-warning-color-disabled: var(--td-warning-color-3);
|
||||
--td-warning-color-light: var(--td-warning-color-1);
|
||||
--td-error-color-1: #fdecee;
|
||||
--td-error-color-2: #f9d7d9;
|
||||
--td-error-color-3: #f8b9be;
|
||||
--td-error-color-4: #f78d94;
|
||||
--td-error-color-5: #f36d78;
|
||||
--td-error-color-6: #e34d59;
|
||||
--td-error-color-7: #c9353f;
|
||||
--td-error-color-8: #b11f26;
|
||||
--td-error-color-9: #951114;
|
||||
--td-error-color-10: #680506;
|
||||
--td-error-color: var(--td-error-color-6);
|
||||
--td-error-color-hover: var(--td-error-color-5);
|
||||
--td-error-color-focus: var(--td-error-color-2);
|
||||
--td-error-color-active: var(--td-error-color-7);
|
||||
--td-error-color-disabled: var(--td-error-color-3);
|
||||
--td-error-color-light: var(--td-error-color-1);
|
||||
--td-success-color-1: #e8f8f2;
|
||||
--td-success-color-2: #bcebdc;
|
||||
--td-success-color-3: #85dbbe;
|
||||
--td-success-color-4: #48c79c;
|
||||
--td-success-color-5: #00a870;
|
||||
--td-success-color-6: #078d5c;
|
||||
--td-success-color-7: #067945;
|
||||
--td-success-color-8: #056334;
|
||||
--td-success-color-9: #044f2a;
|
||||
--td-success-color-10: #033017;
|
||||
--td-success-color: var(--td-success-color-5);
|
||||
--td-success-color-hover: var(--td-success-color-4);
|
||||
--td-success-color-focus: var(--td-success-color-2);
|
||||
--td-success-color-active: var(--td-success-color-6);
|
||||
--td-success-color-disabled: var(--td-success-color-3);
|
||||
--td-success-color-light: var(--td-success-color-1);
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-container: #fff;
|
||||
--td-bg-color-container-select: #fff;
|
||||
--td-bg-color-page: var(--td-gray-color-2);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-1);
|
||||
--td-bg-color-container-active: var(--td-gray-color-3);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-1);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-2);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-4);
|
||||
--td-bg-color-component: var(--td-gray-color-3);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-4);
|
||||
--td-bg-color-component-active: var(--td-gray-color-6);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-2);
|
||||
--td-component-stroke: var(--td-gray-color-3);
|
||||
--td-component-border: var(--td-gray-color-4);
|
||||
--td-font-white-1: #ffffff;
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-gray-1);
|
||||
--td-text-color-secondary: var(--td-font-gray-2);
|
||||
--td-text-color-placeholder: var(--td-font-gray-3);
|
||||
--td-text-color-disabled: var(--td-font-gray-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-brand-color-light-hover: var(--td-brand-color-2);
|
||||
--td-warning-color-light-hover: var(--td-warning-color-2);
|
||||
--td-error-color-light-hover: var(--td-error-color-2);
|
||||
--td-success-color-light-hover: var(--td-success-color-2);
|
||||
--td-bg-color-secondarycomponent: var(--td-gray-color-4);
|
||||
--td-bg-color-secondarycomponent-hover: var(--td-gray-color-5);
|
||||
--td-bg-color-secondarycomponent-active: var(--td-gray-color-6);
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 8%);
|
||||
--td-scrollbar-color: rgba(0, 0, 0, 10%);
|
||||
--td-scrollbar-hover-color: rgba(0, 0, 0, 30%);
|
||||
--td-scroll-track-color: #fff;
|
||||
--td-bg-color-specialcomponent: #fff;
|
||||
--td-border-level-1-color: var(--td-gray-color-3);
|
||||
--td-border-level-2-color: var(--td-gray-color-4);
|
||||
--td-shadow-1: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
--td-shadow-2: 0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
--td-shadow-3: 0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
|
||||
--td-mask-active: rgba(0, 0, 0, 0.6);
|
||||
--td-mask-disabled: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
:root[theme-mode="dark"] {
|
||||
--td-brand-color-1: #e4722820;
|
||||
--td-brand-color-2: #552100;
|
||||
--td-brand-color-3: #753000;
|
||||
--td-brand-color-4: #9a4200;
|
||||
--td-brand-color-5: #c05708;
|
||||
--td-brand-color-6: #e47228;
|
||||
--td-brand-color-7: #fd853a;
|
||||
--td-brand-color-8: #ffb991;
|
||||
--td-brand-color-9: #ffd9c5;
|
||||
--td-brand-color-10: #fff1ea;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-5);
|
||||
--td-brand-color: var(--td-brand-color-6);
|
||||
--td-brand-color-active: var(--td-brand-color-7);
|
||||
--td-warning-color-1: #4f2a1d;
|
||||
--td-warning-color-2: #582f21;
|
||||
--td-warning-color-3: #733c23;
|
||||
--td-warning-color-4: #a75d2b;
|
||||
--td-warning-color-5: #cf6e2d;
|
||||
--td-warning-color-6: #dc7633;
|
||||
--td-warning-color-7: #e8935c;
|
||||
--td-warning-color-8: #ecbf91;
|
||||
--td-warning-color-9: #eed7bf;
|
||||
--td-warning-color-10: #f3e9dc;
|
||||
--td-error-color-1: #472324;
|
||||
--td-error-color-2: #5e2a2d;
|
||||
--td-error-color-3: #703439;
|
||||
--td-error-color-4: #83383e;
|
||||
--td-error-color-5: #a03f46;
|
||||
--td-error-color-6: #c64751;
|
||||
--td-error-color-7: #de6670;
|
||||
--td-error-color-8: #ec888e;
|
||||
--td-error-color-9: #edb1b6;
|
||||
--td-error-color-10: #eeced0;
|
||||
--td-success-color-1: #193a2a;
|
||||
--td-success-color-2: #1a4230;
|
||||
--td-success-color-3: #17533d;
|
||||
--td-success-color-4: #0d7a55;
|
||||
--td-success-color-5: #059465;
|
||||
--td-success-color-6: #43af8a;
|
||||
--td-success-color-7: #46bf96;
|
||||
--td-success-color-8: #80d2b6;
|
||||
--td-success-color-9: #b4e1d3;
|
||||
--td-success-color-10: #deede8;
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-page: var(--td-gray-color-14);
|
||||
--td-bg-color-container: var(--td-gray-color-13);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-12);
|
||||
--td-bg-color-container-active: var(--td-gray-color-10);
|
||||
--td-bg-color-container-select: var(--td-gray-color-9);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-12);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-11);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component: var(--td-gray-color-11);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-10);
|
||||
--td-bg-color-component-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-12);
|
||||
--td-component-stroke: var(--td-gray-color-11);
|
||||
--td-component-border: var(--td-gray-color-9);
|
||||
--td-font-white-1: rgba(255, 255, 255, 0.9);
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-white-1);
|
||||
--td-text-color-secondary: var(--td-font-white-2);
|
||||
--td-text-color-placeholder: var(--td-font-white-3);
|
||||
--td-text-color-disabled: var(--td-font-white-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-shadow-1: 0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
--td-shadow-2: 0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.10), 0 5px 5px rgba(0, 0, 0, 0.16);
|
||||
--td-shadow-3: 0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.20);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #5e5e5e;
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 55%);
|
||||
--td-scrollbar-color: rgba(255, 255, 255, 10%);
|
||||
--td-scrollbar-hover-color: rgba(255, 255, 255, 30%);
|
||||
--td-scroll-track-color: #333;
|
||||
--td-bg-color-specialcomponent: transparent;
|
||||
--td-border-level-1-color: var(--td-gray-color-11);
|
||||
--td-border-level-2-color: var(--td-gray-color-9);
|
||||
--td-mask-active: rgba(0, 0, 0, 0.4);
|
||||
--td-mask-disabled: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
:root {
|
||||
--td-font-family: pingfang sc, microsoft yahei, arial regular;
|
||||
--td-font-family-medium: pingfang sc, microsoft yahei, arial medium;
|
||||
--td-font-size-link-small: 12px;
|
||||
--td-font-size-link-medium: 14px;
|
||||
--td-font-size-link-large: 16px;
|
||||
--td-font-size-mark-small: 12px;
|
||||
--td-font-size-mark-medium: 14px;
|
||||
--td-font-size-body-small: 12px;
|
||||
--td-font-size-body-medium: 14px;
|
||||
--td-font-size-body-large: 16px;
|
||||
--td-font-size-title-small: 14px;
|
||||
--td-font-size-title-medium: 16px;
|
||||
--td-font-size-title-large: 20px;
|
||||
--td-font-size-headline-small: 24px;
|
||||
--td-font-size-headline-medium: 28px;
|
||||
--td-font-size-headline-large: 36px;
|
||||
--td-font-size-display-medium: 48px;
|
||||
--td-font-size-display-large: 64px;
|
||||
--td-line-height-link-small: 20px;
|
||||
--td-line-height-link-medium: 22px;
|
||||
--td-line-height-link-large: 24px;
|
||||
--td-line-height-mark-small: 20px;
|
||||
--td-line-height-mark-medium: 22px;
|
||||
--td-line-height-body-small: 20px;
|
||||
--td-line-height-body-medium: 22px;
|
||||
--td-line-height-body-large: 24px;
|
||||
--td-line-height-title-small: 22px;
|
||||
--td-line-height-title-medium: 24px;
|
||||
--td-line-height-title-large: 28px;
|
||||
--td-line-height-headline-small: 32px;
|
||||
--td-line-height-headline-medium: 36px;
|
||||
--td-line-height-headline-large: 44px;
|
||||
--td-line-height-display-medium: 56px;
|
||||
--td-line-height-display-large: 72px;
|
||||
--td-font-link-small: var(--td-font-size-link-small) / var(--td-line-height-link-small) var(--td-font-family);
|
||||
--td-font-link-medium: var(--td-font-size-link-medium) / var(--td-line-height-link-medium) var(--td-font-family);
|
||||
--td-font-link-large: var(--td-font-size-link-large) / var(--td-line-height-link-large) var(--td-font-family);
|
||||
--td-font-mark-small: 600 var(--td-font-size-mark-small) / var(--td-line-height-mark-small) var(--td-font-family);
|
||||
--td-font-mark-medium: 600 var(--td-font-size-mark-medium) / var(--td-line-height-mark-medium) var(--td-font-family);
|
||||
--td-font-body-small: var(--td-font-size-body-small) / var(--td-line-height-body-small) var(--td-font-family);
|
||||
--td-font-body-medium: var(--td-font-size-body-medium) / var(--td-line-height-body-medium) var(--td-font-family);
|
||||
--td-font-body-large: var(--td-font-size-body-large) / var(--td-line-height-body-large) var(--td-font-family);
|
||||
--td-font-title-small: 600 var(--td-font-size-title-small) / var(--td-line-height-title-small) var(--td-font-family);
|
||||
--td-font-title-medium: 600 var(--td-font-size-title-medium) / var(--td-line-height-title-medium) var(--td-font-family);
|
||||
--td-font-title-large: 600 var(--td-font-size-title-large) / var(--td-line-height-title-large) var(--td-font-family);
|
||||
--td-font-headline-small: 600 var(--td-font-size-headline-small) / var(--td-line-height-headline-small) var(--td-font-family);
|
||||
--td-font-headline-medium: 600 var(--td-font-size-headline-medium) / var(--td-line-height-headline-medium) var(--td-font-family);
|
||||
--td-font-headline-large: 600 var(--td-font-size-headline-large) / var(--td-line-height-headline-large) var(--td-font-family);
|
||||
--td-font-display-medium: 600 var(--td-font-size-display-medium) / var(--td-line-height-display-medium) var(--td-font-family);
|
||||
--td-font-display-large: 600 var(--td-font-size-display-large) / var(--td-line-height-display-large) var(--td-font-family);
|
||||
--td-radius-small: 2px;
|
||||
--td-radius-default: 3px;
|
||||
--td-radius-medium: 6px;
|
||||
--td-radius-large: 9px;
|
||||
--td-radius-extraLarge: 12px;
|
||||
--td-radius-round: 999px;
|
||||
--td-radius-circle: 50%;
|
||||
--td-size-1: 2px;
|
||||
--td-size-2: 4px;
|
||||
--td-size-3: 6px;
|
||||
--td-size-4: 8px;
|
||||
--td-size-5: 12px;
|
||||
--td-size-6: 16px;
|
||||
--td-size-7: 20px;
|
||||
--td-size-8: 24px;
|
||||
--td-size-9: 28px;
|
||||
--td-size-10: 32px;
|
||||
--td-size-11: 36px;
|
||||
--td-size-12: 40px;
|
||||
--td-size-13: 48px;
|
||||
--td-size-14: 56px;
|
||||
--td-size-15: 64px;
|
||||
--td-size-16: 72px;
|
||||
--td-comp-size-xxxs: var(--td-size-6);
|
||||
--td-comp-size-xxs: var(--td-size-7);
|
||||
--td-comp-size-xs: var(--td-size-8);
|
||||
--td-comp-size-s: var(--td-size-9);
|
||||
--td-comp-size-m: var(--td-size-10);
|
||||
--td-comp-size-l: var(--td-size-11);
|
||||
--td-comp-size-xl: var(--td-size-12);
|
||||
--td-comp-size-xxl: var(--td-size-13);
|
||||
--td-comp-size-xxxl: var(--td-size-14);
|
||||
--td-comp-size-xxxxl: var(--td-size-15);
|
||||
--td-comp-size-xxxxxl: var(--td-size-16);
|
||||
--td-pop-padding-s: var(--td-size-2);
|
||||
--td-pop-padding-m: var(--td-size-3);
|
||||
--td-pop-padding-l: var(--td-size-4);
|
||||
--td-pop-padding-xl: var(--td-size-5);
|
||||
--td-pop-padding-xxl: var(--td-size-6);
|
||||
--td-comp-paddingLR-xxs: var(--td-size-1);
|
||||
--td-comp-paddingLR-xs: var(--td-size-2);
|
||||
--td-comp-paddingLR-s: var(--td-size-4);
|
||||
--td-comp-paddingLR-m: var(--td-size-5);
|
||||
--td-comp-paddingLR-l: var(--td-size-6);
|
||||
--td-comp-paddingLR-xl: var(--td-size-8);
|
||||
--td-comp-paddingLR-xxl: var(--td-size-10);
|
||||
--td-comp-paddingTB-xxs: var(--td-size-1);
|
||||
--td-comp-paddingTB-xs: var(--td-size-2);
|
||||
--td-comp-paddingTB-s: var(--td-size-4);
|
||||
--td-comp-paddingTB-m: var(--td-size-5);
|
||||
--td-comp-paddingTB-l: var(--td-size-6);
|
||||
--td-comp-paddingTB-xl: var(--td-size-8);
|
||||
--td-comp-paddingTB-xxl: var(--td-size-10);
|
||||
--td-comp-margin-xxs: var(--td-size-1);
|
||||
--td-comp-margin-xs: var(--td-size-2);
|
||||
--td-comp-margin-s: var(--td-size-4);
|
||||
--td-comp-margin-m: var(--td-size-5);
|
||||
--td-comp-margin-l: var(--td-size-6);
|
||||
--td-comp-margin-xl: var(--td-size-7);
|
||||
--td-comp-margin-xxl: var(--td-size-8);
|
||||
--td-comp-margin-xxxl: var(--td-size-10);
|
||||
--td-comp-margin-xxxxl: var(--td-size-12);
|
||||
}
|
||||
355
src/renderer/src/assets/theme/pink.css
Normal file
355
src/renderer/src/assets/theme/pink.css
Normal file
@@ -0,0 +1,355 @@
|
||||
:root[theme-mode="pink"] {
|
||||
--td-brand-color-1: #fff0f1;
|
||||
--td-brand-color-2: #ffd8dd;
|
||||
--td-brand-color-3: #ffb7c1;
|
||||
--td-brand-color-4: #ff8fa2;
|
||||
--td-brand-color-5: #fc5e7e;
|
||||
--td-brand-color-6: #db3d62;
|
||||
--td-brand-color-7: #b2294b;
|
||||
--td-brand-color-8: #8d1135;
|
||||
--td-brand-color-9: #690021;
|
||||
--td-brand-color-10: #480014;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-4);
|
||||
--td-brand-color: var(--td-brand-color-5);
|
||||
--td-brand-color-active: var(--td-brand-color-6);
|
||||
--td-warning-color-1: #fef3e6;
|
||||
--td-warning-color-2: #f9e0c7;
|
||||
--td-warning-color-3: #f7c797;
|
||||
--td-warning-color-4: #f2995f;
|
||||
--td-warning-color-5: #ed7b2f;
|
||||
--td-warning-color-6: #d35a21;
|
||||
--td-warning-color-7: #ba431b;
|
||||
--td-warning-color-8: #9e3610;
|
||||
--td-warning-color-9: #842b0b;
|
||||
--td-warning-color-10: #5a1907;
|
||||
--td-warning-color: var(--td-warning-color-5);
|
||||
--td-warning-color-hover: var(--td-warning-color-4);
|
||||
--td-warning-color-focus: var(--td-warning-color-2);
|
||||
--td-warning-color-active: var(--td-warning-color-6);
|
||||
--td-warning-color-disabled: var(--td-warning-color-3);
|
||||
--td-warning-color-light: var(--td-warning-color-1);
|
||||
--td-error-color-1: #fdecee;
|
||||
--td-error-color-2: #f9d7d9;
|
||||
--td-error-color-3: #f8b9be;
|
||||
--td-error-color-4: #f78d94;
|
||||
--td-error-color-5: #f36d78;
|
||||
--td-error-color-6: #e34d59;
|
||||
--td-error-color-7: #c9353f;
|
||||
--td-error-color-8: #b11f26;
|
||||
--td-error-color-9: #951114;
|
||||
--td-error-color-10: #680506;
|
||||
--td-error-color: var(--td-error-color-6);
|
||||
--td-error-color-hover: var(--td-error-color-5);
|
||||
--td-error-color-focus: var(--td-error-color-2);
|
||||
--td-error-color-active: var(--td-error-color-7);
|
||||
--td-error-color-disabled: var(--td-error-color-3);
|
||||
--td-error-color-light: var(--td-error-color-1);
|
||||
--td-success-color-1: #e8f8f2;
|
||||
--td-success-color-2: #bcebdc;
|
||||
--td-success-color-3: #85dbbe;
|
||||
--td-success-color-4: #48c79c;
|
||||
--td-success-color-5: #00a870;
|
||||
--td-success-color-6: #078d5c;
|
||||
--td-success-color-7: #067945;
|
||||
--td-success-color-8: #056334;
|
||||
--td-success-color-9: #044f2a;
|
||||
--td-success-color-10: #033017;
|
||||
--td-success-color: var(--td-success-color-5);
|
||||
--td-success-color-hover: var(--td-success-color-4);
|
||||
--td-success-color-focus: var(--td-success-color-2);
|
||||
--td-success-color-active: var(--td-success-color-6);
|
||||
--td-success-color-disabled: var(--td-success-color-3);
|
||||
--td-success-color-light: var(--td-success-color-1);
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-container: #fff;
|
||||
--td-bg-color-container-select: #fff;
|
||||
--td-bg-color-page: var(--td-gray-color-2);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-1);
|
||||
--td-bg-color-container-active: var(--td-gray-color-3);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-1);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-2);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-4);
|
||||
--td-bg-color-component: var(--td-gray-color-3);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-4);
|
||||
--td-bg-color-component-active: var(--td-gray-color-6);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-2);
|
||||
--td-component-stroke: var(--td-gray-color-3);
|
||||
--td-component-border: var(--td-gray-color-4);
|
||||
--td-font-white-1: #ffffff;
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-gray-1);
|
||||
--td-text-color-secondary: var(--td-font-gray-2);
|
||||
--td-text-color-placeholder: var(--td-font-gray-3);
|
||||
--td-text-color-disabled: var(--td-font-gray-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-brand-color-light-hover: var(--td-brand-color-2);
|
||||
--td-warning-color-light-hover: var(--td-warning-color-2);
|
||||
--td-error-color-light-hover: var(--td-error-color-2);
|
||||
--td-success-color-light-hover: var(--td-success-color-2);
|
||||
--td-bg-color-secondarycomponent: var(--td-gray-color-4);
|
||||
--td-bg-color-secondarycomponent-hover: var(--td-gray-color-5);
|
||||
--td-bg-color-secondarycomponent-active: var(--td-gray-color-6);
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 8%);
|
||||
--td-scrollbar-color: rgba(0, 0, 0, 10%);
|
||||
--td-scrollbar-hover-color: rgba(0, 0, 0, 30%);
|
||||
--td-scroll-track-color: #fff;
|
||||
--td-bg-color-specialcomponent: #fff;
|
||||
--td-border-level-1-color: var(--td-gray-color-3);
|
||||
--td-border-level-2-color: var(--td-gray-color-4);
|
||||
--td-shadow-1: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
--td-shadow-2: 0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
--td-shadow-3: 0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
|
||||
--td-mask-active: rgba(0, 0, 0, 0.6);
|
||||
--td-mask-disabled: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
:root[theme-mode="dark"] {
|
||||
--td-brand-color-1: #ff547920;
|
||||
--td-brand-color-2: #690021;
|
||||
--td-brand-color-3: #8d1135;
|
||||
--td-brand-color-4: #b2294b;
|
||||
--td-brand-color-5: #db3d62;
|
||||
--td-brand-color-6: #ff5479;
|
||||
--td-brand-color-7: #ff8fa2;
|
||||
--td-brand-color-8: #ffb7c1;
|
||||
--td-brand-color-9: #ffd8dd;
|
||||
--td-brand-color-10: #fff0f1;
|
||||
--td-brand-color-light: var(--td-brand-color-1);
|
||||
--td-brand-color-focus: var(--td-brand-color-2);
|
||||
--td-brand-color-disabled: var(--td-brand-color-3);
|
||||
--td-brand-color-hover: var(--td-brand-color-5);
|
||||
--td-brand-color: var(--td-brand-color-6);
|
||||
--td-brand-color-active: var(--td-brand-color-7);
|
||||
--td-warning-color-1: #4f2a1d;
|
||||
--td-warning-color-2: #582f21;
|
||||
--td-warning-color-3: #733c23;
|
||||
--td-warning-color-4: #a75d2b;
|
||||
--td-warning-color-5: #cf6e2d;
|
||||
--td-warning-color-6: #dc7633;
|
||||
--td-warning-color-7: #e8935c;
|
||||
--td-warning-color-8: #ecbf91;
|
||||
--td-warning-color-9: #eed7bf;
|
||||
--td-warning-color-10: #f3e9dc;
|
||||
--td-error-color-1: #472324;
|
||||
--td-error-color-2: #5e2a2d;
|
||||
--td-error-color-3: #703439;
|
||||
--td-error-color-4: #83383e;
|
||||
--td-error-color-5: #a03f46;
|
||||
--td-error-color-6: #c64751;
|
||||
--td-error-color-7: #de6670;
|
||||
--td-error-color-8: #ec888e;
|
||||
--td-error-color-9: #edb1b6;
|
||||
--td-error-color-10: #eeced0;
|
||||
--td-success-color-1: #193a2a;
|
||||
--td-success-color-2: #1a4230;
|
||||
--td-success-color-3: #17533d;
|
||||
--td-success-color-4: #0d7a55;
|
||||
--td-success-color-5: #059465;
|
||||
--td-success-color-6: #43af8a;
|
||||
--td-success-color-7: #46bf96;
|
||||
--td-success-color-8: #80d2b6;
|
||||
--td-success-color-9: #b4e1d3;
|
||||
--td-success-color-10: #deede8;
|
||||
--td-gray-color-1: #f3f3f3;
|
||||
--td-gray-color-2: #eee;
|
||||
--td-gray-color-3: #e8e8e8;
|
||||
--td-gray-color-4: #ddd;
|
||||
--td-gray-color-5: #c5c5c5;
|
||||
--td-gray-color-6: #a6a6a6;
|
||||
--td-gray-color-7: #8b8b8b;
|
||||
--td-gray-color-8: #777;
|
||||
--td-gray-color-9: #5e5e5e;
|
||||
--td-gray-color-10: #4b4b4b;
|
||||
--td-gray-color-11: #383838;
|
||||
--td-gray-color-12: #2c2c2c;
|
||||
--td-gray-color-13: #242424;
|
||||
--td-gray-color-14: #181818;
|
||||
--td-bg-color-page: var(--td-gray-color-14);
|
||||
--td-bg-color-container: var(--td-gray-color-13);
|
||||
--td-bg-color-container-hover: var(--td-gray-color-12);
|
||||
--td-bg-color-container-active: var(--td-gray-color-10);
|
||||
--td-bg-color-container-select: var(--td-gray-color-9);
|
||||
--td-bg-color-secondarycontainer: var(--td-gray-color-12);
|
||||
--td-bg-color-secondarycontainer-hover: var(--td-gray-color-11);
|
||||
--td-bg-color-secondarycontainer-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component: var(--td-gray-color-11);
|
||||
--td-bg-color-component-hover: var(--td-gray-color-10);
|
||||
--td-bg-color-component-active: var(--td-gray-color-9);
|
||||
--td-bg-color-component-disabled: var(--td-gray-color-12);
|
||||
--td-component-stroke: var(--td-gray-color-11);
|
||||
--td-component-border: var(--td-gray-color-9);
|
||||
--td-font-white-1: rgba(255, 255, 255, 0.9);
|
||||
--td-font-white-2: rgba(255, 255, 255, 0.55);
|
||||
--td-font-white-3: rgba(255, 255, 255, 0.35);
|
||||
--td-font-white-4: rgba(255, 255, 255, 0.22);
|
||||
--td-font-gray-1: rgba(0, 0, 0, 0.9);
|
||||
--td-font-gray-2: rgba(0, 0, 0, 0.6);
|
||||
--td-font-gray-3: rgba(0, 0, 0, 0.4);
|
||||
--td-font-gray-4: rgba(0, 0, 0, 0.26);
|
||||
--td-text-color-primary: var(--td-font-white-1);
|
||||
--td-text-color-secondary: var(--td-font-white-2);
|
||||
--td-text-color-placeholder: var(--td-font-white-3);
|
||||
--td-text-color-disabled: var(--td-font-white-4);
|
||||
--td-text-color-anti: #fff;
|
||||
--td-text-color-brand: var(--td-brand-color);
|
||||
--td-text-color-link: var(--td-brand-color);
|
||||
--td-shadow-1: 0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
--td-shadow-2: 0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.10), 0 5px 5px rgba(0, 0, 0, 0.16);
|
||||
--td-shadow-3: 0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.20);
|
||||
--td-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
--td-shadow-inset-bottom: inset 0 -0.5px 0 #5e5e5e;
|
||||
--td-shadow-inset-left: inset -0.5px 0 0 #5e5e5e;
|
||||
--td-table-shadow-color: rgba(0, 0, 0, 55%);
|
||||
--td-scrollbar-color: rgba(255, 255, 255, 10%);
|
||||
--td-scrollbar-hover-color: rgba(255, 255, 255, 30%);
|
||||
--td-scroll-track-color: #333;
|
||||
--td-bg-color-specialcomponent: transparent;
|
||||
--td-border-level-1-color: var(--td-gray-color-11);
|
||||
--td-border-level-2-color: var(--td-gray-color-9);
|
||||
--td-mask-active: rgba(0, 0, 0, 0.4);
|
||||
--td-mask-disabled: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
:root {
|
||||
--td-font-family: pingfang sc, microsoft yahei, arial regular;
|
||||
--td-font-family-medium: pingfang sc, microsoft yahei, arial medium;
|
||||
--td-font-size-link-small: 12px;
|
||||
--td-font-size-link-medium: 14px;
|
||||
--td-font-size-link-large: 16px;
|
||||
--td-font-size-mark-small: 12px;
|
||||
--td-font-size-mark-medium: 14px;
|
||||
--td-font-size-body-small: 12px;
|
||||
--td-font-size-body-medium: 14px;
|
||||
--td-font-size-body-large: 16px;
|
||||
--td-font-size-title-small: 14px;
|
||||
--td-font-size-title-medium: 16px;
|
||||
--td-font-size-title-large: 20px;
|
||||
--td-font-size-headline-small: 24px;
|
||||
--td-font-size-headline-medium: 28px;
|
||||
--td-font-size-headline-large: 36px;
|
||||
--td-font-size-display-medium: 48px;
|
||||
--td-font-size-display-large: 64px;
|
||||
--td-line-height-link-small: 20px;
|
||||
--td-line-height-link-medium: 22px;
|
||||
--td-line-height-link-large: 24px;
|
||||
--td-line-height-mark-small: 20px;
|
||||
--td-line-height-mark-medium: 22px;
|
||||
--td-line-height-body-small: 20px;
|
||||
--td-line-height-body-medium: 22px;
|
||||
--td-line-height-body-large: 24px;
|
||||
--td-line-height-title-small: 22px;
|
||||
--td-line-height-title-medium: 24px;
|
||||
--td-line-height-title-large: 28px;
|
||||
--td-line-height-headline-small: 32px;
|
||||
--td-line-height-headline-medium: 36px;
|
||||
--td-line-height-headline-large: 44px;
|
||||
--td-line-height-display-medium: 56px;
|
||||
--td-line-height-display-large: 72px;
|
||||
--td-font-link-small: var(--td-font-size-link-small) / var(--td-line-height-link-small) var(--td-font-family);
|
||||
--td-font-link-medium: var(--td-font-size-link-medium) / var(--td-line-height-link-medium) var(--td-font-family);
|
||||
--td-font-link-large: var(--td-font-size-link-large) / var(--td-line-height-link-large) var(--td-font-family);
|
||||
--td-font-mark-small: 600 var(--td-font-size-mark-small) / var(--td-line-height-mark-small) var(--td-font-family);
|
||||
--td-font-mark-medium: 600 var(--td-font-size-mark-medium) / var(--td-line-height-mark-medium) var(--td-font-family);
|
||||
--td-font-body-small: var(--td-font-size-body-small) / var(--td-line-height-body-small) var(--td-font-family);
|
||||
--td-font-body-medium: var(--td-font-size-body-medium) / var(--td-line-height-body-medium) var(--td-font-family);
|
||||
--td-font-body-large: var(--td-font-size-body-large) / var(--td-line-height-body-large) var(--td-font-family);
|
||||
--td-font-title-small: 600 var(--td-font-size-title-small) / var(--td-line-height-title-small) var(--td-font-family);
|
||||
--td-font-title-medium: 600 var(--td-font-size-title-medium) / var(--td-line-height-title-medium) var(--td-font-family);
|
||||
--td-font-title-large: 600 var(--td-font-size-title-large) / var(--td-line-height-title-large) var(--td-font-family);
|
||||
--td-font-headline-small: 600 var(--td-font-size-headline-small) / var(--td-line-height-headline-small) var(--td-font-family);
|
||||
--td-font-headline-medium: 600 var(--td-font-size-headline-medium) / var(--td-line-height-headline-medium) var(--td-font-family);
|
||||
--td-font-headline-large: 600 var(--td-font-size-headline-large) / var(--td-line-height-headline-large) var(--td-font-family);
|
||||
--td-font-display-medium: 600 var(--td-font-size-display-medium) / var(--td-line-height-display-medium) var(--td-font-family);
|
||||
--td-font-display-large: 600 var(--td-font-size-display-large) / var(--td-line-height-display-large) var(--td-font-family);
|
||||
--td-radius-small: 2px;
|
||||
--td-radius-default: 3px;
|
||||
--td-radius-medium: 6px;
|
||||
--td-radius-large: 9px;
|
||||
--td-radius-extraLarge: 12px;
|
||||
--td-radius-round: 999px;
|
||||
--td-radius-circle: 50%;
|
||||
--td-size-1: 2px;
|
||||
--td-size-2: 4px;
|
||||
--td-size-3: 6px;
|
||||
--td-size-4: 8px;
|
||||
--td-size-5: 12px;
|
||||
--td-size-6: 16px;
|
||||
--td-size-7: 20px;
|
||||
--td-size-8: 24px;
|
||||
--td-size-9: 28px;
|
||||
--td-size-10: 32px;
|
||||
--td-size-11: 36px;
|
||||
--td-size-12: 40px;
|
||||
--td-size-13: 48px;
|
||||
--td-size-14: 56px;
|
||||
--td-size-15: 64px;
|
||||
--td-size-16: 72px;
|
||||
--td-comp-size-xxxs: var(--td-size-6);
|
||||
--td-comp-size-xxs: var(--td-size-7);
|
||||
--td-comp-size-xs: var(--td-size-8);
|
||||
--td-comp-size-s: var(--td-size-9);
|
||||
--td-comp-size-m: var(--td-size-10);
|
||||
--td-comp-size-l: var(--td-size-11);
|
||||
--td-comp-size-xl: var(--td-size-12);
|
||||
--td-comp-size-xxl: var(--td-size-13);
|
||||
--td-comp-size-xxxl: var(--td-size-14);
|
||||
--td-comp-size-xxxxl: var(--td-size-15);
|
||||
--td-comp-size-xxxxxl: var(--td-size-16);
|
||||
--td-pop-padding-s: var(--td-size-2);
|
||||
--td-pop-padding-m: var(--td-size-3);
|
||||
--td-pop-padding-l: var(--td-size-4);
|
||||
--td-pop-padding-xl: var(--td-size-5);
|
||||
--td-pop-padding-xxl: var(--td-size-6);
|
||||
--td-comp-paddingLR-xxs: var(--td-size-1);
|
||||
--td-comp-paddingLR-xs: var(--td-size-2);
|
||||
--td-comp-paddingLR-s: var(--td-size-4);
|
||||
--td-comp-paddingLR-m: var(--td-size-5);
|
||||
--td-comp-paddingLR-l: var(--td-size-6);
|
||||
--td-comp-paddingLR-xl: var(--td-size-8);
|
||||
--td-comp-paddingLR-xxl: var(--td-size-10);
|
||||
--td-comp-paddingTB-xxs: var(--td-size-1);
|
||||
--td-comp-paddingTB-xs: var(--td-size-2);
|
||||
--td-comp-paddingTB-s: var(--td-size-4);
|
||||
--td-comp-paddingTB-m: var(--td-size-5);
|
||||
--td-comp-paddingTB-l: var(--td-size-6);
|
||||
--td-comp-paddingTB-xl: var(--td-size-8);
|
||||
--td-comp-paddingTB-xxl: var(--td-size-10);
|
||||
--td-comp-margin-xxs: var(--td-size-1);
|
||||
--td-comp-margin-xs: var(--td-size-2);
|
||||
--td-comp-margin-s: var(--td-size-4);
|
||||
--td-comp-margin-m: var(--td-size-5);
|
||||
--td-comp-margin-l: var(--td-size-6);
|
||||
--td-comp-margin-xl: var(--td-size-7);
|
||||
--td-comp-margin-xxl: var(--td-size-8);
|
||||
--td-comp-margin-xxxl: var(--td-size-10);
|
||||
--td-comp-margin-xxxxl: var(--td-size-12);
|
||||
}
|
||||
632
src/renderer/src/components/Music/SongVirtualList.vue
Normal file
632
src/renderer/src/components/Music/SongVirtualList.vue
Normal file
@@ -0,0 +1,632 @@
|
||||
<template>
|
||||
<div class="song-virtual-list">
|
||||
<!-- 表头 -->
|
||||
<div class="list-header">
|
||||
<div class="col-index" v-if="showIndex"></div>
|
||||
<div class="col-title">标题</div>
|
||||
<div class="col-album" v-if="showAlbum">专辑</div>
|
||||
<div class="col-like">喜欢</div>
|
||||
<div class="col-duration" v-if="showDuration">时长</div>
|
||||
</div>
|
||||
|
||||
<!-- 虚拟滚动容器 -->
|
||||
<div ref="scrollContainer" class="virtual-scroll-container" @scroll="onScroll">
|
||||
<div class="virtual-scroll-spacer" :style="{ height: totalHeight + 'px' }">
|
||||
<div class="virtual-scroll-content" :style="{ transform: `translateY(${offsetY}px)` }">
|
||||
<div
|
||||
v-for="(song, index) in visibleItems"
|
||||
:key="song.id || song.songmid"
|
||||
class="song-item"
|
||||
@mouseenter="hoveredSong = song.id || song.songmid"
|
||||
@mouseleave="hoveredSong = null"
|
||||
>
|
||||
<!-- 序号或播放状态图标 -->
|
||||
<div class="col-index" v-if="showIndex">
|
||||
<span v-if="hoveredSong !== (song.id || song.songmid)" class="track-number">
|
||||
{{ String(visibleStartIndex + index + 1).padStart(2, '0') }}
|
||||
</span>
|
||||
<button v-else class="play-btn" title="播放" @click.stop="handlePlay(song)">
|
||||
<i class="icon-play"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 歌曲信息 -->
|
||||
<div class="col-title" @dblclick="handleAddToPlaylist(song)">
|
||||
<div v-if="song.img" class="song-cover">
|
||||
<img :src="song.img" loading="lazy" alt="封面" />
|
||||
</div>
|
||||
<div class="song-info">
|
||||
<div class="song-title" :title="song.name">{{ song.name }}</div>
|
||||
<div class="song-artist" :title="song.singer">
|
||||
<span v-if="song.types && song.types.length > 0" class="quality-tag">
|
||||
{{ getQualityDisplayName(song.types[song.types.length - 1]) }}
|
||||
</span>
|
||||
{{ song.singer }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 专辑信息 -->
|
||||
<div class="col-album" v-if="showAlbum">
|
||||
<span class="album-name" :title="song.albumName">
|
||||
{{ song.albumName || '-' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 喜欢按钮 -->
|
||||
<div class="col-like">
|
||||
<button class="action-btn like-btn" @click.stop>
|
||||
<i class="icon-heart"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 时长 -->
|
||||
<div class="col-duration" v-if="showDuration">
|
||||
<div class="duration-wrapper">
|
||||
<span v-if="hoveredSong !== (song.id || song.songmid)" class="duration">
|
||||
{{ formatDuration(song.interval) }}
|
||||
</span>
|
||||
<div v-else class="action-buttons">
|
||||
<button
|
||||
class="action-btn download-btn"
|
||||
title="下载"
|
||||
@click.stop="$emit('download', song)"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</button>
|
||||
<button
|
||||
class="action-btn playlist-btn"
|
||||
title="添加到播放列表"
|
||||
@click.stop="$emit('addToPlaylist', song)"
|
||||
>
|
||||
<i class="iconfont icon-zengjia"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||
import { DownloadIcon } from 'tdesign-icons-vue-next'
|
||||
|
||||
interface Song {
|
||||
id?: number
|
||||
songmid: number
|
||||
singer: string
|
||||
name: string
|
||||
albumName: string
|
||||
albumId: number
|
||||
source: string
|
||||
interval: string | number
|
||||
img: string
|
||||
lrc: null | string
|
||||
types: any[]
|
||||
_types: Record<string, any>
|
||||
typeUrl: Record<string, any>
|
||||
}
|
||||
|
||||
interface Props {
|
||||
songs: Song[]
|
||||
currentSong?: Song | null
|
||||
isPlaying?: boolean
|
||||
showIndex?: boolean
|
||||
showAlbum?: boolean
|
||||
showDuration?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
currentSong: null,
|
||||
isPlaying: false,
|
||||
showIndex: true,
|
||||
showAlbum: true,
|
||||
showDuration: true
|
||||
})
|
||||
|
||||
const emit = defineEmits(['play', 'pause', 'addToPlaylist', 'download','scroll'])
|
||||
|
||||
// 虚拟滚动相关状态
|
||||
const scrollContainer = ref<HTMLElement>()
|
||||
const hoveredSong = ref<number | null>(null)
|
||||
const itemHeight = 64
|
||||
const buffer = 5
|
||||
|
||||
const scrollTop = ref(0)
|
||||
const visibleStartIndex = ref(0)
|
||||
const visibleEndIndex = ref(0)
|
||||
|
||||
// 计算总高度
|
||||
const totalHeight = computed(() => props.songs.length * itemHeight)
|
||||
|
||||
// 计算偏移量
|
||||
const offsetY = computed(() => visibleStartIndex.value * itemHeight)
|
||||
|
||||
// 计算可见项目
|
||||
const visibleItems = computed(() => {
|
||||
const totalItems = props.songs.length
|
||||
if (totalItems === 0) return []
|
||||
|
||||
if (!scrollContainer.value) return props.songs.slice(0, Math.min(10, totalItems))
|
||||
|
||||
const containerRect = scrollContainer.value.getBoundingClientRect()
|
||||
const containerHeight = containerRect.height || 400
|
||||
|
||||
const visibleCount = Math.ceil(containerHeight / itemHeight)
|
||||
const startIndex = Math.floor(scrollTop.value / itemHeight)
|
||||
const endIndex = Math.min(startIndex + visibleCount + buffer * 2, totalItems)
|
||||
|
||||
visibleStartIndex.value = Math.max(0, startIndex - buffer)
|
||||
visibleEndIndex.value = endIndex
|
||||
|
||||
return props.songs.slice(visibleStartIndex.value, visibleEndIndex.value)
|
||||
})
|
||||
|
||||
// 判断是否为当前歌曲
|
||||
const isCurrentSong = (song: Song) => {
|
||||
return (
|
||||
props.currentSong &&
|
||||
(song.id === props.currentSong.id || song.songmid === props.currentSong.songmid)
|
||||
)
|
||||
}
|
||||
|
||||
// 处理播放
|
||||
const handlePlay = (song: Song) => {
|
||||
if (isCurrentSong(song) && props.isPlaying) {
|
||||
emit('pause')
|
||||
} else {
|
||||
emit('play', song)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理添加到播放列表
|
||||
const handleAddToPlaylist = (song: Song) => {
|
||||
emit('addToPlaylist', song)
|
||||
}
|
||||
|
||||
// 格式化时长
|
||||
const formatDuration = (duration: string | number) => {
|
||||
if (!duration) return '--:--'
|
||||
|
||||
let seconds: number
|
||||
if (typeof duration === 'string') {
|
||||
// 如果已经是 "mm:ss" 格式,直接返回
|
||||
if (duration.includes(':')) return duration
|
||||
seconds = parseInt(duration)
|
||||
} else {
|
||||
seconds = duration
|
||||
}
|
||||
|
||||
if (isNaN(seconds)) return '--:--'
|
||||
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const remainingSeconds = Math.floor(seconds % 60)
|
||||
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// 获取音质显示名称
|
||||
const qualityMap: Record<string, string> = {
|
||||
'128k': '标准',
|
||||
'192k': '高品',
|
||||
'320k': '超高',
|
||||
flac: '无损',
|
||||
flac24bit: '超高解析',
|
||||
hires: '高清',
|
||||
atmos: '全景',
|
||||
master: '母带'
|
||||
}
|
||||
|
||||
const getQualityDisplayName = (quality: any) => {
|
||||
if (typeof quality === 'object' && quality.type) {
|
||||
return qualityMap[quality.type] || quality.type
|
||||
}
|
||||
return qualityMap[quality] || quality || ''
|
||||
}
|
||||
|
||||
// 处理滚动事件
|
||||
const onScroll = (event: Event) => {
|
||||
const target = event.target as HTMLElement
|
||||
scrollTop.value = target.scrollTop
|
||||
emit('scroll', event)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 组件挂载后触发一次重新计算
|
||||
nextTick(() => {
|
||||
if (scrollContainer.value) {
|
||||
// 触发一次重新计算可见项目
|
||||
const event = new Event('scroll')
|
||||
onScroll(event)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.song-virtual-list {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr 200px 60px 80px;
|
||||
padding: 8px 20px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
flex-shrink: 0;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
|
||||
.col-index {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.col-album {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.col-like {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.col-duration {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-scroll-container {
|
||||
background: #fff;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.virtual-scroll-spacer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.virtual-scroll-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.song-item {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr 200px 60px 80px;
|
||||
padding: 8px 20px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
height: 64px;
|
||||
|
||||
&:hover,
|
||||
&.is-hovered {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
&.is-current {
|
||||
background: #f0f7ff;
|
||||
color: #507daf;
|
||||
}
|
||||
|
||||
&.is-playing {
|
||||
background: #e6f7ff;
|
||||
color: #507daf;
|
||||
}
|
||||
|
||||
.col-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60px;
|
||||
|
||||
.track-number {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
font-variant-numeric: tabular-nums;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #507daf;
|
||||
font-size: 16px;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-style: none;
|
||||
&:hover {
|
||||
background: rgba(80, 125, 175, 0.1);
|
||||
color: #3a5d8f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: block;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 10px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.song-cover {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.song-info {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
|
||||
.song-title {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.2;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
}
|
||||
}
|
||||
|
||||
.song-artist {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.quality-tag {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
padding: 1px 4px;
|
||||
border-radius: 2px;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-album {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.album-name {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-like {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60px;
|
||||
|
||||
.like-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
background: rgba(80, 125, 175, 0.1);
|
||||
}
|
||||
|
||||
i {
|
||||
display: block;
|
||||
line-height: 1;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-duration {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80px;
|
||||
|
||||
.duration-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
||||
.duration {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
font-variant-numeric: tabular-nums;
|
||||
min-width: 35px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.action-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
padding: 6px;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
background: rgba(80, 125, 175, 0.1);
|
||||
}
|
||||
|
||||
i {
|
||||
display: block;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 图标样式 */
|
||||
.icon-play::before {
|
||||
content: '▶';
|
||||
font-style: normal;
|
||||
}
|
||||
.icon-pause::before {
|
||||
content: '⏸';
|
||||
font-style: normal;
|
||||
}
|
||||
.icon-download::before {
|
||||
content: '⬇';
|
||||
font-style: normal;
|
||||
}
|
||||
.icon-heart::before {
|
||||
content: '♡';
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.list-header {
|
||||
grid-template-columns: 50px 1fr 50px 60px;
|
||||
|
||||
.col-album {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.song-item {
|
||||
grid-template-columns: 50px 1fr 50px 60px;
|
||||
|
||||
.col-album {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
.song-cover {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
.col-index {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.col-like {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.col-duration {
|
||||
width: 60px;
|
||||
|
||||
.duration-wrapper {
|
||||
.action-buttons {
|
||||
gap: 2px;
|
||||
|
||||
.action-btn {
|
||||
padding: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -10,23 +10,20 @@ import {
|
||||
} from '@applemusic-like-lyrics/vue'
|
||||
import type { SongList } from '@renderer/types/audio'
|
||||
import type { LyricLine } from '@applemusic-like-lyrics/core'
|
||||
import { ref, computed, onMounted, watch, reactive, onBeforeUnmount } from 'vue'
|
||||
import { ref, computed, onMounted, watch, reactive, onBeforeUnmount, toRaw } from 'vue'
|
||||
import { shouldUseBlackText } from '@renderer/utils/contrastColor'
|
||||
import { ControlAudioStore } from '@renderer/store/ControlAudio'
|
||||
import { Fullscreen1Icon, FullscreenExit1Icon, ChevronDownIcon } from 'tdesign-icons-vue-next'
|
||||
// 导入歌词请求函数
|
||||
import musicService from '@renderer/services/music'
|
||||
// 直接从包路径导入,避免 WebAssembly 导入问题
|
||||
import { parseYrc, parseLrc, parseTTML } from '@applemusic-like-lyrics/lyric/pkg/amll_lyric.js'
|
||||
|
||||
import _ from 'lodash'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
|
||||
interface Props {
|
||||
show?: boolean
|
||||
coverImage?: string
|
||||
songId?: string|null
|
||||
songInfo: SongList|{songmid:number|null}
|
||||
songId?: string | null
|
||||
songInfo: SongList | { songmid: number | null }
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -53,8 +50,6 @@ const toggleFullscreen = () => {
|
||||
onMounted(async () => {
|
||||
// 添加事件监听器检测全屏状态变化
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||||
|
||||
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -88,46 +83,86 @@ const state = reactive({
|
||||
watch(
|
||||
() => props.songId,
|
||||
async (newId) => {
|
||||
if (!newId) return
|
||||
if (!newId || !props.songInfo) return
|
||||
let lyricText = ''
|
||||
let parsedLyrics: LyricLine[] = []
|
||||
// 创建一个符合 MusicItem 接口的对象,只包含必要的基本属性
|
||||
|
||||
try {
|
||||
// 请求歌词数据,设置yv=true获取逐字歌词
|
||||
try {
|
||||
const res = (await (
|
||||
await fetch(`https://amll.bikonoo.com/ncm-lyrics/${newId}.ttml`)
|
||||
).text()) as any
|
||||
if (!res || res.length < 100) throw new Error('ttml 无歌词')
|
||||
parsedLyrics = parseTTML(res).lines
|
||||
console.log('搜索到ttml歌词', parsedLyrics)
|
||||
} catch {
|
||||
const lyricData = await musicService.request('getLyric', {
|
||||
id: newId,
|
||||
yv: true,
|
||||
lv: true,
|
||||
tv: true
|
||||
})
|
||||
console.log(lyricData)
|
||||
// 优先使用逐字歌词(yrc),如果没有则回退到普通歌词(lrc)
|
||||
// 检查是否为网易云音乐,只有网易云才使用ttml接口
|
||||
const isNetease =
|
||||
props.songInfo && 'source' in props.songInfo && props.songInfo.source === 'wy'
|
||||
const songinfo: any = _.cloneDeep(toRaw(props.songInfo))
|
||||
console.log(songinfo)
|
||||
if (isNetease) {
|
||||
// 网易云音乐优先尝试ttml接口
|
||||
try {
|
||||
const res = (await (
|
||||
await fetch(`https://amll.bikonoo.com/ncm-lyrics/${newId}.ttml`)
|
||||
).text()) as any
|
||||
if (!res || res.length < 100) throw new Error('ttml 无歌词')
|
||||
parsedLyrics = parseTTML(res).lines
|
||||
console.log('搜索到ttml歌词', parsedLyrics)
|
||||
} catch {
|
||||
// ttml失败后使用新的歌词API
|
||||
const lyricData = await window.api.music.requestSdk('getLyric', {
|
||||
source: 'wy',
|
||||
songInfo: songinfo
|
||||
})
|
||||
console.log('网易云歌词数据:', lyricData)
|
||||
|
||||
if (lyricData.yrc?.lyric) {
|
||||
lyricText = lyricData.yrc.lyric
|
||||
parsedLyrics = parseYrc(lyricText)
|
||||
console.log('使用逐字歌词', parsedLyrics)
|
||||
} else if (lyricData.lrc?.lyric) {
|
||||
lyricText = lyricData.lrc.lyric
|
||||
parsedLyrics = parseLrc(lyricText)
|
||||
console.log('使用普通歌词', parsedLyrics)
|
||||
}
|
||||
if (lyricData.tlyric && lyricData.tlyric.lyric) {
|
||||
const translatedline = parseLrc(lyricData.tlyric.lyric)
|
||||
console.log(translatedline)
|
||||
for (let i = 0; i < parsedLyrics.length; i++) {
|
||||
parsedLyrics[i].translatedLyric = translatedline[i].words[0].word
|
||||
if (lyricData.crlyric) {
|
||||
// 使用逐字歌词
|
||||
lyricText = lyricData.crlyric
|
||||
console.log('网易云逐字歌词', lyricText)
|
||||
parsedLyrics = parseYrc(lyricText)
|
||||
console.log('使用网易云逐字歌词', parsedLyrics)
|
||||
} else if (lyricData.lyric) {
|
||||
lyricText = lyricData.lyric
|
||||
parsedLyrics = parseLrc(lyricText)
|
||||
console.log('使用网易云普通歌词', parsedLyrics)
|
||||
}
|
||||
|
||||
if (lyricData.tlyric) {
|
||||
const translatedline = parseLrc(lyricData.tlyric)
|
||||
console.log('网易云翻译歌词:', translatedline)
|
||||
for (let i = 0; i < parsedLyrics.length; i++) {
|
||||
if (translatedline[i] && translatedline[i].words[0]) {
|
||||
parsedLyrics[i].translatedLyric = translatedline[i].words[0].word
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他音乐平台直接使用新的歌词API
|
||||
const source = props.songInfo && 'source' in props.songInfo ? props.songInfo.source : 'kg'
|
||||
// 创建一个纯净的对象,避免Vue响应式对象序列化问题
|
||||
const cleanSongInfo = JSON.parse(JSON.stringify(toRaw(props.songInfo)))
|
||||
const lyricData = await window.api.music.requestSdk('getLyric', {
|
||||
source: source,
|
||||
songInfo: cleanSongInfo
|
||||
})
|
||||
console.log(`${source}歌词数据:`, lyricData)
|
||||
|
||||
if (lyricData.crlyric) {
|
||||
// 使用逐字歌词
|
||||
lyricText = lyricData.crlyric
|
||||
parsedLyrics = parseYrc(lyricText)
|
||||
console.log(`使用${source}逐字歌词`, parsedLyrics)
|
||||
} else if (lyricData.lyric) {
|
||||
lyricText = lyricData.lyric
|
||||
parsedLyrics = parseLrc(lyricText)
|
||||
console.log(`使用${source}普通歌词`, parsedLyrics)
|
||||
}
|
||||
|
||||
if (lyricData.tlyric) {
|
||||
const translatedline = parseLrc(lyricData.tlyric)
|
||||
console.log(`${source}翻译歌词:`, translatedline)
|
||||
for (let i = 0; i < parsedLyrics.length; i++) {
|
||||
if (translatedline[i] && translatedline[i].words[0]) {
|
||||
parsedLyrics[i].translatedLyric = translatedline[i].words[0].word
|
||||
}
|
||||
}
|
||||
console.log('使用翻译歌词', translatedline)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,20 +247,39 @@ watch(
|
||||
<template>
|
||||
<div class="full-play" :class="{ active: props.show, 'use-black-text': useBlackText }">
|
||||
<!-- <ShaderBackground :cover-image="actualCoverImage" /> -->
|
||||
<BackgroundRender ref="bgRef" :album="actualCoverImage" :album-is-video="false" :fps="30" :flow-speed="4"
|
||||
:low-freq-volume="1" :has-lyric="state.lyricLines.length > 10"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1" />
|
||||
<BackgroundRender
|
||||
ref="bgRef"
|
||||
:album="actualCoverImage"
|
||||
:album-is-video="false"
|
||||
:fps="30"
|
||||
:flow-speed="4"
|
||||
:low-freq-volume="1"
|
||||
:has-lyric="state.lyricLines.length > 10"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1"
|
||||
/>
|
||||
<!-- 全屏按钮 -->
|
||||
<button class="fullscreen-btn" :class="{ 'black-text': useBlackText }" @click="toggleFullscreen">
|
||||
<button
|
||||
class="fullscreen-btn"
|
||||
:class="{ 'black-text': useBlackText }"
|
||||
@click="toggleFullscreen"
|
||||
>
|
||||
<Fullscreen1Icon v-if="!isFullscreen" class="icon" />
|
||||
<FullscreenExit1Icon v-else class="icon" />
|
||||
</button>
|
||||
<button class="putawayscreen-btn" :class="{ 'black-text': useBlackText }" @click="emit('toggle-fullscreen')">
|
||||
<button
|
||||
class="putawayscreen-btn"
|
||||
:class="{ 'black-text': useBlackText }"
|
||||
@click="emit('toggle-fullscreen')"
|
||||
>
|
||||
<ChevronDownIcon class="icon" />
|
||||
</button>
|
||||
<Transition name="fade-nav">
|
||||
<TitleBarControls v-if="props.show" class="top" style="-webkit-app-region: drag"
|
||||
:color="useBlackText ? 'black' : 'white'" />
|
||||
<TitleBarControls
|
||||
v-if="props.show"
|
||||
class="top"
|
||||
style="-webkit-app-region: drag"
|
||||
:color="useBlackText ? 'black' : 'white'"
|
||||
/>
|
||||
</Transition>
|
||||
<div class="playbox">
|
||||
<!-- 播放控件内容
|
||||
@@ -234,27 +288,43 @@ watch(
|
||||
<p>这里将显示歌曲信息</p>
|
||||
</div> -->
|
||||
<div class="left" :style="state.lyricLines.length <= 0 && 'width:100vw'">
|
||||
<div class="box" :style="!Audio.isPlay
|
||||
? 'animation-play-state: paused;'
|
||||
: '' +
|
||||
(state.lyricLines.length <= 0
|
||||
? 'width:70vh;height:70vh; transition: width 0.3s ease, height 0.3s ease; transition-delay: 0.8s;'
|
||||
: '')
|
||||
">
|
||||
<t-image :src="coverImage" :style="state.lyricLines.length > 0
|
||||
? 'width: min(20vw, 380px); height: min(20vw, 380px)'
|
||||
: 'width: 45vh; height: 45vh;transition: width 0.3s ease, height 0.3s ease; transition-delay: 1s;'
|
||||
" shape="circle" class="cover" />
|
||||
<div
|
||||
class="box"
|
||||
:style="
|
||||
!Audio.isPlay
|
||||
? 'animation-play-state: paused;'
|
||||
: '' +
|
||||
(state.lyricLines.length <= 0
|
||||
? 'width:70vh;height:70vh; transition: width 0.3s ease, height 0.3s ease; transition-delay: 0.8s;'
|
||||
: '')
|
||||
"
|
||||
>
|
||||
<t-image
|
||||
:src="coverImage"
|
||||
:style="
|
||||
state.lyricLines.length > 0
|
||||
? 'width: min(20vw, 380px); height: min(20vw, 380px)'
|
||||
: 'width: 45vh; height: 45vh;transition: width 0.3s ease, height 0.3s ease; transition-delay: 1s;'
|
||||
"
|
||||
shape="circle"
|
||||
class="cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="state.lyricLines.length > 0" class="right">
|
||||
<LyricPlayer ref="lyricPlayerRef" :lyric-lines="props.show ? state.lyricLines : []"
|
||||
:current-time="state.currentTime" :align-position="0.38" style="mix-blend-mode: plus-lighter"
|
||||
class="lyric-player" @line-click="
|
||||
<LyricPlayer
|
||||
ref="lyricPlayerRef"
|
||||
:lyric-lines="props.show ? state.lyricLines : []"
|
||||
:current-time="state.currentTime"
|
||||
:align-position="0.38"
|
||||
style="mix-blend-mode: plus-lighter"
|
||||
class="lyric-player"
|
||||
@line-click="
|
||||
(e) => {
|
||||
if (Audio.audio) Audio.audio.currentTime = e.line.getLine().startTime / 1000
|
||||
}
|
||||
">
|
||||
"
|
||||
>
|
||||
<template #bottom-line> Test Bottom Line </template>
|
||||
</LyricPlayer>
|
||||
</div>
|
||||
@@ -364,7 +434,7 @@ watch(
|
||||
position: relative;
|
||||
|
||||
:deep(.lyric-player) {
|
||||
--amll-lyric-player-font-size: max(2vw, 38px);
|
||||
--amll-lyric-player-font-size: max(2vw, 29px);
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -59,6 +59,7 @@ onDeactivated(() => {
|
||||
const handleEnded = (): void => {
|
||||
audioStore.Audio.isPlay = false
|
||||
audioStore.publish('ended')
|
||||
console.log('eddddddddd')
|
||||
}
|
||||
|
||||
const handleSeeked = (): void => {
|
||||
|
||||
@@ -223,7 +223,7 @@ const playSong = async (song: SongList) => {
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('播放歌曲失败:', error)
|
||||
MessagePlugin.error('播放失败,原因:'+error.message)
|
||||
MessagePlugin.error('播放失败,原因:' + error.message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ const playNext = async () => {
|
||||
|
||||
// 定期保存当前播放位置
|
||||
let savePositionInterval: number | null = null
|
||||
|
||||
let unEnded:()=>any = ()=>{}
|
||||
// 初始化播放器
|
||||
onMounted(async () => {
|
||||
console.log('加载')
|
||||
@@ -420,8 +420,10 @@ onMounted(async () => {
|
||||
initPlaylistEventListeners(localUserStore, playSong)
|
||||
|
||||
// 监听音频结束事件,根据播放模式播放下一首
|
||||
controlAudio.subscribe('ended', () => {
|
||||
playNext()
|
||||
unEnded = controlAudio.subscribe('ended', () => {
|
||||
window.requestAnimationFrame(()=>{
|
||||
playNext()
|
||||
})
|
||||
})
|
||||
|
||||
// 检查是否有上次播放的歌曲
|
||||
@@ -471,6 +473,7 @@ onUnmounted(() => {
|
||||
if (savePositionInterval !== null) {
|
||||
clearInterval(savePositionInterval)
|
||||
}
|
||||
unEnded()
|
||||
})
|
||||
|
||||
// 组件被激活时(从缓存中恢复)
|
||||
@@ -664,7 +667,7 @@ const handleProgressDragStart = (event: MouseEvent) => {
|
||||
}
|
||||
|
||||
// 歌曲信息
|
||||
const songInfo = ref<Omit<SongList,'songmid'>&{songmid:null|number}>({
|
||||
const songInfo = ref<Omit<SongList, 'songmid'> & { songmid: null | number }>({
|
||||
songmid: null,
|
||||
hash: '',
|
||||
singer: 'CeruMusic',
|
||||
@@ -805,7 +808,7 @@ watch(songInfo, setColor, { deep: true, immediate: true })
|
||||
</div>
|
||||
<div class="fullbox">
|
||||
<FullPlay
|
||||
:song-id="songInfo.songmid?songInfo.songmid.toString():null"
|
||||
:song-id="songInfo.songmid ? songInfo.songmid.toString() : null"
|
||||
:show="showFullPlay"
|
||||
:cover-image="songInfo.img"
|
||||
@toggle-fullscreen="toggleFullPlay"
|
||||
@@ -846,7 +849,13 @@ watch(songInfo, setColor, { deep: true, immediate: true })
|
||||
<div class="song-name">{{ song.name }}</div>
|
||||
<div class="song-artist">{{ song.singer }}</div>
|
||||
</div>
|
||||
<div class="song-duration">{{ song.interval.includes(':') ? song.interval : formatTime(parseInt(song.interval) / 1000) }}</div>
|
||||
<div class="song-duration">
|
||||
{{
|
||||
song.interval.includes(':')
|
||||
? song.interval
|
||||
: formatTime(parseInt(song.interval) / 1000)
|
||||
}}
|
||||
</div>
|
||||
<button class="song-remove" @click.stop="localUserStore.removeSong(song.songmid)">
|
||||
<span class="iconfont icon-xuanxiangshanchu"></span>
|
||||
</button>
|
||||
|
||||
161
src/renderer/src/components/README-ThemeSelector.md
Normal file
161
src/renderer/src/components/README-ThemeSelector.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# 主题切换组件使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
ThemeSelector 是一个现代化的主题切换组件,支持在多个预设主题色之间切换。组件与现有的 TDesign 主题系统完全兼容。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 支持多种预设主题色(默认、粉色、蓝色、青色、橙色)
|
||||
- ✅ 使用 `theme-mode` 属性实现主题切换
|
||||
- ✅ 自动保存用户选择到本地存储
|
||||
- ✅ 现代化的下拉选择界面
|
||||
- ✅ 平滑的过渡动画效果
|
||||
- ✅ 响应式设计,支持移动端
|
||||
- ✅ 与 TDesign 主题系统完全兼容
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 基本使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<!-- 在任何需要的地方使用主题切换器 -->
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ThemeSelector from '@/components/ThemeSelector.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 在导航栏中使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<header class="app-header">
|
||||
<h1>应用标题</h1>
|
||||
<div class="header-actions">
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 3. 在设置页面中使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="settings-page">
|
||||
<div class="setting-item">
|
||||
<label>主题色</label>
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 主题切换原理
|
||||
|
||||
组件通过以下方式实现主题切换:
|
||||
|
||||
1. **默认主题**: 移除 `theme-mode` 属性
|
||||
```javascript
|
||||
document.documentElement.removeAttribute('theme-mode')
|
||||
```
|
||||
|
||||
2. **其他主题**: 设置对应的 `theme-mode` 属性
|
||||
```javascript
|
||||
document.documentElement.setAttribute('theme-mode', 'pink')
|
||||
```
|
||||
|
||||
## 支持的主题
|
||||
|
||||
| 主题名称 | 属性值 | 主色调 |
|
||||
|---------|--------|--------|
|
||||
| 默认 | `default` | #57b4ff |
|
||||
| 粉色 | `pink` | #fc5e7e |
|
||||
| 蓝色 | `blue` | #57b4ff |
|
||||
| 青色 | `cyan` | #3ac2b8 |
|
||||
| 橙色 | `orange` | #fb9458 |
|
||||
|
||||
## 自定义配置
|
||||
|
||||
如果需要添加新的主题,请按以下步骤操作:
|
||||
|
||||
### 1. 创建主题CSS文件
|
||||
|
||||
在 `src/renderer/src/assets/theme/` 目录下创建新的主题文件,例如 `green.css`:
|
||||
|
||||
```css
|
||||
:root[theme-mode="green"] {
|
||||
--td-brand-color: #10b981;
|
||||
--td-brand-color-hover: #059669;
|
||||
/* 其他主题变量... */
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 更新组件配置
|
||||
|
||||
在 `ThemeSelector.vue` 中添加新主题:
|
||||
|
||||
```javascript
|
||||
const themes = [
|
||||
// 现有主题...
|
||||
{ name: 'green', label: '绿色', color: '#10b981' }
|
||||
]
|
||||
```
|
||||
|
||||
## 样式自定义
|
||||
|
||||
组件使用 TDesign 的 CSS 变量,可以通过覆盖这些变量来自定义样式:
|
||||
|
||||
```css
|
||||
.theme-selector {
|
||||
/* 自定义触发器样式 */
|
||||
--td-radius-medium: 8px;
|
||||
}
|
||||
|
||||
.theme-dropdown {
|
||||
/* 自定义下拉菜单样式 */
|
||||
--td-shadow-2: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
```
|
||||
|
||||
## 事件和回调
|
||||
|
||||
组件会自动处理主题切换和本地存储,无需额外配置。如果需要监听主题变化,可以监听 `localStorage` 的变化:
|
||||
|
||||
```javascript
|
||||
// 监听主题变化
|
||||
window.addEventListener('storage', (e) => {
|
||||
if (e.key === 'selected-theme') {
|
||||
console.log('主题已切换到:', e.newValue)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保项目中已引入对应的主题CSS文件
|
||||
2. 组件会自动加载用户上次选择的主题
|
||||
3. 主题切换是全局的,会影响整个应用
|
||||
4. 建议在应用的主入口处使用,避免重复渲染
|
||||
|
||||
## 演示组件
|
||||
|
||||
项目还包含一个 `ThemeDemo.vue` 组件,展示了主题切换的效果:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ThemeDemo />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ThemeDemo from '@/components/ThemeDemo.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
这个演示组件展示了不同UI元素在各种主题下的表现。
|
||||
54
src/renderer/src/components/Settings/MusicCache.vue
Normal file
54
src/renderer/src/components/Settings/MusicCache.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="music-cache">
|
||||
<t-card hover-shadow :loading="cacheInfo ? false : true" title="本地歌曲缓存配置">
|
||||
<template #actions>
|
||||
已有歌曲缓存大小:{{ cacheInfo.sizeFormatted }}
|
||||
</template>
|
||||
<div class="card-body">
|
||||
<t-button size="large" @click="clearCache">
|
||||
清除本地缓存
|
||||
</t-button>
|
||||
</div>
|
||||
</t-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { DialogPlugin } from 'tdesign-vue-next';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const cacheInfo: any = ref({})
|
||||
onMounted(() => {
|
||||
window.api.musicCache.getInfo().then(res => cacheInfo.value = res)
|
||||
})
|
||||
const clearCache = () => {
|
||||
const confirm = DialogPlugin.confirm({
|
||||
header: '确认清除缓存吗',
|
||||
body: '这可能会导致歌曲加载缓慢,你确定要清除所有缓存吗?',
|
||||
confirmBtn: '确定清除',
|
||||
cancelBtn: '我再想想',
|
||||
placement:'center',
|
||||
onClose: () => {
|
||||
confirm.hide()
|
||||
},
|
||||
onConfirm: async () => {
|
||||
confirm.hide()
|
||||
cacheInfo.value = {}
|
||||
await window.api.musicCache.clear()
|
||||
window.api.musicCache.getInfo().then(res => cacheInfo.value = res)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.music-cache {
|
||||
width: 100%;
|
||||
|
||||
.card-body {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -82,6 +82,7 @@ const handleImportFromFile = async () => {
|
||||
const importedPlaylist = await importPlaylistFromFile(uploadedFile.value)
|
||||
|
||||
if (!validateImportedPlaylist(importedPlaylist)) {
|
||||
console.log(importedPlaylist)
|
||||
throw new Error('导入的播放列表格式不正确')
|
||||
}
|
||||
|
||||
@@ -187,11 +188,14 @@ const updatePlaylistStats = () => {
|
||||
stats.totalDuration += duration / 1000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理歌手信息
|
||||
if (song.singer) {
|
||||
// 如果歌手名包含分隔符,分割处理
|
||||
const singers = song.singer.split(/[\/、&]/).map(s => s.trim()).filter(s => s)
|
||||
const singers = song.singer
|
||||
.split(/[\/、&]/)
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s)
|
||||
singers.forEach((singer) => stats.artists.add(singer))
|
||||
}
|
||||
})
|
||||
@@ -235,7 +239,7 @@ watch(
|
||||
<t-card title="播放列表统计" hover-shadow>
|
||||
<div class="stats-content">
|
||||
<div class="stat-item">
|
||||
<span class="iconfont icon-bofang"></span>
|
||||
<t-icon name="play" />
|
||||
<div class="stat-info">
|
||||
<div class="stat-label">歌曲数量</div>
|
||||
<div class="stat-value">{{ playlistStats.totalSongs }} 首</div>
|
||||
|
||||
195
src/renderer/src/components/ThemeDemo.vue
Normal file
195
src/renderer/src/components/ThemeDemo.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div class="theme-demo">
|
||||
<div class="demo-header">
|
||||
<h1 class="demo-title">主题切换演示</h1>
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
|
||||
<div class="demo-content">
|
||||
<div class="demo-card">
|
||||
<h3 class="card-title">主要功能</h3>
|
||||
<p class="card-text">这是一个现代化的主题切换组件,支持多种预设主题色。</p>
|
||||
<button class="btn btn-primary">主要按钮</button>
|
||||
</div>
|
||||
|
||||
<div class="demo-card">
|
||||
<h3 class="card-title">设计特点</h3>
|
||||
<ul class="feature-list">
|
||||
<li>简约美观的界面设计</li>
|
||||
<li>平滑的过渡动画效果</li>
|
||||
<li>响应式布局适配</li>
|
||||
<li>深色模式支持</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="demo-card">
|
||||
<h3 class="card-title">交互元素</h3>
|
||||
<div class="demo-controls">
|
||||
<input type="text" class="form-control" placeholder="输入框示例" />
|
||||
<button class="btn btn-secondary">次要按钮</button>
|
||||
<a href="#" class="demo-link">链接示例</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ThemeSelector from './ThemeSelector.vue'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.theme-demo {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--td-component-border);
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: var(--td-text-color-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
}
|
||||
|
||||
.demo-card {
|
||||
background: var(--td-bg-color-container);
|
||||
border: 1px solid var(--td-component-border);
|
||||
border-radius: var(--td-radius-large);
|
||||
padding: 24px;
|
||||
box-shadow: var(--td-shadow-1);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--td-text-color-primary);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
color: var(--td-text-color-secondary);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
color: var(--td-text-color-secondary);
|
||||
padding: 8px 0;
|
||||
position: relative;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.feature-list li::before {
|
||||
content: '•';
|
||||
color: var(--td-brand-color);
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.demo-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 16px;
|
||||
border-radius: var(--td-radius-medium);
|
||||
border: 1px solid transparent;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--td-brand-color);
|
||||
border-color: var(--td-brand-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--td-brand-color-hover);
|
||||
border-color: var(--td-brand-color-hover);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--td-bg-color-component);
|
||||
border-color: var(--td-component-border);
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--td-bg-color-component-hover);
|
||||
border-color: var(--td-component-border);
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--td-component-border);
|
||||
border-radius: var(--td-radius-medium);
|
||||
background-color: var(--td-bg-color-container);
|
||||
color: var(--td-text-color-primary);
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: var(--td-brand-color);
|
||||
box-shadow: 0 0 0 3px var(--td-brand-color-light);
|
||||
}
|
||||
|
||||
.demo-link {
|
||||
color: var(--td-brand-color);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.demo-link:hover {
|
||||
color: var(--td-brand-color-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.demo-header {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.demo-controls {
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
253
src/renderer/src/components/ThemeSelector.vue
Normal file
253
src/renderer/src/components/ThemeSelector.vue
Normal file
@@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<div class="theme-selector">
|
||||
<div class="theme-selector-trigger" @click="toggleDropdown">
|
||||
<div class="current-theme">
|
||||
<div class="theme-color-preview" :style="{ backgroundColor: currentThemeColor }"></div>
|
||||
<span class="theme-name">{{ currentThemeName }}</span>
|
||||
</div>
|
||||
<svg class="dropdown-icon" :class="{ 'rotated': isDropdownOpen }" viewBox="0 0 24 24" width="16" height="16">
|
||||
<path d="M7 10l5 5 5-5z" fill="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<transition name="dropdown">
|
||||
<div v-if="isDropdownOpen" class="theme-dropdown">
|
||||
<div
|
||||
v-for="theme in themes"
|
||||
:key="theme.name"
|
||||
class="theme-option"
|
||||
:class="{ 'active': currentTheme === theme.name }"
|
||||
@click="selectTheme(theme.name)"
|
||||
>
|
||||
<div class="theme-color-dot" :style="{ backgroundColor: theme.color }"></div>
|
||||
<span class="theme-label">{{ theme.label }}</span>
|
||||
<svg v-if="currentTheme === theme.name" class="check-icon" viewBox="0 0 24 24" width="16" height="16">
|
||||
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" fill="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
const isDropdownOpen = ref(false)
|
||||
const currentTheme = ref('default')
|
||||
|
||||
// 基于现有主题文件的配置
|
||||
const themes = [
|
||||
{ name: 'default', label: '默认', color: '#2ba55b' },
|
||||
{ name: 'pink', label: '粉色', color: '#fc5e7e' },
|
||||
{ name: 'blue', label: '蓝色', color: '#57b4ff' },
|
||||
{ name: 'cyan', label: '青色', color: '#3ac2b8' },
|
||||
{ name: 'orange', label: '橙色', color: '#fb9458' }
|
||||
]
|
||||
|
||||
const loadSavedTheme = () => {
|
||||
const savedTheme = localStorage.getItem('selected-theme')
|
||||
if (savedTheme && themes.some(t => t.name === savedTheme)) {
|
||||
currentTheme.value = savedTheme
|
||||
applyTheme(savedTheme)
|
||||
}
|
||||
}
|
||||
|
||||
const applyTheme = (themeName) => {
|
||||
const documentElement = document.documentElement
|
||||
|
||||
// 移除之前的主题
|
||||
documentElement.removeAttribute('theme-mode')
|
||||
|
||||
// 应用新主题(如果不是默认主题)
|
||||
if (themeName !== 'default') {
|
||||
documentElement.setAttribute('theme-mode', themeName)
|
||||
}
|
||||
|
||||
// 保存到本地存储
|
||||
localStorage.setItem('selected-theme', themeName)
|
||||
}
|
||||
|
||||
const currentThemeColor = computed(() => {
|
||||
const theme = themes.find(t => t.name === currentTheme.value)
|
||||
return theme ? theme.color : '#2ba55b'
|
||||
})
|
||||
|
||||
const currentThemeName = computed(() => {
|
||||
const theme = themes.find(t => t.name === currentTheme.value)
|
||||
return theme ? theme.label : '默认'
|
||||
})
|
||||
|
||||
const toggleDropdown = () => {
|
||||
isDropdownOpen.value = !isDropdownOpen.value
|
||||
}
|
||||
|
||||
const selectTheme = (themeName) => {
|
||||
if (themeName === currentTheme.value) {
|
||||
isDropdownOpen.value = false
|
||||
return
|
||||
}
|
||||
|
||||
currentTheme.value = themeName
|
||||
applyTheme(themeName)
|
||||
isDropdownOpen.value = false
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const handleClickOutside = (event) => {
|
||||
const themeSelector = event.target.closest('.theme-selector')
|
||||
if (!themeSelector) {
|
||||
isDropdownOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSavedTheme()
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.theme-selector {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.theme-selector-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: var(--td-bg-color-container, #ffffff);
|
||||
border: 1px solid var(--td-component-border, #e2e8f0);
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.theme-selector-trigger:hover {
|
||||
background: var(--td-bg-color-container-hover, #f8fafc);
|
||||
border-color: var(--td-brand-color-hover, #cbd5e1);
|
||||
}
|
||||
|
||||
.current-theme {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.theme-color-preview {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--td-bg-color-container, #ffffff);
|
||||
box-shadow: 0 0 0 1px var(--td-component-border, #e2e8f0);
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
font-size: 14px;
|
||||
color: var(--td-text-color-primary, #1e293b);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
color: var(--td-text-color-secondary, #64748b);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown-icon.rotated {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.theme-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: 4px;
|
||||
background: var(--td-bg-color-container, #ffffff);
|
||||
border: 1px solid var(--td-component-border, #e2e8f0);
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
box-shadow: var(--td-shadow-2, 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06));
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.theme-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.theme-option:hover {
|
||||
background: var(--td-bg-color-container-hover, #f8fafc);
|
||||
}
|
||||
|
||||
.theme-option.active {
|
||||
background: var(--td-brand-color-light, #eff6ff);
|
||||
color: var(--td-text-color-primary, #1e293b);
|
||||
}
|
||||
|
||||
.theme-color-dot {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--td-bg-color-container, #ffffff);
|
||||
box-shadow: 0 0 0 1px var(--td-component-border, #e2e8f0);
|
||||
}
|
||||
|
||||
.theme-label {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: var(--td-text-color-primary, #1e293b);
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
color: var(--td-brand-color, #3b82f6);
|
||||
}
|
||||
|
||||
/* 下拉动画 */
|
||||
.dropdown-enter-active,
|
||||
.dropdown-leave-active {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px) scale(0.95);
|
||||
}
|
||||
|
||||
.dropdown-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px) scale(0.95);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 640px) {
|
||||
.theme-selector-trigger {
|
||||
min-width: 100px;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.theme-option {
|
||||
padding: 10px 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,14 @@
|
||||
import './assets/main.css'
|
||||
import './assets/base.css'
|
||||
|
||||
// 引入组件库的少量全局样式变量
|
||||
import 'tdesign-vue-next/es/style/index.css' //tdesign 组件样式
|
||||
// import 'tdesign-vue-next/es/style/index.css' //tdesign 组件样式
|
||||
|
||||
// 引入iconfont图标样式
|
||||
import './assets/icon_font/iconfont.css'
|
||||
import './assets/icon_font/iconfont.js'
|
||||
|
||||
import App from './App.vue'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
const app = createApp(App)
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
@@ -34,6 +34,11 @@ const routes: RouteRecordRaw[] = [
|
||||
path: 'search',
|
||||
name: 'search',
|
||||
component: () => import('@renderer/views/music/search.vue')
|
||||
},
|
||||
{
|
||||
path: 'list/:id',
|
||||
name: 'list',
|
||||
component: () => import('@renderer/views/music/list.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -102,7 +102,7 @@ export const ControlAudioStore = defineStore('controlAudio', () => {
|
||||
|
||||
// 初始化
|
||||
const init = (el: ControlAudioState['audio']) => {
|
||||
userInfo = LocalUserDetailStore().userInfo
|
||||
userInfo = LocalUserDetailStore()
|
||||
console.log(el, '全局音频挂载初始化success')
|
||||
Audio.audio = el
|
||||
}
|
||||
@@ -139,21 +139,20 @@ export const ControlAudioStore = defineStore('controlAudio', () => {
|
||||
transitionVolume(Audio.audio, volume / 100, Audio.volume <= volume)
|
||||
} else {
|
||||
Audio.audio.volume = Number((volume / 100).toFixed(2))
|
||||
console.log('vo', Audio.audio.volume)
|
||||
}
|
||||
Audio.volume = volume
|
||||
userInfo.volume = volume
|
||||
userInfo.userInfo.volume = volume
|
||||
}
|
||||
} else {
|
||||
if (typeof volume === 'number' && Audio.audio) {
|
||||
if (volume <= 0) {
|
||||
Audio.volume = 0
|
||||
Audio.audio.volume = 0
|
||||
userInfo.volume = 0
|
||||
userInfo.userInfo.volume = 0
|
||||
} else {
|
||||
Audio.volume = 100
|
||||
Audio.audio.volume = 100
|
||||
userInfo.volume = 100
|
||||
userInfo.userInfo.volume = 100
|
||||
}
|
||||
} else {
|
||||
throw new Error('音量必须是0-100之间的数字')
|
||||
|
||||
@@ -17,7 +17,7 @@ export const LocalUserDetailStore = defineStore('Local', () => {
|
||||
} else {
|
||||
userInfo.value = {
|
||||
lastPlaySongId: null,
|
||||
topBarStyle: true,
|
||||
topBarStyle: false,
|
||||
mainColor: '#00DAC0',
|
||||
volume: 80,
|
||||
currentTime: 0
|
||||
|
||||
@@ -1,22 +1,56 @@
|
||||
import { NotifyPlugin } from 'tdesign-vue-next'
|
||||
import musicService from '@renderer/services/music'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
import { toRaw } from 'vue'
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
|
||||
async function downloadSingleSong(songId: string, name: string, artist: string): Promise<void> {
|
||||
interface MusicItem {
|
||||
singer: string
|
||||
name: string
|
||||
albumName: string
|
||||
albumId: number
|
||||
source: string
|
||||
interval: string
|
||||
songmid: number
|
||||
img: string
|
||||
lrc: null | string
|
||||
types: string[]
|
||||
_types: Record<string, any>
|
||||
typeUrl: Record<string, any>
|
||||
}
|
||||
|
||||
const qualityMap: Record<string, string> = {
|
||||
'128k': '标准音质',
|
||||
'192k': '高品音质',
|
||||
'320k': '超高品质',
|
||||
flac: '无损音质',
|
||||
flac24bit: '超高解析',
|
||||
hires: '高清臻音',
|
||||
atmos: '全景环绕',
|
||||
master: '超清母带'
|
||||
}
|
||||
const qualityKey = Object.keys(qualityMap)
|
||||
|
||||
async function downloadSingleSong(songInfo: MusicItem): Promise<void> {
|
||||
|
||||
try {
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
const result = await musicService.request(
|
||||
'downloadSingleSong',
|
||||
{ id: songId, name, artist, ...LocalUserDetail.userSource },
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
let quality = LocalUserDetail.userSource.quality as string
|
||||
if (
|
||||
qualityKey.indexOf(quality) >
|
||||
qualityKey.indexOf((songInfo.types[songInfo.types.length - 1] as unknown as { type: any }).type)
|
||||
) {
|
||||
quality = (songInfo.types[songInfo.types.length - 1] as unknown as { type: any }).type
|
||||
}
|
||||
const tip = MessagePlugin.success('开始下载歌曲:'+ songInfo.name)
|
||||
const result = await window.api.music.requestSdk('downloadSingleSong',{
|
||||
pluginId:LocalUserDetail.userSource.pluginId?.toString() || '',
|
||||
source:songInfo.source,
|
||||
quality,
|
||||
songInfo:toRaw(songInfo)
|
||||
})
|
||||
;(await tip).close()
|
||||
if (!Object.hasOwn(result, 'path')) {
|
||||
await NotifyPlugin.info({
|
||||
title: '提示',
|
||||
content: result.message
|
||||
})
|
||||
MessagePlugin.info(result.message)
|
||||
} else {
|
||||
await NotifyPlugin.success({
|
||||
title: '下载成功',
|
||||
@@ -27,7 +61,7 @@ async function downloadSingleSong(songId: string, name: string, artist: string):
|
||||
console.error('下载失败:', error)
|
||||
await NotifyPlugin.error({
|
||||
title: '下载失败',
|
||||
content: `${error.message ?? '未知错误'}`
|
||||
content: `${error.message.includes('歌曲正在')? '歌曲正在下载中':'未知错误'}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,13 +168,11 @@ export function validateImportedPlaylist(playlist: any[]): boolean {
|
||||
// 验证每个歌曲对象是否包含必要的字段
|
||||
return playlist.every(
|
||||
(song) =>
|
||||
typeof song === 'object' &&
|
||||
typeof song.songmid === 'number' &&
|
||||
typeof song.name === 'string' &&
|
||||
song.songmid &&
|
||||
song.name &&
|
||||
typeof song.img === 'string' &&
|
||||
typeof song.singer === 'string' &&
|
||||
typeof song.interval === 'string' &&
|
||||
typeof song.albumName === 'string' &&
|
||||
typeof song.source === 'string'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,17 @@ const emitter = mitt<PlaylistEvents>()
|
||||
|
||||
// 将事件总线挂载到全局
|
||||
;(window as any).musicEmitter = emitter
|
||||
|
||||
const qualityMap: Record<string, string> = {
|
||||
'128k': '标准音质',
|
||||
'192k': '高品音质',
|
||||
'320k': '超高品质',
|
||||
flac: '无损音质',
|
||||
flac24bit: '超高解析',
|
||||
hires: '高清臻音',
|
||||
atmos: '全景环绕',
|
||||
master: '超清母带'
|
||||
}
|
||||
const qualityKey = Object.keys(qualityMap)
|
||||
/**
|
||||
* 获取歌曲真实播放URL
|
||||
* @param song 歌曲对象
|
||||
@@ -25,19 +35,27 @@ export async function getSongRealUrl(song: SongList): Promise<string> {
|
||||
// 获取当前用户的信息
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
// 通过统一的request方法获取真实的播放URL
|
||||
const urlData = await window.api.music.requestSdk('getMusicUrl',{
|
||||
pluginId:(LocalUserDetail.userSource.pluginId as unknown as string),
|
||||
let quality = LocalUserDetail.userSource.quality as string
|
||||
if (
|
||||
qualityKey.indexOf(quality) >
|
||||
qualityKey.indexOf((song.types[song.types.length - 1] as unknown as { type: any }).type)
|
||||
) {
|
||||
quality = (song.types[song.types.length - 1] as unknown as { type: any }).type
|
||||
}
|
||||
console.log(quality)
|
||||
const urlData = await window.api.music.requestSdk('getMusicUrl', {
|
||||
pluginId: LocalUserDetail.userSource.pluginId as unknown as string,
|
||||
source: song.source,
|
||||
songInfo:song,
|
||||
quality: LocalUserDetail.userSource.quality as string
|
||||
songInfo: song,
|
||||
quality
|
||||
})
|
||||
console.log(urlData)
|
||||
if (typeof urlData === 'object'&&urlData.error) {
|
||||
if (typeof urlData === 'object' && urlData.error) {
|
||||
throw new Error(urlData.error)
|
||||
}else{
|
||||
} else {
|
||||
return urlData as string
|
||||
}
|
||||
} catch (error:any) {
|
||||
} catch (error: any) {
|
||||
console.error('获取歌曲URL失败:', error)
|
||||
throw new Error('获取歌曲播放链接失败' + error.message)
|
||||
}
|
||||
@@ -55,22 +73,23 @@ export async function addToPlaylistAndPlay(
|
||||
playSongCallback: (song: SongList) => Promise<void>
|
||||
) {
|
||||
try {
|
||||
// 获取真实播放URL
|
||||
|
||||
await getSongRealUrl(song)
|
||||
const playResult = playSongCallback(song)
|
||||
|
||||
// 使用store的方法添加歌曲到第一位
|
||||
localUserStore.addSongToFirst(song)
|
||||
|
||||
// 获取真实播放URL
|
||||
await getSongRealUrl(song)
|
||||
|
||||
// 播放歌曲 - 确保正确处理Promise
|
||||
const playResult = playSongCallback(song)
|
||||
if (playResult && typeof playResult.then === 'function') {
|
||||
await playResult
|
||||
}
|
||||
|
||||
await MessagePlugin.success('已添加到播放列表并开始播放')
|
||||
} catch (error) {
|
||||
console.error('添加到播放列表并播放失败:', error)
|
||||
await MessagePlugin.error('播放失败,请重试')
|
||||
console.error('播放失败:', error)
|
||||
await MessagePlugin.error('播放失败了,可能还没有版权')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +101,9 @@ export async function addToPlaylistAndPlay(
|
||||
export async function addToPlaylistEnd(song: SongList, localUserStore: any) {
|
||||
try {
|
||||
// 检查歌曲是否已在播放列表中
|
||||
const existingIndex = localUserStore.list.findIndex((item: SongList) => item.songmid === song.songmid)
|
||||
const existingIndex = localUserStore.list.findIndex(
|
||||
(item: SongList) => item.songmid === song.songmid
|
||||
)
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
await MessagePlugin.warning('歌曲已在播放列表中')
|
||||
@@ -92,14 +113,6 @@ export async function addToPlaylistEnd(song: SongList, localUserStore: any) {
|
||||
// 使用store的方法添加歌曲
|
||||
localUserStore.addSong(song)
|
||||
|
||||
// 预加载歌曲URL(可选,提升用户体验)
|
||||
try {
|
||||
await getSongRealUrl(song)
|
||||
} catch (error) {
|
||||
console.warn('预加载歌曲URL失败:', error)
|
||||
// 预加载失败不影响添加到播放列表
|
||||
}
|
||||
|
||||
await MessagePlugin.success('已添加到播放列表')
|
||||
} catch (error) {
|
||||
console.error('添加到播放列表失败:', error)
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import PlayMusic from '@renderer/components/Play/PlayMusic.vue'
|
||||
import TitleBarControls from '@renderer/components/TitleBarControls.vue'
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref, watchEffect } from 'vue'
|
||||
import { SearchIcon } from 'tdesign-icons-vue-next'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { searchValue } from '@renderer/store/search'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
onMounted(() => {
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
watchEffect(() => {
|
||||
source.value = sourceicon[LocalUserDetail.userSource.source || 'wy']
|
||||
})
|
||||
})
|
||||
|
||||
const sourceicon = {
|
||||
kg: 'kugouyinle',
|
||||
wy: 'wangyiyun',
|
||||
mg: 'mg',
|
||||
tx: 'tx',
|
||||
kw: 'kw'
|
||||
}
|
||||
const source = ref('kugouyinle')
|
||||
interface MenuItem {
|
||||
name: string
|
||||
icon: string
|
||||
@@ -91,7 +106,6 @@ const handleKeyDown = () => {
|
||||
<t-button
|
||||
v-for="(item, index) in menuList"
|
||||
:key="index"
|
||||
:theme="menuActive == index ? 'warning' : ''"
|
||||
:variant="menuActive == index ? 'base' : 'text'"
|
||||
:class="menuActive == index ? 'nav-button active' : 'nav-button'"
|
||||
block
|
||||
@@ -104,7 +118,7 @@ const handleKeyDown = () => {
|
||||
</div>
|
||||
</t-aside>
|
||||
|
||||
<t-layout>
|
||||
<t-layout style="flex: 1">
|
||||
<t-content>
|
||||
<div class="content">
|
||||
<!-- Header -->
|
||||
@@ -119,10 +133,7 @@ const handleKeyDown = () => {
|
||||
<div class="search-container">
|
||||
<div class="search-input">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use
|
||||
xlink:href="#icon-wangyiyun
|
||||
"
|
||||
></use>
|
||||
<use :xlink:href="`#icon-${source}`"></use>
|
||||
</svg>
|
||||
<t-input
|
||||
v-model="keyword"
|
||||
@@ -143,6 +154,7 @@ const handleKeyDown = () => {
|
||||
</template>
|
||||
</t-input>
|
||||
</div>
|
||||
|
||||
<TitleBarControls :color="'#000'"></TitleBarControls>
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,6 +187,7 @@ const handleKeyDown = () => {
|
||||
width: 15rem;
|
||||
background-color: #fff;
|
||||
border-right: 0.0625rem solid #e5e7eb;
|
||||
flex-shrink: 0;
|
||||
|
||||
.sidebar-content {
|
||||
padding: 1rem;
|
||||
@@ -189,7 +202,7 @@ const handleKeyDown = () => {
|
||||
.logo-icon {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background-color: #f97316;
|
||||
background-color: var(--td-brand-color-4);
|
||||
border-radius: 0.625rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -207,7 +220,7 @@ const handleKeyDown = () => {
|
||||
color: #111827;
|
||||
span {
|
||||
font-weight: 500;
|
||||
color: #f54a00;
|
||||
color: #b8f0cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,11 +244,11 @@ const handleKeyDown = () => {
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #f97316;
|
||||
color: white;
|
||||
background-color: var(--td-brand-color-4);
|
||||
color: rgb(255, 255, 255);
|
||||
|
||||
&:hover {
|
||||
background-color: #ea580c;
|
||||
background-color: var(--td-brand-color-5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +337,6 @@ const handleKeyDown = () => {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
height: 0; /* 确保flex子元素能够正确计算高度 */
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
|
||||
@@ -1,54 +1,76 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
// 路由实例
|
||||
const router = useRouter()
|
||||
|
||||
// 推荐歌单数据
|
||||
const recommendPlaylists = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '热门流行',
|
||||
description: '最新最热的流行音乐',
|
||||
cover: 'https://via.placeholder.com/200x200/f97316/ffffff?text=热门流行',
|
||||
playCount: '1.2万'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '经典老歌',
|
||||
description: '怀旧经典,永恒旋律',
|
||||
cover: 'https://via.placeholder.com/200x200/3b82f6/ffffff?text=经典老歌',
|
||||
playCount: '8.5万'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '轻音乐',
|
||||
description: '放松心情的轻柔音乐',
|
||||
cover: 'https://via.placeholder.com/200x200/10b981/ffffff?text=轻音乐',
|
||||
playCount: '3.7万'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '摇滚精选',
|
||||
description: '激情澎湃的摇滚乐',
|
||||
cover: 'https://via.placeholder.com/200x200/ef4444/ffffff?text=摇滚精选',
|
||||
playCount: '2.1万'
|
||||
}
|
||||
])
|
||||
const recommendPlaylists: any = ref([])
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
|
||||
// 热门歌曲数据
|
||||
const hotSongs = ref([
|
||||
{ id: 1, title: '夜曲', artist: '周杰伦', album: '十一月的萧邦', duration: '3:37' },
|
||||
{ id: 2, title: '青花瓷', artist: '周杰伦', album: '我很忙', duration: '3:58' },
|
||||
{ id: 3, title: '稻香', artist: '周杰伦', album: '魔杰座', duration: '3:43' },
|
||||
{ id: 4, title: '告白气球', artist: '周杰伦', album: '周杰伦的床边故事', duration: '3:34' },
|
||||
{ id: 5, title: '七里香', artist: '周杰伦', album: '七里香', duration: '4:05' }
|
||||
])
|
||||
const hotSongs:any = ref([])
|
||||
|
||||
// 获取热门歌单数据
|
||||
const fetchHotSonglist = async () => {
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
// 调用真实 API 获取热门歌单
|
||||
const result = await window.api.music.requestSdk('getHotSonglist', {
|
||||
source: LocalUserDetail.userSource.source
|
||||
})
|
||||
|
||||
if (result && result.list) {
|
||||
recommendPlaylists.value = result.list.map((item: any) => ({
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
description: item.desc || '精选歌单',
|
||||
cover: item.img || 'https://via.placeholder.com/200x200/f97316/ffffff?text=歌单',
|
||||
playCount: item.play_count, // 直接使用返回的格式化字符串
|
||||
author: item.author,
|
||||
total: item.total,
|
||||
time: item.time,
|
||||
source: item.source
|
||||
}))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取热门歌单失败:', err)
|
||||
error.value = '获取数据失败,请稍后重试'
|
||||
// 使用备用数据
|
||||
recommendPlaylists.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const playPlaylist = (playlist: any): void => {
|
||||
console.log('播放歌单:', playlist.title)
|
||||
// 跳转到歌曲列表页面,传递歌单ID和其他必要信息
|
||||
router.push({
|
||||
name: 'list',
|
||||
params: { id: playlist.id },
|
||||
query: {
|
||||
title: playlist.title,
|
||||
source: playlist.source,
|
||||
author: playlist.author,
|
||||
cover: playlist.cover,
|
||||
total: playlist.total
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const playSong = (song: any): void => {
|
||||
console.log('播放歌曲:', song.title)
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchHotSonglist()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -61,8 +83,23 @@ const playSong = (song: any): void => {
|
||||
|
||||
<!-- 推荐歌单 -->
|
||||
<div class="section">
|
||||
<h3 class="section-title">推荐歌单</h3>
|
||||
<div class="playlist-grid">
|
||||
<h3 class="section-title">热门歌单Top{{ recommendPlaylists.length }}</h3>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<t-loading size="large" text="正在加载热门歌单..." />
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="error" class="error-container">
|
||||
<t-alert theme="error" :message="error" />
|
||||
<t-button theme="primary" @click="fetchHotSonglist" style="margin-top: 1rem">
|
||||
重新加载
|
||||
</t-button>
|
||||
</div>
|
||||
|
||||
<!-- 歌单列表 -->
|
||||
<div v-else class="playlist-grid">
|
||||
<div
|
||||
v-for="playlist in recommendPlaylists"
|
||||
:key="playlist.id"
|
||||
@@ -71,19 +108,18 @@ const playSong = (song: any): void => {
|
||||
>
|
||||
<div class="playlist-cover">
|
||||
<img :src="playlist.cover" :alt="playlist.title" />
|
||||
<div class="play-overlay">
|
||||
<t-button shape="circle" theme="primary" size="large">
|
||||
<i class="iconfont icon-a-tingzhiwukuang"></i>
|
||||
</t-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="playlist-info">
|
||||
<h4 class="playlist-title">{{ playlist.title }}</h4>
|
||||
<p class="playlist-desc">{{ playlist.description }}</p>
|
||||
<span class="play-count">
|
||||
<i class="iconfont icon-a-tingzhiwukuang"></i>
|
||||
{{ playlist.playCount }}
|
||||
</span>
|
||||
<div class="playlist-meta">
|
||||
<span class="play-count">
|
||||
<i class="iconfont icon-bofang"></i>
|
||||
{{ playlist.playCount }}
|
||||
</span>
|
||||
<span class="song-count" v-if="playlist.total">{{ playlist.total }}首</span>
|
||||
</div>
|
||||
<!-- <div class="playlist-author">by {{ playlist.author }}</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -119,7 +155,7 @@ const playSong = (song: any): void => {
|
||||
<style lang="scss" scoped>
|
||||
.find-container {
|
||||
padding: 2rem;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -150,9 +186,21 @@ const playSong = (song: any): void => {
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 4rem 0;
|
||||
}
|
||||
|
||||
.error-container {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.playlist-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
@@ -177,26 +225,11 @@ const playSong = (song: any): void => {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.play-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-info {
|
||||
@@ -222,6 +255,13 @@ const playSong = (song: any): void => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.playlist-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.play-count {
|
||||
font-size: 0.75rem;
|
||||
color: #9ca3af;
|
||||
@@ -233,6 +273,17 @@ const playSong = (song: any): void => {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.song-count {
|
||||
font-size: 0.75rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.playlist-author {
|
||||
font-size: 0.75rem;
|
||||
color: #6b7280;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,407 +1,319 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted, toRaw } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
import { downloadSingleSong } from '@renderer/utils/download'
|
||||
import SongVirtualList from '@renderer/components/Music/SongVirtualList.vue'
|
||||
|
||||
interface MusicItem {
|
||||
singer: string
|
||||
name: string
|
||||
albumName: string
|
||||
albumId: number
|
||||
source: string
|
||||
interval: string
|
||||
songmid: number
|
||||
img: string
|
||||
lrc: null | string
|
||||
types: string[]
|
||||
_types: Record<string, any>
|
||||
typeUrl: Record<string, any>
|
||||
}
|
||||
|
||||
// 路由实例
|
||||
const route = useRoute()
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
|
||||
// 响应式状态
|
||||
const hoveredSong = ref<number | null>(null)
|
||||
const songs = ref<MusicItem[]>([])
|
||||
const loading = ref(true)
|
||||
const currentSong = ref<MusicItem | null>(null)
|
||||
const isPlaying = ref(false)
|
||||
const playlistInfo = ref({
|
||||
id: '',
|
||||
title: '',
|
||||
author: '',
|
||||
cover: '',
|
||||
total: 0,
|
||||
source: ''
|
||||
})
|
||||
|
||||
// 模拟歌曲数据
|
||||
const mockSongs = ref([
|
||||
{
|
||||
id: 1,
|
||||
index: 1,
|
||||
title: '别让我担心',
|
||||
artist: '刘若英',
|
||||
album: '我等你',
|
||||
duration: '4:32',
|
||||
albumArt: '../../assets/images/cover.png',
|
||||
isPlaying: true,
|
||||
tags: [
|
||||
{ label: 'VIP', theme: 'warning' },
|
||||
{ label: '原唱', theme: 'success' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
index: 2,
|
||||
title: '后来',
|
||||
artist: '刘若英',
|
||||
album: '我等你',
|
||||
duration: '4:18',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: [
|
||||
{ label: '原唱', theme: 'success' },
|
||||
{ label: 'Hot', theme: 'danger' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
index: 3,
|
||||
title: '为爱痴狂',
|
||||
artist: '刘若英',
|
||||
album: '年华',
|
||||
duration: '3:45',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: [{ label: 'VIP', theme: 'warning' }]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
index: 4,
|
||||
title: '很爱很爱你',
|
||||
artist: '刘若英',
|
||||
album: '年华',
|
||||
duration: '4:12',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: []
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
index: 5,
|
||||
title: '原来你也在这里',
|
||||
artist: '刘若英',
|
||||
album: '我等你',
|
||||
duration: '4:28',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: [{ label: '原唱', theme: 'success' }]
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
index: 5,
|
||||
title: '原来你也在这里',
|
||||
artist: '刘若英',
|
||||
album: '我等你',
|
||||
duration: '4:28',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: [
|
||||
{ label: '原唱', theme: 'success' },
|
||||
{ label: 'Hot', theme: 'danger' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
index: 5,
|
||||
title: '原来你也在这里',
|
||||
artist: '刘若英',
|
||||
album: '我等你',
|
||||
duration: '4:28',
|
||||
albumArt: '/placeholder.svg',
|
||||
isPlaying: false,
|
||||
tags: [{ label: '原唱', theme: 'success' }]
|
||||
// 获取歌单歌曲列表
|
||||
const fetchPlaylistSongs = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// 从路由参数中获取歌单信息
|
||||
playlistInfo.value = {
|
||||
id: route.params.id as string,
|
||||
title: (route.query.title as string) || '歌单',
|
||||
author: (route.query.author as string) || '未知',
|
||||
cover: (route.query.cover as string) || '',
|
||||
total: Number(route.query.total) || 0,
|
||||
source: (route.query.source as string) || (LocalUserDetail.userSource.source as any)
|
||||
}
|
||||
|
||||
// 调用API获取歌单详情和歌曲列表
|
||||
const result = await window.api.music.requestSdk('getPlaylistDetail', {
|
||||
source: playlistInfo.value.source,
|
||||
id: playlistInfo.value.id,
|
||||
page: 1
|
||||
}) as any
|
||||
console.log(result)
|
||||
if (result && result.list) {
|
||||
songs.value = result.list
|
||||
|
||||
// 获取歌曲封面
|
||||
setPic(0, playlistInfo.value.source)
|
||||
|
||||
// 如果API返回了歌单详细信息,更新歌单信息
|
||||
if (result.info) {
|
||||
playlistInfo.value = {
|
||||
...playlistInfo.value,
|
||||
title: result.info.name || playlistInfo.value.title,
|
||||
author: result.info.author || playlistInfo.value.author,
|
||||
cover: result.info.img || playlistInfo.value.cover,
|
||||
total: result.info.total || playlistInfo.value.total
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取歌单歌曲失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
// 获取歌曲封面
|
||||
async function setPic(offset: number, source: string) {
|
||||
for (let i = offset; i < songs.value.length; i++) {
|
||||
const tempImg = songs.value[i].img
|
||||
if (tempImg) continue
|
||||
try {
|
||||
const url = await window.api.music.requestSdk('getPic', {
|
||||
source,
|
||||
songInfo: toRaw(songs.value[i])
|
||||
})
|
||||
|
||||
if (typeof url !== 'object') {
|
||||
songs.value[i].img = url
|
||||
} else {
|
||||
songs.value[i].img = 'resources/logo.png'
|
||||
}
|
||||
} catch (e) {
|
||||
songs.value[i].img = 'logo.svg'
|
||||
console.log('获取封面失败 index' + i, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 组件事件处理函数
|
||||
const handlePlay = (song: MusicItem) => {
|
||||
currentSong.value = song
|
||||
isPlaying.value = true
|
||||
console.log('播放歌曲:', song.name)
|
||||
if ((window as any).musicEmitter) {
|
||||
;(window as any).musicEmitter.emit('addToPlaylistAndPlay', toRaw(song))
|
||||
}
|
||||
}
|
||||
|
||||
const handlePause = () => {
|
||||
isPlaying.value = false
|
||||
if ((window as any).musicEmitter) {
|
||||
;(window as any).musicEmitter.emit('pause')
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownload = (song: MusicItem) => {
|
||||
downloadSingleSong(song)
|
||||
}
|
||||
|
||||
const handleAddToPlaylist = (song: MusicItem) => {
|
||||
console.log('添加到播放列表:', song.name)
|
||||
if ((window as any).musicEmitter) {
|
||||
;(window as any).musicEmitter.emit('addToPlaylistEnd', toRaw(song))
|
||||
}
|
||||
}
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchPlaylistSongs()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list-container">
|
||||
<!-- 固定头部区域 -->
|
||||
<div class="fixed-header">
|
||||
<!-- 搜索结果标题 -->
|
||||
<h2 class="search-title"><span class="search-keyword">别让我担心</span> 的搜索结果</h2>
|
||||
|
||||
<!-- 表格头部 -->
|
||||
<div class="table-header">
|
||||
<div class="header-item" style="justify-content: center">#</div>
|
||||
<div class="header-item">标题</div>
|
||||
<div class="header-item">专辑</div>
|
||||
<div class="header-item">时长</div>
|
||||
<!-- 歌单信息 -->
|
||||
<div class="playlist-header">
|
||||
<div class="playlist-cover">
|
||||
<img :src="playlistInfo.cover" :alt="playlistInfo.title" />
|
||||
</div>
|
||||
<div class="playlist-details">
|
||||
<h1 class="playlist-title">{{ playlistInfo.title }}</h1>
|
||||
<p class="playlist-author">by {{ playlistInfo.author }}</p>
|
||||
<p class="playlist-stats">{{ playlistInfo.total }} 首歌曲</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 可滚动的歌曲列表区域 -->
|
||||
<div class="scrollable-content">
|
||||
<div class="song-list">
|
||||
<div
|
||||
v-for="song in mockSongs"
|
||||
:key="song.id"
|
||||
class="song-item"
|
||||
:class="{
|
||||
'song-item--playing': song.isPlaying,
|
||||
'song-item--hovered': hoveredSong === song.id
|
||||
}"
|
||||
@mouseenter="hoveredSong = song.id"
|
||||
@mouseleave="hoveredSong = null"
|
||||
>
|
||||
<!-- Index/Play Icon -->
|
||||
<div class="song-index">
|
||||
<i v-if="song.isPlaying" class="iconfont icon-a-tingzhiwukuang playing-icon"></i>
|
||||
<i
|
||||
v-else-if="hoveredSong === song.id"
|
||||
class="iconfont icon-a-tingzhiwukuang play-icon"
|
||||
></i>
|
||||
<span v-else class="index-number">{{ song.index }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Title and Artist -->
|
||||
<div class="song-info">
|
||||
<img :src="'/src/assets/images/cover.png'" :alt="song.title" class="album-art" />
|
||||
<div class="song-details">
|
||||
<div class="title-row">
|
||||
<span class="song-title" :class="{ 'song-title--playing': song.isPlaying }">
|
||||
{{ song.title }}
|
||||
</span>
|
||||
<div class="tags">
|
||||
<t-tag
|
||||
v-for="(tag, index) in song.tags"
|
||||
:key="index"
|
||||
:theme="tag.theme"
|
||||
variant="light-outline"
|
||||
size="small"
|
||||
shape="round"
|
||||
class="song-tab"
|
||||
>
|
||||
{{ tag.label }}
|
||||
</t-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="artist-name">{{ song.artist }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Album -->
|
||||
<div class="album-name">
|
||||
<span>{{ song.album }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Duration and Actions -->
|
||||
<div class="duration-actions">
|
||||
<span class="duration">{{ song.duration }}</span>
|
||||
<t-button
|
||||
v-if="hoveredSong === song.id"
|
||||
variant="text"
|
||||
size="small"
|
||||
class="more-button"
|
||||
>
|
||||
<i class="iconfont icon-gengduo"></i>
|
||||
</t-button>
|
||||
</div>
|
||||
<div v-if="loading" class="loading-container">
|
||||
<div class="loading-content">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="song-list-wrapper">
|
||||
<SongVirtualList
|
||||
:songs="songs"
|
||||
:current-song="currentSong"
|
||||
:is-playing="isPlaying"
|
||||
:show-index="true"
|
||||
:show-album="true"
|
||||
:show-duration="true"
|
||||
@play="handlePlay"
|
||||
@pause="handlePause"
|
||||
@download="handleDownload"
|
||||
@add-to-playlist="handleAddToPlaylist"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-container {
|
||||
background: #fafafa;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
padding: 1.5rem;
|
||||
padding-top: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.fixed-header {
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
z-index: 10;
|
||||
|
||||
.search-title {
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
color: #9d9a9a;
|
||||
margin-bottom: 1.2rem;
|
||||
|
||||
.search-keyword {
|
||||
font-size: 1.6rem;
|
||||
color: #f97316;
|
||||
font-weight: 600;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem 1fr 1fr 5rem;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
background-color: #efefef;
|
||||
|
||||
.header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-right: 0.25rem;
|
||||
padding-bottom: 4rem;
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.375rem;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #f1f5f9;
|
||||
border-radius: 0.1875rem;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 0.1875rem;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: #94a3b8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Firefox 滚动条样式 */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cbd5e1 #f1f5f9;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.song-list {
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.loading-content {
|
||||
text-align: center;
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #507daf;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
background: #fff;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.playlist-cover {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-details {
|
||||
flex: 1;
|
||||
|
||||
.playlist-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.playlist-author {
|
||||
font-size: 1rem;
|
||||
color: #6b7280;
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.playlist-stats {
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.song-list-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding-bottom: 1rem;
|
||||
.song-item {
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem 1fr 1fr 5rem;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.list-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.playlist-header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 0.1875rem solid transparent;
|
||||
border-radius: 0.5rem;
|
||||
background-color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
&--playing {
|
||||
background-color: #fff7ed;
|
||||
border-left-color: #f97316;
|
||||
}
|
||||
|
||||
.song-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.playing-icon {
|
||||
color: #f97316;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.play-icon {
|
||||
color: #6b7280;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.index-number {
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.song-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
min-width: 0;
|
||||
|
||||
.album-art {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 0.5rem;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.song-details {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
|
||||
.song-title {
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&--playing {
|
||||
color: #ea580c;
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
flex-shrink: 0;
|
||||
|
||||
:deep(.t-tag) {
|
||||
font-size: 0.7rem !important;
|
||||
height: auto;
|
||||
margin-right: 0.25rem;
|
||||
padding: 0rem 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.artist-name {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.album-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 0.875rem;
|
||||
color: #4b5563;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.duration-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.duration {
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
|
||||
.iconfont {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .more-button {
|
||||
opacity: 1;
|
||||
.playlist-cover {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, nextTick, onUnmounted, watch, toRaw } from 'vue'
|
||||
import { PlayIcon, HeartIcon, DownloadIcon, MoreIcon } from 'tdesign-icons-vue-next'
|
||||
import { ref, onMounted, computed, watch, toRaw } from 'vue'
|
||||
import { searchValue } from '@renderer/store/search'
|
||||
import { downloadSingleSong } from '@renderer/utils/download'
|
||||
import { LocalUserDetailStore } from '@renderer/store/LocalUserDetail'
|
||||
import { MessagePlugin } from 'tdesign-vue-next'
|
||||
import SongVirtualList from '@renderer/components/Music/SongVirtualList.vue'
|
||||
|
||||
interface MusicItem {
|
||||
id: number
|
||||
singer: string
|
||||
name: string
|
||||
albumName: string
|
||||
@@ -17,115 +18,30 @@ interface MusicItem {
|
||||
img: string
|
||||
lrc: null | string
|
||||
types: string[]
|
||||
_types: Record<string, any>;
|
||||
_types: Record<string, any>
|
||||
typeUrl: Record<string, any>
|
||||
}
|
||||
|
||||
const keyword = ref('')
|
||||
const searchResults = ref<MusicItem[]>([])
|
||||
const hoveredSong = ref<any>(null)
|
||||
const loading = ref(false)
|
||||
const hasMore = ref(true)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = 50
|
||||
const totalItems = ref(0)
|
||||
|
||||
// 虚拟滚动配置
|
||||
const virtualScrollConfig = ref({
|
||||
containerHeight: 0, // 动态计算容器高度
|
||||
itemHeight: 64, // 每个项目的高度
|
||||
buffer: 5 // 缓冲区项目数量
|
||||
})
|
||||
|
||||
// 虚拟滚动状态
|
||||
const scrollContainer = ref<HTMLElement>()
|
||||
const scrollTop = ref(0)
|
||||
const visibleStartIndex = ref(0)
|
||||
const visibleEndIndex = ref(0)
|
||||
const visibleItems = ref<MusicItem[]>([])
|
||||
const mainContent = document.querySelector('.mainContent')
|
||||
// 计算容器高度
|
||||
const calculateContainerHeight = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
console.log(mainContent?.clientHeight)
|
||||
const listHeaderHeight = 40 // 表头高度
|
||||
const pageHeaderHeight = 52 // 表头高度
|
||||
const padding = 60 // 容器内边距
|
||||
const availableHeight =
|
||||
(mainContent?.clientHeight || document.body.offsetHeight) -
|
||||
pageHeaderHeight -
|
||||
listHeaderHeight -
|
||||
padding
|
||||
virtualScrollConfig.value.containerHeight = Math.max(400, availableHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算虚拟滚动的可见项目
|
||||
const updateVisibleItems = () => {
|
||||
const { containerHeight, itemHeight, buffer } = virtualScrollConfig.value
|
||||
const totalItems = searchResults.value.length
|
||||
|
||||
if (totalItems === 0) {
|
||||
visibleItems.value = []
|
||||
return
|
||||
}
|
||||
|
||||
const visibleCount = Math.ceil(containerHeight / itemHeight)
|
||||
const startIndex = Math.floor(scrollTop.value / itemHeight)
|
||||
const endIndex = Math.min(startIndex + visibleCount + buffer * 2, totalItems)
|
||||
|
||||
visibleStartIndex.value = Math.max(0, startIndex - buffer)
|
||||
visibleEndIndex.value = endIndex
|
||||
|
||||
visibleItems.value = searchResults.value.slice(visibleStartIndex.value, visibleEndIndex.value)
|
||||
}
|
||||
|
||||
// 处理滚动事件
|
||||
const handleScroll = (event: Event) => {
|
||||
const target = event.target as HTMLElement
|
||||
scrollTop.value = target.scrollTop
|
||||
updateVisibleItems()
|
||||
|
||||
// 检查是否需要加载更多
|
||||
const { scrollTop: currentScrollTop, scrollHeight, clientHeight } = target
|
||||
if (scrollHeight - currentScrollTop - clientHeight < 100) {
|
||||
onScrollToBottom()
|
||||
}
|
||||
}
|
||||
|
||||
// 计算总高度
|
||||
const totalHeight = computed(
|
||||
() => searchResults.value.length * virtualScrollConfig.value.itemHeight
|
||||
)
|
||||
|
||||
// 计算偏移量
|
||||
const offsetY = computed(() => visibleStartIndex.value * virtualScrollConfig.value.itemHeight)
|
||||
const currentSong = ref<MusicItem | null>(null)
|
||||
const isPlaying = ref(false)
|
||||
const search = searchValue()
|
||||
// 从路由参数中获取搜索关键词和初始结果
|
||||
|
||||
onMounted(async () => {
|
||||
// 计算容器高度
|
||||
|
||||
watch(
|
||||
search,
|
||||
async () => {
|
||||
keyword.value = search.getValue
|
||||
await performSearch(true)
|
||||
// 确保初始渲染显示内容
|
||||
await nextTick()
|
||||
updateVisibleItems()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
calculateContainerHeight()
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', calculateContainerHeight)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (scrollContainer.value) {
|
||||
scrollContainer.value.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
window.removeEventListener('resize', calculateContainerHeight)
|
||||
})
|
||||
|
||||
// 执行搜索
|
||||
@@ -154,74 +70,87 @@ const performSearch = async (reset = false) => {
|
||||
page: currentPage.value,
|
||||
limit: pageSize
|
||||
})
|
||||
console.log(result)
|
||||
|
||||
totalItems.value = result.total || 0
|
||||
const newSongs = (result.list || []).map((song: any, index: number) => ({
|
||||
...song,
|
||||
id: song.songmid || `${currentPage.value}-${index}` // 确保每首歌都有唯一ID
|
||||
}))
|
||||
|
||||
if (reset) {
|
||||
searchResults.value = result.list || []
|
||||
searchResults.value = newSongs
|
||||
} else {
|
||||
searchResults.value = [...searchResults.value, ...(result.list || [])]
|
||||
searchResults.value = [...searchResults.value, ...newSongs]
|
||||
}
|
||||
|
||||
setPic((currentPage.value-1) * pageSize, source)
|
||||
setPic((currentPage.value - 1) * pageSize, source)
|
||||
currentPage.value += 1
|
||||
hasMore.value = (result.list?.length || 0) >= pageSize
|
||||
|
||||
// 更新虚拟滚动
|
||||
await nextTick()
|
||||
updateVisibleItems()
|
||||
hasMore.value = newSongs.length >= pageSize
|
||||
} catch (error) {
|
||||
console.error('搜索失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
async function setPic(offset:number, source:string) {
|
||||
console.log('get',offset)
|
||||
|
||||
for(let i = offset;i<searchResults.value.length;i++){
|
||||
async function setPic(offset: number, source: string) {
|
||||
for (let i = offset; i < searchResults.value.length; i++) {
|
||||
const tempImg = searchResults.value[i].img
|
||||
if(tempImg) continue
|
||||
try{
|
||||
const url = await window.api.music.requestSdk('getPic',{source,songInfo:toRaw(searchResults.value[i])})
|
||||
|
||||
if(typeof url !== 'object'){
|
||||
if (tempImg) continue
|
||||
try {
|
||||
const url = await window.api.music.requestSdk('getPic', {
|
||||
source,
|
||||
songInfo: toRaw(searchResults.value[i])
|
||||
})
|
||||
if (typeof url !== 'object') {
|
||||
searchResults.value[i].img = url
|
||||
}else{
|
||||
console.log(url)
|
||||
} else {
|
||||
searchResults.value[i].img = 'resources/logo.png'
|
||||
}
|
||||
}catch(e){
|
||||
searchResults.value[i].img = 'logo.svg'
|
||||
|
||||
console.log('获取失败 index'+i,e)
|
||||
} catch (e) {
|
||||
searchResults.value[i].img = 'logo.svg'
|
||||
console.log('获取失败 index' + i, e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// 虚拟滚动触底加载更多
|
||||
const onScrollToBottom = async () => {
|
||||
if (!loading.value && hasMore.value) {
|
||||
await performSearch(false)
|
||||
}
|
||||
}
|
||||
// 计算是否有搜索结果
|
||||
const hasResults = computed(() => searchResults.value && searchResults.value.length > 0)
|
||||
|
||||
// 播放歌曲 - 点击背景时添加到播放列表第一项并播放
|
||||
const playSong = (song: MusicItem): void => {
|
||||
// 组件事件处理函数
|
||||
const handlePlay = (song: MusicItem) => {
|
||||
currentSong.value = song
|
||||
isPlaying.value = true
|
||||
console.log('播放歌曲:', song.name)
|
||||
// 触发添加到播放列表并播放的事件
|
||||
if ((window as any).musicEmitter) {
|
||||
; (window as any).musicEmitter.emit('addToPlaylistAndPlay', toRaw(song))
|
||||
;(window as any).musicEmitter.emit('addToPlaylistAndPlay', toRaw(song))
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到播放列表末尾
|
||||
const addToPlaylist = (song: any): void => {
|
||||
console.log('添加到播放列表:', song.name)
|
||||
// 触发添加到播放列表末尾的事件
|
||||
const handlePause = () => {
|
||||
isPlaying.value = false
|
||||
if ((window as any).musicEmitter) {
|
||||
; (window as any).musicEmitter.emit('addToPlaylistEnd', toRaw(song))
|
||||
;(window as any).musicEmitter.emit('pause')
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownload = (song: MusicItem) => {
|
||||
downloadSingleSong(song)
|
||||
}
|
||||
|
||||
const handleAddToPlaylist = (song: MusicItem) => {
|
||||
console.log('添加到播放列表:', song.name)
|
||||
if ((window as any).musicEmitter) {
|
||||
;(window as any).musicEmitter.emit('addToPlaylistEnd', toRaw(song))
|
||||
}
|
||||
}
|
||||
|
||||
const handleScroll = (event: Event) => {
|
||||
const target = event.target as HTMLElement
|
||||
const { scrollTop, scrollHeight, clientHeight } = target
|
||||
|
||||
// 检查是否需要加载更多
|
||||
if (scrollHeight - scrollTop - clientHeight < 100 && !loading.value && hasMore.value) {
|
||||
performSearch(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -231,94 +160,27 @@ const addToPlaylist = (song: any): void => {
|
||||
<!-- 搜索结果标题 -->
|
||||
<div class="search-header">
|
||||
<h2 class="search-title">
|
||||
搜索"<span class="keyword">{{ keyword }}</span>"
|
||||
搜索"<span class="keyword">{{ keyword }}</span
|
||||
>"
|
||||
</h2>
|
||||
<div v-if="hasResults" class="result-info">找到 {{ totalItems }} 首单曲</div>
|
||||
</div>
|
||||
|
||||
<!-- 歌曲列表 -->
|
||||
<div v-if="hasResults" class="song-list-wrapper">
|
||||
<!-- 表头 -->
|
||||
<div class="list-header">
|
||||
<div class="col-index"></div>
|
||||
<div class="col-title">标题</div>
|
||||
<div class="col-album">专辑</div>
|
||||
<div class="col-like">喜欢</div>
|
||||
<div class="col-duration">时长</div>
|
||||
</div>
|
||||
|
||||
<!-- 虚拟滚动列表 -->
|
||||
<div ref="scrollContainer" class="virtual-scroll-container"
|
||||
:style="{ height: virtualScrollConfig.containerHeight + 'px' }" @scroll="handleScroll">
|
||||
<div class="virtual-scroll-spacer" :style="{ height: totalHeight + 'px' }">
|
||||
<div class="virtual-scroll-content" :style="{ transform: `translateY(${offsetY}px)` }">
|
||||
<div v-for="(song, index) in visibleItems" :key="song.songmid" class="song-item"
|
||||
:class="{ 'is-playing': false, 'is-hovered': hoveredSong === song.songmid }"
|
||||
@mouseenter="hoveredSong = song.songmid" @mouseleave="hoveredSong = null" @dblclick="playSong(song)">
|
||||
<!-- 序号/播放按钮 -->
|
||||
<div class="col-index">
|
||||
<span v-if="hoveredSong !== song.songmid" class="track-number">
|
||||
{{ String(visibleStartIndex + index + 1).padStart(2, '0') }}
|
||||
</span>
|
||||
<t-button v-else variant="text" size="small" class="play-btn" title="添加到播放列表"
|
||||
@click.stop="addToPlaylist(song)">
|
||||
<play-icon size="30" />
|
||||
</t-button>
|
||||
</div>
|
||||
|
||||
<!-- 歌曲信息 -->
|
||||
<div class="col-title">
|
||||
<div v-if="song.img" class="song-cover">
|
||||
<img :src="song.img
|
||||
" loading="lazy" alt="封面" />
|
||||
</div>
|
||||
<div class="song-info">
|
||||
<div class="song-name" :title="song.name">{{ song.name }}</div>
|
||||
<div class="artist-name" :title="song.singer ? song.singer : ''">
|
||||
<template v-if="song.singer">
|
||||
<span class="artist-link">
|
||||
{{ song.singer }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 专辑 -->
|
||||
<div class="col-album">
|
||||
<span class="album-name" :title="song.albumName">
|
||||
{{ song.albumName || '-' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 喜欢按钮 -->
|
||||
<div class="col-like">
|
||||
<t-button variant="text" size="small" class="action-btn like-btn" @click.stop>
|
||||
<heart-icon size="16" />
|
||||
</t-button>
|
||||
</div>
|
||||
|
||||
<!-- 时长和更多操作 -->
|
||||
<div class="col-duration">
|
||||
<div class="duration-wrapper">
|
||||
<span v-if="hoveredSong !== song.songmid" class="duration">{{
|
||||
song.interval
|
||||
}}</span>
|
||||
<div v-else class="action-buttons">
|
||||
<t-button variant="text" size="small" class="action-btn" title="下载"
|
||||
@click.stop="downloadSingleSong(song.songmid as unknown as string, song.name, song.albumName)">
|
||||
<download-icon size="16" />
|
||||
</t-button>
|
||||
<t-button variant="text" size="small" class="action-btn" title="更多" @click.stop>
|
||||
<more-icon size="16" />
|
||||
</t-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SongVirtualList
|
||||
:songs="searchResults"
|
||||
:current-song="currentSong"
|
||||
:is-playing="isPlaying"
|
||||
:show-index="true"
|
||||
:show-album="true"
|
||||
:show-duration="true"
|
||||
@play="handlePlay"
|
||||
@pause="handlePause"
|
||||
@download="handleDownload"
|
||||
@add-to-playlist="handleAddToPlaylist"
|
||||
@scroll="handleScroll"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
@@ -332,7 +194,10 @@ const addToPlaylist = (song: any): void => {
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-else class="loading-state">
|
||||
<t-loading size="large" text="搜索中..." />
|
||||
<div class="loading-content">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>搜索中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -344,6 +209,8 @@ const addToPlaylist = (song: any): void => {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.search-header {
|
||||
@@ -371,237 +238,10 @@ const addToPlaylist = (song: any): void => {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr 200px 60px 80px;
|
||||
padding: 8px 20px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
|
||||
.col-index {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.col-like {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.col-duration {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-scroll-container {
|
||||
background: #fff;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
|
||||
.virtual-scroll-spacer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.virtual-scroll-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.song-item {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr 200px 60px 80px;
|
||||
padding: 8px 20px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
height: 64px;
|
||||
/* 固定高度,与虚拟滚动配置一致 */
|
||||
|
||||
&:hover,
|
||||
&.is-hovered {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
&.is-playing {
|
||||
background: #f0f7ff;
|
||||
color: #507daf;
|
||||
}
|
||||
|
||||
.col-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.track-number {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
color: #507daf;
|
||||
|
||||
&:hover {
|
||||
color: #3a5d8f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 10px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.song-cover {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.song-info {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
|
||||
.song-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.2;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
}
|
||||
}
|
||||
|
||||
.artist-name {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.2;
|
||||
|
||||
.artist-link {
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-album {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.album-name {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-like {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.like-btn {
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
background: rgba(80, 125, 175, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-duration {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.duration-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
||||
.duration {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
font-variant-numeric: tabular-nums;
|
||||
min-width: 35px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
justify-content: center;
|
||||
|
||||
.action-btn {
|
||||
color: #ccc;
|
||||
padding: 0 4px;
|
||||
|
||||
&:hover {
|
||||
color: #507daf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.load-more {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #f5f5f5;
|
||||
background: #fafafa;
|
||||
|
||||
.load-more-tip,
|
||||
.load-complete {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.empty-state,
|
||||
@@ -632,6 +272,35 @@ const addToPlaylist = (song: any): void => {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
text-align: center;
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #507daf;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@@ -639,21 +308,5 @@ const addToPlaylist = (song: any): void => {
|
||||
.search-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.list-header,
|
||||
.song-item {
|
||||
grid-template-columns: 50px 1fr 50px 60px;
|
||||
|
||||
.col-album {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
.song-cover {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -52,6 +52,7 @@ const clearAPIKey = (): void => {
|
||||
}
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed, watch } from 'vue'
|
||||
import MusicCache from '@renderer/components/Settings/MusicCache.vue'
|
||||
const router = useRouter()
|
||||
const goPlugin = () => {
|
||||
router.push('/plugins')
|
||||
@@ -202,16 +203,6 @@ const getCurrentSourceName = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>当前风格预览</h3>
|
||||
<div class="preview-container">
|
||||
<div class="mock-titlebar">
|
||||
<div class="mock-title">Ceru Music - 设置</div>
|
||||
<TitleBarControls :control-style="currentStyle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>两种风格对比</h3>
|
||||
<div class="comparison-container">
|
||||
@@ -232,7 +223,10 @@ const getCurrentSourceName = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>应用主题色</h3>
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
<div class="demo-section">
|
||||
<h3>DeepSeek API 配置</h3>
|
||||
<div class="api-config-container">
|
||||
@@ -303,7 +297,6 @@ const getCurrentSourceName = () => {
|
||||
<PlaylistSettings />
|
||||
<!-- <PlaylistActions></PlaylistActions> -->
|
||||
</div>
|
||||
|
||||
<!-- 插件管理部分 -->
|
||||
<div class="demo-section">
|
||||
<h3>插件管理</h3>
|
||||
@@ -432,6 +425,12 @@ const getCurrentSourceName = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-section">
|
||||
<div>
|
||||
<MusicCache></MusicCache>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>功能说明</h3>
|
||||
@@ -768,8 +767,8 @@ const getCurrentSourceName = () => {
|
||||
}
|
||||
|
||||
.plugin-status {
|
||||
background: #10b981;
|
||||
color: rgb(0, 0, 0);
|
||||
background: var(--td-brand-color-5);
|
||||
color: var(--td-gray-color-1);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 1rem;
|
||||
font-size: 0.875rem;
|
||||
@@ -822,8 +821,8 @@ const getCurrentSourceName = () => {
|
||||
|
||||
&.active {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-color: #10b981;
|
||||
box-shadow: 0 0 20px rgba(16, 185, 129, 0.3);
|
||||
border-color: var(--td-brand-color-5);
|
||||
box-shadow: 0 0 20px var(--td-gray-color-6);
|
||||
}
|
||||
|
||||
.source-icon {
|
||||
@@ -899,12 +898,12 @@ const getCurrentSourceName = () => {
|
||||
}
|
||||
|
||||
:deep(.t-slider__track-active) {
|
||||
background: linear-gradient(90deg, #10b981, #059669);
|
||||
background: linear-gradient(90deg, var(--td-brand-color-5), var(--td-brand-color-6));
|
||||
}
|
||||
|
||||
:deep(.t-slider__button) {
|
||||
background: white;
|
||||
border: 3px solid #10b981;
|
||||
border: 3px solid var(--td-brand-color-5);
|
||||
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
}
|
||||
@@ -951,7 +950,7 @@ const getCurrentSourceName = () => {
|
||||
|
||||
.status-value {
|
||||
font-weight: 600;
|
||||
color: #10b981;
|
||||
color: var(--td-brand-color-6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.current-tag {
|
||||
background-color: #28a745;
|
||||
background-color: var(--td-brand-color-5);
|
||||
color: white;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
@@ -810,7 +810,7 @@ onMounted(async () => {
|
||||
font-size: 12px;
|
||||
|
||||
.console-prompt {
|
||||
color: #00d4aa;
|
||||
color: var(--td-brand-color-5);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
15
src/types/global.d.ts
vendored
15
src/types/global.d.ts
vendored
@@ -1,4 +1,19 @@
|
||||
import { CacheInfo, CacheOperationResult } from './musicCache'
|
||||
|
||||
// 全局类型定义
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: {
|
||||
// 音乐缓存相关
|
||||
musicCache: {
|
||||
getInfo: () => Promise<CacheInfo>
|
||||
clear: () => Promise<CacheOperationResult>
|
||||
getSize: () => Promise<number>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace LX {
|
||||
namespace Music {
|
||||
// 音质类型
|
||||
|
||||
10
src/types/musicCache.ts
Normal file
10
src/types/musicCache.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface CacheInfo {
|
||||
count: number
|
||||
size: number
|
||||
sizeFormatted: string
|
||||
}
|
||||
|
||||
export interface CacheOperationResult {
|
||||
success: boolean
|
||||
message: string
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
log [CeruMusic] Plugin "ikun音源" loaded successfully.
|
||||
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.
|
||||
@@ -16,6 +16,9 @@
|
||||
],
|
||||
"@common/*":[
|
||||
"src/common/*"
|
||||
],
|
||||
"@types/*": [
|
||||
"src/renderer/src/types/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@@ -4512,6 +4512,11 @@ hosted-git-info@^4.1.0:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
hpagent@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmmirror.com/hpagent/-/hpagent-1.2.0.tgz#0ae417895430eb3770c03443456b8d90ca464903"
|
||||
integrity sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==
|
||||
|
||||
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz"
|
||||
@@ -5303,6 +5308,11 @@ lodash@^4.17.15:
|
||||
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
log-symbols@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user