mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 11:29:42 +08:00
add: 多源音乐 优化日志相关功能
This commit is contained in:
@@ -2,3 +2,4 @@ singleQuote: true
|
||||
semi: false
|
||||
printWidth: 100
|
||||
trailingComma: none
|
||||
endOfLine: "auto"
|
||||
@@ -10,10 +10,20 @@ import topLevelAwait from 'vite-plugin-top-level-await'
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
plugins: [externalizeDepsPlugin()]
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@common': resolve('src/common')
|
||||
}
|
||||
}
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin()]
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@common': resolve('src/common')
|
||||
}
|
||||
}
|
||||
},
|
||||
renderer: {
|
||||
plugins: [
|
||||
@@ -44,7 +54,8 @@ export default defineConfig({
|
||||
'@components': resolve('src/renderer/src/components'),
|
||||
'@services': resolve('src/renderer/src/services'),
|
||||
'@types': resolve('src/renderer/src/types'),
|
||||
'@store': resolve('src/renderer/src/store')
|
||||
'@store': resolve('src/renderer/src/store'),
|
||||
'@common': resolve('src/common')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,98 @@
|
||||
import tseslint from '@electron-toolkit/eslint-config-ts'
|
||||
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
|
||||
import eslintPluginVue from 'eslint-plugin-vue'
|
||||
import vueParser from 'vue-eslint-parser'
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules',
|
||||
'**/dist',
|
||||
'**/out',
|
||||
'**/src/renderer/src/assets/icon_font/iconfont.js'
|
||||
]
|
||||
},
|
||||
tseslint.configs.recommended,
|
||||
eslintPluginVue.configs['flat/recommended'],
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parser: vueParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
},
|
||||
extraFileExtensions: ['.vue'],
|
||||
parser: tseslint.parser
|
||||
const baseRule = {
|
||||
'no-new': 'off',
|
||||
camelcase: 'off',
|
||||
'no-return-assign': 'off',
|
||||
'space-before-function-paren': ['error', 'never'],
|
||||
'no-var': 'error',
|
||||
'no-fallthrough': 'off',
|
||||
eqeqeq: 'off',
|
||||
'require-atomic-updates': ['error', { allowProperties: true }],
|
||||
'no-multiple-empty-lines': [1, { max: 2 }],
|
||||
'comma-dangle': [2, 'always-multiline'],
|
||||
'standard/no-callback-literal': 'off',
|
||||
'prefer-const': 'off',
|
||||
'no-labels': 'off',
|
||||
'node/no-callback-literal': 'off',
|
||||
'multiline-ternary': 'off',
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.{ts,mts,tsx,vue}'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'no-empty-pattern': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'@typescript-eslint/no-unsafe-function-return-type': 'off',
|
||||
const typescriptRule = {
|
||||
...baseRule,
|
||||
'@typescript-eslint/strict-boolean-expressions': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'vue/block-lang': [
|
||||
'@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/no-misused-promises': [
|
||||
'error',
|
||||
{
|
||||
script: {
|
||||
lang: 'ts'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
checksVoidReturn: {
|
||||
arguments: false,
|
||||
attributes: false,
|
||||
},
|
||||
eslintConfigPrettier
|
||||
)
|
||||
},
|
||||
],
|
||||
'@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',
|
||||
}
|
||||
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',
|
||||
}
|
||||
|
||||
exports.base = {
|
||||
extends: ['standard'],
|
||||
rules: baseRule,
|
||||
parser: '@babel/eslint-parser',
|
||||
}
|
||||
|
||||
exports.html = {
|
||||
files: ['*.html'],
|
||||
plugins: ['html'],
|
||||
}
|
||||
|
||||
exports.typescript = {
|
||||
files: ['*.ts'],
|
||||
rules: typescriptRule,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: [
|
||||
'standard-with-typescript',
|
||||
],
|
||||
}
|
||||
|
||||
exports.vue = {
|
||||
files: ['*.vue'],
|
||||
rules: vueRule,
|
||||
parser: 'vue-eslint-parser',
|
||||
extends: [
|
||||
// 'plugin:vue/vue3-essential',
|
||||
'plugin:vue/base',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:vue-pug/vue3-recommended',
|
||||
// "plugin:vue/strongly-recommended"
|
||||
'standard-with-typescript',
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
parser: {
|
||||
// Script parser for `<script>`
|
||||
js: '@typescript-eslint/parser',
|
||||
|
||||
// Script parser for `<script lang="ts">`
|
||||
ts: '@typescript-eslint/parser',
|
||||
},
|
||||
extraFileExtensions: ['.vue'],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,20 +40,25 @@
|
||||
"@pixi/filter-bulge-pinch": "^5.1.1",
|
||||
"@pixi/filter-color-matrix": "^7.4.3",
|
||||
"@pixi/sprite": "^7.4.3",
|
||||
"@types/needle": "^3.3.0",
|
||||
"NeteaseCloudMusicApi": "^4.27.0",
|
||||
"axios": "^1.11.0",
|
||||
"color-extraction": "^1.0.8",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dompurify": "^3.2.6",
|
||||
"electron-log": "^5.4.3",
|
||||
"electron-updater": "^6.3.9",
|
||||
"iconv-lite": "^0.7.0",
|
||||
"jss": "^10.10.0",
|
||||
"jss-preset-default": "^10.10.0",
|
||||
"marked": "^16.1.2",
|
||||
"mitt": "^3.0.1",
|
||||
"NeteaseCloudMusicApi": "^4.27.0",
|
||||
"needle": "^3.3.1",
|
||||
"node-fetch": "2",
|
||||
"pinia": "^3.0.3",
|
||||
"tdesign-vue-next": "^1.15.2",
|
||||
"vue-router": "^4.5.1"
|
||||
"vue-router": "^4.5.1",
|
||||
"zlib": "^1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-arrow-functions": "^7.27.1",
|
||||
|
||||
1243
plugin/logs/03016a9582c847969d16ebc8931361da.txt
Normal file
1243
plugin/logs/03016a9582c847969d16ebc8931361da.txt
Normal file
File diff suppressed because it is too large
Load Diff
145
plugin/logs/36e8a2339944464684ff81e9be5799c4.txt
Normal file
145
plugin/logs/36e8a2339944464684ff81e9be5799c4.txt
Normal file
@@ -0,0 +1,145 @@
|
||||
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.
|
||||
100
plugin/logs/4e26ad8b68d44462bbe7efbdeeebf7b5.txt
Normal file
100
plugin/logs/4e26ad8b68d44462bbe7efbdeeebf7b5.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
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]
|
||||
28
plugin/logs/5985227eb30140bea43e5eac567aede6.txt
Normal file
28
plugin/logs/5985227eb30140bea43e5eac567aede6.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
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 音乐插件] 请求失败: 歌曲不存在"
|
||||
200
plugin/logs/69d0f04fad5a4ae3bdb2d256eb05939f.txt
Normal file
200
plugin/logs/69d0f04fad5a4ae3bdb2d256eb05939f.txt
Normal file
@@ -0,0 +1,200 @@
|
||||
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
|
||||
611
plugin/logs/92f1f743bf4e4ef2897f1697a0ccde8f.txt
Normal file
611
plugin/logs/92f1f743bf4e4ef2897f1697a0ccde8f.txt
Normal file
@@ -0,0 +1,611 @@
|
||||
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] 事件驱动插件初始化成功
|
||||
2523
plugin/logs/a4f47a9638be4caba2eb850e4a0a7230.txt
Normal file
2523
plugin/logs/a4f47a9638be4caba2eb850e4a0a7230.txt
Normal file
File diff suppressed because it is too large
Load Diff
83
plugin/logs/b02cbd5dd80442f1802d8e62a5f7998d.txt
Normal file
83
plugin/logs/b02cbd5dd80442f1802d8e62a5f7998d.txt
Normal file
@@ -0,0 +1,83 @@
|
||||
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
|
||||
52
plugin/logs/temp.txt
Normal file
52
plugin/logs/temp.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
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
|
||||
75
plugins/36e8a2339944464684ff81e9be5799c4-ceruplugin_js
Normal file
75
plugins/36e8a2339944464684ff81e9be5799c4-ceruplugin_js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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,
|
||||
}
|
||||
284
plugins/a4f47a9638be4caba2eb850e4a0a7230-ikun-music-source_js
Normal file
284
plugins/a4f47a9638be4caba2eb850e4a0a7230-ikun-music-source_js
Normal file
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* 由 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
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* ikun 音源插件 for CeruMusic
|
||||
* @author ikunshare
|
||||
* @version v1.0
|
||||
*/
|
||||
|
||||
// 插件元信息
|
||||
const pluginInfo = {
|
||||
name: 'ikun音源',
|
||||
version: '1.0.0',
|
||||
author: 'ikunshare',
|
||||
description: '基于 ikunshare API 的音源插件',
|
||||
};
|
||||
|
||||
// API 配置
|
||||
const API_URL = "https://api.ikunshare.com";
|
||||
const API_KEY = ``; // 如果需要,请填入你的API Key
|
||||
|
||||
// 支持的音源和音质
|
||||
const sources = {
|
||||
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"],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取音乐URL的核心函数
|
||||
* @param {string} source - 音源标识 (e.g., "kw", "wy")
|
||||
* @param {object} musicInfo - 歌曲信息
|
||||
* @param {string} quality - 音质
|
||||
* @returns {Promise<string>} 歌曲的URL
|
||||
*/
|
||||
async function musicUrl(source, musicInfo, quality) {
|
||||
// cerumusic 对象由插件宿主提供
|
||||
const { request, env, version } = cerumusic;
|
||||
|
||||
const songId = musicInfo.hash ?? musicInfo.songmid;
|
||||
const url = `${API_URL}/url?source=${source}&songId=${songId}&quality=${quality}`;
|
||||
|
||||
console.log(`[${pluginInfo.name}] Requesting URL: ${url}`);
|
||||
|
||||
const { body, statusCode } = await request(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': `cerumusic-${env}/${version}`,
|
||||
'X-Request-Key': API_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
if (statusCode !== 200 || body.code !== 200) {
|
||||
const errorMessage = body.msg || `接口错误 (HTTP: ${statusCode}, Body: ${body.code})`;
|
||||
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
console.log(`[${pluginInfo.name}] Got URL: ${body.url}`);
|
||||
return body.url;
|
||||
}
|
||||
|
||||
// 导出插件模块
|
||||
module.exports = {
|
||||
pluginInfo,
|
||||
sources,
|
||||
musicUrl,
|
||||
// 如果需要,可以继续实现 getPic, getLyric 等方法
|
||||
// getPic: async function(source, musicInfo) { ... },
|
||||
// getLyric: async function(source, musicInfo) { ... },
|
||||
};
|
||||
42
src/common/index.ts
Normal file
42
src/common/index.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import log from 'electron-log/node'
|
||||
|
||||
export const isLinux = process.platform == 'linux'
|
||||
export const isWin = process.platform == 'win32'
|
||||
export const isMac = process.platform == 'darwin'
|
||||
export const isProd = process.env.NODE_ENV == 'production'
|
||||
|
||||
export const getPlatform = (platform: NodeJS.Platform = process.platform) => {
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
return 'windows'
|
||||
case 'darwin':
|
||||
return 'mac'
|
||||
default:
|
||||
return 'linux'
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/53387532
|
||||
export function compareVer(currentVer: string, targetVer: string): -1 | 0 | 1 {
|
||||
// treat non-numerical characters as lower version
|
||||
// replacing them with a negative number based on charcode of each character
|
||||
const fix = (s: string) => `.${s.toLowerCase().charCodeAt(0) - 2147483647}.`
|
||||
|
||||
const currentVerArr: Array<string | number> = ('' + currentVer)
|
||||
.replace(/[^0-9.]/g, fix)
|
||||
.split('.')
|
||||
const targetVerArr: Array<string | number> = ('' + targetVer).replace(/[^0-9.]/g, fix).split('.')
|
||||
let c = Math.max(currentVerArr.length, targetVerArr.length)
|
||||
for (let i = 0; i < c; i++) {
|
||||
// convert to integer the most efficient way
|
||||
currentVerArr[i] = ~~currentVerArr[i]
|
||||
targetVerArr[i] = ~~targetVerArr[i]
|
||||
if (currentVerArr[i] > targetVerArr[i]) return 1
|
||||
else if (currentVerArr[i] < targetVerArr[i]) return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
export { log }
|
||||
|
||||
export * from './utils/common'
|
||||
239
src/common/utils/common.ts
Normal file
239
src/common/utils/common.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
// 非业务工具方法
|
||||
|
||||
/**
|
||||
* 获取两个数之间的随机整数,大于等于min,小于max
|
||||
* @param {*} min
|
||||
* @param {*} max
|
||||
*/
|
||||
export const getRandom = (min: number, max: number): number =>
|
||||
Math.floor(Math.random() * (max - min)) + min
|
||||
|
||||
export const sizeFormate = (size: number): string => {
|
||||
// https://gist.github.com/thomseddon/3511330
|
||||
if (!size) return '0 B'
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
const number = Math.floor(Math.log(size) / Math.log(1024))
|
||||
return `${(size / Math.pow(1024, Math.floor(number))).toFixed(2)} ${units[number]}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串、时间戳等格式转成时间对象
|
||||
* @param date 时间
|
||||
* @returns 时间对象或空字符串
|
||||
*/
|
||||
export const toDateObj = (date: any): Date | '' => {
|
||||
// console.log(date)
|
||||
if (!date) return ''
|
||||
switch (typeof date) {
|
||||
case 'string':
|
||||
if (!date.includes('T')) date = date.split('.')[0].replace(/-/g, '/')
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case 'number':
|
||||
date = new Date(date)
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case 'object':
|
||||
break
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
const numFix = (n: number): string => (n < 10 ? `0${n}` : n.toString())
|
||||
/**
|
||||
* 时间格式化
|
||||
* @param _date 时间
|
||||
* @param format Y-M-D h:m:s Y年 M月 D日 h时 m分 s秒
|
||||
*/
|
||||
export const dateFormat = (_date: any, format = 'Y-M-D h:m:s') => {
|
||||
// console.log(date)
|
||||
const date = toDateObj(_date)
|
||||
if (!date) return ''
|
||||
return format
|
||||
.replace('Y', date.getFullYear().toString())
|
||||
.replace('M', numFix(date.getMonth() + 1))
|
||||
.replace('D', numFix(date.getDate()))
|
||||
.replace('h', numFix(date.getHours()))
|
||||
.replace('m', numFix(date.getMinutes()))
|
||||
.replace('s', numFix(date.getSeconds()))
|
||||
}
|
||||
|
||||
export const formatPlayTime = (time: number) => {
|
||||
const m = Math.trunc(time / 60)
|
||||
const s = Math.trunc(time % 60)
|
||||
return m == 0 && s == 0 ? '--/--' : numFix(m) + ':' + numFix(s)
|
||||
}
|
||||
|
||||
export const formatPlayTime2 = (time: number) => {
|
||||
const m = Math.trunc(time / 60)
|
||||
const s = Math.trunc(time % 60)
|
||||
return numFix(m) + ':' + numFix(s)
|
||||
}
|
||||
|
||||
export const isUrl = (path: string) => /https?:\/\//.test(path)
|
||||
|
||||
// 解析URL参数为对象
|
||||
export const parseUrlParams = (str: string): Record<string, string> => {
|
||||
const params: Record<string, string> = {}
|
||||
if (typeof str !== 'string') return params
|
||||
const paramsArr = str.split('&')
|
||||
for (const param of paramsArr) {
|
||||
const [key, value] = param.split('=')
|
||||
params[key] = value
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成节流函数
|
||||
* @param fn 回调
|
||||
* @param delay 延迟
|
||||
* @returns
|
||||
*/
|
||||
export function throttle<Args extends any[]>(
|
||||
fn: (...args: Args) => void | Promise<void>,
|
||||
delay = 100
|
||||
) {
|
||||
let timer: NodeJS.Timeout | null = null
|
||||
let _args: Args
|
||||
return (...args: Args) => {
|
||||
_args = args
|
||||
if (timer) return
|
||||
timer = setTimeout(() => {
|
||||
timer = null
|
||||
void fn(..._args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成防抖函数
|
||||
* @param fn 回调
|
||||
* @param delay 延迟
|
||||
* @returns
|
||||
*/
|
||||
export function debounce<Args extends any[]>(
|
||||
fn: (...args: Args) => void | Promise<void>,
|
||||
delay = 100
|
||||
) {
|
||||
let timer: NodeJS.Timeout | null = null
|
||||
let _args: Args
|
||||
return (...args: Args) => {
|
||||
_args = args
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
timer = null
|
||||
void fn(..._args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
const fileNameRxp = /[\\/:*?#"<>|]/g
|
||||
export const filterFileName = (name: string): string => name.replace(fileNameRxp, '')
|
||||
|
||||
// https://blog.csdn.net/xcxy2015/article/details/77164126#comments
|
||||
/**
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
export const similar = (a: string, b: string) => {
|
||||
if (!a || !b) return 0
|
||||
if (a.length > b.length) {
|
||||
// 保证 a <= b
|
||||
const t = b
|
||||
b = a
|
||||
a = t
|
||||
}
|
||||
const al = a.length
|
||||
const bl = b.length
|
||||
const mp: number[] = [] // 一个表
|
||||
let i, j, ai, lt, tmp // ai:字符串a的第i个字符。 lt:左上角的值。 tmp:暂存新的值。
|
||||
for (i = 0; i <= bl; i++) mp[i] = i
|
||||
for (i = 1; i <= al; i++) {
|
||||
ai = a.charAt(i - 1)
|
||||
lt = mp[0]
|
||||
mp[0] = mp[0] + 1
|
||||
for (j = 1; j <= bl; j++) {
|
||||
tmp = Math.min(mp[j] + 1, mp[j - 1] + 1, lt + (ai == b.charAt(j - 1) ? 0 : 1))
|
||||
lt = mp[j]
|
||||
mp[j] = tmp
|
||||
}
|
||||
}
|
||||
return 1 - mp[bl] / bl
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序字符串
|
||||
* @param arr
|
||||
* @param data
|
||||
*/
|
||||
export const sortInsert = <T>(
|
||||
arr: Array<{ num: number; data: T }>,
|
||||
data: { num: number; data: T }
|
||||
) => {
|
||||
const key = data.num
|
||||
let left = 0
|
||||
let right = arr.length - 1
|
||||
|
||||
while (left <= right) {
|
||||
const middle = Math.trunc((left + right) / 2)
|
||||
if (key == arr[middle].num) {
|
||||
left = middle
|
||||
break
|
||||
} else if (key < arr[middle].num) {
|
||||
right = middle - 1
|
||||
} else {
|
||||
left = middle + 1
|
||||
}
|
||||
}
|
||||
while (left > 0) {
|
||||
if (arr[left - 1].num != key) break
|
||||
left--
|
||||
}
|
||||
|
||||
arr.splice(left, 0, data)
|
||||
}
|
||||
|
||||
export const encodePath = (path: string) => {
|
||||
return encodeURI(path.replaceAll('\\', '/'))
|
||||
}
|
||||
|
||||
export const arrPush = <T>(list: T[], newList: T[]) => {
|
||||
for (let i = 0; i * 1000 < newList.length; i++) {
|
||||
list.push(...newList.slice(i * 1000, (i + 1) * 1000))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
export const arrUnshift = <T>(list: T[], newList: T[]) => {
|
||||
for (let i = 0; i * 1000 < newList.length; i++) {
|
||||
list.splice(i * 1000, 0, ...newList.slice(i * 1000, (i + 1) * 1000))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
export const arrPushByPosition = <T>(list: T[], newList: T[], position: number) => {
|
||||
for (let i = 0; i * 1000 < newList.length; i++) {
|
||||
list.splice(position + i * 1000, 0, ...newList.slice(i * 1000, (i + 1) * 1000))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/2450976
|
||||
export const arrShuffle = <T>(array: T[]) => {
|
||||
let currentIndex = array.length
|
||||
let randomIndex
|
||||
|
||||
// While there remain elements to shuffle.
|
||||
while (currentIndex != 0) {
|
||||
// Pick a remaining element.
|
||||
randomIndex = Math.floor(Math.random() * currentIndex)
|
||||
currentIndex--
|
||||
|
||||
// And swap it with the current element.
|
||||
;[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
82
src/common/utils/lyricUtils/kg.js
Normal file
82
src/common/utils/lyricUtils/kg.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import { inflate } from 'zlib'
|
||||
import { decodeName } from './util'
|
||||
|
||||
// https://github.com/lyswhut/lx-music-desktop/issues/296#issuecomment-683285784
|
||||
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
|
||||
const buf_str = Buffer.from(str, 'base64').subarray(4)
|
||||
for (let i = 0, len = buf_str.length; i < len; i++) {
|
||||
buf_str[i] = buf_str[i] ^ enc_key[i % 16]
|
||||
}
|
||||
inflate(buf_str, (err, result) => {
|
||||
if (err) return reject(err)
|
||||
resolve(result.toString())
|
||||
})
|
||||
})
|
||||
|
||||
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, '')
|
||||
let trans = str.match(/\[language:([\w=\\/+]+)\]/)
|
||||
let lyric
|
||||
let rlyric
|
||||
let tlyric
|
||||
if (trans) {
|
||||
str = str.replace(/\[language:[\w=\\/+]+\]\n/, '')
|
||||
let json = JSON.parse(Buffer.from(trans[1], 'base64').toString())
|
||||
for (const item of json.content) {
|
||||
switch (item.type) {
|
||||
case 0:
|
||||
rlyric = item.lyricContent
|
||||
break
|
||||
case 1:
|
||||
tlyric = item.lyricContent
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
let i = 0
|
||||
let lxlyric = str.replace(/\[((\d+),\d+)\].*/g, (str) => {
|
||||
let result = str.match(/\[((\d+),\d+)\].*/)
|
||||
let time = parseInt(result[2])
|
||||
let ms = time % 1000
|
||||
time /= 1000
|
||||
let m = parseInt(time / 60)
|
||||
.toString()
|
||||
.padStart(2, '0')
|
||||
time %= 60
|
||||
let s = parseInt(time).toString().padStart(2, '0')
|
||||
time = `${m}:${s}.${ms}`
|
||||
if (rlyric) rlyric[i] = `[${time}]${rlyric[i]?.join('') ?? ''}`
|
||||
if (tlyric) tlyric[i] = `[${time}]${tlyric[i]?.join('') ?? ''}`
|
||||
i++
|
||||
return str.replace(result[1], time)
|
||||
})
|
||||
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, '')
|
||||
rlyric = decodeName(rlyric)
|
||||
tlyric = decodeName(tlyric)
|
||||
return {
|
||||
lyric,
|
||||
tlyric,
|
||||
rlyric,
|
||||
lxlyric
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export const decodeKrc = async (data) => {
|
||||
return decodeLyric(data).then(parseLyric)
|
||||
}
|
||||
18
src/common/utils/lyricUtils/util.ts
Normal file
18
src/common/utils/lyricUtils/util.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
const encodeNames = {
|
||||
' ': ' ',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
''': "'",
|
||||
''': "'"
|
||||
} as const
|
||||
|
||||
export const decodeName = (str: string | null = '') => {
|
||||
return (
|
||||
str?.replace(
|
||||
/(?:&|<|>|"|'|'| )/gm,
|
||||
(s: string) => encodeNames[s as keyof typeof encodeNames]
|
||||
) ?? ''
|
||||
)
|
||||
}
|
||||
187
src/common/utils/nodejs.ts
Normal file
187
src/common/utils/nodejs.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import fs from 'node:fs'
|
||||
import crypto from 'node:crypto'
|
||||
import { gzip, gunzip } from 'node:zlib'
|
||||
import path from 'node:path'
|
||||
import { networkInterfaces } from 'node:os'
|
||||
|
||||
export const joinPath = (...paths: string[]): string => path.join(...paths)
|
||||
|
||||
export const extname = (p: string): string => path.extname(p)
|
||||
export const basename = (p: string, ext?: string): string => path.basename(p, ext)
|
||||
export const dirname = (p: string): string => path.dirname(p)
|
||||
|
||||
/**
|
||||
* 检查路径是否存在
|
||||
* @param {*} path 路径
|
||||
*/
|
||||
export const checkPath = async (path: string): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
if (!path) {
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
fs.access(path, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径并创建目录
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
export const checkAndCreateDir = async (path: string) => {
|
||||
return fs.promises
|
||||
.access(path, fs.constants.F_OK | fs.constants.W_OK)
|
||||
.catch(async (err: NodeJS.ErrnoException) => {
|
||||
if (err.code != 'ENOENT') throw err as Error
|
||||
return fs.promises.mkdir(path, { recursive: true })
|
||||
})
|
||||
.then(() => true)
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
export const getFileStats = async (path: string): Promise<fs.Stats | null> => {
|
||||
return new Promise((resolve) => {
|
||||
if (!path) {
|
||||
resolve(null)
|
||||
return
|
||||
}
|
||||
fs.stat(path, (err, stats) => {
|
||||
if (err) {
|
||||
resolve(null)
|
||||
return
|
||||
}
|
||||
resolve(stats)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径并创建目录
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
export const createDir = async (path: string) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
fs.access(path, fs.constants.F_OK | fs.constants.W_OK, (err) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
fs.mkdir(path, { recursive: true }, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
export const removeFile = async (path: string) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
fs.access(path, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
err.code == 'ENOENT' ? resolve() : reject(err)
|
||||
return
|
||||
}
|
||||
fs.unlink(path, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export const readFile = async (path: string) => fs.promises.readFile(path)
|
||||
|
||||
/**
|
||||
* 创建 MD5 hash
|
||||
* @param {*} str
|
||||
*/
|
||||
export const toMD5 = (str: string) => crypto.createHash('md5').update(str).digest('hex')
|
||||
|
||||
export const gzipData = async (str: string): Promise<Buffer> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
gzip(str, (err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve(result)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const gunzipData = async (buf: Buffer): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
gunzip(buf, (err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve(result.toString())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const saveStrToFile = async (path: string, str: string | Buffer): Promise<void> => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
fs.writeFile(path, str, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const b64DecodeUnicode = (str: string): string => {
|
||||
// Going backwards: from bytestream, to percent-encoding, to original string.
|
||||
// return decodeURIComponent(window.atob(str).split('').map(function(c) {
|
||||
// return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
|
||||
// }).join(''))
|
||||
|
||||
return Buffer.from(str, 'base64').toString()
|
||||
}
|
||||
|
||||
export const copyFile = async (sourcePath: string, distPath: string) => {
|
||||
return fs.promises.copyFile(sourcePath, distPath)
|
||||
}
|
||||
|
||||
export const moveFile = async (sourcePath: string, distPath: string) => {
|
||||
return fs.promises.rename(sourcePath, distPath)
|
||||
}
|
||||
|
||||
export const getAddress = (): string[] => {
|
||||
const nets = networkInterfaces()
|
||||
const results: string[] = []
|
||||
// console.log(nets)
|
||||
|
||||
for (const interfaceInfos of Object.values(nets)) {
|
||||
if (!interfaceInfos) continue
|
||||
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
||||
for (const interfaceInfo of interfaceInfos) {
|
||||
if (interfaceInfo.family === 'IPv4' && !interfaceInfo.internal) {
|
||||
results.push(interfaceInfo.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
378
src/common/utils/renderer.ts
Normal file
378
src/common/utils/renderer.ts
Normal file
@@ -0,0 +1,378 @@
|
||||
const easeInOutQuad = (t: number, b: number, c: number, d: number): number => {
|
||||
t /= d / 2
|
||||
if (t < 1) return (c / 2) * t * t + b
|
||||
t--
|
||||
return (-c / 2) * (t * (t - 2) - 1) + b
|
||||
}
|
||||
|
||||
type Noop = () => void
|
||||
const noop: Noop = () => {}
|
||||
type ScrollElement<T> = {
|
||||
lx_scrollLockKey?: number
|
||||
lx_scrollNextParams?: [ScrollElement<HTMLElement>, number, number, Noop]
|
||||
lx_scrollTimeout?: number
|
||||
lx_scrollDelayTimeout?: number
|
||||
} & T
|
||||
|
||||
const handleScrollY = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = noop
|
||||
): Noop => {
|
||||
if (!element) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
const clean = () => {
|
||||
element.lx_scrollLockKey = undefined
|
||||
element.lx_scrollNextParams = undefined
|
||||
if (element.lx_scrollTimeout) window.clearTimeout(element.lx_scrollTimeout)
|
||||
element.lx_scrollTimeout = undefined
|
||||
}
|
||||
if (element.lx_scrollLockKey) {
|
||||
element.lx_scrollNextParams = [element, to, duration, fn]
|
||||
element.lx_scrollLockKey = -1
|
||||
return clean
|
||||
}
|
||||
// @ts-expect-error
|
||||
const start = element.scrollTop ?? element.scrollY ?? 0
|
||||
if (to > start) {
|
||||
let maxScrollTop = element.scrollHeight - element.clientHeight
|
||||
if (to > maxScrollTop) to = maxScrollTop
|
||||
} else if (to < start) {
|
||||
if (to < 0) to = 0
|
||||
} else {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
const change = to - start
|
||||
const increment = 10
|
||||
if (!change) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
|
||||
let currentTime = 0
|
||||
let val: number
|
||||
let key = Math.random()
|
||||
|
||||
const animateScroll = () => {
|
||||
element.lx_scrollTimeout = undefined
|
||||
// if (element.lx_scrollLockKey != key) {
|
||||
if (element.lx_scrollNextParams && currentTime > duration * 0.75) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
return
|
||||
}
|
||||
|
||||
currentTime += increment
|
||||
val = Math.trunc(easeInOutQuad(currentTime, start, change, duration))
|
||||
if (element.scrollTo) {
|
||||
element.scrollTo(0, val)
|
||||
} else {
|
||||
element.scrollTop = val
|
||||
}
|
||||
if (currentTime < duration) {
|
||||
element.lx_scrollTimeout = window.setTimeout(animateScroll, increment)
|
||||
} else {
|
||||
if (element.lx_scrollNextParams) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
} else {
|
||||
clean()
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
element.lx_scrollLockKey = key
|
||||
animateScroll()
|
||||
|
||||
return clean
|
||||
}
|
||||
/**
|
||||
* 设置滚动条位置
|
||||
* @param {*} element 要设置滚动的容器 dom
|
||||
* @param {*} to 滚动的目标位置
|
||||
* @param {*} duration 滚动完成时间 ms
|
||||
* @param {*} fn 滚动完成后的回调
|
||||
* @param {*} delay 延迟执行时间
|
||||
*/
|
||||
export const scrollTo = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = () => {},
|
||||
delay = 0
|
||||
): (() => void) => {
|
||||
let cancelFn: () => void
|
||||
if (element.lx_scrollDelayTimeout != null) {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
if (delay) {
|
||||
let scrollCancelFn: Noop
|
||||
cancelFn = () => {
|
||||
if (element.lx_scrollDelayTimeout == null) {
|
||||
scrollCancelFn?.()
|
||||
} else {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
}
|
||||
element.lx_scrollDelayTimeout = window.setTimeout(() => {
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
scrollCancelFn = handleScrollY(element, to, duration, fn)
|
||||
}, delay)
|
||||
} else {
|
||||
cancelFn = handleScrollY(element, to, duration, fn) ?? noop
|
||||
}
|
||||
return cancelFn
|
||||
}
|
||||
const handleScrollX = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = () => {}
|
||||
): (() => void) => {
|
||||
if (!element) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
const clean = () => {
|
||||
element.lx_scrollLockKey = undefined
|
||||
element.lx_scrollNextParams = undefined
|
||||
if (element.lx_scrollTimeout) window.clearTimeout(element.lx_scrollTimeout)
|
||||
element.lx_scrollTimeout = undefined
|
||||
}
|
||||
if (element.lx_scrollLockKey) {
|
||||
element.lx_scrollNextParams = [element, to, duration, fn]
|
||||
element.lx_scrollLockKey = -1
|
||||
return clean
|
||||
}
|
||||
// @ts-expect-error
|
||||
const start = element.scrollLeft || element.scrollX || 0
|
||||
if (to > start) {
|
||||
let maxScrollLeft = element.scrollWidth - element.clientWidth
|
||||
if (to > maxScrollLeft) to = maxScrollLeft
|
||||
} else if (to < start) {
|
||||
if (to < 0) to = 0
|
||||
} else {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
const change = to - start
|
||||
const increment = 10
|
||||
if (!change) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
|
||||
let currentTime = 0
|
||||
let val: number
|
||||
let key = Math.random()
|
||||
|
||||
const animateScroll = () => {
|
||||
element.lx_scrollTimeout = undefined
|
||||
if (element.lx_scrollNextParams && currentTime > duration * 0.75) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
return
|
||||
}
|
||||
|
||||
currentTime += increment
|
||||
val = Math.trunc(easeInOutQuad(currentTime, start, change, duration))
|
||||
if (element.scrollTo) {
|
||||
element.scrollTo(val, 0)
|
||||
} else {
|
||||
element.scrollLeft = val
|
||||
}
|
||||
if (currentTime < duration) {
|
||||
element.lx_scrollTimeout = window.setTimeout(animateScroll, increment)
|
||||
} else {
|
||||
if (element.lx_scrollNextParams) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
} else {
|
||||
clean()
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
element.lx_scrollLockKey = key
|
||||
animateScroll()
|
||||
return clean
|
||||
}
|
||||
/**
|
||||
* 设置滚动条位置
|
||||
* @param {*} element 要设置滚动的容器 dom
|
||||
* @param {*} to 滚动的目标位置
|
||||
* @param {*} duration 滚动完成时间 ms
|
||||
* @param {*} fn 滚动完成后的回调
|
||||
* @param {*} delay 延迟执行时间
|
||||
*/
|
||||
export const scrollXTo = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = () => {},
|
||||
delay = 0
|
||||
): (() => void) => {
|
||||
let cancelFn: Noop
|
||||
if (element.lx_scrollDelayTimeout != null) {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
if (delay) {
|
||||
let scrollCancelFn: Noop
|
||||
cancelFn = () => {
|
||||
if (element.lx_scrollDelayTimeout == null) {
|
||||
scrollCancelFn?.()
|
||||
} else {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
}
|
||||
element.lx_scrollDelayTimeout = window.setTimeout(() => {
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
scrollCancelFn = handleScrollX(element, to, duration, fn)
|
||||
}, delay)
|
||||
} else {
|
||||
cancelFn = handleScrollX(element, to, duration, fn)
|
||||
}
|
||||
return cancelFn
|
||||
}
|
||||
|
||||
const handleScrollXR = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = () => {}
|
||||
): (() => void) => {
|
||||
if (!element) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
const clean = () => {
|
||||
element.lx_scrollLockKey = undefined
|
||||
element.lx_scrollNextParams = undefined
|
||||
if (element.lx_scrollTimeout) window.clearTimeout(element.lx_scrollTimeout)
|
||||
element.lx_scrollTimeout = undefined
|
||||
}
|
||||
if (element.lx_scrollLockKey) {
|
||||
element.lx_scrollNextParams = [element, to, duration, fn]
|
||||
element.lx_scrollLockKey = -1
|
||||
return clean
|
||||
}
|
||||
// @ts-expect-error
|
||||
const start = element.scrollLeft || (element.scrollX as number) || 0
|
||||
if (to < start) {
|
||||
let maxScrollLeft = -element.scrollWidth + element.clientWidth
|
||||
if (to < maxScrollLeft) to = maxScrollLeft
|
||||
} else if (to > start) {
|
||||
if (to > 0) to = 0
|
||||
} else {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
|
||||
const change = to - start
|
||||
const increment = 10
|
||||
if (!change) {
|
||||
fn()
|
||||
return noop
|
||||
}
|
||||
|
||||
let currentTime = 0
|
||||
let val: number
|
||||
let key = Math.random()
|
||||
|
||||
const animateScroll = () => {
|
||||
element.lx_scrollTimeout = undefined
|
||||
if (element.lx_scrollNextParams && currentTime > duration * 0.75) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
return
|
||||
}
|
||||
|
||||
currentTime += increment
|
||||
val = Math.trunc(easeInOutQuad(currentTime, start, change, duration))
|
||||
|
||||
if (element.scrollTo) {
|
||||
element.scrollTo(val, 0)
|
||||
} else {
|
||||
element.scrollLeft = val
|
||||
}
|
||||
if (currentTime < duration) {
|
||||
element.lx_scrollTimeout = window.setTimeout(animateScroll, increment)
|
||||
} else {
|
||||
if (element.lx_scrollNextParams) {
|
||||
const [_element, to, duration, fn] = element.lx_scrollNextParams
|
||||
clean()
|
||||
handleScrollY(_element, to, duration, fn)
|
||||
} else {
|
||||
clean()
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
element.lx_scrollLockKey = key
|
||||
animateScroll()
|
||||
|
||||
return clean
|
||||
}
|
||||
/**
|
||||
* 设置滚动条位置 (writing-mode: vertical-rl 专用)
|
||||
* @param element 要设置滚动的容器 dom
|
||||
* @param to 滚动的目标位置
|
||||
* @param duration 滚动完成时间 ms
|
||||
* @param fn 滚动完成后的回调
|
||||
* @param delay 延迟执行时间
|
||||
*/
|
||||
export const scrollXRTo = (
|
||||
element: ScrollElement<HTMLElement>,
|
||||
to: number,
|
||||
duration = 300,
|
||||
fn = () => {},
|
||||
delay = 0
|
||||
): (() => void) => {
|
||||
let cancelFn: Noop
|
||||
if (element.lx_scrollDelayTimeout != null) {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
if (delay) {
|
||||
let scrollCancelFn: Noop
|
||||
cancelFn = () => {
|
||||
if (element.lx_scrollDelayTimeout == null) {
|
||||
scrollCancelFn?.()
|
||||
} else {
|
||||
window.clearTimeout(element.lx_scrollDelayTimeout)
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
}
|
||||
}
|
||||
element.lx_scrollDelayTimeout = window.setTimeout(() => {
|
||||
element.lx_scrollDelayTimeout = undefined
|
||||
scrollCancelFn = handleScrollXR(element, to, duration, fn)
|
||||
}, delay)
|
||||
} else {
|
||||
cancelFn = handleScrollXR(element, to, duration, fn)
|
||||
}
|
||||
return cancelFn
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置标题
|
||||
*/
|
||||
let dom_title = document.getElementsByTagName('title')[0]
|
||||
export const setTitle = (title: string | null) => {
|
||||
title ||= 'LX Music'
|
||||
dom_title.innerText = title
|
||||
}
|
||||
148
src/common/utils/tools.ts
Normal file
148
src/common/utils/tools.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
// 业务工具方法
|
||||
|
||||
export const toNewMusicInfo = (oldMusicInfo: any): LX.Music.MusicInfo => {
|
||||
const meta: Record<string, any> = {
|
||||
songId: oldMusicInfo.songmid, // 歌曲ID,local为文件路径
|
||||
albumName: oldMusicInfo.albumName, // 歌曲专辑名称
|
||||
picUrl: oldMusicInfo.img // 歌曲图片链接
|
||||
}
|
||||
const newInfo = {
|
||||
id: `${oldMusicInfo.source}_${oldMusicInfo.songmid}`,
|
||||
name: oldMusicInfo.name,
|
||||
singer: oldMusicInfo.singer,
|
||||
source: oldMusicInfo.source,
|
||||
interval: oldMusicInfo.interval,
|
||||
meta: meta as LX.Music.MusicInfoOnline['meta']
|
||||
}
|
||||
|
||||
if (oldMusicInfo.source == 'local') {
|
||||
meta.filePath = oldMusicInfo.filePath ?? oldMusicInfo.songmid ?? ''
|
||||
meta.ext = oldMusicInfo.ext ?? /\.(\w+)$/.exec(meta.filePath)?.[1] ?? ''
|
||||
} else {
|
||||
meta.qualitys = oldMusicInfo.types
|
||||
meta._qualitys = oldMusicInfo._types
|
||||
meta.albumId = oldMusicInfo.albumId
|
||||
if (meta._qualitys.flac32bit && !meta._qualitys.flac24bit) {
|
||||
meta._qualitys.flac24bit = meta._qualitys.flac32bit
|
||||
delete meta._qualitys.flac32bit
|
||||
|
||||
meta.qualitys = (meta.qualitys as any[]).map((quality) => {
|
||||
if (quality.type == 'flac32bit') quality.type = 'flac24bit'
|
||||
return quality
|
||||
})
|
||||
}
|
||||
|
||||
switch (oldMusicInfo.source) {
|
||||
case 'kg':
|
||||
meta.hash = oldMusicInfo.hash
|
||||
newInfo.id = oldMusicInfo.songmid + '_' + oldMusicInfo.hash
|
||||
break
|
||||
case 'tx':
|
||||
meta.strMediaMid = oldMusicInfo.strMediaMid
|
||||
meta.id = oldMusicInfo.songId
|
||||
meta.albumMid = oldMusicInfo.albumMid
|
||||
break
|
||||
case 'mg':
|
||||
meta.copyrightId = oldMusicInfo.copyrightId
|
||||
meta.lrcUrl = oldMusicInfo.lrcUrl
|
||||
meta.mrcUrl = oldMusicInfo.mrcUrl
|
||||
meta.trcUrl = oldMusicInfo.trcUrl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return newInfo
|
||||
}
|
||||
|
||||
export const toOldMusicInfo = (minfo: LX.Music.MusicInfo) => {
|
||||
const oInfo: Record<string, any> = {
|
||||
name: minfo.name,
|
||||
singer: minfo.singer,
|
||||
source: minfo.source,
|
||||
songmid: minfo.meta.songId,
|
||||
interval: minfo.interval,
|
||||
albumName: minfo.meta.albumName,
|
||||
img: minfo.meta.picUrl ?? '',
|
||||
typeUrl: {}
|
||||
}
|
||||
if (minfo.source == 'local') {
|
||||
oInfo.filePath = minfo.meta.filePath
|
||||
oInfo.ext = minfo.meta.ext
|
||||
oInfo.albumId = ''
|
||||
oInfo.types = []
|
||||
oInfo._types = {}
|
||||
} else {
|
||||
oInfo.albumId = minfo.meta.albumId
|
||||
oInfo.types = minfo.meta.qualitys
|
||||
oInfo._types = minfo.meta._qualitys
|
||||
|
||||
switch (minfo.source) {
|
||||
case 'kg':
|
||||
oInfo.hash = minfo.meta.hash
|
||||
break
|
||||
case 'tx':
|
||||
oInfo.strMediaMid = minfo.meta.strMediaMid
|
||||
oInfo.albumMid = minfo.meta.albumMid
|
||||
oInfo.songId = minfo.meta.id
|
||||
break
|
||||
case 'mg':
|
||||
oInfo.copyrightId = minfo.meta.copyrightId
|
||||
oInfo.lrcUrl = minfo.meta.lrcUrl
|
||||
oInfo.mrcUrl = minfo.meta.mrcUrl
|
||||
oInfo.trcUrl = minfo.meta.trcUrl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return oInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复2.0.0-dev.8之前的新列表数据音质
|
||||
* @param musicInfo
|
||||
*/
|
||||
export const fixNewMusicInfoQuality = (musicInfo: LX.Music.MusicInfo) => {
|
||||
if (musicInfo.source == 'local') return musicInfo
|
||||
|
||||
// @ts-expect-error
|
||||
if (musicInfo.meta._qualitys.flac32bit && !musicInfo.meta._qualitys.flac24bit) {
|
||||
// @ts-expect-error
|
||||
musicInfo.meta._qualitys.flac24bit = musicInfo.meta._qualitys.flac32bit
|
||||
// @ts-expect-error
|
||||
delete musicInfo.meta._qualitys.flac32bit
|
||||
|
||||
musicInfo.meta.qualitys = musicInfo.meta.qualitys.map((quality) => {
|
||||
// @ts-expect-error
|
||||
if (quality.type == 'flac32bit') quality.type = 'flac24bit'
|
||||
return quality
|
||||
})
|
||||
}
|
||||
|
||||
return musicInfo
|
||||
}
|
||||
|
||||
export const filterMusicList = <T extends LX.Music.MusicInfo>(list: T[]): T[] => {
|
||||
const ids = new Set<string>()
|
||||
return list.filter((s) => {
|
||||
if (!s.id || ids.has(s.id) || !s.name) return false
|
||||
if (s.singer == null) s.singer = ''
|
||||
ids.add(s.id)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const MAX_NAME_LENGTH = 80
|
||||
const MAX_FILE_NAME_LENGTH = 150
|
||||
export const clipNameLength = (name: string) => {
|
||||
if (name.length <= MAX_NAME_LENGTH || !name.includes('、')) return name
|
||||
const names = name.split('、')
|
||||
let newName = names.shift()!
|
||||
for (const name of names) {
|
||||
if (newName.length + name.length > MAX_NAME_LENGTH) break
|
||||
newName = newName + '、' + name
|
||||
}
|
||||
return newName
|
||||
}
|
||||
export const clipFileNameLength = (name: string) => {
|
||||
return name.length > MAX_FILE_NAME_LENGTH ? name.substring(0, MAX_FILE_NAME_LENGTH) : name
|
||||
}
|
||||
@@ -6,6 +6,16 @@ import path from 'node:path'
|
||||
import musicService from './services/music'
|
||||
import pluginService from './services/plugin'
|
||||
import aiEvents from './events/ai'
|
||||
import './services/musicSdk/index'
|
||||
|
||||
// import wy from './utils/musicSdk/wy/index'
|
||||
// import kg from './utils/musicSdk/kg/index'
|
||||
// wy.hotSearch.getList().then((res) => {
|
||||
// console.log(res)
|
||||
// })
|
||||
// kg.hotSearch.getList().then((res) => {
|
||||
// console.log(res)
|
||||
// })
|
||||
let tray: Tray | null = null
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
let isQuitting = false
|
||||
@@ -60,6 +70,7 @@ function createTray(): void {
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
// return
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1100,
|
||||
@@ -179,6 +190,7 @@ ipcMain.handle('service-music-request', async (_, api, args) => {
|
||||
return await musicService.request(api, args)
|
||||
})
|
||||
|
||||
|
||||
aiEvents(mainWindow)
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
@@ -186,6 +198,7 @@ aiEvents(mainWindow)
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(async () => {
|
||||
// Set app user model id for windows
|
||||
|
||||
electronApp.setAppUserModelId('com.cerulean.music')
|
||||
|
||||
// 初始化插件系统
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { MusicServiceBase, ServiceNamesType, ServiceArgsType } from './service-base'
|
||||
|
||||
import {
|
||||
GetToplistArgs,
|
||||
SearchArgs,
|
||||
@@ -10,7 +9,6 @@ import {
|
||||
GetListSongsArgs,
|
||||
DownloadSingleSongArgs
|
||||
} from './service-base'
|
||||
|
||||
import { netEaseService } from './net-ease-service'
|
||||
import { AxiosError } from 'axios'
|
||||
|
||||
@@ -68,3 +66,12 @@ async function request(api: ServiceNamesType, args: ServiceArgsType): Promise<an
|
||||
}
|
||||
|
||||
export default { request }
|
||||
// netEaseService
|
||||
// .search({
|
||||
// keyword: '稻香',
|
||||
// type: 1,
|
||||
// limit: 25
|
||||
// })
|
||||
// .then((res) => {
|
||||
// console.log(res)
|
||||
// })
|
||||
|
||||
@@ -5,6 +5,8 @@ import fsPromise from 'fs/promises'
|
||||
import NeteaseCloudMusicApi from 'NeteaseCloudMusicApi'
|
||||
import { axiosClient, MusicServiceBase } from './service-base'
|
||||
import { pipeline } from 'node:stream/promises'
|
||||
import pluginService from '../plugin'
|
||||
import musicSdk from '../../utils/musicSdk'
|
||||
|
||||
import {
|
||||
SearchArgs,
|
||||
@@ -22,13 +24,110 @@ import { SongDetailResponse, SongResponse } from './service-base'
|
||||
import { fieldsSelector } from '../../utils/object'
|
||||
import { getAppDirPath } from '../../utils/path'
|
||||
|
||||
// 音乐源映射
|
||||
const MUSIC_SOURCES = {
|
||||
kg: 'kg', // 酷狗音乐
|
||||
wy: 'wy', // 网易云音乐
|
||||
tx: 'tx', // QQ音乐
|
||||
kw: 'kw', // 酷我音乐
|
||||
mg: 'mg' // 咪咕音乐
|
||||
}
|
||||
|
||||
// 扩展搜索参数接口
|
||||
interface ExtendedSearchArgs extends SearchArgs {
|
||||
source?: string // 音乐源参数 kg|wy|tx|kw|mg
|
||||
}
|
||||
|
||||
// 扩展歌曲详情参数接口
|
||||
interface ExtendedGetSongDetailArgs extends GetSongDetailArgs {
|
||||
source?: string
|
||||
}
|
||||
|
||||
// 扩展歌词参数接口
|
||||
interface ExtendedGetLyricArgs extends GetLyricArgs {
|
||||
source?: string
|
||||
}
|
||||
|
||||
const baseUrl: string = 'https://music.163.com'
|
||||
const baseTwoUrl: string = 'https://www.lihouse.xyz/coco_widget'
|
||||
|
||||
const fileLock: Record<string, boolean> = {}
|
||||
|
||||
/**
|
||||
* 获取支持的音乐源列表
|
||||
*/
|
||||
export const getSupportedSources = () => {
|
||||
return Object.keys(MUSIC_SOURCES).map((key) => ({
|
||||
id: key,
|
||||
name: getSourceName(key),
|
||||
available: !!musicSdk[key]
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取音乐源名称
|
||||
*/
|
||||
const getSourceName = (source: string): string => {
|
||||
const sourceNames = {
|
||||
kg: '酷狗音乐',
|
||||
wy: '网易云音乐',
|
||||
tx: 'QQ音乐',
|
||||
kw: '酷我音乐',
|
||||
mg: '咪咕音乐'
|
||||
}
|
||||
return sourceNames[source] || source
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能音乐匹配(使用musicSdk的findMusic功能)
|
||||
*/
|
||||
export const findMusic = async (musicInfo: {
|
||||
name: string
|
||||
singer?: string
|
||||
albumName?: string
|
||||
interval?: string
|
||||
source?: string
|
||||
}) => {
|
||||
try {
|
||||
return await musicSdk.findMusic(musicInfo)
|
||||
} catch (error) {
|
||||
console.error('智能音乐匹配失败:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export const netEaseService: MusicServiceBase = {
|
||||
async search({ type, keyword, offset, limit }: SearchArgs): Promise<SongResponse> {
|
||||
async search({
|
||||
type,
|
||||
keyword,
|
||||
offset,
|
||||
limit,
|
||||
source
|
||||
}: ExtendedSearchArgs): Promise<SongResponse> {
|
||||
// 如果指定了音乐源且不是网易云,使用对应的musicSdk
|
||||
if (source && source !== 'wy' && MUSIC_SOURCES[source]) {
|
||||
try {
|
||||
const sourceModule = musicSdk[source]
|
||||
if (sourceModule && sourceModule.musicSearch) {
|
||||
const page = Math.floor((offset || 0) / (limit || 25)) + 1
|
||||
const result = await sourceModule.musicSearch.search(keyword, page, limit || 25)
|
||||
|
||||
// 转换为统一格式
|
||||
return {
|
||||
songs: result.list || [],
|
||||
songCount: result.total || result.list?.length || 0
|
||||
}
|
||||
} else {
|
||||
throw new Error(`不支持的音乐源: ${source}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`${source}音乐源搜索失败:`, error)
|
||||
// 如果指定源失败,回退到网易云
|
||||
console.log('回退到网易云音乐搜索')
|
||||
}
|
||||
}
|
||||
|
||||
// 默认使用网易云音乐搜索
|
||||
return await axiosClient
|
||||
.get(`${baseUrl}/api/search/get/web`, {
|
||||
params: {
|
||||
@@ -46,7 +145,27 @@ export const netEaseService: MusicServiceBase = {
|
||||
return data.result
|
||||
})
|
||||
},
|
||||
async getSongDetail({ ids }: GetSongDetailArgs): Promise<SongDetailResponse> {
|
||||
async getSongDetail({ ids, source }: ExtendedGetSongDetailArgs): Promise<SongDetailResponse> {
|
||||
// 如果指定了音乐源且不是网易云,使用对应的musicSdk
|
||||
if (source && source !== 'wy' && MUSIC_SOURCES[source]) {
|
||||
try {
|
||||
const sourceModule = musicSdk[source]
|
||||
if (sourceModule && sourceModule.musicInfo) {
|
||||
// 对于多个ID,并行获取详情
|
||||
const promises = ids.map((id) => sourceModule.musicInfo.getMusicInfo(id))
|
||||
const results = await Promise.all(promises)
|
||||
return results.filter((result :any) => result) // 过滤掉失败的结果
|
||||
} else {
|
||||
throw new Error(`不支持的音乐源: ${source}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`${source}音乐源获取歌曲详情失败:`, error)
|
||||
// 如果指定源失败,回退到网易云
|
||||
console.log('回退到网易云音乐获取歌曲详情')
|
||||
}
|
||||
}
|
||||
|
||||
// 默认使用网易云音乐
|
||||
return await axiosClient
|
||||
.get(`${baseUrl}/api/song/detail?ids=[${ids.join(',')}]`)
|
||||
.then(({ data }) => {
|
||||
@@ -58,7 +177,48 @@ export const netEaseService: MusicServiceBase = {
|
||||
return data.songs
|
||||
})
|
||||
},
|
||||
async getSongUrl({ id }: GetSongUrlArgs): Promise<any> {
|
||||
async getSongUrl({ id, pluginId, quality, source }: GetSongUrlArgs): Promise<any> {
|
||||
// 如果提供了插件ID、音质和音乐源,则使用插件获取音乐URL
|
||||
if (pluginId && (quality || source)) {
|
||||
try {
|
||||
// 获取插件实例
|
||||
const plugin = pluginService.getPluginById(pluginId)
|
||||
if (!plugin) {
|
||||
throw new Error(`未找到ID为 ${pluginId} 的插件`)
|
||||
}
|
||||
|
||||
// 准备音乐信息对象,确保符合MusicInfo类型要求
|
||||
const musicInfo = {
|
||||
songmid: id as unknown as number,
|
||||
singer: '',
|
||||
name: '',
|
||||
albumName: '',
|
||||
albumId: 0,
|
||||
source: source || 'wy',
|
||||
interval: '',
|
||||
img: '',
|
||||
lrc: null,
|
||||
types: [],
|
||||
_types: {},
|
||||
typeUrl: {}
|
||||
}
|
||||
|
||||
// 调用插件的getMusicUrl方法获取音乐URL
|
||||
const url: string = await plugin.getMusicUrl(
|
||||
source || 'wy',
|
||||
musicInfo,
|
||||
quality || 'standard'
|
||||
)
|
||||
|
||||
// 构建返回对象
|
||||
return { url }
|
||||
} catch (error: any) {
|
||||
console.error('通过插件获取音乐URL失败:', error)
|
||||
throw new Error(`插件获取音乐URL失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有提供插件信息或插件调用失败,则使用默认方法获取
|
||||
return await axiosClient.get(`${baseTwoUrl}/music_resource/id/${id}`).then(({ data }) => {
|
||||
if (!data.status) {
|
||||
throw new Error('歌曲不存在')
|
||||
@@ -67,8 +227,33 @@ export const netEaseService: MusicServiceBase = {
|
||||
return data.song_data
|
||||
})
|
||||
},
|
||||
async getLyric({ id, lv, yv, tv }: GetLyricArgs): Promise<any> {
|
||||
// 默认什么都不获取
|
||||
async getLyric({ id, lv, yv, tv, source }: ExtendedGetLyricArgs): Promise<any> {
|
||||
// 如果指定了音乐源且不是网易云,使用对应的musicSdk
|
||||
if (source && source !== 'wy' && MUSIC_SOURCES[source]) {
|
||||
try {
|
||||
const sourceModule = musicSdk[source]
|
||||
if (sourceModule && sourceModule.getLyric) {
|
||||
// 构建歌曲信息对象,不同源可能需要不同的参数
|
||||
const songInfo = { id, songmid: id, hash: id }
|
||||
const result = await sourceModule.getLyric(songInfo)
|
||||
|
||||
// 转换为统一格式
|
||||
return {
|
||||
lrc: { lyric: result.lyric || '' },
|
||||
tlyric: { lyric: result.tlyric || '' },
|
||||
yrc: { lyric: result.yrc || '' }
|
||||
}
|
||||
} else {
|
||||
throw new Error(`不支持的音乐源: ${source}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`${source}音乐源获取歌词失败:`, error)
|
||||
// 如果指定源失败,回退到网易云
|
||||
console.log('回退到网易云音乐获取歌词')
|
||||
}
|
||||
}
|
||||
|
||||
// 默认使用网易云音乐
|
||||
const optionalParams: any = {}
|
||||
if (lv) {
|
||||
optionalParams.lv = -1
|
||||
@@ -137,14 +322,42 @@ export const netEaseService: MusicServiceBase = {
|
||||
throw err.body?.msg ?? err
|
||||
})
|
||||
},
|
||||
async downloadSingleSong({ id }: DownloadSingleSongArgs) {
|
||||
const songDownloadDetail = await this.getSongUrl({ id })
|
||||
async downloadSingleSong({
|
||||
id,
|
||||
name,
|
||||
artist,
|
||||
pluginId,
|
||||
source,
|
||||
quality
|
||||
}: DownloadSingleSongArgs) {
|
||||
const { url } = await this.getSongUrl({ id, pluginId, source, quality })
|
||||
|
||||
// 从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(),
|
||||
'download',
|
||||
'songs',
|
||||
`${songDownloadDetail.name}-${songDownloadDetail.artist}-${songDownloadDetail.id}.mp3`
|
||||
`${name}-${artist}-${id}.${fileExtension}`
|
||||
.replace(/[/\\:*?"<>|]/g, '')
|
||||
.replace(/^\.+/, '')
|
||||
.replace(/\.+$/, '')
|
||||
@@ -168,7 +381,7 @@ export const netEaseService: MusicServiceBase = {
|
||||
|
||||
const songDataRes = await axiosClient({
|
||||
method: 'GET',
|
||||
url: songDownloadDetail.url,
|
||||
url: url,
|
||||
responseType: 'stream'
|
||||
})
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ type SearchArgs = {
|
||||
keyword: string
|
||||
offset?: number
|
||||
limit: number
|
||||
source?: string
|
||||
}
|
||||
|
||||
type GetSongDetailArgs = {
|
||||
@@ -24,6 +25,9 @@ type GetSongDetailArgs = {
|
||||
|
||||
type GetSongUrlArgs = {
|
||||
id: string
|
||||
pluginId?: string // 插件ID
|
||||
quality?: string // 音质
|
||||
source?: string // 音乐源(wy, tx等)
|
||||
}
|
||||
|
||||
type GetLyricArgs = {
|
||||
@@ -45,6 +49,11 @@ type GetListSongsArgs = {
|
||||
|
||||
type DownloadSingleSongArgs = {
|
||||
id: string
|
||||
name: string
|
||||
artist: string
|
||||
pluginId?: string
|
||||
quality?: string
|
||||
source?: string
|
||||
}
|
||||
|
||||
type ServiceNamesType =
|
||||
@@ -243,7 +252,7 @@ interface SongUrlResponse {
|
||||
interface MusicServiceBase {
|
||||
search({ type, keyword, offset, limit }: SearchArgs): Promise<SongResponse>
|
||||
getSongDetail({ ids }: GetSongDetailArgs): Promise<SongDetailResponse>
|
||||
getSongUrl({ id }: GetSongUrlArgs): Promise<SongUrlResponse>
|
||||
getSongUrl({ id, pluginId, quality, source }: GetSongUrlArgs): Promise<SongUrlResponse>
|
||||
getLyric({ id, lv, yv, tv }: GetLyricArgs): Promise<any>
|
||||
getToplist({}: GetToplistArgs): Promise<any>
|
||||
getToplistDetail({}: GetToplistDetailArgs): Promise<any>
|
||||
|
||||
20
src/main/services/musicSdk/index.ts
Normal file
20
src/main/services/musicSdk/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
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
|
||||
? Parameters<MainApi[T]>[0]
|
||||
: 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);
|
||||
}
|
||||
throw new Error(`未知的方法: ${method}`);
|
||||
}
|
||||
ipcMain.handle('service-music-sdk-request', request)
|
||||
35
src/main/services/musicSdk/service.ts
Normal file
35
src/main/services/musicSdk/service.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { SearchSongArg, SearchResult, GetMusicUrlArg, GetMusicPicArg } from './type'
|
||||
import pluginService from '../plugin/index'
|
||||
import musicSdk from '../../utils/musicSdk/index'
|
||||
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>
|
||||
},
|
||||
|
||||
async getMusicUrl({ pluginId, songInfo, quality }: GetMusicUrlArg) {
|
||||
try {
|
||||
const usePlugin = pluginService.getPluginById(pluginId)
|
||||
if (!pluginId || !usePlugin) return { error: '请配置音源来播放歌曲' }
|
||||
return await usePlugin.getMusicUrl(source, songInfo , quality)
|
||||
} catch (e: any) {
|
||||
return {
|
||||
error: '获取歌曲失败 ' + e.error || e
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getPic({songInfo}: GetMusicPicArg) {
|
||||
try {
|
||||
return await Api.getPic(songInfo)
|
||||
} catch (e: any) {
|
||||
return {
|
||||
error: '获取歌曲失败 ' + e.error || e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default main
|
||||
51
src/main/services/musicSdk/type.ts
Normal file
51
src/main/services/musicSdk/type.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
export interface sdkArg {
|
||||
source: string
|
||||
[key:string]: any
|
||||
}
|
||||
|
||||
export interface SearchSongArg {
|
||||
keyword: string
|
||||
page: number
|
||||
limit: number
|
||||
}
|
||||
// 可以添加到 src/main/services/music/service-base.ts 文件中
|
||||
|
||||
// 单首歌曲的类型定义
|
||||
export interface MusicItem {
|
||||
hash?: string
|
||||
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>
|
||||
}
|
||||
|
||||
// 搜索结果的类型定义
|
||||
export interface SearchResult {
|
||||
list: MusicItem[]
|
||||
allPage: number
|
||||
limit: number
|
||||
total: number
|
||||
source: string
|
||||
}
|
||||
|
||||
export interface GetMusicUrlArg {
|
||||
pluginId: string
|
||||
songInfo: MusicItem
|
||||
quality: string
|
||||
}
|
||||
|
||||
export interface GetMusicPicArg {
|
||||
songInfo: MusicItem
|
||||
}
|
||||
|
||||
export interface GetLyricArg {
|
||||
songInfo: MusicItem
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const pluginService = {
|
||||
}
|
||||
},
|
||||
|
||||
getPluginById(pluginId: string) {
|
||||
getPluginById(pluginId: string): CeruMusicPluginHost | null{
|
||||
if (!Object.hasOwn(loadedPlugins, pluginId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -66,19 +66,27 @@ class Logger {
|
||||
}
|
||||
|
||||
log(...args: any[]): void {
|
||||
this.write(`log ${args.join(' ')}`)
|
||||
this.write(`log ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
info(...args: any[]): void {
|
||||
this.write(`info ${args.join(' ')}`)
|
||||
this.write(`info ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
warn(...args: any[]): void {
|
||||
this.write(`warn ${args.join(' ')}`)
|
||||
this.write(`warn ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
error(...args: any[]): void {
|
||||
this.write(`error ${args.join(' ')}`)
|
||||
this.write(`error ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
group(...args: any[]): void {
|
||||
args.unshift('groupStart---------')
|
||||
this.write(`start ${parseArgs(args)}\n`)
|
||||
}
|
||||
groupEnd(...args: any[]): void {
|
||||
this.write(`end ${parseArgs(args)}\n`)
|
||||
}
|
||||
|
||||
private write(msg: string): void {
|
||||
@@ -86,6 +94,16 @@ class Logger {
|
||||
}
|
||||
}
|
||||
|
||||
function parseArgs(args){
|
||||
return args.map(arg=>{
|
||||
if(typeof arg==='object'){
|
||||
return JSON.stringify(arg)
|
||||
}
|
||||
|
||||
return arg
|
||||
}).join(' ')
|
||||
}
|
||||
|
||||
async function getLog(pluginId: string) {
|
||||
const logFilePath: string = getLogPath(pluginId)
|
||||
return await add_promise(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as vm from 'vm'
|
||||
import fetch from 'node-fetch'
|
||||
import * as fs from 'fs'
|
||||
import {MusicItem} from '../../musicSdk/type'
|
||||
|
||||
// 定义插件结构接口
|
||||
export interface PluginInfo {
|
||||
@@ -25,9 +26,8 @@ interface CeruMusicPlugin {
|
||||
getLyric?: (source: string, musicInfo: MusicInfo) => Promise<string>
|
||||
}
|
||||
|
||||
interface MusicInfo {
|
||||
id: string
|
||||
[key: string]: any
|
||||
interface MusicInfo extends MusicItem{
|
||||
id?: string
|
||||
}
|
||||
|
||||
interface RequestResult {
|
||||
@@ -155,21 +155,8 @@ class CeruMusicPluginHost {
|
||||
|
||||
// 尝试解析JSON,如果失败则返回文本
|
||||
let body: any
|
||||
const contentType = response.headers.get('content-type')
|
||||
|
||||
try {
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
body = await response.json()
|
||||
} else {
|
||||
const text = await response.text()
|
||||
console.log(`[CeruMusic] 响应不是JSON格式,内容: ${text.substring(0, 200)}...`)
|
||||
// 对于非JSON响应,创建一个错误状态的body
|
||||
body = {
|
||||
code: response.status,
|
||||
msg: `Expected JSON response but got: ${contentType || 'unknown content type'}`,
|
||||
data: text
|
||||
}
|
||||
}
|
||||
} catch (parseError: any) {
|
||||
console.error(`[CeruMusic] 解析响应失败: ${parseError.message}`)
|
||||
// 解析失败时创建错误body
|
||||
|
||||
60
src/main/utils/index.ts
Normal file
60
src/main/utils/index.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
// 导入通用工具函数
|
||||
import { dateFormat } from '../../common/utils/common'
|
||||
|
||||
// 导出通用工具函数
|
||||
export * from '../../common/utils/nodejs'
|
||||
export * from '../../common/utils/common'
|
||||
export * from '../../common/utils/tools'
|
||||
|
||||
/**
|
||||
* 格式化播放数量
|
||||
* @param {*} num 数字
|
||||
*/
|
||||
export const formatPlayCount = (num: number): string => {
|
||||
if (num > 100000000) return `${Math.trunc(num / 10000000) / 10}亿`
|
||||
if (num > 10000) return `${Math.trunc(num / 1000) / 10}万`
|
||||
return String(num)
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式化 - 主进程版本
|
||||
*/
|
||||
export const dateFormat2 = (time: number): string => {
|
||||
const differ = Math.trunc((Date.now() - time) / 1000)
|
||||
if (differ < 60) {
|
||||
return `${differ}秒前`
|
||||
} else if (differ < 3600) {
|
||||
return `${Math.trunc(differ / 60)}分钟前`
|
||||
} else if (differ < 86400) {
|
||||
return `${Math.trunc(differ / 3600)}小时前`
|
||||
} else {
|
||||
return dateFormat(time)
|
||||
}
|
||||
}
|
||||
|
||||
// 定义简单的音乐信息接口
|
||||
interface MusicInfo {
|
||||
id: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export const deduplicationList = <T extends MusicInfo>(list: T[]): T[] => {
|
||||
const ids = new Set<string>()
|
||||
return list.filter((s) => {
|
||||
if (ids.has(s.id)) return false
|
||||
ids.add(s.id)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// 主进程中的字符串解码函数
|
||||
export const decodeName = (str: string | null = '') => {
|
||||
if (!str) return ''
|
||||
// 在 Node.js 中使用简单的 HTML 实体解码
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
}
|
||||
32
src/main/utils/musicSdk/api-source-info.ts
Normal file
32
src/main/utils/musicSdk/api-source-info.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// Support qualitys: 128k 320k flac wav
|
||||
|
||||
const sources: Array<{
|
||||
id: string
|
||||
name: string
|
||||
disabled: boolean
|
||||
supportQualitys: any
|
||||
}> = [
|
||||
// {
|
||||
// id: 'test',
|
||||
// name: '测试接口',
|
||||
// disabled: false,
|
||||
// supportQualitys: {
|
||||
// kw: ['128k'],
|
||||
// kg: ['128k'],
|
||||
// tx: ['128k'],
|
||||
// wy: ['128k'],
|
||||
// mg: ['128k'],
|
||||
// // bd: ['128k'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// id: 'temp',
|
||||
// name: '临时接口',
|
||||
// disabled: false,
|
||||
// supportQualitys: {
|
||||
// kw: ['128k'],
|
||||
// },
|
||||
// },
|
||||
]
|
||||
|
||||
export default sources
|
||||
207
src/main/utils/musicSdk/index.js
Normal file
207
src/main/utils/musicSdk/index.js
Normal file
@@ -0,0 +1,207 @@
|
||||
import kw from './kw/index'
|
||||
import kg from './kg/index'
|
||||
import tx from './tx/index'
|
||||
import wy from './wy/index'
|
||||
import mg from './mg/index'
|
||||
|
||||
// 导入工具函数
|
||||
export {
|
||||
decodeName,
|
||||
formatPlayTime,
|
||||
sizeFormate,
|
||||
dateFormat,
|
||||
formatPlayCount,
|
||||
dateFormat2
|
||||
} from '../utils'
|
||||
|
||||
const sources = {
|
||||
sources: [
|
||||
{
|
||||
name: '酷我音乐',
|
||||
id: 'kw'
|
||||
},
|
||||
{
|
||||
name: '酷狗音乐',
|
||||
id: 'kg'
|
||||
},
|
||||
{
|
||||
name: 'QQ音乐',
|
||||
id: 'tx'
|
||||
},
|
||||
{
|
||||
name: '网易音乐',
|
||||
id: 'wy'
|
||||
},
|
||||
{
|
||||
name: '咪咕音乐',
|
||||
id: 'mg'
|
||||
},
|
||||
{
|
||||
name: '虾米音乐',
|
||||
id: 'xm'
|
||||
}
|
||||
],
|
||||
kw,
|
||||
kg,
|
||||
tx,
|
||||
wy,
|
||||
mg
|
||||
}
|
||||
export default {
|
||||
...sources,
|
||||
init() {
|
||||
const tasks = []
|
||||
for (let source of sources.sources) {
|
||||
let sm = sources[source.id]
|
||||
sm && sm.init && tasks.push(sm.init())
|
||||
}
|
||||
return Promise.all(tasks)
|
||||
},
|
||||
async searchMusic({ name, singer, source: s, limit = 25 }) {
|
||||
const trimStr = (str) => (typeof str == 'string' ? str.trim() : str)
|
||||
const musicName = trimStr(name)
|
||||
const tasks = []
|
||||
const excludeSource = ['xm']
|
||||
for (const source of sources.sources) {
|
||||
if (!sources[source.id].musicSearch || source.id == s || excludeSource.includes(source.id))
|
||||
continue
|
||||
tasks.push(
|
||||
sources[source.id].musicSearch
|
||||
.search(`${musicName} ${singer || ''}`.trim(), 1, limit)
|
||||
.catch((_) => null)
|
||||
)
|
||||
}
|
||||
return (await Promise.all(tasks)).filter((s) => s)
|
||||
},
|
||||
|
||||
async findMusic({ name, singer, albumName, interval, source: s }) {
|
||||
const lists = await this.searchMusic({ name, singer, source: s, limit: 25 })
|
||||
// console.log(lists)
|
||||
// console.log({ name, singer, albumName, interval, source: s })
|
||||
|
||||
const singersRxp = /、|&|;|;|\/|,|,|\|/
|
||||
const sortSingle = (singer) =>
|
||||
singersRxp.test(singer)
|
||||
? singer
|
||||
.split(singersRxp)
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.join('、')
|
||||
: singer || ''
|
||||
const sortMusic = (arr, callback) => {
|
||||
const tempResult = []
|
||||
for (let i = arr.length - 1; i > -1; i--) {
|
||||
const item = arr[i]
|
||||
if (callback(item)) {
|
||||
delete item.fSinger
|
||||
delete item.fMusicName
|
||||
delete item.fAlbumName
|
||||
delete item.fInterval
|
||||
tempResult.push(item)
|
||||
arr.splice(i, 1)
|
||||
}
|
||||
}
|
||||
tempResult.reverse()
|
||||
return tempResult
|
||||
}
|
||||
const getIntv = (interval) => {
|
||||
if (!interval) return 0
|
||||
// if (musicInfo._interval) return musicInfo._interval
|
||||
let intvArr = interval.split(':')
|
||||
let intv = 0
|
||||
let unit = 1
|
||||
while (intvArr.length) {
|
||||
intv += parseInt(intvArr.pop()) * unit
|
||||
unit *= 60
|
||||
}
|
||||
return intv
|
||||
}
|
||||
const trimStr = (str) => (typeof str == 'string' ? str.trim() : str || '')
|
||||
const filterStr = (str) =>
|
||||
typeof str == 'string'
|
||||
? str.replace(/\s|'|\.|,|,|&|"|、|\(|\)|(|)|`|~|-|<|>|\||\/|\]|\[|!|!/g, '')
|
||||
: String(str || '')
|
||||
const fMusicName = filterStr(name).toLowerCase()
|
||||
const fSinger = filterStr(sortSingle(singer)).toLowerCase()
|
||||
const fAlbumName = filterStr(albumName).toLowerCase()
|
||||
const fInterval = getIntv(interval)
|
||||
const isEqualsInterval = (intv) => Math.abs((fInterval || intv) - (intv || fInterval)) < 5
|
||||
const isIncludesName = (name) => fMusicName.includes(name) || name.includes(fMusicName)
|
||||
const isIncludesSinger = (singer) =>
|
||||
fSinger ? fSinger.includes(singer) || singer.includes(fSinger) : true
|
||||
const isEqualsAlbum = (album) => (fAlbumName ? fAlbumName == album : true)
|
||||
|
||||
const result = lists
|
||||
.map((source) => {
|
||||
for (const item of source.list) {
|
||||
item.name = trimStr(item.name)
|
||||
item.singer = trimStr(item.singer)
|
||||
item.fSinger = filterStr(sortSingle(item.singer).toLowerCase())
|
||||
item.fMusicName = filterStr(String(item.name ?? '').toLowerCase())
|
||||
item.fAlbumName = filterStr(String(item.albumName ?? '').toLowerCase())
|
||||
item.fInterval = getIntv(item.interval)
|
||||
// console.log(fMusicName, item.fMusicName, item.source)
|
||||
if (!isEqualsInterval(item.fInterval)) {
|
||||
item.name = null
|
||||
continue
|
||||
}
|
||||
if (item.fMusicName == fMusicName && isIncludesSinger(item.fSinger)) return item
|
||||
}
|
||||
for (const item of source.list) {
|
||||
if (item.name == null) continue
|
||||
if (item.fSinger == fSinger && isIncludesName(item.fMusicName)) return item
|
||||
}
|
||||
for (const item of source.list) {
|
||||
if (item.name == null) continue
|
||||
if (
|
||||
isEqualsAlbum(item.fAlbumName) &&
|
||||
isIncludesSinger(item.fSinger) &&
|
||||
isIncludesName(item.fMusicName)
|
||||
)
|
||||
return item
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((s) => s)
|
||||
const newResult = []
|
||||
if (result.length) {
|
||||
newResult.push(
|
||||
...sortMusic(
|
||||
result,
|
||||
(item) =>
|
||||
item.fSinger == fSinger && item.fMusicName == fMusicName && item.interval == interval
|
||||
)
|
||||
)
|
||||
newResult.push(
|
||||
...sortMusic(
|
||||
result,
|
||||
(item) =>
|
||||
item.fMusicName == fMusicName &&
|
||||
item.fSinger == fSinger &&
|
||||
item.fAlbumName == fAlbumName
|
||||
)
|
||||
)
|
||||
newResult.push(
|
||||
...sortMusic(result, (item) => item.fSinger == fSinger && item.fMusicName == fMusicName)
|
||||
)
|
||||
newResult.push(
|
||||
...sortMusic(result, (item) => item.fMusicName == fMusicName && item.interval == interval)
|
||||
)
|
||||
newResult.push(
|
||||
...sortMusic(result, (item) => item.fSinger == fSinger && item.interval == interval)
|
||||
)
|
||||
newResult.push(...sortMusic(result, (item) => item.interval == interval))
|
||||
newResult.push(...sortMusic(result, (item) => item.fMusicName == fMusicName))
|
||||
newResult.push(...sortMusic(result, (item) => item.fSinger == fSinger))
|
||||
newResult.push(...sortMusic(result, (item) => item.fAlbumName == fAlbumName))
|
||||
for (const item of result) {
|
||||
delete item.fSinger
|
||||
delete item.fMusicName
|
||||
delete item.fAlbumName
|
||||
delete item.fInterval
|
||||
}
|
||||
newResult.push(...result)
|
||||
}
|
||||
// console.log(newResult)
|
||||
return newResult
|
||||
}
|
||||
}
|
||||
69
src/main/utils/musicSdk/kg/album.js
Normal file
69
src/main/utils/musicSdk/kg/album.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import { getMusicInfosByList } from './musicInfo'
|
||||
import { createHttpFetch } from './util'
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 通过AlbumId获取专辑信息
|
||||
* @param {*} id
|
||||
*/
|
||||
async getAlbumInfo(id) {
|
||||
const albumInfoRequest = await createHttpFetch(
|
||||
'http://kmrserviceretry.kugou.com/container/v1/album?dfid=1tT5He3kxrNC4D29ad1MMb6F&mid=22945702112173152889429073101964063697&userid=0&appid=1005&clientver=11589',
|
||||
{
|
||||
method: 'POST',
|
||||
body: {
|
||||
appid: 1005,
|
||||
clienttime: 1681833686,
|
||||
clientver: 11589,
|
||||
data: [{ album_id: id }],
|
||||
fields:
|
||||
'language,grade_count,intro,mix_intro,heat,category,sizable_cover,cover,album_name,type,quality,publish_company,grade,special_tag,author_name,publish_date,language_id,album_id,exclusive,is_publish,trans_param,authors,album_tag',
|
||||
isBuy: 0,
|
||||
key: 'e6f3306ff7e2afb494e89fbbda0becbf',
|
||||
mid: '22945702112173152889429073101964063697',
|
||||
show_album_tag: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
if (!albumInfoRequest) return Promise.reject(new Error('get album info failed.'))
|
||||
const albumInfo = albumInfoRequest[0]
|
||||
|
||||
return {
|
||||
name: albumInfo.album_name,
|
||||
image: albumInfo.sizable_cover.replace('{size}', 240),
|
||||
desc: albumInfo.intro,
|
||||
authorName: albumInfo.author_name
|
||||
// play_count: this.formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 通过AlbumId获取专辑
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getAlbumDetail(id, page = 1, limit = 200) {
|
||||
const albumList = await createHttpFetch(
|
||||
`http://mobiles.kugou.com/api/v3/album/song?version=9108&albumid=${id}&plat=0&pagesize=${limit}&area_code=0&page=${page}&with_res_tag=0`
|
||||
)
|
||||
if (!albumList.info) return Promise.reject(new Error('Get album list failed.'))
|
||||
|
||||
let result = await getMusicInfosByList(albumList.info)
|
||||
|
||||
const info = await this.getAlbumInfo(id)
|
||||
|
||||
return {
|
||||
list: result || [],
|
||||
page,
|
||||
limit,
|
||||
total: albumList.total,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: info.name,
|
||||
img: info.image,
|
||||
desc: info.desc,
|
||||
author: info.authorName
|
||||
// play_count: this.formatPlayCount(info.count),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/main/utils/musicSdk/kg/api-test.js
Normal file
59
src/main/utils/musicSdk/kg/api-test.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(
|
||||
`http://ts.tempmusics.tk/url/kg/${songInfo._types[type].hash}/${type}`,
|
||||
{
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
}
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(requestMsg.fail))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/pic/kg/${songInfo.hash}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0
|
||||
? Promise.resolve(body.data)
|
||||
: Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/lrc/kg/${songInfo.hash}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0
|
||||
? Promise.resolve(body.data)
|
||||
: Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
|
||||
export default api_test
|
||||
129
src/main/utils/musicSdk/kg/comment.js
Normal file
129
src/main/utils/musicSdk/kg/comment.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, dateFormat2 } from '../index'
|
||||
import { signatureParams } from './util'
|
||||
// import { getMusicInfoRaw } from './musicInfo'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
async getComment({ hash }, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
|
||||
// const res_id = (await getMusicInfoRaw(hash)).classification?.[0]?.res_id
|
||||
// if (!res_id) throw new Error('获取评论失败')
|
||||
|
||||
let timestamp = Date.now()
|
||||
const params = `dfid=0&mid=16249512204336365674023395779019&clienttime=${timestamp}&uuid=0&extdata=${hash}&appid=1005&code=fc4be23b4e972707f36b8a828a93ba8a&schash=${hash}&clientver=11409&p=${page}&clienttoken=&pagesize=${limit}&ver=10&kugouid=0`
|
||||
// const params = `appid=1005&clienttime=${timestamp}&clienttoken=0&clientver=11409&code=fc4be23b4e972707f36b8a828a93ba8a&dfid=0&extdata=${hash}&kugouid=0&mid=16249512204336365674023395779019&mixsongid=${res_id}&p=${page}&pagesize=${limit}&uuid=0&ver=10`
|
||||
const _requestObj = httpFetch(
|
||||
`http://m.comment.service.kugou.com/r/v1/rank/newest?${params}&signature=${signatureParams(params)}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.24'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.err_code !== 0) throw new Error('获取评论失败')
|
||||
const total = body.count ?? 0
|
||||
return {
|
||||
source: 'kg',
|
||||
comments: this.filterComment(body.list || []),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(total / limit) || 1
|
||||
}
|
||||
},
|
||||
async getHotComment({ hash }, page = 1, limit = 20) {
|
||||
// console.log(songmid)
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
let timestamp = Date.now()
|
||||
const params = `dfid=0&mid=16249512204336365674023395779019&clienttime=${timestamp}&uuid=0&extdata=${hash}&appid=1005&code=fc4be23b4e972707f36b8a828a93ba8a&schash=${hash}&clientver=11409&p=${page}&clienttoken=&pagesize=${limit}&ver=10&kugouid=0`
|
||||
// https://github.com/GitHub-ZC/wp_MusicApi/blob/bf9307dd138dc8ac6c4f7de29361209d4f5b665f/routes/v1/kugou/comment.js#L53
|
||||
const _requestObj2 = httpFetch(
|
||||
`http://m.comment.service.kugou.com/r/v1/rank/topliked?${params}&signature=${signatureParams(params)}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.24'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.err_code !== 0) throw new Error('获取热门评论失败')
|
||||
const total = body.count ?? 0
|
||||
return {
|
||||
source: 'kg',
|
||||
comments: this.filterComment(body.list || []),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(total / limit) || 1
|
||||
}
|
||||
},
|
||||
async getReplyComment({ songmid, audioId }, replyId, page = 1, limit = 100) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
|
||||
songmid =
|
||||
songmid.length == 32 // 修复歌曲ID存储变更导致图片获取失败的问题
|
||||
? audioId.split('_')[0]
|
||||
: songmid
|
||||
|
||||
const _requestObj2 = httpFetch(
|
||||
`http://comment.service.kugou.com/index.php?r=commentsv2/getReplyWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&kugouid=687373022&need_show_image=1&appid=1001&childrenid=${songmid}&tid=${replyId}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.err_code !== 0) throw new Error('获取回复评论失败')
|
||||
return { source: 'kg', comments: this.filterComment(body.list || []) }
|
||||
},
|
||||
replaceAt(raw, atList) {
|
||||
atList.forEach((atobj) => {
|
||||
raw = raw.replaceAll(`[at=${atobj.id}]`, `@${atobj.name} `)
|
||||
})
|
||||
return raw
|
||||
},
|
||||
filterComment(rawList) {
|
||||
return rawList.map((item) => {
|
||||
let data = {
|
||||
id: item.id,
|
||||
text: decodeName(
|
||||
(item.atlist ? this.replaceAt(item.content, item.atlist) : item.content) || ''
|
||||
),
|
||||
images: item.images ? item.images.map((i) => i.url) : [],
|
||||
location: item.location,
|
||||
time: item.addtime,
|
||||
timeStr: dateFormat2(new Date(item.addtime).getTime()),
|
||||
userName: item.user_name,
|
||||
avatar: item.user_pic,
|
||||
userId: item.user_id,
|
||||
likedCount: item.like.likenum,
|
||||
replyNum: item.reply_num,
|
||||
reply: []
|
||||
}
|
||||
|
||||
return item.pcontent
|
||||
? {
|
||||
id: item.id,
|
||||
text: decodeName(item.pcontent),
|
||||
time: null,
|
||||
userName: item.puser,
|
||||
avatar: null,
|
||||
userId: item.puser_id,
|
||||
likedCount: null,
|
||||
replyNum: null,
|
||||
reply: [data]
|
||||
}
|
||||
: data
|
||||
})
|
||||
}
|
||||
}
|
||||
36
src/main/utils/musicSdk/kg/hotSearch.js
Normal file
36
src/main/utils/musicSdk/kg/hotSearch.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName } from '../index'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const _requestObj = httpFetch(
|
||||
'http://gateway.kugou.com/api/v3/search/hot_tab?signature=ee44edb9d7155821412d220bcaf509dd&appid=1005&clientver=10026&plat=0',
|
||||
{
|
||||
method: 'get',
|
||||
headers: {
|
||||
dfid: '1ssiv93oVqMp27cirf2CvoF1',
|
||||
mid: '156798703528610303473757548878786007104',
|
||||
clienttime: 1584257267,
|
||||
'x-router': 'msearch.kugou.com',
|
||||
'user-agent': 'Android9-AndroidPhone-10020-130-0-searchrecommendprotocol-wifi',
|
||||
'kg-rc': 1
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.errcode !== 0) throw new Error('获取热搜词失败')
|
||||
// console.log(body, statusCode)
|
||||
return { source: 'kg', list: this.filterList(body.data.list) }
|
||||
},
|
||||
filterList(rawList) {
|
||||
const list = []
|
||||
rawList.forEach((item) => {
|
||||
item.keywords.map((k) => list.push(decodeName(k.keyword)))
|
||||
})
|
||||
return list
|
||||
}
|
||||
}
|
||||
28
src/main/utils/musicSdk/kg/index.js
Normal file
28
src/main/utils/musicSdk/kg/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import leaderboard from './leaderboard'
|
||||
import songList from './songList'
|
||||
import musicSearch from './musicSearch'
|
||||
import pic from './pic'
|
||||
import lyric from './lyric'
|
||||
import hotSearch from './hotSearch'
|
||||
import comment from './comment'
|
||||
// import tipSearch from './tipSearch'
|
||||
|
||||
const kg = {
|
||||
// tipSearch,
|
||||
leaderboard,
|
||||
songList,
|
||||
musicSearch,
|
||||
hotSearch,
|
||||
comment,
|
||||
getLyric(songInfo) {
|
||||
return lyric.getLyric(songInfo)
|
||||
},
|
||||
getPic(songInfo) {
|
||||
return pic.getPic(songInfo)
|
||||
},
|
||||
getMusicDetailPageUrl(songInfo) {
|
||||
return `https://www.kugou.com/song/#hash=${songInfo.hash}&album_id=${songInfo.albumId}`
|
||||
}
|
||||
}
|
||||
|
||||
export default kg
|
||||
262
src/main/utils/musicSdk/kg/leaderboard.js
Normal file
262
src/main/utils/musicSdk/kg/leaderboard.js
Normal file
@@ -0,0 +1,262 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
let boardList = [
|
||||
{ id: 'kg__8888', name: 'TOP500', bangid: '8888' },
|
||||
{ id: 'kg__6666', name: '飙升榜', bangid: '6666' },
|
||||
{ id: 'kg__59703', name: '蜂鸟流行音乐榜', bangid: '59703' },
|
||||
{ id: 'kg__52144', name: '抖音热歌榜', bangid: '52144' },
|
||||
{ id: 'kg__52767', name: '快手热歌榜', bangid: '52767' },
|
||||
{ id: 'kg__24971', name: 'DJ热歌榜', bangid: '24971' },
|
||||
{ id: 'kg__23784', name: '网络红歌榜', bangid: '23784' },
|
||||
{ id: 'kg__44412', name: '说唱先锋榜', bangid: '44412' },
|
||||
{ id: 'kg__31308', name: '内地榜', bangid: '31308' },
|
||||
{ id: 'kg__33160', name: '电音榜', bangid: '33160' },
|
||||
{ id: 'kg__31313', name: '香港地区榜', bangid: '31313' },
|
||||
{ id: 'kg__51341', name: '民谣榜', bangid: '51341' },
|
||||
{ id: 'kg__54848', name: '台湾地区榜', bangid: '54848' },
|
||||
{ id: 'kg__31310', name: '欧美榜', bangid: '31310' },
|
||||
{ id: 'kg__33162', name: 'ACG新歌榜', bangid: '33162' },
|
||||
{ id: 'kg__31311', name: '韩国榜', bangid: '31311' },
|
||||
{ id: 'kg__31312', name: '日本榜', bangid: '31312' },
|
||||
{ id: 'kg__49225', name: '80后热歌榜', bangid: '49225' },
|
||||
{ id: 'kg__49223', name: '90后热歌榜', bangid: '49223' },
|
||||
{ id: 'kg__49224', name: '00后热歌榜', bangid: '49224' },
|
||||
{ id: 'kg__33165', name: '粤语金曲榜', bangid: '33165' },
|
||||
{ id: 'kg__33166', name: '欧美金曲榜', bangid: '33166' },
|
||||
{ id: 'kg__33163', name: '影视金曲榜', bangid: '33163' },
|
||||
{ id: 'kg__51340', name: '伤感榜', bangid: '51340' },
|
||||
{ id: 'kg__35811', name: '会员专享榜', bangid: '35811' },
|
||||
{ id: 'kg__37361', name: '雷达榜', bangid: '37361' },
|
||||
{ id: 'kg__21101', name: '分享榜', bangid: '21101' },
|
||||
{ id: 'kg__46910', name: '综艺新歌榜', bangid: '46910' },
|
||||
{ id: 'kg__30972', name: '酷狗音乐人原创榜', bangid: '30972' },
|
||||
{ id: 'kg__60170', name: '闽南语榜', bangid: '60170' },
|
||||
{ id: 'kg__65234', name: '儿歌榜', bangid: '65234' },
|
||||
{ id: 'kg__4681', name: '美国BillBoard榜', bangid: '4681' },
|
||||
{ id: 'kg__25028', name: 'Beatport电子舞曲榜', bangid: '25028' },
|
||||
{ id: 'kg__4680', name: '英国单曲榜', bangid: '4680' },
|
||||
{ id: 'kg__38623', name: '韩国Melon音乐榜', bangid: '38623' },
|
||||
{ id: 'kg__42807', name: 'joox本地热歌榜', bangid: '42807' },
|
||||
{ id: 'kg__36107', name: '小语种热歌榜', bangid: '36107' },
|
||||
{ id: 'kg__4673', name: '日本公信榜', bangid: '4673' },
|
||||
{ id: 'kg__46868', name: '日本SPACE SHOWER榜', bangid: '46868' },
|
||||
{ id: 'kg__42808', name: 'KKBOX风云榜', bangid: '42808' },
|
||||
{ id: 'kg__60171', name: '越南语榜', bangid: '60171' },
|
||||
{ id: 'kg__60172', name: '泰语榜', bangid: '60172' },
|
||||
{ id: 'kg__59895', name: 'R&B榜', bangid: '59895' },
|
||||
{ id: 'kg__59896', name: '摇滚榜', bangid: '59896' },
|
||||
{ id: 'kg__59897', name: '爵士榜', bangid: '59897' },
|
||||
{ id: 'kg__59898', name: '乡村音乐榜', bangid: '59898' },
|
||||
{ id: 'kg__59900', name: '纯音乐榜', bangid: '59900' },
|
||||
{ id: 'kg__59899', name: '古典榜', bangid: '59899' },
|
||||
{ id: 'kg__22603', name: '5sing音乐榜', bangid: '22603' },
|
||||
{ id: 'kg__21335', name: '繁星音乐榜', bangid: '21335' },
|
||||
{ id: 'kg__33161', name: '古风新歌榜', bangid: '33161' }
|
||||
]
|
||||
|
||||
export default {
|
||||
listDetailLimit: 100,
|
||||
list: [
|
||||
{
|
||||
id: 'kgtop500',
|
||||
name: 'TOP500',
|
||||
bangid: '8888'
|
||||
},
|
||||
{
|
||||
id: 'kgwlhgb',
|
||||
name: '网络榜',
|
||||
bangid: '23784'
|
||||
},
|
||||
{
|
||||
id: 'kgbsb',
|
||||
name: '飙升榜',
|
||||
bangid: '6666'
|
||||
},
|
||||
{
|
||||
id: 'kgfxb',
|
||||
name: '分享榜',
|
||||
bangid: '21101'
|
||||
},
|
||||
{
|
||||
id: 'kgcyyb',
|
||||
name: '纯音乐榜',
|
||||
bangid: '33164'
|
||||
},
|
||||
{
|
||||
id: 'kggfjqb',
|
||||
name: '古风榜',
|
||||
bangid: '33161'
|
||||
},
|
||||
{
|
||||
id: 'kgyyjqb',
|
||||
name: '粤语榜',
|
||||
bangid: '33165'
|
||||
},
|
||||
{
|
||||
id: 'kgomjqb',
|
||||
name: '欧美榜',
|
||||
bangid: '33166'
|
||||
},
|
||||
{
|
||||
id: 'kgdyrgb',
|
||||
name: '电音榜',
|
||||
bangid: '33160'
|
||||
},
|
||||
{
|
||||
id: 'kgjdrgb',
|
||||
name: 'DJ热歌榜',
|
||||
bangid: '24971'
|
||||
},
|
||||
{
|
||||
id: 'kghyxgb',
|
||||
name: '华语新歌榜',
|
||||
bangid: '31308'
|
||||
}
|
||||
],
|
||||
getUrl(p, id, limit) {
|
||||
return `http://mobilecdnbj.kugou.com/api/v3/rank/song?version=9108&ranktype=1&plat=0&pagesize=${limit}&area_code=1&page=${p}&rankid=${id}&with_res_tag=0&show_portrait_mv=1`
|
||||
},
|
||||
regExps: {
|
||||
total: /total: '(\d+)',/,
|
||||
page: /page: '(\d+)',/,
|
||||
limit: /pagesize: '(\d+)',/,
|
||||
listData: /global\.features = (\[.+\]);/
|
||||
},
|
||||
_requestBoardsObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch(
|
||||
'http://mobilecdnbj.kugou.com/api/v5/rank/list?version=9108&plat=0&showtype=2&parentid=0&apiver=6&area_code=1&withsong=1'
|
||||
)
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach((singer) => {
|
||||
arr.push(singer.author_name)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
return rawList.map((item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.filesize !== 0) {
|
||||
let size = sizeFormate(item.filesize)
|
||||
types.push({ type: '128k', size, hash: item.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.hash
|
||||
}
|
||||
}
|
||||
if (item['320filesize'] !== 0) {
|
||||
let size = sizeFormate(item['320filesize'])
|
||||
types.push({ type: '320k', size, hash: item['320hash'] })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item['320hash']
|
||||
}
|
||||
}
|
||||
if (item.sqfilesize !== 0) {
|
||||
let size = sizeFormate(item.sqfilesize)
|
||||
types.push({ type: 'flac', size, hash: item.sqhash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.sqhash
|
||||
}
|
||||
}
|
||||
if (item.filesize_high !== 0) {
|
||||
let size = sizeFormate(item.filesize_high)
|
||||
types.push({ type: 'flac24bit', size, hash: item.hash_high })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: item.hash_high
|
||||
}
|
||||
}
|
||||
return {
|
||||
singer: formatSingerName(item.authors, 'author_name'),
|
||||
name: decodeName(item.songname),
|
||||
albumName: decodeName(item.remark),
|
||||
albumId: item.album_id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.duration),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
for (const board of rawList) {
|
||||
if (board.isvol != 1) continue
|
||||
list.push({
|
||||
id: 'kg__' + board.rankid,
|
||||
name: board.rankname,
|
||||
bangid: String(board.rankid)
|
||||
})
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// // console.log(response.body)
|
||||
// if (response.statusCode !== 200 || response.body.errcode !== 0) return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.data.info)
|
||||
// console.log(list)
|
||||
// // console.log(JSON.stringify(list))
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'kg',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'kg'
|
||||
}
|
||||
},
|
||||
async getList(bangid, page, retryNum = 0) {
|
||||
if (++retryNum > 3) throw new Error('try max num')
|
||||
const { body } = await this.getData(this.getUrl(page, bangid, this.listDetailLimit))
|
||||
|
||||
if (body.errcode != 0) return this.getList(bangid, page, retryNum)
|
||||
|
||||
// console.log(body)
|
||||
let total = body.data.total
|
||||
let limit = 100
|
||||
let listData = this.filterData(body.data.info)
|
||||
// console.log(listData)
|
||||
return {
|
||||
total,
|
||||
list: listData,
|
||||
limit,
|
||||
page,
|
||||
source: 'kg'
|
||||
}
|
||||
},
|
||||
getDetailPageUrl(id) {
|
||||
if (typeof id == 'string') id = id.replace('kg__', '')
|
||||
return `https://www.kugou.com/yy/rank/home/1-${id}.html`
|
||||
}
|
||||
}
|
||||
122
src/main/utils/musicSdk/kg/lyric.js
Normal file
122
src/main/utils/musicSdk/kg/lyric.js
Normal file
@@ -0,0 +1,122 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeKrc } from '../../../../common/utils/lyricUtils/kg'
|
||||
|
||||
export default {
|
||||
getIntv(interval) {
|
||||
if (!interval) return 0
|
||||
let intvArr = interval.split(':')
|
||||
let intv = 0
|
||||
let unit = 1
|
||||
while (intvArr.length) {
|
||||
intv += intvArr.pop() * unit
|
||||
unit *= 60
|
||||
}
|
||||
return parseInt(intv)
|
||||
},
|
||||
// getLyric(songInfo, tryNum = 0) {
|
||||
// let requestObj = httpFetch(`http://m.kugou.com/app/i/krc.php?cmd=100&keyword=${encodeURIComponent(songInfo.name)}&hash=${songInfo.hash}&timelength=${songInfo._interval || this.getIntv(songInfo.interval)}&d=0.38664927426725626`, {
|
||||
// headers: {
|
||||
// 'KG-RC': 1,
|
||||
// 'KG-THash': 'expand_search_manager.cpp:852736169:451',
|
||||
// 'User-Agent': 'KuGou2012-9020-ExpandSearchManager',
|
||||
// },
|
||||
// })
|
||||
// requestObj.promise = requestObj.promise.then(({ body, statusCode }) => {
|
||||
// if (statusCode !== 200) {
|
||||
// if (tryNum > 5) return Promise.reject(new Error('歌词获取失败'))
|
||||
// let tryRequestObj = this.getLyric(songInfo, ++tryNum)
|
||||
// requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
// return tryRequestObj.promise
|
||||
// }
|
||||
// return {
|
||||
// lyric: body,
|
||||
// tlyric: '',
|
||||
// }
|
||||
// })
|
||||
// return requestObj
|
||||
// },
|
||||
searchLyric(name, hash, time, tryNum = 0) {
|
||||
let requestObj = httpFetch(
|
||||
`http://lyrics.kugou.com/search?ver=1&man=yes&client=pc&keyword=${encodeURIComponent(name)}&hash=${hash}&timelength=${time}&lrctxt=1`,
|
||||
{
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'expand_search_manager.cpp:852736169:451',
|
||||
'User-Agent': 'KuGou2012-9020-ExpandSearchManager'
|
||||
}
|
||||
}
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ body, statusCode }) => {
|
||||
if (statusCode !== 200) {
|
||||
if (tryNum > 5) return Promise.reject(new Error('歌词获取失败'))
|
||||
let tryRequestObj = this.searchLyric(name, hash, time, ++tryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
if (body.candidates.length) {
|
||||
let info = body.candidates[0]
|
||||
return {
|
||||
id: info.id,
|
||||
accessKey: info.accesskey,
|
||||
fmt: info.krctype == 1 && info.contenttype != 1 ? 'krc' : 'lrc'
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyricDownload(id, accessKey, fmt, tryNum = 0) {
|
||||
let requestObj = httpFetch(
|
||||
`http://lyrics.kugou.com/download?ver=1&client=pc&id=${id}&accesskey=${accessKey}&fmt=${fmt}&charset=utf8`,
|
||||
{
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'expand_search_manager.cpp:852736169:451',
|
||||
'User-Agent': 'KuGou2012-9020-ExpandSearchManager'
|
||||
}
|
||||
}
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ body, statusCode }) => {
|
||||
if (statusCode !== 200) {
|
||||
if (tryNum > 5) return Promise.reject(new Error('歌词获取失败'))
|
||||
let tryRequestObj = this.getLyric(id, accessKey, fmt, ++tryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
|
||||
switch (body.fmt) {
|
||||
case 'krc':
|
||||
return decodeKrc(body.content)
|
||||
case 'lrc':
|
||||
return {
|
||||
lyric: Buffer.from(body.content, 'base64').toString('utf-8'),
|
||||
tlyric: '',
|
||||
rlyric: '',
|
||||
lxlyric: ''
|
||||
}
|
||||
default:
|
||||
return Promise.reject(new Error(`未知歌词格式: ${body.fmt}`))
|
||||
}
|
||||
})
|
||||
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo, tryNum = 0) {
|
||||
let requestObj = this.searchLyric(
|
||||
songInfo.name,
|
||||
songInfo.hash,
|
||||
songInfo._interval || this.getIntv(songInfo.interval)
|
||||
)
|
||||
|
||||
requestObj.promise = requestObj.promise.then((result) => {
|
||||
if (!result) return Promise.reject(new Error('Get lyric failed'))
|
||||
|
||||
let requestObj2 = this.getLyricDownload(result.id, result.accessKey, result.fmt)
|
||||
|
||||
requestObj.cancelHttp = requestObj2.cancelHttp.bind(requestObj2)
|
||||
|
||||
return requestObj2.promise
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
120
src/main/utils/musicSdk/kg/musicInfo.js
Normal file
120
src/main/utils/musicSdk/kg/musicInfo.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../../index'
|
||||
import { createHttpFetch } from './util'
|
||||
|
||||
const createGetMusicInfosTask = (hashs) => {
|
||||
let data = {
|
||||
area_code: '1',
|
||||
show_privilege: 1,
|
||||
show_album_info: '1',
|
||||
is_publish: '',
|
||||
appid: 1005,
|
||||
clientver: 11451,
|
||||
mid: '1',
|
||||
dfid: '-',
|
||||
clienttime: Date.now(),
|
||||
key: 'OIlwieks28dk2k092lksi2UIkp',
|
||||
fields: 'album_info,author_name,audio_info,ori_audio_name,base,songname,classification'
|
||||
}
|
||||
let list = hashs
|
||||
let tasks = []
|
||||
while (list.length) {
|
||||
tasks.push(Object.assign({ data: list.slice(0, 100) }, data))
|
||||
if (list.length < 100) break
|
||||
list = list.slice(100)
|
||||
}
|
||||
let url = 'http://gateway.kugou.com/v3/album_audio/audio'
|
||||
return tasks.map((task) =>
|
||||
createHttpFetch(url, {
|
||||
method: 'POST',
|
||||
body: task,
|
||||
headers: {
|
||||
'KG-THash': '13a3164',
|
||||
'KG-RC': '1',
|
||||
'KG-Fake': '0',
|
||||
'KG-RF': '00869891',
|
||||
'User-Agent': 'Android712-AndroidPhone-11451-376-0-FeeCacheUpdate-wifi',
|
||||
'x-router': 'kmr.service.kugou.com'
|
||||
}
|
||||
}).then((data) => data.map((s) => s[0]))
|
||||
)
|
||||
}
|
||||
|
||||
export const filterMusicInfoList = (rawList) => {
|
||||
// console.log(rawList)
|
||||
let ids = new Set()
|
||||
let list = []
|
||||
rawList.forEach((item) => {
|
||||
if (!item) return
|
||||
if (ids.has(item.audio_info.audio_id)) return
|
||||
ids.add(item.audio_info.audio_id)
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.audio_info.filesize !== '0') {
|
||||
let size = sizeFormate(parseInt(item.audio_info.filesize))
|
||||
types.push({ type: '128k', size, hash: item.audio_info.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.audio_info.hash
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_320 !== '0') {
|
||||
let size = sizeFormate(parseInt(item.audio_info.filesize_320))
|
||||
types.push({ type: '320k', size, hash: item.audio_info.hash_320 })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item.audio_info.hash_320
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_flac !== '0') {
|
||||
let size = sizeFormate(parseInt(item.audio_info.filesize_flac))
|
||||
types.push({ type: 'flac', size, hash: item.audio_info.hash_flac })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.audio_info.hash_flac
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_high !== '0') {
|
||||
let size = sizeFormate(parseInt(item.audio_info.filesize_high))
|
||||
types.push({ type: 'flac24bit', size, hash: item.audio_info.hash_high })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: item.audio_info.hash_high
|
||||
}
|
||||
}
|
||||
list.push({
|
||||
singer: decodeName(item.author_name),
|
||||
name: decodeName(item.songname),
|
||||
albumName: decodeName(item.album_info.album_name),
|
||||
albumId: item.album_info.album_id,
|
||||
songmid: item.audio_info.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(parseInt(item.audio_info.timelength) / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.audio_info.hash,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
export const getMusicInfos = async (hashs) => {
|
||||
return filterMusicInfoList(
|
||||
await Promise.all(createGetMusicInfosTask(hashs)).then((data) => data.flat())
|
||||
)
|
||||
}
|
||||
|
||||
export const getMusicInfoRaw = async (hash) => {
|
||||
return Promise.all(createGetMusicInfosTask([{ hash }])).then((data) => data.flat()[0])
|
||||
}
|
||||
|
||||
export const getMusicInfo = async (hash) => {
|
||||
return getMusicInfos([{ hash }]).then((data) => data[0])
|
||||
}
|
||||
|
||||
export const getMusicInfosByList = (list) => {
|
||||
return getMusicInfos(list.map((item) => ({ hash: item.hash })))
|
||||
}
|
||||
109
src/main/utils/musicSdk/kg/musicSearch.js
Normal file
109
src/main/utils/musicSdk/kg/musicSearch.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
const searchRequest = httpFetch(
|
||||
`https://songsearch.kugou.com/song_search_v2?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${limit}&userid=0&clientver=&platform=WebFilter&filter=2&iscorrection=1&privilege_filter=0&area_code=1`
|
||||
)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
filterData(rawData) {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (rawData.FileSize !== 0) {
|
||||
let size = sizeFormate(rawData.FileSize)
|
||||
types.push({ type: '128k', size, hash: rawData.FileHash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: rawData.FileHash
|
||||
}
|
||||
}
|
||||
if (rawData.HQFileSize !== 0) {
|
||||
let size = sizeFormate(rawData.HQFileSize)
|
||||
types.push({ type: '320k', size, hash: rawData.HQFileHash })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: rawData.HQFileHash
|
||||
}
|
||||
}
|
||||
if (rawData.SQFileSize !== 0) {
|
||||
let size = sizeFormate(rawData.SQFileSize)
|
||||
types.push({ type: 'flac', size, hash: rawData.SQFileHash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: rawData.SQFileHash
|
||||
}
|
||||
}
|
||||
if (rawData.ResFileSize !== 0) {
|
||||
let size = sizeFormate(rawData.ResFileSize)
|
||||
types.push({ type: 'flac24bit', size, hash: rawData.ResFileHash })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: rawData.ResFileHash
|
||||
}
|
||||
}
|
||||
return {
|
||||
singer: decodeName(formatSingerName(rawData.Singers, 'name')),
|
||||
name: decodeName(rawData.SongName),
|
||||
albumName: decodeName(rawData.AlbumName),
|
||||
albumId: rawData.AlbumID,
|
||||
songmid: rawData.Audioid,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(rawData.Duration),
|
||||
_interval: rawData.Duration,
|
||||
img: null,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
hash: rawData.FileHash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
},
|
||||
handleResult(rawData) {
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawData.forEach((item) => {
|
||||
const key = item.Audioid + item.FileHash
|
||||
if (ids.has(key)) return
|
||||
ids.add(key)
|
||||
list.push(this.filterData(item))
|
||||
for (const childItem of item.Grp) {
|
||||
const key = item.Audioid + item.FileHash
|
||||
if (ids.has(key)) continue
|
||||
ids.add(key)
|
||||
list.push(this.filterData(childItem))
|
||||
}
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then((result) => {
|
||||
if (!result || result.error_code !== 0) return this.search(str, page, limit, retryNum)
|
||||
let list = this.handleResult(result.data.lists)
|
||||
|
||||
if (list == null) return this.search(str, page, limit, retryNum)
|
||||
|
||||
this.total = result.data.total
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'kg'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
45
src/main/utils/musicSdk/kg/pic.js
Normal file
45
src/main/utils/musicSdk/kg/pic.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFetch('http://media.store.kugou.com/v1/get_res_privilege', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'expand_search_manager.cpp:852736169:451',
|
||||
'User-Agent': 'KuGou2012-9020-ExpandSearchManager'
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
area_code: '1',
|
||||
behavior: 'play',
|
||||
clientver: '9020',
|
||||
need_hash_offset: 1,
|
||||
relate: 1,
|
||||
resource: [
|
||||
{
|
||||
album_audio_id:
|
||||
songInfo.songmid.length == 32 // 修复歌曲ID存储变更导致图片获取失败的问题
|
||||
? songInfo.audioId.split('_')[0]
|
||||
: songInfo.songmid,
|
||||
album_id: songInfo.albumId,
|
||||
hash: songInfo.hash,
|
||||
id: 0,
|
||||
name: `${songInfo.singer} - ${songInfo.name}.mp3`,
|
||||
type: 'audio'
|
||||
}
|
||||
],
|
||||
token: '',
|
||||
userid: 2626431536,
|
||||
vip: 1
|
||||
}
|
||||
})
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
if (body.error_code !== 0) return Promise.reject(new Error('图片获取失败'))
|
||||
let info = body.data[0].info
|
||||
const img = info.imgsize ? info.image.replace('{size}', info.imgsize[0]) : info.image
|
||||
if (!img) return Promise.reject(new Error('Pic get failed'))
|
||||
return img
|
||||
})
|
||||
}
|
||||
}
|
||||
91
src/main/utils/musicSdk/kg/singer.js
Normal file
91
src/main/utils/musicSdk/kg/singer.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { getMusicInfosByList } from './musicInfo'
|
||||
import { createHttpFetch } from './util'
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 获取歌手信息
|
||||
* @param {*} id
|
||||
*/
|
||||
getInfo(id) {
|
||||
if (id == 0) throw new Error('歌手不存在') // kg源某些歌曲在歌手没被kg收录时返回的歌手id为0
|
||||
return createHttpFetch(`http://mobiles.kugou.com/api/v5/singer/info?singerid=${id}`).then(
|
||||
(body) => {
|
||||
if (!body) throw new Error('get singer info faild.')
|
||||
|
||||
return {
|
||||
source: 'kg',
|
||||
id: body.singerid,
|
||||
info: {
|
||||
name: body.singername,
|
||||
desc: body.intro,
|
||||
avatar: body.imgurl.replace('{size}', 480),
|
||||
gender: body.grade === 1 ? 'man' : 'woman'
|
||||
},
|
||||
count: {
|
||||
music: body.songcount,
|
||||
album: body.albumcount
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
/**
|
||||
* 获取歌手专辑列表
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
* @param {*} limit
|
||||
*/
|
||||
getAlbumList(id, page = 1, limit = 10) {
|
||||
if (id == 0) throw new Error('歌手不存在')
|
||||
return createHttpFetch(
|
||||
`http://mobiles.kugou.com/api/v5/singer/album?singerid=${id}&page=${page}&pagesize=${limit}`
|
||||
).then((body) => {
|
||||
if (!body.info) throw new Error('get singer album list faild.')
|
||||
|
||||
const list = this.filterAlbumList(body.info)
|
||||
return {
|
||||
source: 'kg',
|
||||
list,
|
||||
limit,
|
||||
page,
|
||||
total: body.total
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取歌手歌曲列表
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
* @param {*} limit
|
||||
*/
|
||||
async getSongList(id, page = 1, limit = 100) {
|
||||
if (id == 0) throw new Error('歌手不存在')
|
||||
const body = await createHttpFetch(
|
||||
`http://mobiles.kugou.com/api/v5/singer/song?singerid=${id}&page=${page}&pagesize=${limit}`
|
||||
)
|
||||
if (!body.info) throw new Error('get singer song list faild.')
|
||||
|
||||
const list = await getMusicInfosByList(body.info)
|
||||
return {
|
||||
source: 'kg',
|
||||
list,
|
||||
limit,
|
||||
page,
|
||||
total: body.total
|
||||
}
|
||||
},
|
||||
filterAlbumList(raw) {
|
||||
return raw.map((item) => {
|
||||
return {
|
||||
id: item.albumid,
|
||||
count: item.songcount,
|
||||
info: {
|
||||
name: item.albumname,
|
||||
author: item.singername,
|
||||
img: item.replaceAll('{size}', '480'),
|
||||
desc: item.intro
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1007
src/main/utils/musicSdk/kg/songList.js
Normal file
1007
src/main/utils/musicSdk/kg/songList.js
Normal file
File diff suppressed because it is too large
Load Diff
119
src/main/utils/musicSdk/kg/temp/musicSearch-new.js
Normal file
119
src/main/utils/musicSdk/kg/temp/musicSearch-new.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../../index'
|
||||
import { signatureParams, createHttpFetch } from './util'
|
||||
import { formatSingerName } from '../../utils'
|
||||
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
const sign = signatureParams(
|
||||
`userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&keyword=${str}&dfid=-&clientver=11409&platform=AndroidFilter&tag=`,
|
||||
3
|
||||
)
|
||||
return createHttpFetch(
|
||||
`https://gateway.kugou.com/complexsearch/v3/search/song?userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&dfid=-&clientver=11409&platform=AndroidFilter&tag=&keyword=${encodeURIComponent(str)}&signature=${sign}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
|
||||
referer: 'https://kugou.com'
|
||||
}
|
||||
}
|
||||
).then((body) => body)
|
||||
},
|
||||
filterList(raw) {
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
|
||||
raw.forEach((item) => {
|
||||
if (ids.has(item.Audioid)) return
|
||||
ids.add(item.Audioid)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.FileSize !== 0) {
|
||||
let size = sizeFormate(item.FileSize)
|
||||
types.push({ type: '128k', size, hash: item.FileHash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.FileHash
|
||||
}
|
||||
}
|
||||
if (item.HQ != undefined) {
|
||||
let size = sizeFormate(item.HQ.FileSize)
|
||||
types.push({ type: '320k', size, hash: item.HQ.Hash })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item.HQ.Hash
|
||||
}
|
||||
}
|
||||
if (item.SQ != undefined) {
|
||||
let size = sizeFormate(item.SQ.FileSize)
|
||||
types.push({ type: 'flac', size, hash: item.SQ.Hash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.SQ.Hash
|
||||
}
|
||||
}
|
||||
if (item.Res != undefined) {
|
||||
let size = sizeFormate(item.Res.FileSize)
|
||||
types.push({ type: 'flac24bit', size, hash: item.Res.Hash })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: item.Res.Hash
|
||||
}
|
||||
}
|
||||
list.push({
|
||||
singer: decodeName(formatSingerName(item.Singers)),
|
||||
name: decodeName(item.SongName),
|
||||
albumName: decodeName(item.AlbumName),
|
||||
albumId: item.AlbumID,
|
||||
songmid: item.Audioid,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.Duration),
|
||||
_interval: item.Duration,
|
||||
img: null,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
hash: item.FileHash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
|
||||
return list
|
||||
},
|
||||
handleResult(rawData) {
|
||||
const rawList = []
|
||||
rawData.forEach((item) => {
|
||||
rawList.push(item)
|
||||
item.Grp.forEach((e) => rawList.push(e))
|
||||
})
|
||||
|
||||
return this.filterList(rawList)
|
||||
},
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
|
||||
return this.musicSearch(str, page, limit).then((data) => {
|
||||
let list = this.handleResult(data.lists)
|
||||
if (!list) return this.search(str, page, limit, retryNum)
|
||||
|
||||
this.total = data.total
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'kg'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
915
src/main/utils/musicSdk/kg/temp/songList-new.js
Normal file
915
src/main/utils/musicSdk/kg/temp/songList-new.js
Normal file
@@ -0,0 +1,915 @@
|
||||
import { httpFetch } from '../../../request'
|
||||
import { formatSingerName } from '../../utils'
|
||||
import {
|
||||
decodeName,
|
||||
formatPlayTime,
|
||||
sizeFormate,
|
||||
dateFormat,
|
||||
formatPlayCount
|
||||
} from '../../../index'
|
||||
import { signatureParams, createHttpFetch } from './../util'
|
||||
import { getMusicInfosByList } from '../musicInfo'
|
||||
import album from '../album'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_listInfo: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listRecommend: null,
|
||||
listDetailLimit: 10000,
|
||||
currentTagInfo: {
|
||||
id: undefined,
|
||||
info: undefined
|
||||
},
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: '5'
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: '6'
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: '7'
|
||||
},
|
||||
{
|
||||
name: '热藏',
|
||||
id: '3'
|
||||
},
|
||||
{
|
||||
name: '飙升',
|
||||
id: '8'
|
||||
}
|
||||
],
|
||||
cache: new Map(),
|
||||
collectionIdListInfoCache: new Map(),
|
||||
regExps: {
|
||||
listData: /global\.data = (\[.+\]);/,
|
||||
listInfo: /global = {[\s\S]+?name: "(.+)"[\s\S]+?pic: "(.+)"[\s\S]+?};/,
|
||||
// https://www.kugou.com/yy/special/single/1067062.html
|
||||
listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取歌曲列表内的音乐
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getListDetail(id, page) {
|
||||
id = id.toString()
|
||||
|
||||
if (id.includes('special/single/')) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
// fix https://www.kugou.com/songlist/xxx/?uid=xxx&chl=qq_client&cover=http%3A%2F%2Fimge.kugou.com%xxx.jpg&iszlist=1
|
||||
if (/https?:/.test(id)) {
|
||||
if (id.includes('#')) id = id.replace(/#.*$/, '')
|
||||
if (id.includes('global_collection_id'))
|
||||
return this.getUserListDetailByCollectionId(
|
||||
id.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
if (id.includes('chain='))
|
||||
return this.getUserListDetail3(id.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (id.includes('.html')) {
|
||||
if (id.includes('zlist.html')) {
|
||||
id = id.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
if (id.includes('pagesize')) {
|
||||
id = id
|
||||
.replace('pagesize=30', 'pagesize=' + this.listDetailLimit)
|
||||
.replace('page=1', 'page=' + page)
|
||||
} else {
|
||||
id += `&pagesize=${this.listDetailLimit}&page=${page}`
|
||||
}
|
||||
} else if (!id.includes('song.html'))
|
||||
return this.getUserListDetail3(
|
||||
id.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
}
|
||||
return this.getUserListDetail(id.replace(/^.*?http/, 'http'), page)
|
||||
}
|
||||
if (/^\d+$/.test(id)) return this.getUserListDetailByCode(id, page)
|
||||
if (id.startsWith('gid_'))
|
||||
return this.getUserListDetailByCollectionId(id.replace('gid_', ''), page)
|
||||
if (id.startsWith('id_')) return this.getUserListDetailBySpecialId(id.replace('id_', ''), page)
|
||||
|
||||
return new Error('Failed.')
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取SpecialId歌单
|
||||
* @param {*} id
|
||||
*/
|
||||
async getUserListDetailBySpecialId(id, page, tryNum = 0) {
|
||||
if (tryNum > 2) throw new Error('try max num')
|
||||
|
||||
const { body } = await httpFetch(this.getSongListDetailUrl(id)).promise
|
||||
let listData = body.match(this.regExps.listData)
|
||||
let listInfo = body.match(this.regExps.listInfo)
|
||||
if (!listData) return this.getListDetailBySpecialId(id, page, ++tryNum)
|
||||
let list = await getMusicInfosByList(JSON.parse(listData[1]))
|
||||
let name
|
||||
let pic
|
||||
if (listInfo) {
|
||||
name = listInfo[1]
|
||||
pic = listInfo[2]
|
||||
}
|
||||
let desc = this.parseHtmlDesc(body)
|
||||
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
limit: 10000,
|
||||
total: list.length,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name,
|
||||
img: pic,
|
||||
desc
|
||||
// author: body.result.info.userinfo.username,
|
||||
// play_count: formatPlayCount(body.result.listen_num),
|
||||
}
|
||||
}
|
||||
},
|
||||
parseHtmlDesc(html) {
|
||||
const prefix = '<div class="pc_specail_text pc_singer_tab_content" id="specailIntroduceWrap">'
|
||||
let index = html.indexOf(prefix)
|
||||
if (index < 0) return null
|
||||
const afterStr = html.substring(index + prefix.length)
|
||||
index = afterStr.indexOf('</div>')
|
||||
if (index < 0) return null
|
||||
return decodeName(afterStr.substring(0, index))
|
||||
},
|
||||
|
||||
/**
|
||||
* 使用SpecialId获取CollectionId
|
||||
* @param {*} specialId
|
||||
*/
|
||||
async getCollectionIdBySpecialId(specialId) {
|
||||
return httpFetch(`http://mobilecdnbj.kugou.com/api/v5/special/info?specialid=${specialId}`, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; Android 10; HLK-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Mobile Safari/537.36 EdgA/104.0.1293.70'
|
||||
}
|
||||
}).promise.then(({ body }) => {
|
||||
// console.log('getCollectionIdBySpecialId', body)
|
||||
if (!body.data.global_specialid)
|
||||
return Promise.reject(new Error('Failed to get global collection id.'))
|
||||
return body.data.global_specialid
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取歌单URL
|
||||
* @param {*} sortId
|
||||
* @param {*} tagId
|
||||
* @param {*} page
|
||||
*/
|
||||
getSongListUrl(sortId, tagId, page) {
|
||||
if (tagId == null) tagId = ''
|
||||
return `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_ajax=1&cdn=cdn&t=${sortId}&c=${tagId}&p=${page}`
|
||||
},
|
||||
getInfoUrl(tagId) {
|
||||
return tagId
|
||||
? `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&cdn=cdn&t=5&c=${tagId}`
|
||||
: 'http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&'
|
||||
},
|
||||
getSongListDetailUrl(id) {
|
||||
return `http://www2.kugou.kugou.com/yueku/v9/special/single/${id}-5-9999.html`
|
||||
},
|
||||
|
||||
filterInfoHotTag(rawData) {
|
||||
const result = []
|
||||
if (rawData.status !== 1) return result
|
||||
for (const key of Object.keys(rawData.data)) {
|
||||
let tag = rawData.data[key]
|
||||
result.push({
|
||||
id: tag.special_id,
|
||||
name: tag.special_name,
|
||||
source: 'kg'
|
||||
})
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
filterTagInfo(rawData) {
|
||||
const result = []
|
||||
for (const name of Object.keys(rawData)) {
|
||||
result.push({
|
||||
name,
|
||||
list: rawData[name].data.map((tag) => ({
|
||||
parent_id: tag.parent_id,
|
||||
parent_name: tag.pname,
|
||||
id: tag.id,
|
||||
name: tag.name,
|
||||
source: 'kg'
|
||||
}))
|
||||
})
|
||||
}
|
||||
return result
|
||||
},
|
||||
filterSongList(rawData) {
|
||||
return rawData.map((item) => ({
|
||||
play_count: item.total_play_count || formatPlayCount(item.play_count),
|
||||
id: 'id_' + item.specialid,
|
||||
author: item.nickname,
|
||||
name: item.specialname,
|
||||
time: dateFormat(item.publish_time || item.publishtime, 'Y-M-D'),
|
||||
img: item.img || item.imgurl,
|
||||
total: item.songcount,
|
||||
grade: item.grade,
|
||||
desc: item.intro,
|
||||
source: 'kg'
|
||||
}))
|
||||
},
|
||||
|
||||
getSongList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(this.getSongListUrl(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (!body || body.status !== 1) return this.getSongList(sortId, tagId, page, ++tryNum)
|
||||
return this.filterSongList(body.special_db)
|
||||
})
|
||||
},
|
||||
getSongListRecommend(tryNum = 0) {
|
||||
if (this._requestObj_listRecommend) this._requestObj_listRecommend.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_listRecommend = httpFetch(
|
||||
'http://everydayrec.service.kugou.com/guess_special_recommend',
|
||||
{
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'KuGou2012-8275-web_browser_event_handler'
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
clienttime: 1566798337219,
|
||||
clientver: 8275,
|
||||
key: 'f1f93580115bb106680d2375f8032d96',
|
||||
mid: '21511157a05844bd085308bc76ef3343',
|
||||
platform: 'pc',
|
||||
userid: '262643156',
|
||||
return_min: 6,
|
||||
return_max: 15
|
||||
}
|
||||
}
|
||||
)
|
||||
return this._requestObj_listRecommend.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getSongListRecommend(++tryNum)
|
||||
return this.filterSongList(body.data.special_list)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 通过CollectionId获取歌单详情
|
||||
* @param {*} id
|
||||
*/
|
||||
async getUserListInfoByCollectionId(id) {
|
||||
if (!id || id.length > 1000) return Promise.reject(new Error('get list error'))
|
||||
if (this.collectionIdListInfoCache.has(id)) return this.collectionIdListInfoCache.get(id)
|
||||
|
||||
const params = `appid=1058&specialid=0&global_specialid=${id}&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-`
|
||||
return createHttpFetch(
|
||||
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`,
|
||||
{
|
||||
headers: {
|
||||
mid: '1586163242519',
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163242519'
|
||||
}
|
||||
}
|
||||
).then((body) => {
|
||||
let info = {
|
||||
type: body.type,
|
||||
userName: body.nickname,
|
||||
userAvatar: body.user_avatar,
|
||||
imageUrl: body.imgurl,
|
||||
desc: body.intro,
|
||||
name: body.specialname,
|
||||
globalSpecialid: body.global_specialid,
|
||||
total: body.songcount,
|
||||
playCount: body.playcount
|
||||
}
|
||||
|
||||
this.collectionIdListInfoCache.set(id, info)
|
||||
return info
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 通过SpecialId获取歌单
|
||||
* @param {*} id
|
||||
*/
|
||||
// async getUserListDetailBySpecialId(id, page = 1, limit = 300) {
|
||||
// if (!id || id.length > 1000) return Promise.reject(new Error('get list error.'))
|
||||
// const listInfo = await this.getListInfoBySpecialId(id)
|
||||
|
||||
// const params = `specialid=${id}&need_sort=1&module=CloudMusic&clientver=11589&pagesize=${limit}&userid=0&page=${page}&type=0&area_code=1&appid=1005`
|
||||
// return createHttpFetch(`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 2)}`, {
|
||||
// headers: {
|
||||
// 'User-Agent': 'Android10-AndroidPhone-11589-201-0-playlist-wifi',
|
||||
// },
|
||||
// }).then(body => {
|
||||
// if (!body.info) return Promise.reject(new Error('Get list failed.'))
|
||||
// const songList = this.filterListByCollectionId(body.info)
|
||||
|
||||
// return {
|
||||
// list: songList || [],
|
||||
// page,
|
||||
// limit,
|
||||
// total: body.count,
|
||||
// source: 'kg',
|
||||
// info: {
|
||||
// name: listInfo.name,
|
||||
// img: listInfo.image,
|
||||
// desc: listInfo.desc,
|
||||
// // author: listInfo.userName,
|
||||
// // play_count: formatPlayCount(listInfo.playCount),
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
/**
|
||||
* 通过CollectionId获取歌单
|
||||
* @param {*} id
|
||||
*/
|
||||
async getUserListDetailByCollectionId(id, page = 1, limit = 300) {
|
||||
if (!id || id.length > 1000) return Promise.reject(new Error('ID error.'))
|
||||
const listInfo = await this.getUserListInfoByCollectionId(id)
|
||||
|
||||
const params = `need_sort=1&module=CloudMusic&clientver=11589&pagesize=${limit}&global_collection_id=${id}&userid=0&page=${page}&type=0&area_code=1&appid=1005`
|
||||
return createHttpFetch(
|
||||
`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 'android')}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Android10-AndroidPhone-11589-201-0-playlist-wifi'
|
||||
}
|
||||
}
|
||||
).then((body) => {
|
||||
if (!body.info) return Promise.reject(new Error('Get list failed.'))
|
||||
const songList = this.filterListByCollectionId(body.info)
|
||||
|
||||
return {
|
||||
list: songList || [],
|
||||
page,
|
||||
limit,
|
||||
total: listInfo.total,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: listInfo.name,
|
||||
img: listInfo.imageUrl && listInfo.imageUrl.replace('{size}', 240),
|
||||
desc: listInfo.desc,
|
||||
author: listInfo.userName,
|
||||
play_count: formatPlayCount(listInfo.playCount)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 过滤GlobalSpecialId歌单数据
|
||||
* @param {*} rawData
|
||||
*/
|
||||
filterListByCollectionId(rawData) {
|
||||
let ids = new Set()
|
||||
let list = []
|
||||
rawData.forEach((item) => {
|
||||
if (!item) return
|
||||
if (ids.has(item.hash)) return
|
||||
ids.add(item.hash)
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
item.relate_goods.forEach((data) => {
|
||||
let size = sizeFormate(data.size)
|
||||
switch (data.level) {
|
||||
case 2:
|
||||
types.push({ type: '128k', size, hash: data.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: data.hash
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
types.push({ type: '320k', size, hash: data.hash })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: data.hash
|
||||
}
|
||||
break
|
||||
case 5:
|
||||
types.push({ type: 'flac', size, hash: data.hash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: data.hash
|
||||
}
|
||||
break
|
||||
case 6:
|
||||
types.push({ type: 'flac24bit', size, hash: data.hash })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: data.hash
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
list.push({
|
||||
singer:
|
||||
formatSingerName(item.singerinfo, 'name') ||
|
||||
decodeName(item.name).split(' - ')[0].replace(/&/g, '、'),
|
||||
name: decodeName(item.name).split(' - ')[1],
|
||||
albumName: decodeName(item.albuminfo.name),
|
||||
albumId: item.albuminfo.id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(parseInt(item.timelen) / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
/**
|
||||
* 通过酷狗码获取歌单
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getUserListDetailByCode(id, page = 1) {
|
||||
// type 1单曲,2歌单,3电台,4酷狗码,5别人的播放队列
|
||||
const codeData = await createHttpFetch('http://t.kugou.com/command/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'network_super_call.cpp:3676261689:379',
|
||||
'User-Agent': ''
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
clientver: 9020,
|
||||
mid: '21511157a05844bd085308bc76ef3343',
|
||||
clienttime: 640612895,
|
||||
key: '36164c4015e704673c588ee202b9ecb8',
|
||||
data: id
|
||||
}
|
||||
})
|
||||
if (!codeData) return Promise.reject(new Error('Get list failed.'))
|
||||
const codeInfo = codeData.info
|
||||
|
||||
switch (codeInfo.type) {
|
||||
case 2:
|
||||
if (!codeInfo.global_collection_id)
|
||||
return this.getUserListDetailBySpecialId(codeInfo.id, page)
|
||||
break
|
||||
case 3:
|
||||
return album.getAlbumDetail(codeInfo.id, page)
|
||||
}
|
||||
if (codeInfo.global_collection_id)
|
||||
return this.getUserListDetailByCollectionId(codeInfo.global_collection_id, page)
|
||||
|
||||
if (codeInfo.userid != null) {
|
||||
const songList = await createHttpFetch(
|
||||
'http://www2.kugou.kugou.com/apps/kucodeAndShare/app/',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'network_super_call.cpp:3676261689:379',
|
||||
'User-Agent': ''
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
clientver: 9020,
|
||||
mid: '21511157a05844bd085308bc76ef3343',
|
||||
clienttime: 640612895,
|
||||
key: '36164c4015e704673c588ee202b9ecb8',
|
||||
data: {
|
||||
id: codeInfo.id,
|
||||
type: 3,
|
||||
userid: codeInfo.userid,
|
||||
collect_type: 0,
|
||||
page: 1,
|
||||
pagesize: codeInfo.count
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// console.log(songList)
|
||||
let list = await getMusicInfosByList(songList || codeInfo.list)
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
limit: codeInfo.count,
|
||||
total: list.length,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: codeInfo.name,
|
||||
img: (codeInfo.img_size && codeInfo.img_size.replace('{size}', 240)) || codeInfo.img,
|
||||
// desc: body.result.info.list_desc,
|
||||
author: codeInfo.username
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetail3(chain, page) {
|
||||
const songInfo = await createHttpFetch(
|
||||
`http://m.kugou.com/schain/transfer?pagesize=${this.listDetailLimit}&chain=${chain}&su=1&page=${page}&n=0.7928855356604456`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
|
||||
}
|
||||
}
|
||||
)
|
||||
if (!songInfo.list) {
|
||||
if (songInfo.global_collection_id)
|
||||
return this.getUserListDetailByCollectionId(songInfo.global_collection_id, page)
|
||||
else
|
||||
return this.getUserListDetail4(songInfo, chain, page).catch(() =>
|
||||
this.getUserListDetail5(chain)
|
||||
)
|
||||
}
|
||||
let list = await getMusicInfosByList(songInfo.list)
|
||||
// console.log(info, songInfo)
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
limit: this.listDetailLimit,
|
||||
total: list.length,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: songInfo.info.name,
|
||||
img: songInfo.info.img,
|
||||
// desc: body.result.info.list_desc,
|
||||
author: songInfo.info.username
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetailByLink({ info }, link) {
|
||||
let listInfo = info['0']
|
||||
let total = listInfo.count
|
||||
let tasks = []
|
||||
let page = 0
|
||||
while (total) {
|
||||
const limit = total > 90 ? 90 : total
|
||||
total -= limit
|
||||
page += 1
|
||||
tasks.push(
|
||||
createHttpFetch(
|
||||
link.replace(/pagesize=\d+/, 'pagesize=' + limit).replace(/page=\d+/, 'page=' + page),
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
|
||||
Referer: link
|
||||
}
|
||||
}
|
||||
).then((data) => data.list.info)
|
||||
)
|
||||
}
|
||||
let result = await Promise.all(tasks).then(([...datas]) => datas.flat())
|
||||
result = await getMusicInfosByList(result)
|
||||
// console.log(result)
|
||||
return {
|
||||
list: result,
|
||||
page,
|
||||
limit: this.listDetailLimit,
|
||||
total: result.length,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: listInfo.name,
|
||||
img: listInfo.pic && listInfo.pic.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.list_create_username
|
||||
// play_count: formatPlayCount(listInfo.count),
|
||||
}
|
||||
}
|
||||
},
|
||||
createGetListDetail2Task(id, total) {
|
||||
let tasks = []
|
||||
let page = 0
|
||||
while (total) {
|
||||
const limit = total > 300 ? 300 : total
|
||||
total -= limit
|
||||
page += 1
|
||||
const params =
|
||||
'appid=1058&global_specialid=' +
|
||||
id +
|
||||
'&specialid=0&plat=0&version=8000&page=' +
|
||||
page +
|
||||
'&pagesize=' +
|
||||
limit +
|
||||
'&srcappid=2919&clientver=20000&clienttime=1586163263991&mid=1586163263991&uuid=1586163263991&dfid=-'
|
||||
tasks.push(
|
||||
createHttpFetch(
|
||||
`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 'web')}`,
|
||||
{
|
||||
headers: {
|
||||
mid: '1586163263991',
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163263991'
|
||||
}
|
||||
}
|
||||
).then((data) => data.info)
|
||||
)
|
||||
}
|
||||
return Promise.all(tasks).then(([...datas]) => datas.flat())
|
||||
},
|
||||
async getUserListDetail2(global_collection_id) {
|
||||
let id = global_collection_id
|
||||
if (id.length > 1000) throw new Error('get list error')
|
||||
const params =
|
||||
'appid=1058&specialid=0&global_specialid=' +
|
||||
id +
|
||||
'&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-'
|
||||
let info = await createHttpFetch(
|
||||
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`,
|
||||
{
|
||||
headers: {
|
||||
mid: '1586163242519',
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163242519'
|
||||
}
|
||||
}
|
||||
)
|
||||
const songInfo = await this.createGetListDetail2Task(id, info.songcount)
|
||||
let list = await getMusicInfosByList(songInfo)
|
||||
// console.log(info, songInfo, list)
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
limit: this.listDetailLimit,
|
||||
total: list.length,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: info.specialname,
|
||||
img: info.imgurl && info.imgurl.replace('{size}', 240),
|
||||
desc: info.intro,
|
||||
author: info.nickname,
|
||||
play_count: formatPlayCount(info.playcount)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getListInfoByChain(chain) {
|
||||
if (this.cache.has(chain)) return this.cache.get(chain)
|
||||
const { body } = await httpFetch(`https://m.kugou.com/share/?chain=${chain}&id=${chain}`, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
||||
}
|
||||
}).promise
|
||||
// console.log(body)
|
||||
let result = body.match(/var\sphpParam\s=\s({.+?});/)
|
||||
if (result) result = JSON.parse(result[1])
|
||||
this.cache.set(chain, result)
|
||||
return result
|
||||
},
|
||||
|
||||
async getUserListDetailByPcChain(chain) {
|
||||
let key = `${chain}_pc_list`
|
||||
if (this.cache.has(key)) return this.cache.get(key)
|
||||
const { body } = await httpFetch(`http://www.kugou.com/share/${chain}.html`, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
|
||||
}
|
||||
}).promise
|
||||
let result = body.match(/var\sdataFromSmarty\s=\s(\[.+?\])/)
|
||||
if (result) result = JSON.parse(result[1])
|
||||
this.cache.set(chain, result)
|
||||
result = await getMusicInfosByList(result)
|
||||
// console.log(info, songInfo)
|
||||
return result
|
||||
},
|
||||
|
||||
async getUserListDetail4(songInfo, chain, page) {
|
||||
const limit = 100
|
||||
const [listInfo, list] = await Promise.all([
|
||||
this.getListInfoByChain(chain),
|
||||
this.getUserListDetailBySpecialId(songInfo.id, page, limit)
|
||||
])
|
||||
return {
|
||||
list: list || [],
|
||||
page,
|
||||
limit,
|
||||
total: list.length ?? 0,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: listInfo.specialname,
|
||||
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.nickname
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetail5(chain) {
|
||||
const [listInfo, list] = await Promise.all([
|
||||
this.getListInfoByChain(chain),
|
||||
this.getUserListDetailByPcChain(chain)
|
||||
])
|
||||
return {
|
||||
list: list || [],
|
||||
page: 1,
|
||||
limit: this.listDetailLimit,
|
||||
total: list.length ?? 0,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: listInfo.specialname,
|
||||
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.nickname
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetail(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
|
||||
const requestLink = httpFetch(link, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
|
||||
Referer: link
|
||||
},
|
||||
follow_max: 2
|
||||
})
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode,
|
||||
body
|
||||
} = await requestLink.promise
|
||||
// console.log(body, location, statusCode)
|
||||
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
|
||||
if (typeof body == 'string') {
|
||||
if (body.includes('"global_collection_id":'))
|
||||
return this.getUserListDetailByCollectionId(
|
||||
body.replace(/^[\s\S]+?"global_collection_id":"(\w+)"[\s\S]+?$/, '$1'),
|
||||
page
|
||||
)
|
||||
if (body.includes('"albumid":'))
|
||||
return album.getAlbumDetail(body.replace(/^[\s\S]+?"albumid":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('"album_id":') && link.includes('album/info'))
|
||||
return album.getAlbumDetail(body.replace(/^[\s\S]+?"album_id":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('list_id = "') && link.includes('album/info'))
|
||||
return album.getAlbumDetail(body.replace(/^[\s\S]+?list_id = "(\w+)"[\s\S]+?$/, '$1'), page)
|
||||
}
|
||||
if (location) {
|
||||
// 概念版分享链接 https://t1.kugou.com/xxx
|
||||
if (location.includes('global_specialid'))
|
||||
return this.getUserListDetailByCollectionId(
|
||||
location.replace(/^.*?global_specialid=(\w+)(?:&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
if (location.includes('global_collection_id'))
|
||||
return this.getUserListDetailByCollectionId(
|
||||
location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
if (location.includes('chain='))
|
||||
return this.getUserListDetail3(
|
||||
location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
if (location.includes('.html')) {
|
||||
if (location.includes('zlist.html')) {
|
||||
let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
if (link.includes('pagesize')) {
|
||||
link = link
|
||||
.replace('pagesize=30', 'pagesize=' + this.listDetailLimit)
|
||||
.replace('page=1', 'page=' + page)
|
||||
} else {
|
||||
link += `&pagesize=${this.listDetailLimit}&page=${page}`
|
||||
}
|
||||
return this.getUserListDetail(link, page, ++retryNum)
|
||||
} else
|
||||
return this.getUserListDetail3(
|
||||
location.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
}
|
||||
return this.getUserListDetail(location, page, ++retryNum)
|
||||
}
|
||||
if (body.errcode !== 0) return this.getUserListDetail(link, page, ++retryNum)
|
||||
return this.getUserListDetailByLink(body, link)
|
||||
},
|
||||
|
||||
// 获取列表信息
|
||||
getListInfo(tagId, tryNum = 0) {
|
||||
if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_listInfo = httpFetch(this.getInfoUrl(tagId))
|
||||
return this._requestObj_listInfo.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getListInfo(tagId, ++tryNum)
|
||||
return {
|
||||
limit: body.data.params.pagesize,
|
||||
page: body.data.params.p,
|
||||
total: body.data.params.total,
|
||||
source: 'kg'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page) {
|
||||
let tasks = [this.getSongList(sortId, tagId, page)]
|
||||
tasks.push(
|
||||
this.currentTagInfo.id === tagId
|
||||
? Promise.resolve(this.currentTagInfo.info)
|
||||
: this.getListInfo(tagId).then((info) => {
|
||||
this.currentTagInfo.id = tagId
|
||||
this.currentTagInfo.info = Object.assign({}, info)
|
||||
return info
|
||||
})
|
||||
)
|
||||
if (!tagId && page === 1 && sortId === this.sortList[0].id)
|
||||
tasks.push(this.getSongListRecommend()) // 如果是所有类别,则顺便获取推荐列表
|
||||
return Promise.all(tasks).then(([list, info, recommendList]) => {
|
||||
if (recommendList) list.unshift(...recommendList)
|
||||
return {
|
||||
list,
|
||||
...info
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取标签
|
||||
getTags(tryNum = 0) {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_tags = httpFetch(this.getInfoUrl())
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getTags(++tryNum)
|
||||
return {
|
||||
hotTag: this.filterInfoHotTag(body.data.hotTag),
|
||||
tags: this.filterTagInfo(body.data.tagids),
|
||||
source: 'kg'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getDetailPageUrl(id) {
|
||||
if (typeof id == 'string') {
|
||||
if (/^https?:\/\//.test(id)) return id
|
||||
id = id.replace('id_', '')
|
||||
}
|
||||
return `https://www.kugou.com/yy/special/single/${id}.html`
|
||||
},
|
||||
|
||||
search(text, page, limit = 20) {
|
||||
const params = `userid=1384394652&req_custom=1&appid=1005&req_multi=1&version=11589&page=${page}&filter=0&pagesize=${limit}&order=0&clienttime=1681779443&iscorrection=1&searchsong=0&keyword=${text}&mid=288799920684148686226285199951543865551&dfid=3eSBsO1u97EY1zeIZd40hH4p&clientver=11589&platform=AndroidFilter`
|
||||
const url = encodeURI(
|
||||
`http://complexsearchretry.kugou.com/v1/search/special?${params}&signature=${signatureParams(params, 'android')}`
|
||||
)
|
||||
return createHttpFetch(url).then((body) => {
|
||||
// console.log(body)
|
||||
return {
|
||||
list: body.lists.map((item) => {
|
||||
return {
|
||||
play_count: formatPlayCount(item.total_play_count),
|
||||
id: item.gid ? `gid_${item.gid}` : `id_${item.specialid}`,
|
||||
author: item.nickname,
|
||||
name: item.specialname,
|
||||
time: dateFormat(item.publish_time, 'Y-M-D'),
|
||||
img: item.img,
|
||||
grade: item.grade,
|
||||
desc: item.intro,
|
||||
total: item.song_count,
|
||||
source: 'kg'
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: body.total,
|
||||
source: 'kg'
|
||||
}
|
||||
})
|
||||
// http://msearchretry.kugou.com/api/v3/search/special?version=9209&keyword=%E5%91%A8%E6%9D%B0%E4%BC%A6&pagesize=20&filter=0&page=1&sver=2&with_res_tag=0
|
||||
// http://ioscdn.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&correct=1&sver=5
|
||||
// http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2
|
||||
}
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
28
src/main/utils/musicSdk/kg/tipSearch.js
Normal file
28
src/main/utils/musicSdk/kg/tipSearch.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { createHttpFetch } from './util'
|
||||
|
||||
export default {
|
||||
requestObj: null,
|
||||
cancelTipSearch() {
|
||||
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
|
||||
},
|
||||
tipSearchBySong(str) {
|
||||
this.cancelTipSearch()
|
||||
this.requestObj = createHttpFetch(
|
||||
`https://searchtip.kugou.com/getSearchTip?MusicTipCount=10&keyword=${encodeURIComponent(str)}`,
|
||||
{
|
||||
headers: {
|
||||
referer: 'https://www.kugou.com/'
|
||||
}
|
||||
}
|
||||
)
|
||||
return this.requestObj.then((body) => {
|
||||
return body[0].RecordDatas
|
||||
})
|
||||
},
|
||||
handleResult(rawData) {
|
||||
return rawData.map((info) => info.HintInfo)
|
||||
},
|
||||
async search(str) {
|
||||
return this.tipSearchBySong(str).then((result) => this.handleResult(result))
|
||||
}
|
||||
}
|
||||
46
src/main/utils/musicSdk/kg/util.js
Normal file
46
src/main/utils/musicSdk/kg/util.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { toMD5 } from '../utils'
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
// s.content[0].lyricContent.forEach(([str]) => {
|
||||
// console.log(str)
|
||||
// })
|
||||
|
||||
/**
|
||||
* 签名
|
||||
* @param {*} params
|
||||
* @param {*} apiver
|
||||
*/
|
||||
export const signatureParams = (params, platform = 'android', body = '') => {
|
||||
let keyparam = 'OIlwieks28dk2k092lksi2UIkp'
|
||||
if (platform === 'web') keyparam = 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt'
|
||||
let param_list = params.split('&')
|
||||
param_list.sort()
|
||||
let sign_params = `${keyparam}${param_list.join('')}${body}${keyparam}`
|
||||
return toMD5(sign_params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个适用于KG的Http请求
|
||||
* @param {*} url
|
||||
* @param {*} options
|
||||
* @param {*} retryNum
|
||||
*/
|
||||
export const createHttpFetch = async (url, options, retryNum = 0) => {
|
||||
if (retryNum > 2) throw new Error('try max num')
|
||||
let result
|
||||
try {
|
||||
result = await httpFetch(url, options).promise
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return createHttpFetch(url, options, ++retryNum)
|
||||
}
|
||||
// console.log(result.statusCode, result.body)
|
||||
if (
|
||||
result.statusCode !== 200 ||
|
||||
(result.body.error_code ?? result.body.errcode ?? result.body.err_code) != 0
|
||||
)
|
||||
return createHttpFetch(url, options, ++retryNum)
|
||||
if (result.body.data) return result.body.data
|
||||
if (Array.isArray(result.body.info)) return result.body
|
||||
return result.body.info
|
||||
}
|
||||
907
src/main/utils/musicSdk/kg/vendors/infSign.min.js
vendored
Normal file
907
src/main/utils/musicSdk/kg/vendors/infSign.min.js
vendored
Normal file
@@ -0,0 +1,907 @@
|
||||
!(function (t, n) {
|
||||
'object' == typeof exports && 'undefined' != typeof module
|
||||
? (module.exports = n())
|
||||
: 'function' == typeof define && define.amd
|
||||
? define(n)
|
||||
: ((t = t || self), (t.infSign = n()))
|
||||
})(this, function () {
|
||||
'use strict'
|
||||
function t(t, n, r) {
|
||||
return (
|
||||
n in t
|
||||
? Object.defineProperty(t, n, { value: r, enumerable: !0, configurable: !0, writable: !0 })
|
||||
: (t[n] = r),
|
||||
t
|
||||
)
|
||||
}
|
||||
function n(t, n) {
|
||||
var r = Object.keys(t)
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var e = Object.getOwnPropertySymbols(t)
|
||||
;(n &&
|
||||
(e = e.filter(function (n) {
|
||||
return Object.getOwnPropertyDescriptor(t, n).enumerable
|
||||
})),
|
||||
r.push.apply(r, e))
|
||||
}
|
||||
return r
|
||||
}
|
||||
function r(r) {
|
||||
for (var e = 1; e < arguments.length; e++) {
|
||||
var o = null != arguments[e] ? arguments[e] : {}
|
||||
e % 2
|
||||
? n(o, !0).forEach(function (n) {
|
||||
t(r, n, o[n])
|
||||
})
|
||||
: Object.getOwnPropertyDescriptors
|
||||
? Object.defineProperties(r, Object.getOwnPropertyDescriptors(o))
|
||||
: n(o).forEach(function (t) {
|
||||
Object.defineProperty(r, t, Object.getOwnPropertyDescriptor(o, t))
|
||||
})
|
||||
}
|
||||
return r
|
||||
}
|
||||
function e(t, n) {
|
||||
return ((n = { exports: {} }), t(n, n.exports), n.exports)
|
||||
}
|
||||
function o(t) {
|
||||
return (
|
||||
!!t.constructor && 'function' == typeof t.constructor.isBuffer && t.constructor.isBuffer(t)
|
||||
)
|
||||
}
|
||||
function i(t) {
|
||||
return 'function' == typeof t.readFloatLE && 'function' == typeof t.slice && o(t.slice(0, 0))
|
||||
}
|
||||
function c() {
|
||||
var t,
|
||||
n = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
|
||||
e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '',
|
||||
o = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
|
||||
i = !1,
|
||||
c = !1,
|
||||
a = 'json',
|
||||
l = r({}, n),
|
||||
u = s.isInClient()
|
||||
;('function' == typeof o
|
||||
? (t = o)
|
||||
: ((t = o.callback), (i = o.useH5 || !1), (a = o.postType || 'json'), (c = o.isCDN || !1)),
|
||||
e &&
|
||||
('[object Object]' != Object.prototype.toString.call(e)
|
||||
? (u = !1)
|
||||
: 'urlencoded' == a && (u = !1)))
|
||||
var f = function () {
|
||||
var n = new Date().getTime(),
|
||||
i = [],
|
||||
s = [],
|
||||
u = 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
|
||||
f = { srcappid: '2919', clientver: '20000', clienttime: n, mid: n, uuid: n, dfid: '-' }
|
||||
;(c && (delete f.clienttime, delete f.mid, delete f.uuid, delete f.dfid),
|
||||
(l = r({}, f, {}, l)))
|
||||
for (var g in l) i.push(g)
|
||||
if (
|
||||
(i.sort(),
|
||||
i.forEach(function (t) {
|
||||
s.push(t + '=' + l[t])
|
||||
}),
|
||||
e)
|
||||
)
|
||||
if ('[object Object]' == Object.prototype.toString.call(e))
|
||||
if ('json' == a) s.push(JSON.stringify(e))
|
||||
else {
|
||||
var b = []
|
||||
for (var g in e) b.push(g + '=' + e[g])
|
||||
s.push(b.join('&'))
|
||||
}
|
||||
else s.push(e)
|
||||
;(s.unshift(u),
|
||||
s.push(u),
|
||||
(l.signature = d(s.join(''))),
|
||||
o.log && (console.log('H5签名前参数', s), console.log('H5签名后返回', l)),
|
||||
e
|
||||
? t &&
|
||||
t(
|
||||
l,
|
||||
'[object Object]' == Object.prototype.toString.call(e) && 'json' == a
|
||||
? JSON.stringify(e)
|
||||
: e
|
||||
)
|
||||
: t && t(l))
|
||||
}
|
||||
if (u && !i) {
|
||||
var g = !1
|
||||
s.mobileCall(764, { get: l, post: e }, function (n) {
|
||||
return (
|
||||
!g &&
|
||||
((g = !0),
|
||||
n && n.status
|
||||
? (delete n.status,
|
||||
o.log &&
|
||||
(console.log('客户端签名前参数', { get: l, post: e }),
|
||||
console.log('客户端签名后返回', r({}, l, {}, n))),
|
||||
(l = r({}, l, {}, n)),
|
||||
e
|
||||
? t &&
|
||||
t(
|
||||
l,
|
||||
'[object Object]' == Object.prototype.toString.call(e) && 'json' == a
|
||||
? JSON.stringify(e)
|
||||
: e
|
||||
)
|
||||
: t && t(l),
|
||||
!1)
|
||||
: ((u = !1), void f()))
|
||||
)
|
||||
})
|
||||
} else ((u = !1), f())
|
||||
}
|
||||
'undefined' != typeof globalThis
|
||||
? globalThis
|
||||
: 'undefined' != typeof window
|
||||
? window
|
||||
: 'undefined' != typeof global
|
||||
? global
|
||||
: 'undefined' != typeof self && self
|
||||
var s = e(function (t, n) {
|
||||
!(function (n, r) {
|
||||
t.exports = (function () {
|
||||
var t = {
|
||||
str2Json: function (t) {
|
||||
var n = {}
|
||||
if ('[object String]' === Object.prototype.toString.call(t))
|
||||
try {
|
||||
n = JSON.parse(t)
|
||||
} catch (t) {
|
||||
n = {}
|
||||
}
|
||||
return n
|
||||
},
|
||||
json2Str: function (t) {
|
||||
var n = t
|
||||
if ('string' != typeof t)
|
||||
try {
|
||||
n = JSON.stringify(t)
|
||||
} catch (t) {
|
||||
n = ''
|
||||
}
|
||||
return n
|
||||
},
|
||||
_extend: function (t, n) {
|
||||
if (n) for (var r in t) n.hasOwnProperty(r) || (n[r] = t[r])
|
||||
return n
|
||||
},
|
||||
formatURL: { browser: '', url: '' },
|
||||
formatSong: {
|
||||
filename: '',
|
||||
filesize: '',
|
||||
hash: '',
|
||||
bitrate: '',
|
||||
extname: '',
|
||||
duration: '',
|
||||
mvhash: '',
|
||||
m4afilesize: '',
|
||||
'320hash': '',
|
||||
'320filesize': '',
|
||||
sqhash: '',
|
||||
sqfilesize: 0,
|
||||
feetype: 0,
|
||||
isfirst: 0
|
||||
},
|
||||
formatMV: { filename: '', singername: '', hash: '', imgurl: '' },
|
||||
formatShare: {
|
||||
shareName: '',
|
||||
topicName: '',
|
||||
hash: '',
|
||||
listID: '',
|
||||
type: '',
|
||||
suid: '',
|
||||
slid: '',
|
||||
imgUrl: '',
|
||||
filename: '',
|
||||
duration: '',
|
||||
shareData: { linkUrl: '', picUrl: '', content: '', title: '' }
|
||||
},
|
||||
cbNum: 0,
|
||||
isIOS: !!navigator.userAgent.match(/KGBrowser/gi),
|
||||
isKugouAndroid: !!navigator.userAgent.match(/kugouandroid/gi),
|
||||
isAndroid: 'undefined' != typeof external && void 0 !== external.superCall,
|
||||
loadUrl: function (t) {
|
||||
var n = document.createElement('iframe')
|
||||
;(n.setAttribute('src', t),
|
||||
n.setAttribute('style', 'display:none;'),
|
||||
n.setAttribute('height', '0px'),
|
||||
n.setAttribute('width', '0px'),
|
||||
n.setAttribute('frameborder', '0'),
|
||||
document.body.appendChild(n),
|
||||
n.parentNode.removeChild(n),
|
||||
(n = null))
|
||||
},
|
||||
callCmd: function (n) {
|
||||
var r = t
|
||||
if (r.isKugouAndroid) {
|
||||
var e = {},
|
||||
o = ''
|
||||
if (
|
||||
(n.cmd && (e.cmd = n.cmd),
|
||||
n.jsonStr && (e.jsonStr = n.jsonStr),
|
||||
n.callback &&
|
||||
((o =
|
||||
'kgandroidmobilecall' + ++r.cbNum + Math.random().toString().substr(2, 9)),
|
||||
(e.callback = o),
|
||||
(window[o] = function (t, e) {
|
||||
void 0 !== t &&
|
||||
('[object String]' === Object.prototype.toString.call(t)
|
||||
? ((t =
|
||||
'#' === e
|
||||
? decodeURIComponent(t)
|
||||
: decodeURIComponent(decodeURIComponent(t))),
|
||||
n.callback(r.str2Json(t)))
|
||||
: n.callback(t))
|
||||
})),
|
||||
n.AndroidCallback)
|
||||
) {
|
||||
var i = r.str2Json(n.jsonStr)
|
||||
;((i.AndroidCallback = o),
|
||||
(n.jsonStr = r.json2Str(i)),
|
||||
n.jsonStr && (e.jsonStr = n.jsonStr))
|
||||
}
|
||||
var c = encodeURIComponent(JSON.stringify(e)),
|
||||
s = 'kugoujsbridge://start.kugou_jsbridge/?'.concat(c)
|
||||
r.loadUrl(s)
|
||||
} else if (r.isAndroid) {
|
||||
var a = '',
|
||||
l = ''
|
||||
if (n.jsonStr) {
|
||||
if (n.callback && '' !== n.callback && !0 === n.AndroidCallback) {
|
||||
;((l = 'kgmobilecall' + ++r.cbNum + Math.random().toString().substr(2, 9)),
|
||||
(window[l] = function (t, e) {
|
||||
void 0 !== t &&
|
||||
('[object String]' === Object.prototype.toString.call(t)
|
||||
? ((t =
|
||||
'#' === e
|
||||
? decodeURIComponent(t)
|
||||
: decodeURIComponent(decodeURIComponent(t))),
|
||||
n.callback(r.str2Json(t)))
|
||||
: n.callback(t))
|
||||
}))
|
||||
var u = r.str2Json(n.jsonStr)
|
||||
;((u.AndroidCallback = l), (n.jsonStr = r.json2Str(u)))
|
||||
}
|
||||
try {
|
||||
a = external.superCall(n.cmd, n.jsonStr)
|
||||
} catch (t) {}
|
||||
} else
|
||||
try {
|
||||
a = external.superCall(n.cmd)
|
||||
} catch (t) {}
|
||||
n.callback &&
|
||||
'' !== n.callback &&
|
||||
'AndroidCallback' != a &&
|
||||
((a = r.str2Json(a)), n.callback(a))
|
||||
} else {
|
||||
var f = '',
|
||||
d = ''
|
||||
;(n.callback &&
|
||||
((d = 'kgmobilecall' + ++r.cbNum + Math.random().toString().substr(2, 9)),
|
||||
(window[d] = function (t) {
|
||||
void 0 !== t &&
|
||||
n.callback &&
|
||||
('[object String]' === Object.prototype.toString.call(t)
|
||||
? n.callback(r.str2Json(t))
|
||||
: n.callback(t))
|
||||
})),
|
||||
d &&
|
||||
'' != d &&
|
||||
n.jsonStr &&
|
||||
(f =
|
||||
'kugouurl://start.music/?{"cmd":' +
|
||||
n.cmd +
|
||||
', "jsonStr":' +
|
||||
n.jsonStr +
|
||||
', "callback":"' +
|
||||
d +
|
||||
'"}'),
|
||||
d &&
|
||||
'' != d &&
|
||||
!n.jsonStr &&
|
||||
(f = 'kugouurl://start.music/?{"cmd":' + n.cmd + ', "callback":"' + d + '"}'),
|
||||
'' == d &&
|
||||
n.jsonStr &&
|
||||
(f =
|
||||
'kugouurl://start.music/?{"cmd":' + n.cmd + ', "jsonStr":' + n.jsonStr + '}'),
|
||||
'' != d || n.jsonStr || (f = 'kugouurl://start.music/?{"cmd":' + n.cmd + '}'),
|
||||
r.loadUrl(f))
|
||||
}
|
||||
},
|
||||
formartData: function (n, r) {
|
||||
;(n && 123 == n && r && (r = t._extend(t.formatURL, r)),
|
||||
n && 123 == n && r && (r = t._extend(t.formatURL, r)))
|
||||
}
|
||||
}
|
||||
return {
|
||||
isIOS: t.isIOS,
|
||||
isKugouAndroid: t.isKugouAndroid,
|
||||
isAndroid: t.isAndroid,
|
||||
isInClient: function () {
|
||||
return !(!t.isAndroid && !t.isKugouAndroid && !t.isIOS)
|
||||
},
|
||||
mobileCall: function (n, r, e) {
|
||||
var o = ''
|
||||
if ((r && (o = t.json2Str(r)), !n)) return (console.error('请输入命令号!'), !1)
|
||||
var i = {}
|
||||
;(n && (i.cmd = n),
|
||||
'' != o && (i.jsonStr = o),
|
||||
e && (i.callback = e),
|
||||
n && 186 == n && e && (i.AndroidCallback = !0),
|
||||
t.callCmd(i))
|
||||
},
|
||||
KgWebMobileCall: function (t, n) {
|
||||
if (t)
|
||||
try {
|
||||
var r = t.split('.')
|
||||
r.reduce(function (e, o) {
|
||||
if (e[o]) {
|
||||
if (o === r[r.length - 1]) {
|
||||
var i = e[o]
|
||||
return 'function' == typeof i
|
||||
? ((e[o] = function (t) {
|
||||
;(i && i(t), n && n(t))
|
||||
}),
|
||||
e[o])
|
||||
: (console.error(
|
||||
'请检查,当前环境变量已注册了对象:' + t + ',且该对象不是方法'
|
||||
),
|
||||
null)
|
||||
}
|
||||
return e[o]
|
||||
}
|
||||
return (
|
||||
o === r[r.length - 1]
|
||||
? (e[o] = function (t) {
|
||||
n && n(t)
|
||||
})
|
||||
: (e[o] = new Object()),
|
||||
e[o]
|
||||
)
|
||||
}, window)
|
||||
} catch (t) {}
|
||||
}
|
||||
}
|
||||
})()
|
||||
})()
|
||||
}),
|
||||
a = e(function (t) {
|
||||
!(function () {
|
||||
var n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
||||
r = {
|
||||
rotl: function (t, n) {
|
||||
return (t << n) | (t >>> (32 - n))
|
||||
},
|
||||
rotr: function (t, n) {
|
||||
return (t << (32 - n)) | (t >>> n)
|
||||
},
|
||||
endian: function (t) {
|
||||
if (t.constructor == Number)
|
||||
return (16711935 & r.rotl(t, 8)) | (4278255360 & r.rotl(t, 24))
|
||||
for (var n = 0; n < t.length; n++) t[n] = r.endian(t[n])
|
||||
return t
|
||||
},
|
||||
randomBytes: function (t) {
|
||||
for (var n = []; t > 0; t--) n.push(Math.floor(256 * Math.random()))
|
||||
return n
|
||||
},
|
||||
bytesToWords: function (t) {
|
||||
for (var n = [], r = 0, e = 0; r < t.length; r++, e += 8)
|
||||
n[e >>> 5] |= t[r] << (24 - (e % 32))
|
||||
return n
|
||||
},
|
||||
wordsToBytes: function (t) {
|
||||
for (var n = [], r = 0; r < 32 * t.length; r += 8)
|
||||
n.push((t[r >>> 5] >>> (24 - (r % 32))) & 255)
|
||||
return n
|
||||
},
|
||||
bytesToHex: function (t) {
|
||||
for (var n = [], r = 0; r < t.length; r++)
|
||||
(n.push((t[r] >>> 4).toString(16)), n.push((15 & t[r]).toString(16)))
|
||||
return n.join('')
|
||||
},
|
||||
hexToBytes: function (t) {
|
||||
for (var n = [], r = 0; r < t.length; r += 2) n.push(parseInt(t.substr(r, 2), 16))
|
||||
return n
|
||||
},
|
||||
bytesToBase64: function (t) {
|
||||
for (var r = [], e = 0; e < t.length; e += 3)
|
||||
for (var o = (t[e] << 16) | (t[e + 1] << 8) | t[e + 2], i = 0; i < 4; i++)
|
||||
8 * e + 6 * i <= 8 * t.length
|
||||
? r.push(n.charAt((o >>> (6 * (3 - i))) & 63))
|
||||
: r.push('=')
|
||||
return r.join('')
|
||||
},
|
||||
base64ToBytes: function (t) {
|
||||
t = t.replace(/[^A-Z0-9+\/]/gi, '')
|
||||
for (var r = [], e = 0, o = 0; e < t.length; o = ++e % 4)
|
||||
0 != o &&
|
||||
r.push(
|
||||
((n.indexOf(t.charAt(e - 1)) & (Math.pow(2, -2 * o + 8) - 1)) << (2 * o)) |
|
||||
(n.indexOf(t.charAt(e)) >>> (6 - 2 * o))
|
||||
)
|
||||
return r
|
||||
}
|
||||
}
|
||||
t.exports = r
|
||||
})()
|
||||
}),
|
||||
l = {
|
||||
utf8: {
|
||||
stringToBytes: function (t) {
|
||||
return l.bin.stringToBytes(unescape(encodeURIComponent(t)))
|
||||
},
|
||||
bytesToString: function (t) {
|
||||
return decodeURIComponent(escape(l.bin.bytesToString(t)))
|
||||
}
|
||||
},
|
||||
bin: {
|
||||
stringToBytes: function (t) {
|
||||
for (var n = [], r = 0; r < t.length; r++) n.push(255 & t.charCodeAt(r))
|
||||
return n
|
||||
},
|
||||
bytesToString: function (t) {
|
||||
for (var n = [], r = 0; r < t.length; r++) n.push(String.fromCharCode(t[r]))
|
||||
return n.join('')
|
||||
}
|
||||
}
|
||||
},
|
||||
u = l,
|
||||
f = function (t) {
|
||||
return null != t && (o(t) || i(t) || !!t._isBuffer)
|
||||
},
|
||||
d = e(function (t) {
|
||||
!(function () {
|
||||
var n = a,
|
||||
r = u.utf8,
|
||||
e = f,
|
||||
o = u.bin,
|
||||
i = function (t, c) {
|
||||
t.constructor == String
|
||||
? (t = c && 'binary' === c.encoding ? o.stringToBytes(t) : r.stringToBytes(t))
|
||||
: e(t)
|
||||
? (t = Array.prototype.slice.call(t, 0))
|
||||
: Array.isArray(t) || (t = t.toString())
|
||||
for (
|
||||
var s = n.bytesToWords(t),
|
||||
a = 8 * t.length,
|
||||
l = 1732584193,
|
||||
u = -271733879,
|
||||
f = -1732584194,
|
||||
d = 271733878,
|
||||
g = 0;
|
||||
g < s.length;
|
||||
g++
|
||||
)
|
||||
s[g] =
|
||||
(16711935 & ((s[g] << 8) | (s[g] >>> 24))) |
|
||||
(4278255360 & ((s[g] << 24) | (s[g] >>> 8)))
|
||||
;((s[a >>> 5] |= 128 << a % 32), (s[14 + (((a + 64) >>> 9) << 4)] = a))
|
||||
for (var b = i._ff, p = i._gg, h = i._hh, m = i._ii, g = 0; g < s.length; g += 16) {
|
||||
var y = l,
|
||||
j = u,
|
||||
S = f,
|
||||
v = d
|
||||
;((u = m(
|
||||
(u = m(
|
||||
(u = m(
|
||||
(u = m(
|
||||
(u = h(
|
||||
(u = h(
|
||||
(u = h(
|
||||
(u = h(
|
||||
(u = p(
|
||||
(u = p(
|
||||
(u = p(
|
||||
(u = p(
|
||||
(u = b(
|
||||
(u = b(
|
||||
(u = b(
|
||||
(u = b(
|
||||
u,
|
||||
(f = b(
|
||||
f,
|
||||
(d = b(
|
||||
d,
|
||||
(l = b(l, u, f, d, s[g + 0], 7, -680876936)),
|
||||
u,
|
||||
f,
|
||||
s[g + 1],
|
||||
12,
|
||||
-389564586
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 2],
|
||||
17,
|
||||
606105819
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 3],
|
||||
22,
|
||||
-1044525330
|
||||
)),
|
||||
(f = b(
|
||||
f,
|
||||
(d = b(
|
||||
d,
|
||||
(l = b(l, u, f, d, s[g + 4], 7, -176418897)),
|
||||
u,
|
||||
f,
|
||||
s[g + 5],
|
||||
12,
|
||||
1200080426
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 6],
|
||||
17,
|
||||
-1473231341
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 7],
|
||||
22,
|
||||
-45705983
|
||||
)),
|
||||
(f = b(
|
||||
f,
|
||||
(d = b(
|
||||
d,
|
||||
(l = b(l, u, f, d, s[g + 8], 7, 1770035416)),
|
||||
u,
|
||||
f,
|
||||
s[g + 9],
|
||||
12,
|
||||
-1958414417
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 10],
|
||||
17,
|
||||
-42063
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 11],
|
||||
22,
|
||||
-1990404162
|
||||
)),
|
||||
(f = b(
|
||||
f,
|
||||
(d = b(
|
||||
d,
|
||||
(l = b(l, u, f, d, s[g + 12], 7, 1804603682)),
|
||||
u,
|
||||
f,
|
||||
s[g + 13],
|
||||
12,
|
||||
-40341101
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 14],
|
||||
17,
|
||||
-1502002290
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 15],
|
||||
22,
|
||||
1236535329
|
||||
)),
|
||||
(f = p(
|
||||
f,
|
||||
(d = p(
|
||||
d,
|
||||
(l = p(l, u, f, d, s[g + 1], 5, -165796510)),
|
||||
u,
|
||||
f,
|
||||
s[g + 6],
|
||||
9,
|
||||
-1069501632
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 11],
|
||||
14,
|
||||
643717713
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 0],
|
||||
20,
|
||||
-373897302
|
||||
)),
|
||||
(f = p(
|
||||
f,
|
||||
(d = p(
|
||||
d,
|
||||
(l = p(l, u, f, d, s[g + 5], 5, -701558691)),
|
||||
u,
|
||||
f,
|
||||
s[g + 10],
|
||||
9,
|
||||
38016083
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 15],
|
||||
14,
|
||||
-660478335
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 4],
|
||||
20,
|
||||
-405537848
|
||||
)),
|
||||
(f = p(
|
||||
f,
|
||||
(d = p(
|
||||
d,
|
||||
(l = p(l, u, f, d, s[g + 9], 5, 568446438)),
|
||||
u,
|
||||
f,
|
||||
s[g + 14],
|
||||
9,
|
||||
-1019803690
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 3],
|
||||
14,
|
||||
-187363961
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 8],
|
||||
20,
|
||||
1163531501
|
||||
)),
|
||||
(f = p(
|
||||
f,
|
||||
(d = p(
|
||||
d,
|
||||
(l = p(l, u, f, d, s[g + 13], 5, -1444681467)),
|
||||
u,
|
||||
f,
|
||||
s[g + 2],
|
||||
9,
|
||||
-51403784
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 7],
|
||||
14,
|
||||
1735328473
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 12],
|
||||
20,
|
||||
-1926607734
|
||||
)),
|
||||
(f = h(
|
||||
f,
|
||||
(d = h(
|
||||
d,
|
||||
(l = h(l, u, f, d, s[g + 5], 4, -378558)),
|
||||
u,
|
||||
f,
|
||||
s[g + 8],
|
||||
11,
|
||||
-2022574463
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 11],
|
||||
16,
|
||||
1839030562
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 14],
|
||||
23,
|
||||
-35309556
|
||||
)),
|
||||
(f = h(
|
||||
f,
|
||||
(d = h(
|
||||
d,
|
||||
(l = h(l, u, f, d, s[g + 1], 4, -1530992060)),
|
||||
u,
|
||||
f,
|
||||
s[g + 4],
|
||||
11,
|
||||
1272893353
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 7],
|
||||
16,
|
||||
-155497632
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 10],
|
||||
23,
|
||||
-1094730640
|
||||
)),
|
||||
(f = h(
|
||||
f,
|
||||
(d = h(
|
||||
d,
|
||||
(l = h(l, u, f, d, s[g + 13], 4, 681279174)),
|
||||
u,
|
||||
f,
|
||||
s[g + 0],
|
||||
11,
|
||||
-358537222
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 3],
|
||||
16,
|
||||
-722521979
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 6],
|
||||
23,
|
||||
76029189
|
||||
)),
|
||||
(f = h(
|
||||
f,
|
||||
(d = h(
|
||||
d,
|
||||
(l = h(l, u, f, d, s[g + 9], 4, -640364487)),
|
||||
u,
|
||||
f,
|
||||
s[g + 12],
|
||||
11,
|
||||
-421815835
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 15],
|
||||
16,
|
||||
530742520
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 2],
|
||||
23,
|
||||
-995338651
|
||||
)),
|
||||
(f = m(
|
||||
f,
|
||||
(d = m(
|
||||
d,
|
||||
(l = m(l, u, f, d, s[g + 0], 6, -198630844)),
|
||||
u,
|
||||
f,
|
||||
s[g + 7],
|
||||
10,
|
||||
1126891415
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 14],
|
||||
15,
|
||||
-1416354905
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 5],
|
||||
21,
|
||||
-57434055
|
||||
)),
|
||||
(f = m(
|
||||
f,
|
||||
(d = m(
|
||||
d,
|
||||
(l = m(l, u, f, d, s[g + 12], 6, 1700485571)),
|
||||
u,
|
||||
f,
|
||||
s[g + 3],
|
||||
10,
|
||||
-1894986606
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 10],
|
||||
15,
|
||||
-1051523
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 1],
|
||||
21,
|
||||
-2054922799
|
||||
)),
|
||||
(f = m(
|
||||
f,
|
||||
(d = m(
|
||||
d,
|
||||
(l = m(l, u, f, d, s[g + 8], 6, 1873313359)),
|
||||
u,
|
||||
f,
|
||||
s[g + 15],
|
||||
10,
|
||||
-30611744
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 6],
|
||||
15,
|
||||
-1560198380
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 13],
|
||||
21,
|
||||
1309151649
|
||||
)),
|
||||
(f = m(
|
||||
f,
|
||||
(d = m(
|
||||
d,
|
||||
(l = m(l, u, f, d, s[g + 4], 6, -145523070)),
|
||||
u,
|
||||
f,
|
||||
s[g + 11],
|
||||
10,
|
||||
-1120210379
|
||||
)),
|
||||
l,
|
||||
u,
|
||||
s[g + 2],
|
||||
15,
|
||||
718787259
|
||||
)),
|
||||
d,
|
||||
l,
|
||||
s[g + 9],
|
||||
21,
|
||||
-343485551
|
||||
)),
|
||||
(l = (l + y) >>> 0),
|
||||
(u = (u + j) >>> 0),
|
||||
(f = (f + S) >>> 0),
|
||||
(d = (d + v) >>> 0))
|
||||
}
|
||||
return n.endian([l, u, f, d])
|
||||
}
|
||||
;((i._ff = function (t, n, r, e, o, i, c) {
|
||||
var s = t + ((n & r) | (~n & e)) + (o >>> 0) + c
|
||||
return ((s << i) | (s >>> (32 - i))) + n
|
||||
}),
|
||||
(i._gg = function (t, n, r, e, o, i, c) {
|
||||
var s = t + ((n & e) | (r & ~e)) + (o >>> 0) + c
|
||||
return ((s << i) | (s >>> (32 - i))) + n
|
||||
}),
|
||||
(i._hh = function (t, n, r, e, o, i, c) {
|
||||
var s = t + (n ^ r ^ e) + (o >>> 0) + c
|
||||
return ((s << i) | (s >>> (32 - i))) + n
|
||||
}),
|
||||
(i._ii = function (t, n, r, e, o, i, c) {
|
||||
var s = t + (r ^ (n | ~e)) + (o >>> 0) + c
|
||||
return ((s << i) | (s >>> (32 - i))) + n
|
||||
}),
|
||||
(i._blocksize = 16),
|
||||
(i._digestsize = 16),
|
||||
(t.exports = function (t, r) {
|
||||
if (void 0 === t || null === t) throw new Error('Illegal argument ' + t)
|
||||
var e = n.wordsToBytes(i(t, r))
|
||||
return r && r.asBytes ? e : r && r.asString ? o.bytesToString(e) : n.bytesToHex(e)
|
||||
}))
|
||||
})()
|
||||
})
|
||||
return c
|
||||
})
|
||||
133
src/main/utils/musicSdk/kw/album.js
Normal file
133
src/main/utils/musicSdk/kw/album.js
Normal file
@@ -0,0 +1,133 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName } from '../index'
|
||||
import { formatSinger, objStr2JSON } from './util'
|
||||
|
||||
// let requestObj_list
|
||||
export default {
|
||||
limit_list: 36,
|
||||
limit_song: 1000,
|
||||
filterListDetail(rawList, albumName, albumId) {
|
||||
// console.log(rawList)
|
||||
// console.log(rawList.length, rawList2.length)
|
||||
return rawList.map((item, inedx) => {
|
||||
let formats = item.formats.split('|')
|
||||
let types = []
|
||||
let _types = {}
|
||||
if (formats.includes('MP3128')) {
|
||||
types.push({ type: '128k', size: null })
|
||||
_types['128k'] = {
|
||||
size: null
|
||||
}
|
||||
}
|
||||
// if (formats.includes('MP3192')) {
|
||||
// types.push({ type: '192k', size: null })
|
||||
// _types['192k'] = {
|
||||
// size: null,
|
||||
// }
|
||||
// }
|
||||
if (formats.includes('MP3H')) {
|
||||
types.push({ type: '320k', size: null })
|
||||
_types['320k'] = {
|
||||
size: null
|
||||
}
|
||||
}
|
||||
// if (formats.includes('AL')) {
|
||||
// types.push({ type: 'ape', size: null })
|
||||
// _types.ape = {
|
||||
// size: null,
|
||||
// }
|
||||
// }
|
||||
if (formats.includes('ALFLAC')) {
|
||||
types.push({ type: 'flac', size: null })
|
||||
_types.flac = {
|
||||
size: null
|
||||
}
|
||||
}
|
||||
if (formats.includes('HIRFLAC')) {
|
||||
types.push({ type: 'flac24bit', size: null })
|
||||
_types.flac24bit = {
|
||||
size: null
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
return {
|
||||
singer: formatSinger(decodeName(item.artist)),
|
||||
name: decodeName(item.name),
|
||||
albumName,
|
||||
albumId,
|
||||
songmid: item.id,
|
||||
source: 'kw',
|
||||
interval: null,
|
||||
img: item.pic,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 格式化播放数量
|
||||
* @param {*} num
|
||||
*/
|
||||
formatPlayCount(num) {
|
||||
if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿'
|
||||
if (num > 10000) return parseInt(num / 1000) / 10 + '万'
|
||||
return num
|
||||
},
|
||||
getAlbumListDetail(id, page, retryNum = 0) {
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
const requestObj_listDetail = httpFetch(
|
||||
`http://search.kuwo.cn/r.s?pn=${page - 1}&rn=${this.limit_song}&stype=albuminfo&albumid=${id}&show_copyright_off=0&encoding=utf&vipver=MUSIC_9.1.0`
|
||||
)
|
||||
return requestObj_listDetail.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum)
|
||||
body = objStr2JSON(body)
|
||||
// console.log(body)
|
||||
if (!body.musiclist) return this.getAlbumListDetail(id, page, ++retryNum)
|
||||
body.name = decodeName(body.name)
|
||||
return {
|
||||
list: this.filterListDetail(body.musiclist, body.name, body.albumid),
|
||||
page,
|
||||
limit: this.limit_song,
|
||||
total: parseInt(body.songnum),
|
||||
source: 'kw',
|
||||
info: {
|
||||
name: body.name,
|
||||
img: body.img || body.hts_img,
|
||||
desc: decodeName(body.info),
|
||||
author: decodeName(body.artist)
|
||||
// play_count: this.formatPlayCount(body.playnum),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// getAlbumListDetail(id, page, retryNum = 0) {
|
||||
// if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
// return tokenRequest(`http://www.kuwo.cn/api/www/album/albumInfo?albumId=${id}&pn=${page}&rn=${this.limit_song}&httpsStatus=1`).then((resp) => {
|
||||
// return resp.promise.then(({ statusCode, body }) => {
|
||||
// console.log(body)
|
||||
// return Promise.reject(new Error('failed'))
|
||||
// // if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum)
|
||||
// // const data = body.data
|
||||
// // console.log(data)
|
||||
// // if (!data.musicList) return this.getAlbumListDetail(id, page, ++retryNum)
|
||||
// // return {
|
||||
// // list: this.filterListDetail(data.musiclist),
|
||||
// // page,
|
||||
// // limit: this.limit_song,
|
||||
// // total: data.total,
|
||||
// // source: 'kw',
|
||||
// // info: {
|
||||
// // name: data.album,
|
||||
// // img: data.pic,
|
||||
// // desc: data.albuminfo,
|
||||
// // author: data.artist,
|
||||
// // play_count: this.formatPlayCount(data.playCnt),
|
||||
// // },
|
||||
// // }
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
}
|
||||
28
src/main/utils/musicSdk/kw/api-temp.js
Normal file
28
src/main/utils/musicSdk/kw/api-temp.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_temp = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://tm.tempmusics.tk/url/kw/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
headers,
|
||||
timeout,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(body.msg))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
|
||||
export default api_temp
|
||||
39
src/main/utils/musicSdk/kw/api-test.js
Normal file
39
src/main/utils/musicSdk/kw/api-test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_test = {
|
||||
// getMusicUrl(songInfo, type) {
|
||||
// const requestObj = httpFetch(`http://45.32.53.128:3002/m/kw/u/${songInfo.songmid}/${type}`, {
|
||||
// method: 'get',
|
||||
// headers,
|
||||
// timeout,
|
||||
// })
|
||||
// requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
// return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
// })
|
||||
// return requestObj
|
||||
// },
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/url/kw/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(requestMsg.fail))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
|
||||
export default api_test
|
||||
88
src/main/utils/musicSdk/kw/comment.js
Normal file
88
src/main/utils/musicSdk/kw/comment.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { dateFormat2 } from '../index'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
async getComment({ songmid }, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
|
||||
const _requestObj = httpFetch(
|
||||
`http://ncomment.kuwo.cn/com.s?f=web&type=get_comment&aapiver=1&prod=kwplayer_ar_10.5.2.0&digest=15&sid=${songmid}&start=${limit * (page - 1)}&msgflag=1&count=${limit}&newver=3&uid=0`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9;)'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.code != '200') throw new Error('获取评论失败')
|
||||
// console.log(body)
|
||||
|
||||
const total = body.comments_counts
|
||||
return {
|
||||
source: 'kw',
|
||||
comments: this.filterComment(body.comments),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(total / limit) || 1
|
||||
}
|
||||
},
|
||||
async getHotComment({ songmid }, page = 1, limit = 100) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
|
||||
const _requestObj2 = httpFetch(
|
||||
`http://ncomment.kuwo.cn/com.s?f=web&type=get_rec_comment&aapiver=1&prod=kwplayer_ar_10.5.2.0&digest=15&sid=${songmid}&start=${limit * (page - 1)}&msgflag=1&count=${limit}&newver=3&uid=0`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9;)'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
if (statusCode != 200 || body.code != '200') throw new Error('获取热门评论失败')
|
||||
// console.log(body)
|
||||
|
||||
const total = body.hot_comments_counts
|
||||
return {
|
||||
source: 'kw',
|
||||
comments: this.filterComment(body.hot_comments),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(total / limit) || 1
|
||||
}
|
||||
},
|
||||
filterComment(rawList) {
|
||||
if (!rawList) return []
|
||||
return rawList.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.msg,
|
||||
time: item.time,
|
||||
timeStr: dateFormat2(Number(item.time) * 1000),
|
||||
userName: item.u_name,
|
||||
avatar: item.u_pic,
|
||||
userId: item.u_id,
|
||||
likedCount: item.like_num,
|
||||
images: item.mpic ? [decodeURIComponent(item.mpic)] : [],
|
||||
reply: item.child_comments
|
||||
? item.child_comments.map((i) => {
|
||||
return {
|
||||
id: i.id,
|
||||
text: i.msg,
|
||||
time: i.time,
|
||||
timeStr: dateFormat2(Number(i.time) * 1000),
|
||||
userName: i.u_name,
|
||||
avatar: i.u_pic,
|
||||
userId: i.u_id,
|
||||
likedCount: i.like_num,
|
||||
images: i.mpic ? [i.mpic] : []
|
||||
}
|
||||
})
|
||||
: []
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
25
src/main/utils/musicSdk/kw/hotSearch.js
Normal file
25
src/main/utils/musicSdk/kw/hotSearch.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const _requestObj = httpFetch(
|
||||
'http://hotword.kuwo.cn/hotword.s?prod=kwplayer_ar_9.3.0.1&corp=kuwo&newver=2&vipver=9.3.0.1&source=kwplayer_ar_9.3.0.1_40.apk&p2p=1¬race=0&uid=0&plat=kwplayer_ar&rformat=json&encoding=utf8&tabid=1',
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9;)'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.status !== 'ok') throw new Error('获取热搜词失败')
|
||||
// console.log(body, statusCode)
|
||||
return { source: 'kw', list: this.filterList(body.tagvalue) }
|
||||
},
|
||||
filterList(rawList) {
|
||||
return rawList.map((item) => item.key)
|
||||
}
|
||||
}
|
||||
98
src/main/utils/musicSdk/kw/index.js
Normal file
98
src/main/utils/musicSdk/kw/index.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import tipSearch from './tipSearch'
|
||||
import musicSearch from './musicSearch'
|
||||
import { formatSinger } from './util'
|
||||
import leaderboard from './leaderboard'
|
||||
import lyric from './lyric'
|
||||
import pic from './pic'
|
||||
import songList from './songList'
|
||||
import hotSearch from './hotSearch'
|
||||
import comment from './comment'
|
||||
|
||||
const kw = {
|
||||
_musicInfoRequestObj: null,
|
||||
_musicInfoPromiseCancelFn: null,
|
||||
_musicPicRequestObj: null,
|
||||
_musicPicPromiseCancelFn: null,
|
||||
// context: null,
|
||||
|
||||
// init(context) {
|
||||
// if (this.isInited) return
|
||||
// this.isInited = true
|
||||
// this.context = context
|
||||
|
||||
// // this.musicSearch.search('我又想你了').then(res => {
|
||||
// // console.log(res)
|
||||
// // })
|
||||
|
||||
// // this.getMusicUrl('62355680', '320k').then(url => {
|
||||
// // console.log(url)
|
||||
// // })
|
||||
// },
|
||||
|
||||
tipSearch,
|
||||
musicSearch,
|
||||
leaderboard,
|
||||
songList,
|
||||
hotSearch,
|
||||
comment,
|
||||
getLyric(songInfo, isGetLyricx) {
|
||||
// let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer
|
||||
return lyric.getLyric(songInfo, isGetLyricx)
|
||||
},
|
||||
handleMusicInfo(songInfo) {
|
||||
return this.getMusicInfo(songInfo).then((info) => {
|
||||
// console.log(JSON.stringify(info))
|
||||
songInfo.name = info.name
|
||||
songInfo.singer = formatSinger(info.artist)
|
||||
songInfo.img = info.pic
|
||||
songInfo.albumName = info.album
|
||||
return songInfo
|
||||
// return Object.assign({}, songInfo, {
|
||||
// name: info.name,
|
||||
// singer: formatSinger(info.artist),
|
||||
// img: info.pic,
|
||||
// albumName: info.album,
|
||||
// })
|
||||
})
|
||||
},
|
||||
|
||||
getMusicInfo(songInfo) {
|
||||
if (this._musicInfoRequestObj) this._musicInfoRequestObj.cancelHttp()
|
||||
this._musicInfoRequestObj = httpFetch(
|
||||
`http://www.kuwo.cn/api/www/music/musicInfo?mid=${songInfo.songmid}`
|
||||
)
|
||||
return this._musicInfoRequestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? body.data : Promise.reject(new Error(body.msg))
|
||||
})
|
||||
},
|
||||
|
||||
getMusicUrls(musicInfo, cb) {
|
||||
let tasks = []
|
||||
let songId = musicInfo.songmid
|
||||
musicInfo.types.forEach((type) => {
|
||||
tasks.push(kw.getMusicUrl(songId, type.type).promise)
|
||||
})
|
||||
Promise.all(tasks).then((urlInfo) => {
|
||||
let typeUrl = {}
|
||||
urlInfo.forEach((info) => {
|
||||
typeUrl[info.type] = info.url
|
||||
})
|
||||
cb(typeUrl)
|
||||
})
|
||||
},
|
||||
|
||||
getPic(songInfo) {
|
||||
return pic.getPic(songInfo)
|
||||
},
|
||||
|
||||
getMusicDetailPageUrl(songInfo) {
|
||||
return `http://www.kuwo.cn/play_detail/${songInfo.songmid}`
|
||||
}
|
||||
|
||||
// init() {
|
||||
// return getToken()
|
||||
// },
|
||||
}
|
||||
|
||||
export default kw
|
||||
48
src/main/utils/musicSdk/kw/kwdecode.ts
Normal file
48
src/main/utils/musicSdk/kw/kwdecode.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { inflate } from 'zlib'
|
||||
import iconv from 'iconv-lite'
|
||||
|
||||
const handleInflate = async (data: Buffer) => {
|
||||
return new Promise((resolve: (result: Buffer) => void, reject) => {
|
||||
inflate(data, (err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve(result)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const buf_key = Buffer.from('yeelion')
|
||||
const buf_key_len = buf_key.length
|
||||
|
||||
const decodeLyric = async (buf: Buffer, isGetLyricx: boolean) => {
|
||||
// const info = buf.slice(0, index).toString()
|
||||
// if (!info.startsWith('tp=content')) return null
|
||||
// const isLyric = info.includes('\r\nlrcx=0\r\n')
|
||||
if (buf.toString('utf8', 0, 10) != 'tp=content') return ''
|
||||
// const index = buf.indexOf('\r\n\r\n') + 4
|
||||
const lrcData = await handleInflate(buf.subarray(buf.indexOf('\r\n\r\n') + 4))
|
||||
|
||||
if (!isGetLyricx) return iconv.decode(lrcData, 'gb18030')
|
||||
|
||||
const buf_str = Buffer.from(lrcData.toString(), 'base64')
|
||||
const buf_str_len = buf_str.length
|
||||
const output = new Uint8Array(buf_str_len)
|
||||
let i = 0
|
||||
while (i < buf_str_len) {
|
||||
let j = 0
|
||||
while (j < buf_key_len && i < buf_str_len) {
|
||||
output[i] = buf_str[i] ^ buf_key[j]
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
return iconv.decode(Buffer.from(output), 'gb18030')
|
||||
}
|
||||
|
||||
export default async (lrcBase64: string, isGetLyricx: boolean) => {
|
||||
const lrc = await decodeLyric(Buffer.from(lrcBase64, 'base64'), isGetLyricx)
|
||||
return Buffer.from(lrc).toString('base64')
|
||||
}
|
||||
284
src/main/utils/musicSdk/kw/leaderboard.js
Normal file
284
src/main/utils/musicSdk/kw/leaderboard.js
Normal file
@@ -0,0 +1,284 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../index'
|
||||
import { formatSinger, wbdCrypto } from './util'
|
||||
|
||||
const boardList = [
|
||||
{ id: 'kw__93', name: '飙升榜', bangid: '93' },
|
||||
{ id: 'kw__17', name: '新歌榜', bangid: '17' },
|
||||
{ id: 'kw__16', name: '热歌榜', bangid: '16' },
|
||||
{ id: 'kw__158', name: '抖音热歌榜', bangid: '158' },
|
||||
{ id: 'kw__292', name: '铃声榜', bangid: '292' },
|
||||
{ id: 'kw__284', name: '热评榜', bangid: '284' },
|
||||
{ id: 'kw__290', name: 'ACG新歌榜', bangid: '290' },
|
||||
{ id: 'kw__286', name: '台湾KKBOX榜', bangid: '286' },
|
||||
{ id: 'kw__279', name: '冬日暖心榜', bangid: '279' },
|
||||
{ id: 'kw__281', name: '巴士随身听榜', bangid: '281' },
|
||||
{ id: 'kw__255', name: 'KTV点唱榜', bangid: '255' },
|
||||
{ id: 'kw__280', name: '家务进行曲榜', bangid: '280' },
|
||||
{ id: 'kw__282', name: '熬夜修仙榜', bangid: '282' },
|
||||
{ id: 'kw__283', name: '枕边轻音乐榜', bangid: '283' },
|
||||
{ id: 'kw__278', name: '古风音乐榜', bangid: '278' },
|
||||
{ id: 'kw__264', name: 'Vlog音乐榜', bangid: '264' },
|
||||
{ id: 'kw__242', name: '电音榜', bangid: '242' },
|
||||
{ id: 'kw__187', name: '流行趋势榜', bangid: '187' },
|
||||
{ id: 'kw__204', name: '现场音乐榜', bangid: '204' },
|
||||
{ id: 'kw__186', name: 'ACG神曲榜', bangid: '186' },
|
||||
{ id: 'kw__185', name: '最强翻唱榜', bangid: '185' },
|
||||
{ id: 'kw__26', name: '经典怀旧榜', bangid: '26' },
|
||||
{ id: 'kw__104', name: '华语榜', bangid: '104' },
|
||||
{ id: 'kw__182', name: '粤语榜', bangid: '182' },
|
||||
{ id: 'kw__22', name: '欧美榜', bangid: '22' },
|
||||
{ id: 'kw__184', name: '韩语榜', bangid: '184' },
|
||||
{ id: 'kw__183', name: '日语榜', bangid: '183' },
|
||||
{ id: 'kw__145', name: '会员畅听榜', bangid: '145' },
|
||||
{ id: 'kw__153', name: '网红新歌榜', bangid: '153' },
|
||||
{ id: 'kw__64', name: '影视金曲榜', bangid: '64' },
|
||||
{ id: 'kw__176', name: 'DJ嗨歌榜', bangid: '176' },
|
||||
{ id: 'kw__106', name: '真声音', bangid: '106' },
|
||||
{ id: 'kw__12', name: 'Billboard榜', bangid: '12' },
|
||||
{ id: 'kw__49', name: 'iTunes音乐榜', bangid: '49' },
|
||||
{ id: 'kw__180', name: 'beatport电音榜', bangid: '180' },
|
||||
{ id: 'kw__13', name: '英国UK榜', bangid: '13' },
|
||||
{ id: 'kw__164', name: '百大DJ榜', bangid: '164' },
|
||||
{ id: 'kw__246', name: 'YouTube音乐排行榜', bangid: '246' },
|
||||
{ id: 'kw__265', name: '韩国Genie榜', bangid: '265' },
|
||||
{ id: 'kw__14', name: '韩国M-net榜', bangid: '14' },
|
||||
{ id: 'kw__8', name: '香港电台榜', bangid: '8' },
|
||||
{ id: 'kw__15', name: '日本公信榜', bangid: '15' },
|
||||
{ id: 'kw__151', name: '腾讯音乐人原创榜', bangid: '151' }
|
||||
]
|
||||
|
||||
const sortQualityArray = (array) => {
|
||||
const qualityMap = {
|
||||
flac24bit: 4,
|
||||
flac: 3,
|
||||
'320k': 2,
|
||||
'128k': 1
|
||||
}
|
||||
const rawQualityArray = []
|
||||
const newQualityArray = []
|
||||
|
||||
array.forEach((item, index) => {
|
||||
const type = qualityMap[item.type]
|
||||
if (!type) return
|
||||
rawQualityArray.push({ type, index })
|
||||
})
|
||||
|
||||
rawQualityArray.sort((a, b) => a.type - b.type)
|
||||
|
||||
rawQualityArray.forEach((item) => {
|
||||
newQualityArray.push(array[item.index])
|
||||
})
|
||||
|
||||
return newQualityArray
|
||||
}
|
||||
|
||||
export default {
|
||||
list: [
|
||||
{
|
||||
id: 'kwbiaosb',
|
||||
name: '飙升榜',
|
||||
bangid: 93
|
||||
},
|
||||
{
|
||||
id: 'kwregb',
|
||||
name: '热歌榜',
|
||||
bangid: 16
|
||||
},
|
||||
{
|
||||
id: 'kwhuiyb',
|
||||
name: '会员榜',
|
||||
bangid: 145
|
||||
},
|
||||
{
|
||||
id: 'kwdouyb',
|
||||
name: '抖音榜',
|
||||
bangid: 158
|
||||
},
|
||||
{
|
||||
id: 'kwqsb',
|
||||
name: '趋势榜',
|
||||
bangid: 187
|
||||
},
|
||||
{
|
||||
id: 'kwhuaijb',
|
||||
name: '怀旧榜',
|
||||
bangid: 26
|
||||
},
|
||||
{
|
||||
id: 'kwhuayb',
|
||||
name: '华语榜',
|
||||
bangid: 104
|
||||
},
|
||||
{
|
||||
id: 'kwyueyb',
|
||||
name: '粤语榜',
|
||||
bangid: 182
|
||||
},
|
||||
{
|
||||
id: 'kwoumb',
|
||||
name: '欧美榜',
|
||||
bangid: 22
|
||||
},
|
||||
{
|
||||
id: 'kwhanyb',
|
||||
name: '韩语榜',
|
||||
bangid: 184
|
||||
},
|
||||
{
|
||||
id: 'kwriyb',
|
||||
name: '日语榜',
|
||||
bangid: 183
|
||||
}
|
||||
],
|
||||
// getUrl: (p, l, id) => `http://kbangserver.kuwo.cn/ksong.s?from=pc&fmt=json&pn=${p - 1}&rn=${l}&type=bang&data=content&id=${id}&show_copyright_off=0&pcmp4=1&isbang=1`,
|
||||
regExps: {
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/
|
||||
},
|
||||
limit: 100,
|
||||
_requestBoardsObj: null,
|
||||
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch(
|
||||
'http://qukudata.kuwo.cn/q.k?op=query&cont=tree&node=2&pn=0&rn=1000&fmt=json&level=2'
|
||||
)
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
filterData(rawList) {
|
||||
return rawList.map((item) => {
|
||||
let types = []
|
||||
const _types = {}
|
||||
const qualitys = new Set()
|
||||
|
||||
item.n_minfo.split(';').forEach((i) => {
|
||||
const info = i.match(this.regExps.mInfo)
|
||||
if (!info) return
|
||||
|
||||
const quality = info[2]
|
||||
const size = info[4].toLocaleUpperCase()
|
||||
|
||||
if (qualitys.has(quality)) return
|
||||
qualitys.add(quality)
|
||||
|
||||
switch (quality) {
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = { size }
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = { size }
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = { size }
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
break
|
||||
}
|
||||
})
|
||||
types = sortQualityArray(types)
|
||||
|
||||
return {
|
||||
singer: formatSinger(decodeName(item.artist)),
|
||||
name: decodeName(item.name),
|
||||
albumName: decodeName(item.album),
|
||||
albumId: item.albumId,
|
||||
songmid: item.id,
|
||||
source: 'kw',
|
||||
interval: formatPlayTime(parseInt(item.duration)),
|
||||
img: item.pic,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
for (const board of rawList) {
|
||||
if (board.source != '1') continue
|
||||
list.push({
|
||||
id: 'kw__' + board.sourceid,
|
||||
name: board.name,
|
||||
bangid: String(board.sourceid)
|
||||
})
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// console.log(response.body)
|
||||
// if (response.statusCode !== 200 || !response.body.child) return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.child)
|
||||
// // console.log(list)
|
||||
// console.log(JSON.stringify(list))
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'kw',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'kw'
|
||||
}
|
||||
},
|
||||
|
||||
getList(id, page, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const requestBody = {
|
||||
uid: '',
|
||||
devId: '',
|
||||
sFrom: 'kuwo_sdk',
|
||||
user_type: 'AP',
|
||||
carSource: 'kwplayercar_ar_6.0.1.0_apk_keluze.apk',
|
||||
id,
|
||||
pn: page - 1,
|
||||
rn: this.limit
|
||||
}
|
||||
const requestUrl = `https://wbd.kuwo.cn/api/bd/bang/bang_info?${wbdCrypto.buildParam(requestBody)}`
|
||||
const request = httpFetch(requestUrl).promise
|
||||
|
||||
return request.then(({ statusCode, body }) => {
|
||||
const rawData = wbdCrypto.decodeData(body)
|
||||
// console.log(rawData)
|
||||
const data = rawData.data
|
||||
if (statusCode !== 200 || rawData.code != 200 || !data.musiclist)
|
||||
return this.getList(id, page, retryNum)
|
||||
|
||||
const total = parseInt(data.total)
|
||||
const list = this.filterData(data.musiclist)
|
||||
|
||||
return {
|
||||
total,
|
||||
list,
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'kw'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// getDetailPageUrl(id) {
|
||||
// return `http://www.kuwo.cn/rankList/${id}`
|
||||
// },
|
||||
}
|
||||
272
src/main/utils/musicSdk/kw/lyric.js
Normal file
272
src/main/utils/musicSdk/kw/lyric.js
Normal file
@@ -0,0 +1,272 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeLyric, lrcTools } from './util'
|
||||
import { decodeName } from '../index'
|
||||
|
||||
/*
|
||||
export default {
|
||||
formatTime(time) {
|
||||
let m = parseInt(time / 60)
|
||||
let s = (time % 60).toFixed(2)
|
||||
return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s)
|
||||
},
|
||||
sortLrcArr(arr) {
|
||||
const lrcSet = new Set()
|
||||
let lrc = []
|
||||
let lrcT = []
|
||||
|
||||
for (const item of arr) {
|
||||
if (lrcSet.has(item.time)) {
|
||||
const tItem = lrc.pop()
|
||||
tItem.time = lrc[lrc.length - 1].time
|
||||
lrcT.push(tItem)
|
||||
lrc.push(item)
|
||||
} else {
|
||||
lrc.push(item)
|
||||
lrcSet.add(item.time)
|
||||
}
|
||||
}
|
||||
|
||||
if (lrcT.length && lrc.length > lrcT.length) {
|
||||
const tItem = lrc.pop()
|
||||
tItem.time = lrc[lrc.length - 1].time
|
||||
lrcT.push(tItem)
|
||||
}
|
||||
|
||||
return {
|
||||
lrc,
|
||||
lrcT,
|
||||
}
|
||||
},
|
||||
transformLrc(songinfo, lrclist) {
|
||||
return `[ti:${songinfo.songName}]\n[ar:${songinfo.artist}]\n[al:${songinfo.album}]\n[by:]\n[offset:0]\n${lrclist ? lrclist.map(l => `[${this.formatTime(l.time)}]${l.lineLyric}\n`).join('') : '暂无歌词'}`
|
||||
},
|
||||
getLyric(songId) {
|
||||
const requestObj = httpFetch(`http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=${songId}`)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (!body.data?.lrclist?.length) return Promise.reject(new Error('Get lyric failed'))
|
||||
let lrcInfo
|
||||
try {
|
||||
lrcInfo = this.sortLrcArr(body.data.lrclist)
|
||||
} catch {
|
||||
return Promise.reject(new Error('Get lyric failed'))
|
||||
}
|
||||
// console.log(body.data.lrclist)
|
||||
// console.log(lrcInfo.lrc, lrcInfo.lrcT)
|
||||
// console.log({
|
||||
// lyric: decodeName(this.transformLrc(body.data.songinfo, lrc)),
|
||||
// tlyric: decodeName(this.transformLrc(body.data.songinfo, lrcT)),
|
||||
// })
|
||||
return {
|
||||
lyric: decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrc)),
|
||||
tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrcT)) : '',
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
*/
|
||||
|
||||
const buf_key = Buffer.from('yeelion')
|
||||
const buf_key_len = buf_key.length
|
||||
const buildParams = (id, isGetLyricx) => {
|
||||
let params = `user=12345,web,web,web&requester=localhost&req=1&rid=MUSIC_${id}`
|
||||
if (isGetLyricx) params += '&lrcx=1'
|
||||
const buf_str = Buffer.from(params)
|
||||
const buf_str_len = buf_str.length
|
||||
const output = new Uint16Array(buf_str_len)
|
||||
let i = 0
|
||||
while (i < buf_str_len) {
|
||||
let j = 0
|
||||
while (j < buf_key_len && i < buf_str_len) {
|
||||
output[i] = buf_key[j] ^ buf_str[i]
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
return Buffer.from(output).toString('base64')
|
||||
}
|
||||
|
||||
// console.log(buildParams('207527604', false))
|
||||
// console.log(buildParams('207527604', true))
|
||||
|
||||
const timeExp = /^\[([\d:.]*)\]{1}/g
|
||||
const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/
|
||||
const lyricxTag = /^<-?\d+,-?\d+>/
|
||||
export default {
|
||||
/* sortLrcArr(arr) {
|
||||
const lrcSet = new Set()
|
||||
let lrc = []
|
||||
let lrcT = []
|
||||
let markIndex = []
|
||||
for (const item of arr) {
|
||||
if (lrcSet.has(item.time)) {
|
||||
if (lrc.length < 2) continue
|
||||
const index = lrc.findIndex(l => l.time == item.time)
|
||||
markIndex.push(index)
|
||||
if (index == lrc.length - 1) {
|
||||
lrcT.push({ ...lrc[index], time: item.time })
|
||||
lrc.push(item)
|
||||
} else {
|
||||
lrcT.push({ ...lrc[index], time: lrc[index + 1].time })
|
||||
if (item.text) {
|
||||
// const lastIndex = lrc.length - 1
|
||||
// markIndex.push(lastIndex)
|
||||
// lrcT.push({ ...lrc[lastIndex], time: lrc[lastIndex - 1].time })
|
||||
lrc.push(item)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lrc.push(item)
|
||||
lrcSet.add(item.time)
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(markIndex)
|
||||
markIndex = Array.from(new Set(markIndex))
|
||||
for (let index = markIndex.length - 1; index >= 0; index--) {
|
||||
lrc.splice(markIndex[index], 1)
|
||||
}
|
||||
|
||||
// if (lrcT.length) {
|
||||
// if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||
// const tItem = lrc.pop()
|
||||
// tItem.time = lrc[lrc.length - 1].time
|
||||
// lrcT.push(tItem)
|
||||
// } else {
|
||||
// lrc = arr
|
||||
// lrcT = []
|
||||
// }
|
||||
// }
|
||||
|
||||
console.log(lrc, lrcT)
|
||||
|
||||
return {
|
||||
lrc,
|
||||
lrcT,
|
||||
}
|
||||
}, */
|
||||
sortLrcArr(arr) {
|
||||
const lrcSet = new Set()
|
||||
let lrc = []
|
||||
let lrcT = []
|
||||
|
||||
let isLyricx = false
|
||||
for (const item of arr) {
|
||||
if (lrcSet.has(item.time)) {
|
||||
if (lrc.length < 2) continue
|
||||
const tItem = lrc.pop()
|
||||
tItem.time = lrc[lrc.length - 1].time
|
||||
lrcT.push(tItem)
|
||||
lrc.push(item)
|
||||
} else {
|
||||
lrc.push(item)
|
||||
lrcSet.add(item.time)
|
||||
}
|
||||
if (!isLyricx && lyricxTag.test(item.text)) isLyricx = true
|
||||
}
|
||||
|
||||
if (!isLyricx && lrcT.length > lrc.length * 0.3 && lrc.length - lrcT.length > 6) {
|
||||
throw new Error('failed')
|
||||
// if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||
// const tItem = lrc.pop()
|
||||
// tItem.time = lrc[lrc.length - 1].time
|
||||
// lrcT.push(tItem)
|
||||
// } else {
|
||||
// lrc = arr
|
||||
// lrcT = []
|
||||
// }
|
||||
}
|
||||
|
||||
return {
|
||||
lrc,
|
||||
lrcT
|
||||
}
|
||||
},
|
||||
transformLrc(tags, lrclist) {
|
||||
return `${tags.join('\n')}\n${lrclist ? lrclist.map((l) => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}`
|
||||
},
|
||||
parseLrc(lrc) {
|
||||
const lines = lrc.split(/\r\n|\r|\n/)
|
||||
let tags = []
|
||||
let lrcArr = []
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim()
|
||||
let result = timeExp.exec(line)
|
||||
if (result) {
|
||||
const text = line.replace(timeExp, '').trim()
|
||||
let time = RegExp.$1
|
||||
if (/\.\d\d$/.test(time)) time += '0'
|
||||
lrcArr.push({
|
||||
time,
|
||||
text
|
||||
})
|
||||
} else if (lrcTools.rxps.tagLine.test(line)) {
|
||||
tags.push(line)
|
||||
}
|
||||
}
|
||||
const lrcInfo = this.sortLrcArr(lrcArr)
|
||||
return {
|
||||
lyric: decodeName(this.transformLrc(tags, lrcInfo.lrc)),
|
||||
tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(tags, lrcInfo.lrcT)) : ''
|
||||
}
|
||||
},
|
||||
// getLyric2(musicInfo, isGetLyricx = true) {
|
||||
// const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`)
|
||||
// requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
||||
// if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
||||
// return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => {
|
||||
// let lrcInfo
|
||||
// console.log(Buffer.from(base64Data, 'base64').toString())
|
||||
// try {
|
||||
// lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||
// } catch {
|
||||
// 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)
|
||||
// // console.log(lrcInfo.lyric)
|
||||
// // console.log(lrcInfo.tlyric)
|
||||
// // console.log(lrcInfo.lxlyric)
|
||||
// // console.log(JSON.stringify(lrcInfo))
|
||||
// })
|
||||
// })
|
||||
// return requestObj
|
||||
// },
|
||||
getLyric(musicInfo, isGetLyricx = true) {
|
||||
// this.getLyric2(musicInfo)
|
||||
const requestObj = httpFetch(
|
||||
`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
||||
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
||||
return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then((base64Data) => {
|
||||
// let lrcInfo
|
||||
// try {
|
||||
// lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||
// } catch {
|
||||
// return Promise.reject(new Error('Get lyric failed'))
|
||||
// }
|
||||
let lrcInfo
|
||||
// console.log(Buffer.from(base64Data, 'base64').toString())
|
||||
try {
|
||||
lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||
} catch (err) {
|
||||
return Promise.reject(new Error('Get lyric failed'))
|
||||
}
|
||||
// console.log(lrcInfo)
|
||||
if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||
try {
|
||||
lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
|
||||
} catch {
|
||||
lrcInfo.lxlyric = ''
|
||||
}
|
||||
lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||
if (!existTimeExp.test(lrcInfo.lyric)) return Promise.reject(new Error('Get lyric failed'))
|
||||
// console.log(lrcInfo)
|
||||
return lrcInfo
|
||||
})
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
129
src/main/utils/musicSdk/kw/musicSearch.js
Normal file
129
src/main/utils/musicSdk/kw/musicSearch.js
Normal file
@@ -0,0 +1,129 @@
|
||||
// import '../../polyfill/array.find'
|
||||
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../index'
|
||||
// import { debug } from '../../utils/env'
|
||||
import { formatSinger } from './util'
|
||||
|
||||
export default {
|
||||
regExps: {
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/
|
||||
},
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
// cancelFn: null,
|
||||
musicSearch(str, page, limit) {
|
||||
const musicSearchRequestObj = httpFetch(
|
||||
`http://search.kuwo.cn/r.s?client=kt&all=${encodeURIComponent(str)}&pn=${page - 1}&rn=${limit}&uid=794762570&ver=kwplayer_ar_9.2.2.1&vipver=1&show_copyright_off=1&newver=1&ft=music&cluster=0&strategy=2012&encoding=utf8&rformat=json&vermerge=1&mobi=1&issubtitle=1`
|
||||
)
|
||||
return musicSearchRequestObj.promise
|
||||
},
|
||||
// getImg(songId) {
|
||||
// return httpGet(`http://player.kuwo.cn/webmusic/sj/dtflagdate?flag=6&rid=MUSIC_${songId}`)
|
||||
// },
|
||||
// getLrc(songId) {
|
||||
// return httpGet(`http://mobile.kuwo.cn/mpage/html5/songinfoandlrc?mid=${songId}&flag=0`)
|
||||
// },
|
||||
handleResult(rawData) {
|
||||
const result = []
|
||||
if (!rawData) return result
|
||||
// console.log(rawData)
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
const info = rawData[i]
|
||||
let songId = info.MUSICRID.replace('MUSIC_', '')
|
||||
// const format = (info.FORMATS || info.formats).split('|')
|
||||
|
||||
if (!info.N_MINFO) {
|
||||
console.log('N_MINFO is undefined')
|
||||
return null
|
||||
}
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
let infoArr = info.N_MINFO.split(';')
|
||||
for (let info of infoArr) {
|
||||
info = info.match(this.regExps.mInfo)
|
||||
if (info) {
|
||||
switch (info[2]) {
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info[4] })
|
||||
_types.flac24bit = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info[4] })
|
||||
_types.flac = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info[4] })
|
||||
_types['320k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info[4] })
|
||||
_types['128k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
let interval = parseInt(info.DURATION)
|
||||
|
||||
result.push({
|
||||
name: decodeName(info.SONGNAME),
|
||||
singer: formatSinger(decodeName(info.ARTIST)),
|
||||
source: 'kw',
|
||||
// img = (info.album.name === '' || info.album.name === '空')
|
||||
// ? `http://player.kuwo.cn/webmusic/sj/dtflagdate?flag=6&rid=MUSIC_160911.jpg`
|
||||
// : `https://y.gtimg.cn/music/photo_new/T002R500x500M000${info.album.mid}.jpg`
|
||||
songmid: songId,
|
||||
albumId: decodeName(info.ALBUMID || ''),
|
||||
interval: Number.isNaN(interval) ? 0 : formatPlayTime(interval),
|
||||
albumName: info.ALBUM ? decodeName(info.ALBUM) : '',
|
||||
lrc: null,
|
||||
img: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
}
|
||||
// console.log(result)
|
||||
return result
|
||||
},
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then(({ body: result }) => {
|
||||
// console.log(result)
|
||||
if (!result || (result.TOTAL !== '0' && result.SHOW === '0'))
|
||||
return this.search(str, page, limit, ++retryNum)
|
||||
let list = this.handleResult(result.abslist)
|
||||
|
||||
if (list == null) return this.search(str, page, limit, ++retryNum)
|
||||
|
||||
this.total = parseInt(result.TOTAL)
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
total: this.total,
|
||||
limit,
|
||||
source: 'kw'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
11
src/main/utils/musicSdk/kw/pic.js
Normal file
11
src/main/utils/musicSdk/kw/pic.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
getPic({ songmid }) {
|
||||
const requestObj = httpFetch(
|
||||
`http://artistpicserver.kuwo.cn/pic.web?corp=kuwo&type=rid_pic&pictype=500&size=500&rid=${songmid}`
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => (/^http/.test(body) ? body : null))
|
||||
return requestObj.promise
|
||||
}
|
||||
}
|
||||
517
src/main/utils/musicSdk/kw/songList.js
Normal file
517
src/main/utils/musicSdk/kw/songList.js
Normal file
@@ -0,0 +1,517 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../index'
|
||||
import { formatSinger, objStr2JSON } from './util'
|
||||
import album from './album'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
limit_list: 36,
|
||||
limit_song: 1000,
|
||||
successCode: 200,
|
||||
sortList: [
|
||||
{
|
||||
name: '最新',
|
||||
id: 'new'
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot'
|
||||
}
|
||||
],
|
||||
regExps: {
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/,
|
||||
// http://www.kuwo.cn/playlist_detail/2886046289
|
||||
// https://m.kuwo.cn/h5app/playlist/2736267853?t=qqfriend
|
||||
listDetailLink: /^.+\/playlist(?:_detail)?\/(\d+)(?:\?.*|&.*$|#.*$|$)/
|
||||
},
|
||||
tagsUrl:
|
||||
'http://wapi.kuwo.cn/api/pc/classify/playlist/getTagList?cmd=rcm_keyword_playlist&user=0&prod=kwplayer_pc_9.0.5.0&vipver=9.0.5.0&source=kwplayer_pc_9.0.5.0&loginUid=0&loginSid=0&appUid=76039576',
|
||||
hotTagUrl:
|
||||
'http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmTagList?loginUid=0&loginSid=0&appUid=76039576',
|
||||
getListUrl({ sortId, id, type, page }) {
|
||||
if (!id)
|
||||
return `http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmPlayList?loginUid=0&loginSid=0&appUid=76039576&&pn=${page}&rn=${this.limit_list}&order=${sortId}`
|
||||
switch (type) {
|
||||
case '10000':
|
||||
return `http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&pn=${page}&id=${id}&rn=${this.limit_list}`
|
||||
case '43':
|
||||
return `http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=${id}&prod=pc`
|
||||
}
|
||||
// http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&id=173&pn=1&rn=100
|
||||
},
|
||||
getListDetailUrl(id, page) {
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2858093057&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit_song}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1`
|
||||
// http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=140&prod=pc
|
||||
},
|
||||
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2849349915&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
// 获取标签
|
||||
getTag(tryNum = 0) {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_tags = httpFetch(this.tagsUrl)
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
return this.filterTagInfo(body.data)
|
||||
})
|
||||
},
|
||||
// 获取标签
|
||||
getHotTag(tryNum = 0) {
|
||||
if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_hotTags = httpFetch(this.hotTagUrl)
|
||||
return this._requestObj_hotTags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getHotTag(++tryNum)
|
||||
return this.filterInfoHotTag(body.data[0].data)
|
||||
})
|
||||
},
|
||||
filterInfoHotTag(rawList) {
|
||||
return rawList.map((item) => ({
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw'
|
||||
}))
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return rawList.map((type) => ({
|
||||
name: type.name,
|
||||
list: type.data.map((item) => ({
|
||||
parent_id: type.id,
|
||||
parent_name: type.name,
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw'
|
||||
}))
|
||||
}))
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
let id
|
||||
let type
|
||||
if (tagId) {
|
||||
let arr = tagId.split('-')
|
||||
id = arr[0]
|
||||
type = arr[1]
|
||||
} else {
|
||||
id = null
|
||||
}
|
||||
this._requestObj_list = httpFetch(this.getListUrl({ sortId, id, type, page }))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (!id || type == '10000') {
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterList(body.data.data),
|
||||
total: body.data.total,
|
||||
page: body.data.pn,
|
||||
limit: body.data.rn,
|
||||
source: 'kw'
|
||||
}
|
||||
} else if (!body.length) {
|
||||
return this.getList(sortId, tagId, page, ++tryNum)
|
||||
}
|
||||
return {
|
||||
list: this.filterList2(body),
|
||||
total: 1000,
|
||||
page,
|
||||
limit: 1000,
|
||||
source: 'kw'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化播放数量
|
||||
* @param {*} num
|
||||
*/
|
||||
formatPlayCount(num) {
|
||||
if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿'
|
||||
if (num > 10000) return parseInt(num / 1000) / 10 + '万'
|
||||
return num
|
||||
},
|
||||
filterList(rawData) {
|
||||
return rawData.map((item) => ({
|
||||
play_count: this.formatPlayCount(item.listencnt),
|
||||
id: `digest-${item.digest}__${item.id}`,
|
||||
author: item.uname,
|
||||
name: item.name,
|
||||
// time: item.publish_time,
|
||||
total: item.total,
|
||||
img: item.img,
|
||||
grade: item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
source: 'kw'
|
||||
}))
|
||||
},
|
||||
filterList2(rawData) {
|
||||
// console.log(rawData)
|
||||
const list = []
|
||||
rawData.forEach((item) => {
|
||||
if (!item.label) return
|
||||
list.push(
|
||||
...item.list.map((item) => ({
|
||||
play_count: item.play_count && this.formatPlayCount(item.listencnt),
|
||||
id: `digest-${item.digest}__${item.id}`,
|
||||
author: item.uname,
|
||||
name: item.name,
|
||||
total: item.total,
|
||||
// time: item.publish_time,
|
||||
img: item.img,
|
||||
grade: item.favorcnt && item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
source: 'kw'
|
||||
}))
|
||||
)
|
||||
})
|
||||
return list
|
||||
},
|
||||
|
||||
getListDetailDigest8(id, page, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const requestObj = httpFetch(this.getListDetailUrl(id, page))
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterListDetail(body.musiclist),
|
||||
page,
|
||||
limit: body.rn,
|
||||
total: body.total,
|
||||
source: 'kw',
|
||||
info: {
|
||||
name: body.title,
|
||||
img: body.pic,
|
||||
desc: body.info,
|
||||
author: body.uname,
|
||||
play_count: this.formatPlayCount(body.playnum)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
getListDetailDigest5Info(id, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
const requestObj = httpFetch(
|
||||
`http://qukudata.kuwo.cn/q.k?op=query&cont=ninfo&node=${id}&pn=0&rn=1&fmt=json&src=mbox&level=2`
|
||||
)
|
||||
return requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode != 200 || !body.child) return this.getListDetail(id, ++tryNum)
|
||||
// console.log(body)
|
||||
return body.child.length ? body.child[0].sourceid : null
|
||||
})
|
||||
},
|
||||
getListDetailDigest5Music(id, page, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
const requestObj = httpFetch(
|
||||
`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}}&rn=${this.limit_song}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`
|
||||
)
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterListDetail(body.musiclist),
|
||||
page,
|
||||
limit: body.rn,
|
||||
total: body.total,
|
||||
source: 'kw',
|
||||
info: {
|
||||
name: body.title,
|
||||
img: body.pic,
|
||||
desc: body.info,
|
||||
author: body.uname,
|
||||
play_count: this.formatPlayCount(body.playnum)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
async getListDetailDigest5(id, page, retryNum) {
|
||||
const detailId = await this.getListDetailDigest5Info(id, retryNum)
|
||||
return this.getListDetailDigest5Music(detailId, page, retryNum)
|
||||
},
|
||||
|
||||
filterBDListDetail(rawList) {
|
||||
return rawList.map((item) => {
|
||||
let types = []
|
||||
let _types = {}
|
||||
for (let info of item.audios) {
|
||||
info.size = info.size?.toLocaleUpperCase()
|
||||
switch (info.bitrate) {
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info.size })
|
||||
_types.flac24bit = {
|
||||
size: info.size
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info.size })
|
||||
_types.flac = {
|
||||
size: info.size
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info.size })
|
||||
_types['320k'] = {
|
||||
size: info.size
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info.size })
|
||||
_types['128k'] = {
|
||||
size: info.size
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
return {
|
||||
singer: item.artists.map((s) => s.name).join('、'),
|
||||
name: item.name,
|
||||
albumName: item.album,
|
||||
albumId: item.albumId,
|
||||
songmid: item.id,
|
||||
source: 'kw',
|
||||
interval: formatPlayTime(item.duration),
|
||||
img: item.albumPic,
|
||||
releaseDate: item.releaseDate,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
getReqId() {
|
||||
function t() {
|
||||
return ((65536 * (1 + Math.random())) | 0).toString(16).substring(1)
|
||||
}
|
||||
return t() + t() + t() + t() + t() + t() + t() + t()
|
||||
},
|
||||
async getListDetailMusicListByBDListInfo(id, source) {
|
||||
const { body: infoData } = await httpFetch(
|
||||
`https://bd-api.kuwo.cn/api/service/playlist/info/${id}?reqId=${this.getReqId()}&source=${source}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
}
|
||||
).promise.catch(() => ({ code: 0 }))
|
||||
|
||||
if (infoData.code != 200) return null
|
||||
|
||||
return {
|
||||
name: infoData.data.name,
|
||||
img: infoData.data.pic,
|
||||
desc: infoData.data.description,
|
||||
author: infoData.data.creatorName,
|
||||
play_count: infoData.data.playNum
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBDUserPub(id) {
|
||||
const { body: infoData } = await httpFetch(
|
||||
`https://bd-api.kuwo.cn/api/ucenter/users/pub/${id}?reqId=${this.getReqId()}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
}
|
||||
).promise.catch(() => ({ code: 0 }))
|
||||
|
||||
if (infoData.code != 200) return null
|
||||
|
||||
// console.log(infoData)
|
||||
return {
|
||||
name: infoData.data.userInfo.nickname + '喜欢的音乐',
|
||||
img: infoData.data.userInfo.headImg,
|
||||
desc: '',
|
||||
author: infoData.data.userInfo.nickname,
|
||||
play_count: ''
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBDList(id, source, page, tryNum = 0) {
|
||||
const { body: listData } = await httpFetch(
|
||||
`https://bd-api.kuwo.cn/api/service/playlist/${id}/musicList?reqId=${this.getReqId()}&source=${source}&pn=${page}&rn=${this.limit_song}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
}
|
||||
).promise.catch(() => {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
return this.getListDetailMusicListByBDList(id, source, page, ++tryNum)
|
||||
})
|
||||
|
||||
if (listData.code !== 200) return Promise.reject(new Error('failed'))
|
||||
|
||||
return {
|
||||
list: this.filterBDListDetail(listData.data.list),
|
||||
page,
|
||||
limit: listData.data.pageSize,
|
||||
total: listData.data.total,
|
||||
source: 'kw'
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBD(id, page) {
|
||||
const uid = /uid=(\d+)/.exec(id)?.[1]
|
||||
const listId = /playlistId=(\d+)/.exec(id)?.[1]
|
||||
const source = /source=(\d+)/.exec(id)?.[1]
|
||||
if (!listId) return Promise.reject(new Error('failed'))
|
||||
|
||||
const task = [this.getListDetailMusicListByBDList(listId, source, page)]
|
||||
switch (source) {
|
||||
case '4':
|
||||
task.push(this.getListDetailMusicListByBDListInfo(listId, source))
|
||||
break
|
||||
case '5':
|
||||
task.push(this.getListDetailMusicListByBDUserPub(uid ?? listId))
|
||||
break
|
||||
}
|
||||
const [listData, info] = await Promise.all(task)
|
||||
listData.info = info ?? {
|
||||
name: '',
|
||||
img: '',
|
||||
desc: '',
|
||||
author: '',
|
||||
play_count: ''
|
||||
}
|
||||
// console.log(listData)
|
||||
return listData
|
||||
},
|
||||
|
||||
// 获取歌曲列表内的音乐
|
||||
getListDetail(id, page, retryNum = 0) {
|
||||
// console.log(id)
|
||||
// https://h5app.kuwo.cn/m/bodian/collection.html?uid=000&playlistId=000&source=5&ownerId=000
|
||||
// https://h5app.kuwo.cn/m/bodian/collection.html?uid=000&playlistId=000&source=4&ownerId=
|
||||
if (/\/bodian\//.test(id)) return this.getListDetailMusicListByBD(id, page)
|
||||
if (/[?&:/]/.test(id)) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
else if (/^digest-/.test(id)) {
|
||||
let [digest, _id] = id.split('__')
|
||||
digest = digest.replace('digest-', '')
|
||||
id = _id
|
||||
switch (digest) {
|
||||
case '8':
|
||||
break
|
||||
case '13':
|
||||
return album.getAlbumListDetail(id, page, retryNum)
|
||||
case '5':
|
||||
default:
|
||||
return this.getListDetailDigest5(id, page, retryNum)
|
||||
}
|
||||
}
|
||||
return this.getListDetailDigest8(id, page, retryNum)
|
||||
},
|
||||
filterListDetail(rawData) {
|
||||
// console.log(rawData)
|
||||
return rawData.map((item) => {
|
||||
let infoArr = item.N_MINFO.split(';')
|
||||
let types = []
|
||||
let _types = {}
|
||||
for (let info of infoArr) {
|
||||
info = info.match(this.regExps.mInfo)
|
||||
if (info) {
|
||||
switch (info[2]) {
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info[4] })
|
||||
_types.flac24bit = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info[4] })
|
||||
_types.flac = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info[4] })
|
||||
_types['320k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info[4] })
|
||||
_types['128k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
return {
|
||||
singer: formatSinger(decodeName(item.artist)),
|
||||
name: decodeName(item.name),
|
||||
albumName: decodeName(item.album),
|
||||
albumId: item.albumid,
|
||||
songmid: item.id,
|
||||
source: 'kw',
|
||||
interval: formatPlayTime(parseInt(item.duration)),
|
||||
img: null,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
getTags() {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({
|
||||
tags,
|
||||
hotTag,
|
||||
source: 'kw'
|
||||
}))
|
||||
},
|
||||
getDetailPageUrl(id) {
|
||||
if (/[?&:/]/.test(id)) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
else if (/^digest-/.test(id)) {
|
||||
let result = id.split('__')
|
||||
id = result[1]
|
||||
}
|
||||
return `http://www.kuwo.cn/playlist_detail/${id}`
|
||||
},
|
||||
|
||||
search(text, page, limit = 20) {
|
||||
return httpFetch(
|
||||
`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${page - 1}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`
|
||||
).promise.then(({ body }) => {
|
||||
body = objStr2JSON(body)
|
||||
// console.log(body)
|
||||
return {
|
||||
list: body.abslist.map((item) => {
|
||||
return {
|
||||
play_count: this.formatPlayCount(item.playcnt),
|
||||
id: String(item.playlistid),
|
||||
author: decodeName(item.nickname),
|
||||
name: decodeName(item.name),
|
||||
total: item.songnum,
|
||||
// time: item.publish_time,
|
||||
img: item.pic,
|
||||
desc: decodeName(item.intro),
|
||||
source: 'kw'
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: parseInt(body.TOTAL),
|
||||
source: 'kw'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
35
src/main/utils/musicSdk/kw/tipSearch.js
Normal file
35
src/main/utils/musicSdk/kw/tipSearch.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// import { decodeName } from '../../index'
|
||||
// import { tokenRequest } from './util'
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
regExps: {
|
||||
relWord: /RELWORD=(.+)/
|
||||
},
|
||||
requestObj: null,
|
||||
async tipSearchBySong(str) {
|
||||
// 报错403,加了referer还是有问题(直接换一个
|
||||
// this.requestObj = await tokenRequest(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`)
|
||||
|
||||
this.cancelTipSearch()
|
||||
this.requestObj = httpFetch(
|
||||
`https://tips.kuwo.cn/t.s?corp=kuwo&newver=3&p2p=1¬race=0&c=mbox&w=${encodeURIComponent(str)}&encoding=utf8&rformat=json`,
|
||||
{
|
||||
Referer: 'http://www.kuwo.cn/'
|
||||
}
|
||||
)
|
||||
return this.requestObj.promise.then(({ body, statusCode }) => {
|
||||
if (statusCode != 200 || !body.WORDITEMS) return Promise.reject(new Error('请求失败'))
|
||||
return body.WORDITEMS
|
||||
})
|
||||
},
|
||||
handleResult(rawData) {
|
||||
return rawData.map((item) => item.RELWORD)
|
||||
},
|
||||
cancelTipSearch() {
|
||||
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
|
||||
},
|
||||
async search(str) {
|
||||
return this.tipSearchBySong(str).then((result) => this.handleResult(result))
|
||||
}
|
||||
}
|
||||
231
src/main/utils/musicSdk/kw/util.js
Normal file
231
src/main/utils/musicSdk/kw/util.js
Normal file
@@ -0,0 +1,231 @@
|
||||
// import { httpGet, httpFetch } from '../../request'
|
||||
// import { WIN_MAIN_RENDERER_EVENT_NAME } from '@common/ipcNames'
|
||||
|
||||
// import { rendererInvoke } from '@common/rendererIpc'
|
||||
import kwdecode from './kwdecode'
|
||||
import { createCipheriv, createDecipheriv } from 'crypto'
|
||||
import { toMD5 } from '../utils'
|
||||
|
||||
// const kw_token = {
|
||||
// token: null,
|
||||
// isGetingToken: false,
|
||||
// }
|
||||
|
||||
// const translationMap = {
|
||||
// "{'": '{"',
|
||||
// "'}\n": '"}',
|
||||
// "'}": '"}',
|
||||
// "':'": '":"',
|
||||
// "','": '","',
|
||||
// "':{'": '":{"',
|
||||
// "':['": '":["',
|
||||
// "'}],'": '"}],"',
|
||||
// "':[{'": '":[{"',
|
||||
// "'},'": '"},"',
|
||||
// "'},{'": '"},{"',
|
||||
// "':[],'": '":[],"',
|
||||
// "':{},'": '":{},"',
|
||||
// "'}]}": '"}]}',
|
||||
// }
|
||||
|
||||
// export const objStr2JSON = str => {
|
||||
// return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},'|'}]})/g, s => translationMap[s]))
|
||||
// }
|
||||
|
||||
export const objStr2JSON = (str) => {
|
||||
return JSON.parse(
|
||||
str.replace(/('(?=(,\s*')))|('(?=:))|((?<=([:,]\s*))')|((?<={)')|('(?=}))/g, '"')
|
||||
)
|
||||
}
|
||||
|
||||
export const formatSinger = (rawData) => rawData.replace(/&/g, '、')
|
||||
|
||||
export const matchToken = (headers) => {
|
||||
try {
|
||||
return headers['set-cookie'][0].match(/kw_token=(\w+)/)[1]
|
||||
} catch (err) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// const wait = time => new Promise(resolve => setTimeout(() => resolve(), time))
|
||||
|
||||
// export const getToken = (retryNum = 0) => new Promise((resolve, reject) => {
|
||||
// if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
// if (kw_token.isGetingToken) return wait(1000).then(() => getToken(retryNum).then(token => resolve(token)))
|
||||
// if (kw_token.token) return resolve(kw_token.token)
|
||||
// kw_token.isGetingToken = true
|
||||
// httpGet('http://www.kuwo.cn/', (err, resp) => {
|
||||
// kw_token.isGetingToken = false
|
||||
// if (err) return getToken(++retryNum)
|
||||
// if (resp.statusCode != 200) return reject(new Error('获取失败'))
|
||||
// const token = kw_token.token = matchToken(resp.headers)
|
||||
// resolve(token)
|
||||
// })
|
||||
// })
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export const decodeLyric = (base64Data) => kwdecode(base64Data, false)
|
||||
|
||||
// export const tokenRequest = async(url, options = {}) => {
|
||||
// let token = kw_token.token
|
||||
// if (!token) token = await getToken()
|
||||
// if (!options.headers) {
|
||||
// options.headers = {
|
||||
// Referer: 'http://www.kuwo.cn/',
|
||||
// csrf: token,
|
||||
// cookie: 'kw_token=' + token,
|
||||
// }
|
||||
// }
|
||||
// const requestObj = httpFetch(url, options)
|
||||
// requestObj.promise = requestObj.promise.then(resp => {
|
||||
// // console.log(resp)
|
||||
// if (resp.statusCode == 200) {
|
||||
// kw_token.token = matchToken(resp.headers)
|
||||
// }
|
||||
// return resp
|
||||
// })
|
||||
// return requestObj
|
||||
// }
|
||||
|
||||
export const lrcTools = {
|
||||
rxps: {
|
||||
wordLine: /^(\[\d{1,2}:.*\d{1,4}\])\s*(\S+(?:\s+\S+)*)?\s*/,
|
||||
tagLine: /\[(ver|ti|ar|al|offset|by|kuwo):\s*(\S+(?:\s+\S+)*)\s*\]/,
|
||||
wordTimeAll: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/g,
|
||||
wordTime: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/
|
||||
},
|
||||
offset: 1,
|
||||
offset2: 1,
|
||||
isOK: false,
|
||||
lines: [],
|
||||
tags: [],
|
||||
getWordInfo(str, str2, prevWord) {
|
||||
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
|
||||
}
|
||||
|
||||
prevWord.newTimeStr = `<${prevWord.startTime},${prevWord.endTime - prevWord.startTime}>`
|
||||
// console.log(prevWord)
|
||||
}
|
||||
}
|
||||
return {
|
||||
startTime,
|
||||
endTime,
|
||||
timeStr: `<${startTime},${endTime - startTime}>`
|
||||
}
|
||||
},
|
||||
parseLine(line) {
|
||||
if (line.length < 6) return
|
||||
let result = this.rxps.wordLine.exec(line)
|
||||
if (result) {
|
||||
const time = result[1]
|
||||
let words = result[2]
|
||||
if (words == null) {
|
||||
words = ''
|
||||
}
|
||||
const wordTimes = words.match(this.rxps.wordTimeAll)
|
||||
if (!wordTimes) return
|
||||
// console.log(wordTimes)
|
||||
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)
|
||||
if (preTimeInfo?.newTimeStr)
|
||||
words = words.replace(preTimeInfo.timeStr, preTimeInfo.newTimeStr)
|
||||
preTimeInfo = wordInfo
|
||||
}
|
||||
this.lines.push(time + words)
|
||||
return
|
||||
}
|
||||
result = this.rxps.tagLine.exec(line)
|
||||
if (!result) return
|
||||
if (result[1] == 'kuwo') {
|
||||
let content = result[2]
|
||||
if (content != null && content.includes('][')) {
|
||||
content = content.substring(0, content.indexOf(']['))
|
||||
}
|
||||
const valueOf = parseInt(content, 8)
|
||||
this.offset = Math.trunc(valueOf / 10)
|
||||
this.offset2 = Math.trunc(valueOf % 10)
|
||||
if (
|
||||
this.offset == 0 ||
|
||||
Number.isNaN(this.offset) ||
|
||||
this.offset2 == 0 ||
|
||||
Number.isNaN(this.offset2)
|
||||
) {
|
||||
this.isOK = false
|
||||
}
|
||||
} else {
|
||||
this.tags.push(line)
|
||||
}
|
||||
},
|
||||
parse(lrc) {
|
||||
// console.log(lrc)
|
||||
const lines = lrc.split(/\r\n|\r|\n/)
|
||||
const tools = Object.create(this)
|
||||
tools.isOK = true
|
||||
tools.offset = 1
|
||||
tools.offset2 = 1
|
||||
tools.lines = []
|
||||
tools.tags = []
|
||||
|
||||
for (const line of lines) {
|
||||
if (!tools.isOK) throw new Error('failed')
|
||||
tools.parseLine(line)
|
||||
}
|
||||
if (!tools.lines.length) return ''
|
||||
let lrcs = tools.lines.join('\n')
|
||||
if (tools.tags.length) lrcs = `${tools.tags.join('\n')}\n${lrcs}`
|
||||
// console.log(lrcs)
|
||||
return lrcs
|
||||
}
|
||||
}
|
||||
|
||||
const createAesEncrypt = (buffer, mode, key, iv) => {
|
||||
const cipher = createCipheriv(mode, key, iv)
|
||||
return Buffer.concat([cipher.update(buffer), cipher.final()])
|
||||
}
|
||||
|
||||
const createAesDecrypt = (buffer, mode, key, iv) => {
|
||||
const cipher = createDecipheriv(mode, key, iv)
|
||||
return Buffer.concat([cipher.update(buffer), cipher.final()])
|
||||
}
|
||||
|
||||
export const wbdCrypto = {
|
||||
aesMode: 'aes-128-ecb',
|
||||
aesKey: Buffer.from(
|
||||
[112, 87, 39, 61, 199, 250, 41, 191, 57, 68, 45, 114, 221, 94, 140, 228],
|
||||
'binary'
|
||||
),
|
||||
aesIv: '',
|
||||
appId: 'y67sprxhhpws',
|
||||
decodeData(base64Result) {
|
||||
const data = Buffer.from(decodeURIComponent(base64Result), 'base64')
|
||||
return JSON.parse(createAesDecrypt(data, this.aesMode, this.aesKey, this.aesIv).toString())
|
||||
},
|
||||
createSign(data, time) {
|
||||
const str = `${this.appId}${data}${time}`
|
||||
return toMD5(str).toUpperCase()
|
||||
},
|
||||
buildParam(jsonData) {
|
||||
const data = Buffer.from(JSON.stringify(jsonData))
|
||||
const time = Date.now()
|
||||
|
||||
const encodeData = createAesEncrypt(data, this.aesMode, this.aesKey, this.aesIv).toString(
|
||||
'base64'
|
||||
)
|
||||
const sign = this.createSign(encodeData, time)
|
||||
|
||||
return `data=${encodeURIComponent(encodeData)}&time=${time}&appId=${this.appId}&sign=${sign}`
|
||||
}
|
||||
}
|
||||
55
src/main/utils/musicSdk/mg/album.js
Normal file
55
src/main/utils/musicSdk/mg/album.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { createHttpFetch } from './utils'
|
||||
import { filterMusicInfoList } from './musicInfo'
|
||||
import { formatPlayCount } from '../../index'
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 通过AlbumId获取专辑
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getAlbumDetail(id, page = 1) {
|
||||
const list = await createHttpFetch(
|
||||
`http://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/queryAlbumSong?albumId=${id}&pageNo=${page}`
|
||||
)
|
||||
if (!list.songList) return Promise.reject(new Error('Get album list error.'))
|
||||
|
||||
const songList = filterMusicInfoList(list.songList)
|
||||
const listInfo = await this.getAlbumInfo(id)
|
||||
|
||||
return {
|
||||
list: songList || [],
|
||||
page,
|
||||
limit: listInfo.total,
|
||||
total: listInfo.total,
|
||||
source: 'mg',
|
||||
info: {
|
||||
name: listInfo.name,
|
||||
img: listInfo.image,
|
||||
desc: listInfo.desc,
|
||||
author: listInfo.author,
|
||||
play_count: listInfo.play_count
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 通过AlbumId获取专辑信息
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getAlbumInfo(id) {
|
||||
const info = await createHttpFetch(
|
||||
`https://app.c.nf.migu.cn/MIGUM3.0/resource/album/v2.0?albumId=${id}`
|
||||
)
|
||||
if (!info) return Promise.reject(new Error('Get album info error.'))
|
||||
|
||||
return {
|
||||
name: info.title,
|
||||
image: info.imgItems.length ? info.imgItems[0].img : null,
|
||||
desc: info.summary,
|
||||
author: info.singer,
|
||||
play_count: formatPlayCount(info.opNumItem.playNum),
|
||||
total: info.totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/main/utils/musicSdk/mg/api-test.js
Normal file
28
src/main/utils/musicSdk/mg/api-test.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/url/mg/${songInfo.copyrightId}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(requestMsg.fail))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
|
||||
export default api_test
|
||||
110
src/main/utils/musicSdk/mg/comment.js
Normal file
110
src/main/utils/musicSdk/mg/comment.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import getSongId from './songId'
|
||||
import { dateFormat2 } from '../index'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
_requestObj3: null,
|
||||
async getComment(musicInfo, page = 1, limit = 10) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (!musicInfo.songId) {
|
||||
let id = await getSongId(musicInfo)
|
||||
if (!id) throw new Error('获取评论失败')
|
||||
musicInfo.songId = id
|
||||
}
|
||||
|
||||
const _requestObj = httpFetch(
|
||||
`https://music.migu.cn/v3/api/comment/listComments?targetId=${musicInfo.songId}&pageSize=${limit}&pageNo=${page}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4195.1 Safari/537.36',
|
||||
Referer: 'https://music.migu.cn'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.returnCode !== '000000') throw new Error('获取评论失败')
|
||||
return {
|
||||
source: 'mg',
|
||||
comments: this.filterComment(body.data.items),
|
||||
total: body.data.itemTotal,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(body.data.itemTotal / limit) || 1
|
||||
}
|
||||
},
|
||||
async getHotComment(musicInfo, page = 1, limit = 5) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
|
||||
if (!musicInfo.songId) {
|
||||
let id = await getSongId(musicInfo)
|
||||
if (!id) throw new Error('获取评论失败')
|
||||
musicInfo.songId = id
|
||||
}
|
||||
|
||||
const _requestObj2 = httpFetch(
|
||||
`https://music.migu.cn/v3/api/comment/listTopComments?targetId=${musicInfo.songId}&pageSize=${limit}&pageNo=${page}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4195.1 Safari/537.36',
|
||||
Referer: 'https://music.migu.cn'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.returnCode !== '000000') throw new Error('获取热门评论失败')
|
||||
return {
|
||||
source: 'mg',
|
||||
comments: this.filterComment(body.data.items),
|
||||
total: body.data.itemTotal,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(body.data.itemTotal / limit) || 1
|
||||
}
|
||||
},
|
||||
async getReplyComment(musicInfo, replyId, page = 1, limit = 10) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
|
||||
const _requestObj2 = httpFetch(
|
||||
`https://music.migu.cn/v3/api/comment/listCommentsById?commentId=${replyId}&pageSize=${limit}&pageNo=${page}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi'
|
||||
}
|
||||
}
|
||||
)
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.returnCode !== '000000') throw new Error('获取回复评论失败')
|
||||
return { source: 'mg', comments: this.filterComment(body.data.items) }
|
||||
},
|
||||
filterComment(rawList) {
|
||||
return rawList.map((item) => ({
|
||||
id: item.commentId,
|
||||
text: item.body,
|
||||
time: item.createTime,
|
||||
timeStr: dateFormat2(new Date(item.createTime).getTime()),
|
||||
userName: item.author.name,
|
||||
avatar: /^\/\//.test(item.author.avatar) ? `http:${item.author.avatar}` : item.author.avatar,
|
||||
userId: item.author.id,
|
||||
likedCount: item.praiseCount,
|
||||
replyNum: item.replyTotal,
|
||||
reply: item.replyCommentList.map((c) => ({
|
||||
id: c.commentId,
|
||||
text: c.body,
|
||||
time: c.createTime,
|
||||
timeStr: dateFormat2(new Date(c.createTime).getTime()),
|
||||
userName: c.author.name,
|
||||
avatar: /^\/\//.test(c.author.avatar) ? `http:${c.author.avatar}` : c.author.avatar,
|
||||
userId: c.author.id,
|
||||
likedCount: c.praiseCount,
|
||||
replyNum: c.replyTotal
|
||||
}))
|
||||
}))
|
||||
}
|
||||
}
|
||||
18
src/main/utils/musicSdk/mg/hotSearch.js
Normal file
18
src/main/utils/musicSdk/mg/hotSearch.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const _requestObj = httpFetch('http://jadeite.migu.cn:7090/music_search/v3/search/hotword')
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.code !== '000000') throw new Error('获取热搜词失败')
|
||||
// console.log(body, statusCode)
|
||||
return { source: 'mg', list: this.filterList(body.data.hotwords[0].hotwordList) }
|
||||
},
|
||||
filterList(rawList) {
|
||||
return rawList.filter((item) => item.resourceType == 'song').map((item) => item.word)
|
||||
}
|
||||
}
|
||||
28
src/main/utils/musicSdk/mg/index.js
Normal file
28
src/main/utils/musicSdk/mg/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import leaderboard from './leaderboard'
|
||||
import songList from './songList'
|
||||
import musicSearch from './musicSearch'
|
||||
import pic from './pic'
|
||||
import lyric from './lyric'
|
||||
import hotSearch from './hotSearch'
|
||||
import comment from './comment'
|
||||
// import tipSearch from './tipSearch'
|
||||
|
||||
const mg = {
|
||||
// tipSearch,
|
||||
songList,
|
||||
musicSearch,
|
||||
leaderboard,
|
||||
hotSearch,
|
||||
comment,
|
||||
getLyric(songInfo) {
|
||||
return lyric.getLyric(songInfo)
|
||||
},
|
||||
getPic(songInfo) {
|
||||
return pic.getPic(songInfo)
|
||||
},
|
||||
getMusicDetailPageUrl(songInfo) {
|
||||
return `http://music.migu.cn/v3/music/song/${songInfo.copyrightId}`
|
||||
}
|
||||
}
|
||||
|
||||
export default mg
|
||||
175
src/main/utils/musicSdk/mg/leaderboard.js
Normal file
175
src/main/utils/musicSdk/mg/leaderboard.js
Normal file
@@ -0,0 +1,175 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { filterMusicInfoList } from './musicInfo'
|
||||
|
||||
// const boardList = [{ id: 'mg__27553319', name: '咪咕尖叫新歌榜', bangid: '27553319' }, { id: 'mg__27186466', name: '咪咕尖叫热歌榜', bangid: '27186466' }, { id: 'mg__27553408', name: '咪咕尖叫原创榜', bangid: '27553408' }, { id: 'mg__23189800', name: '咪咕港台榜', bangid: '23189800' }, { id: 'mg__23189399', name: '咪咕内地榜', bangid: '23189399' }, { id: 'mg__19190036', name: '咪咕欧美榜', bangid: '19190036' }, { id: 'mg__23189813', name: '咪咕日韩榜', bangid: '23189813' }, { id: 'mg__23190126', name: '咪咕彩铃榜', bangid: '23190126' }, { id: 'mg__15140045', name: '咪咕KTV榜', bangid: '15140045' }, { id: 'mg__15140034', name: '咪咕网络榜', bangid: '15140034' }, { id: 'mg__23217754', name: 'MV榜', bangid: '23217754' }, { id: 'mg__23218151', name: '新专辑榜', bangid: '23218151' }, { id: 'mg__21958042', name: 'iTunes榜', bangid: '21958042' }, { id: 'mg__21975570', name: 'billboard榜', bangid: '21975570' }, { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815' }, { id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' }, { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943' }, { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437' }]
|
||||
|
||||
const boardList = [
|
||||
{ id: 'mg__27553319', name: '尖叫新歌榜', bangid: '27553319', webId: 'jianjiao_newsong' },
|
||||
{ id: 'mg__27186466', name: '尖叫热歌榜', bangid: '27186466', webId: 'jianjiao_hotsong' },
|
||||
{ id: 'mg__27553408', name: '尖叫原创榜', bangid: '27553408', webId: 'jianjiao_original' },
|
||||
{ id: 'mg__23189800', name: '港台榜', bangid: '23189800', webId: 'hktw' },
|
||||
{ id: 'mg__23189399', name: '内地榜', bangid: '23189399', webId: 'mainland' },
|
||||
{ id: 'mg__19190036', name: '欧美榜', bangid: '19190036', webId: 'eur_usa' },
|
||||
{ id: 'mg__23189813', name: '日韩榜', bangid: '23189813', webId: 'jpn_kor' },
|
||||
{ id: 'mg__23190126', name: '彩铃榜', bangid: '23190126', webId: 'coloring' },
|
||||
{ id: 'mg__15140045', name: 'KTV榜', bangid: '15140045', webId: 'ktv' },
|
||||
{ id: 'mg__15140034', name: '网络榜', bangid: '15140034', webId: 'network' }
|
||||
// { id: 'mg__21958042', name: '美国iTunes榜', bangid: '21958042', webId: 'itunes' },
|
||||
// { id: 'mg__21975570', name: '美国billboard榜', bangid: '21975570', webId: 'billboard' },
|
||||
// { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815', webId: 'hito' },
|
||||
// { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943', webId: 'mnet' },
|
||||
// { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437', webId: 'uk' },
|
||||
]
|
||||
export default {
|
||||
limit: 200,
|
||||
list: [
|
||||
{
|
||||
id: 'mgyyb',
|
||||
name: '音乐榜',
|
||||
bangid: '27553319'
|
||||
},
|
||||
{
|
||||
id: 'mgysb',
|
||||
name: '影视榜',
|
||||
bangid: '23603721'
|
||||
},
|
||||
{
|
||||
id: 'mghybnd',
|
||||
name: '华语内地榜',
|
||||
bangid: '23603926'
|
||||
},
|
||||
{
|
||||
id: 'mghyjqbgt',
|
||||
name: '华语港台榜',
|
||||
bangid: '23603954'
|
||||
},
|
||||
{
|
||||
id: 'mgomb',
|
||||
name: '欧美榜',
|
||||
bangid: '23603974'
|
||||
},
|
||||
{
|
||||
id: 'mgrhb',
|
||||
name: '日韩榜',
|
||||
bangid: '23603982'
|
||||
},
|
||||
{
|
||||
id: 'mgwlb',
|
||||
name: '网络榜',
|
||||
bangid: '23604058'
|
||||
},
|
||||
{
|
||||
id: 'mgclb',
|
||||
name: '彩铃榜',
|
||||
bangid: '23604023'
|
||||
},
|
||||
{
|
||||
id: 'mgktvb',
|
||||
name: 'KTV榜',
|
||||
bangid: '23604040'
|
||||
},
|
||||
{
|
||||
id: 'mgrcb',
|
||||
name: '原创榜',
|
||||
bangid: '23604032'
|
||||
}
|
||||
],
|
||||
getUrl(id, page) {
|
||||
return `https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/querycontentbyId.do?columnId=${id}&needAll=0`
|
||||
// return `http://m.music.migu.cn/migu/remoting/cms_list_tag?nid=${id}&pageSize=${this.limit}&pageNo=${page - 1}`
|
||||
},
|
||||
successCode: '000000',
|
||||
requestBoardsObj: null,
|
||||
getBoardsData() {
|
||||
if (this.requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this.requestBoardsObj = httpFetch(
|
||||
'https://app.c.nf.migu.cn/MIGUM3.0/v1.0/template/rank-list/release',
|
||||
{
|
||||
// this.requestBoardsObj = httpFetch('https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/indexrank.do?templateVersion=8', {
|
||||
headers: {
|
||||
Referer: 'https://app.c.nf.migu.cn/',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36',
|
||||
channel: '0146921'
|
||||
}
|
||||
}
|
||||
)
|
||||
return this.requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
const requestObj = httpFetch(url)
|
||||
return requestObj.promise
|
||||
},
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
for (const board of rawList) {
|
||||
if (board.template != 'group1') continue
|
||||
for (const item of board.itemList) {
|
||||
if (
|
||||
(item.template != 'row1' && item.template != 'grid1' && !item.actionUrl) ||
|
||||
!item.actionUrl.includes('rank-info')
|
||||
)
|
||||
continue
|
||||
|
||||
let data = item.displayLogId.param
|
||||
list.push({
|
||||
id: 'mg__' + data.rankId,
|
||||
name: data.rankName,
|
||||
bangid: String(data.rankId)
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// // console.log(response.body.data.contentItemList)
|
||||
// if (response.statusCode !== 200 || response.body.code !== this.successCode) return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.data.contentItemList)
|
||||
// // console.log(list)
|
||||
// // console.log(JSON.stringify(list))
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'mg',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'mg'
|
||||
}
|
||||
},
|
||||
getList(bangid, page, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
return this.getData(this.getUrl(bangid, page)).then(({ statusCode, body }) => {
|
||||
// console.log(body)
|
||||
if (statusCode !== 200 || body.code !== this.successCode)
|
||||
return this.getList(bangid, page, retryNum)
|
||||
const list = filterMusicInfoList(body.columnInfo.contents.map((m) => m.objectInfo))
|
||||
return {
|
||||
total: list.length,
|
||||
list,
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'mg'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getDetailPageUrl(id) {
|
||||
if (typeof id == 'string') id = id.replace('mg__', '')
|
||||
for (const item of boardList) {
|
||||
if (item.bangid == id) {
|
||||
return `https://music.migu.cn/v3/music/top/${item.webId}`
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
151
src/main/utils/musicSdk/mg/lyric.js
Normal file
151
src/main/utils/musicSdk/mg/lyric.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { getMusicInfo } from './musicInfo'
|
||||
import { decrypt } from './utils/mrc'
|
||||
|
||||
const mrcTools = {
|
||||
rxps: {
|
||||
lineTime: /^\s*\[(\d+),\d+\]/,
|
||||
wordTime: /\(\d+,\d+\)/,
|
||||
wordTimeAll: /(\(\d+,\d+\))/g
|
||||
},
|
||||
parseLyric(str) {
|
||||
str = str.replace(/\r/g, '')
|
||||
const lines = str.split('\n')
|
||||
const lxlrcLines = []
|
||||
const lrcLines = []
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.length < 6) continue
|
||||
let result = this.rxps.lineTime.exec(line)
|
||||
if (!result) continue
|
||||
|
||||
const startTime = parseInt(result[1])
|
||||
let time = startTime
|
||||
let ms = time % 1000
|
||||
time /= 1000
|
||||
let m = parseInt(time / 60)
|
||||
.toString()
|
||||
.padStart(2, '0')
|
||||
time %= 60
|
||||
let s = parseInt(time).toString().padStart(2, '0')
|
||||
time = `${m}:${s}.${ms}`
|
||||
|
||||
let words = line.replace(this.rxps.lineTime, '')
|
||||
|
||||
lrcLines.push(`[${time}]${words.replace(this.rxps.wordTimeAll, '')}`)
|
||||
|
||||
let times = words.match(this.rxps.wordTimeAll)
|
||||
if (!times) continue
|
||||
times = times.map((time) => {
|
||||
const result = /\((\d+),(\d+)\)/.exec(time)
|
||||
return `<${parseInt(result[1]) - startTime},${result[2]}>`
|
||||
})
|
||||
const wordArr = words.split(this.rxps.wordTime)
|
||||
const newWords = times.map((time, index) => `${time}${wordArr[index]}`).join('')
|
||||
lxlrcLines.push(`[${time}]${newWords}`)
|
||||
}
|
||||
return {
|
||||
lyric: lrcLines.join('\n'),
|
||||
lxlyric: lxlrcLines.join('\n')
|
||||
}
|
||||
},
|
||||
getText(url, tryNum = 0) {
|
||||
const requestObj = httpFetch(url, {
|
||||
headers: {
|
||||
Referer: 'https://app.c.nf.migu.cn/',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36',
|
||||
channel: '0146921'
|
||||
}
|
||||
})
|
||||
return requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 200) return body
|
||||
if (tryNum > 5 || statusCode == 404) return Promise.reject(new Error('歌词获取失败'))
|
||||
return this.getText(url, ++tryNum)
|
||||
})
|
||||
},
|
||||
getMrc(url) {
|
||||
return this.getText(url).then((text) => {
|
||||
return this.parseLyric(decrypt(text))
|
||||
})
|
||||
},
|
||||
getLrc(url) {
|
||||
return this.getText(url).then((text) => ({ lxlyric: '', lyric: text }))
|
||||
},
|
||||
getTrc(url) {
|
||||
if (!url) return Promise.resolve('')
|
||||
return this.getText(url)
|
||||
},
|
||||
async getMusicInfo(songInfo) {
|
||||
return songInfo.mrcUrl == null ? getMusicInfo(songInfo.copyrightId) : songInfo
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
return {
|
||||
promise: this.getMusicInfo(songInfo).then((info) => {
|
||||
let p
|
||||
if (info.mrcUrl) p = this.getMrc(info.mrcUrl)
|
||||
else if (info.lrcUrl) p = this.getLrc(info.lrcUrl)
|
||||
if (p == null) return Promise.reject(new Error('获取歌词失败'))
|
||||
return Promise.all([p, this.getTrc(info.trcUrl)]).then(([lrcInfo, tlyric]) => {
|
||||
lrcInfo.tlyric = tlyric
|
||||
return lrcInfo
|
||||
})
|
||||
}),
|
||||
cancelHttp() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getLyricWeb(songInfo, tryNum = 0) {
|
||||
// console.log(songInfo.copyrightId)
|
||||
if (songInfo.lrcUrl) {
|
||||
let requestObj = httpFetch(songInfo.lrcUrl)
|
||||
requestObj.promise = requestObj.promise.then(({ body, statusCode }) => {
|
||||
if (statusCode !== 200) {
|
||||
if (tryNum > 5) return Promise.reject(new Error('歌词获取失败'))
|
||||
let tryRequestObj = this.getLyricWeb(songInfo, ++tryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
return {
|
||||
lyric: body,
|
||||
tlyric: ''
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
} else {
|
||||
let requestObj = httpFetch(
|
||||
`https://music.migu.cn/v3/api/music/audioPlayer/getLyric?copyrightId=${songInfo.copyrightId}`,
|
||||
{
|
||||
headers: {
|
||||
Referer: 'https://music.migu.cn/v3/music/player/audio?from=migu'
|
||||
}
|
||||
}
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
if (body.returnCode !== '000000' || !body.lyric) {
|
||||
if (tryNum > 5) return Promise.reject(new Error('Get lyric failed'))
|
||||
let tryRequestObj = this.getLyricWeb(songInfo, ++tryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
return {
|
||||
lyric: body.lyric,
|
||||
tlyric: ''
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
},
|
||||
|
||||
getLyric(songInfo) {
|
||||
let requestObj = mrcTools.getLyric(songInfo)
|
||||
requestObj.promise = requestObj.promise.catch(() => {
|
||||
let webRequestObj = this.getLyricWeb(songInfo)
|
||||
requestObj.cancelHttp = webRequestObj.cancelHttp.bind(webRequestObj)
|
||||
return webRequestObj.promise
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
}
|
||||
102
src/main/utils/musicSdk/mg/musicInfo.js
Normal file
102
src/main/utils/musicSdk/mg/musicInfo.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { sizeFormate } from '../index'
|
||||
import { createHttpFetch } from './utils'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
const createGetMusicInfosTask = (ids) => {
|
||||
let list = ids
|
||||
let tasks = []
|
||||
while (list.length) {
|
||||
tasks.push(list.slice(0, 100))
|
||||
if (list.length < 100) break
|
||||
list = list.slice(100)
|
||||
}
|
||||
let url = 'https://c.musicapp.migu.cn/MIGUM2.0/v1.0/content/resourceinfo.do?resourceType=2'
|
||||
return Promise.all(
|
||||
tasks.map((task) =>
|
||||
createHttpFetch(url, {
|
||||
method: 'POST',
|
||||
form: {
|
||||
resourceId: task.join('|')
|
||||
}
|
||||
}).then((data) => data.resource)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const filterMusicInfoList = (rawList) => {
|
||||
// console.log(rawList)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawList.forEach((item) => {
|
||||
if (!item.songId || ids.has(item.songId)) return
|
||||
ids.add(item.songId)
|
||||
const types = []
|
||||
const _types = {}
|
||||
item.newRateFormats?.forEach((type) => {
|
||||
let size
|
||||
switch (type.formatType) {
|
||||
case 'PQ':
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'ZQ':
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
const intervalTest = /(\d\d:\d\d)$/.test(item.length)
|
||||
|
||||
list.push({
|
||||
singer: formatSingerName(item.artists, 'name'),
|
||||
name: item.songName,
|
||||
albumName: item.album,
|
||||
albumId: item.albumId,
|
||||
songmid: item.songId,
|
||||
copyrightId: item.copyrightId,
|
||||
source: 'mg',
|
||||
interval: intervalTest ? RegExp.$1 : null,
|
||||
img: item.albumImgs?.length ? item.albumImgs[0].img : null,
|
||||
lrc: null,
|
||||
lrcUrl: item.lrcUrl,
|
||||
mrcUrl: item.mrcUrl,
|
||||
trcUrl: item.trcUrl,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
export const getMusicInfo = async (copyrightId) => {
|
||||
return getMusicInfos([copyrightId]).then((data) => data[0])
|
||||
}
|
||||
|
||||
export const getMusicInfos = async (copyrightIds) => {
|
||||
return filterMusicInfoList(
|
||||
await Promise.all(createGetMusicInfosTask(copyrightIds)).then((data) => data.flat())
|
||||
)
|
||||
}
|
||||
231
src/main/utils/musicSdk/mg/musicSearch.js
Normal file
231
src/main/utils/musicSdk/mg/musicSearch.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { sizeFormate, formatPlayTime } from '../index'
|
||||
import { toMD5, formatSingerName } from '../utils'
|
||||
|
||||
export const createSignature = (time, str) => {
|
||||
const deviceId = '963B7AA0D21511ED807EE5846EC87D20'
|
||||
const signatureMd5 = '6cdc72a439cef99a3418d2a78aa28c73'
|
||||
const sign = toMD5(
|
||||
`${str}${signatureMd5}yyapp2d16148780a1dcc7408e06336b98cfd50${deviceId}${time}`
|
||||
)
|
||||
return { sign, deviceId }
|
||||
}
|
||||
|
||||
export default {
|
||||
limit: 20,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
|
||||
// 旧版API
|
||||
// musicSearch(str, page, limit) {
|
||||
// const searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
// searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
// searchRequest = httpFetch(`http://jadeite.migu.cn:7090/music_search/v2/search/searchAll?sid=4f87090d01c84984a11976b828e2b02c18946be88a6b4c47bcdc92fbd40762db&isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
|
||||
// searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
|
||||
// // searchRequest = httpFetch(`http://jadeite.migu.cn:7090/music_search/v2/search/searchAll?sid=4f87090d01c84984a11976b828e2b02c18946be88a6b4c47bcdc92fbd40762db&isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
|
||||
// headers: {
|
||||
// // sign: 'c3b7ae985e2206e97f1b2de8f88691e2',
|
||||
// // timestamp: 1578225871982,
|
||||
// // appId: 'yyapp2',
|
||||
// // mode: 'android',
|
||||
// // ua: 'Android_migu',
|
||||
// // version: '6.9.4',
|
||||
// osVersion: 'android 7.0',
|
||||
// 'User-Agent': 'okhttp/3.9.1',
|
||||
// },
|
||||
// })
|
||||
// // searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
|
||||
// return searchRequest.promise.then(({ body }) => body)
|
||||
// },
|
||||
// handleResult(rawData) {
|
||||
// // console.log(rawData)
|
||||
// let ids = new Set()
|
||||
// const list = []
|
||||
// rawData.forEach(item => {
|
||||
// if (ids.has(item.id)) return
|
||||
// ids.add(item.id)
|
||||
// const types = []
|
||||
// const _types = {}
|
||||
// item.newRateFormats && item.newRateFormats.forEach(type => {
|
||||
// let size
|
||||
// switch (type.formatType) {
|
||||
// case 'PQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: '128k', size })
|
||||
// _types['128k'] = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'HQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: '320k', size })
|
||||
// _types['320k'] = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'SQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: 'flac', size })
|
||||
// _types.flac = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'ZQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: 'flac24bit', size })
|
||||
// _types.flac24bit = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// })
|
||||
|
||||
// const albumNInfo = item.albums && item.albums.length
|
||||
// ? {
|
||||
// id: item.albums[0].id,
|
||||
// name: item.albums[0].name,
|
||||
// }
|
||||
// : {}
|
||||
|
||||
// list.push({
|
||||
// singer: this.getSinger(item.singers),
|
||||
// name: item.name,
|
||||
// albumName: albumNInfo.name,
|
||||
// albumId: albumNInfo.id,
|
||||
// songmid: item.songId,
|
||||
// copyrightId: item.copyrightId,
|
||||
// source: 'mg',
|
||||
// interval: null,
|
||||
// img: item.imgItems && item.imgItems.length ? item.imgItems[0].img : null,
|
||||
// lrc: null,
|
||||
// lrcUrl: item.lyricUrl,
|
||||
// mrcUrl: item.mrcurl,
|
||||
// trcUrl: item.trcUrl,
|
||||
// otherSource: null,
|
||||
// types,
|
||||
// _types,
|
||||
// typeUrl: {},
|
||||
// })
|
||||
// })
|
||||
// return list
|
||||
// },
|
||||
|
||||
musicSearch(str, page, limit) {
|
||||
const time = Date.now().toString()
|
||||
const signData = createSignature(time, str)
|
||||
const searchRequest = httpFetch(
|
||||
`https://jadeite.migu.cn/music_search/v3/search/searchAll?isCorrect=0&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0&sid=USS`,
|
||||
{
|
||||
headers: {
|
||||
uiVersion: 'A_music_3.6.1',
|
||||
deviceId: signData.deviceId,
|
||||
timestamp: time,
|
||||
sign: signData.sign,
|
||||
channel: '0146921',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; U; Android 11.0.0; zh-cn; MI 11 Build/OPR1.170623.032) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30'
|
||||
}
|
||||
}
|
||||
)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
filterData(rawData) {
|
||||
// console.log(rawData)
|
||||
const list = []
|
||||
const ids = new Set()
|
||||
|
||||
rawData.forEach((item) => {
|
||||
item.forEach((data) => {
|
||||
if (!data.songId || !data.copyrightId || ids.has(data.copyrightId)) return
|
||||
ids.add(data.copyrightId)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
data.audioFormats &&
|
||||
data.audioFormats.forEach((type) => {
|
||||
let size
|
||||
switch (type.formatType) {
|
||||
case 'PQ':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
break
|
||||
case 'ZQ24':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
let img = data.img3 || data.img2 || data.img1 || null
|
||||
if (img && !/https?:/.test(data.img3)) img = 'http://d.musicapp.migu.cn' + img
|
||||
|
||||
list.push({
|
||||
singer: formatSingerName(data.singerList),
|
||||
name: data.name,
|
||||
albumName: data.album,
|
||||
albumId: data.albumId,
|
||||
songmid: data.songId,
|
||||
copyrightId: data.copyrightId,
|
||||
source: 'mg',
|
||||
interval: formatPlayTime(data.duration),
|
||||
img,
|
||||
lrc: null,
|
||||
lrcUrl: data.lrcUrl,
|
||||
mrcUrl: data.mrcurl,
|
||||
trcUrl: data.trcUrl,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then((result) => {
|
||||
// console.log(result)
|
||||
if (!result || result.code !== '000000')
|
||||
return Promise.reject(new Error(result ? result.info : '搜索失败'))
|
||||
const songResultData = result.songResultData || { resultList: [], totalCount: 0 }
|
||||
|
||||
let list = this.filterData(songResultData.resultList)
|
||||
if (list == null) return this.search(str, page, limit, retryNum)
|
||||
|
||||
this.total = parseInt(songResultData.totalCount)
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return {
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'mg'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
31
src/main/utils/musicSdk/mg/pic.js
Normal file
31
src/main/utils/musicSdk/mg/pic.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import getSongId from './songId'
|
||||
|
||||
export default {
|
||||
async getPicUrl(songId, tryNum = 0) {
|
||||
let requestObj = httpFetch(
|
||||
`http://music.migu.cn/v3/api/music/audioPlayer/getSongPic?songId=${songId}`,
|
||||
{
|
||||
headers: {
|
||||
Referer: 'http://music.migu.cn/v3/music/player/audio?from=migu'
|
||||
}
|
||||
}
|
||||
)
|
||||
requestObj.promise.then(({ body }) => {
|
||||
if (body.returnCode !== '000000') {
|
||||
if (tryNum > 5) return Promise.reject(new Error('图片获取失败'))
|
||||
let tryRequestObj = this.getPic(songId, ++tryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
let url = body.largePic || body.mediumPic || body.smallPic
|
||||
if (!/https?:/.test(url)) url = 'http:' + url
|
||||
return url
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
async getPic(songInfo) {
|
||||
const songId = await getSongId(songInfo)
|
||||
return this.getPicUrl(songId)
|
||||
}
|
||||
}
|
||||
30
src/main/utils/musicSdk/mg/songId.js
Normal file
30
src/main/utils/musicSdk/mg/songId.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// import { httpFetch } from '../../request'
|
||||
import { getMusicInfo } from './musicInfo'
|
||||
|
||||
const getSongId = async (mInfo) => {
|
||||
if (mInfo.songmid != mInfo.copyrightId) return mInfo.songmid
|
||||
const musicInfo = await getMusicInfo(mInfo.copyrightId)
|
||||
return musicInfo.songmid
|
||||
}
|
||||
|
||||
// export const getSongId = async(musicInfo, retry = 0) => {
|
||||
// if (musicInfo.songmid != musicInfo.copyrightId) return musicInfo.songmid
|
||||
// if (++retry > 2) return Promise.reject(new Error('max retry'))
|
||||
|
||||
// const requestObj = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/listen-url?netType=00&resourceType=2&songId=${musicInfo.copyrightId}&toneFlag=PQ`, {
|
||||
// headers: {
|
||||
// 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
|
||||
// channel: '0146921',
|
||||
// },
|
||||
// })
|
||||
|
||||
// return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
// if (!body || body.code !== '000000') return this.getSongId(musicInfo, retry)
|
||||
// const id = body.data.songItem.songId
|
||||
// if (!id) throw new Error('failed')
|
||||
// return id
|
||||
// })
|
||||
// }
|
||||
|
||||
export default getSongId
|
||||
353
src/main/utils/musicSdk/mg/songList.js
Normal file
353
src/main/utils/musicSdk/mg/songList.js
Normal file
File diff suppressed because one or more lines are too long
196
src/main/utils/musicSdk/mg/temp/leaderboard-old.js
Normal file
196
src/main/utils/musicSdk/mg/temp/leaderboard-old.js
Normal file
@@ -0,0 +1,196 @@
|
||||
import { httpFetch } from '../../../request'
|
||||
import { formatPlayTime } from '../../../index'
|
||||
// import { sizeFormate } from '../../index'
|
||||
|
||||
// const boardList = [{ id: 'mg__27553319', name: '咪咕尖叫新歌榜', bangid: '27553319' }, { id: 'mg__27186466', name: '咪咕尖叫热歌榜', bangid: '27186466' }, { id: 'mg__27553408', name: '咪咕尖叫原创榜', bangid: '27553408' }, { id: 'mg__23189800', name: '咪咕港台榜', bangid: '23189800' }, { id: 'mg__23189399', name: '咪咕内地榜', bangid: '23189399' }, { id: 'mg__19190036', name: '咪咕欧美榜', bangid: '19190036' }, { id: 'mg__23189813', name: '咪咕日韩榜', bangid: '23189813' }, { id: 'mg__23190126', name: '咪咕彩铃榜', bangid: '23190126' }, { id: 'mg__15140045', name: '咪咕KTV榜', bangid: '15140045' }, { id: 'mg__15140034', name: '咪咕网络榜', bangid: '15140034' }, { id: 'mg__23217754', name: 'MV榜', bangid: '23217754' }, { id: 'mg__23218151', name: '新专辑榜', bangid: '23218151' }, { id: 'mg__21958042', name: 'iTunes榜', bangid: '21958042' }, { id: 'mg__21975570', name: 'billboard榜', bangid: '21975570' }, { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815' }, { id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' }, { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943' }, { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437' }]
|
||||
const boardList = [
|
||||
{ id: 'mg__27553319', name: '尖叫新歌榜', bangid: '27553319', webId: 'jianjiao_newsong' },
|
||||
{ id: 'mg__27186466', name: '尖叫热歌榜', bangid: '27186466', webId: 'jianjiao_hotsong' },
|
||||
{ id: 'mg__27553408', name: '尖叫原创榜', bangid: '27553408', webId: 'jianjiao_original' },
|
||||
{ id: 'mg__migumusic', name: '音乐榜', bangid: 'migumusic', webId: 'migumusic' },
|
||||
{ id: 'mg__movies', name: '影视榜', bangid: 'movies', webId: 'movies' },
|
||||
{ id: 'mg__23189800', name: '港台榜', bangid: '23189800', webId: 'hktw' },
|
||||
{ id: 'mg__23189399', name: '内地榜', bangid: '23189399', webId: 'mainland' },
|
||||
{ id: 'mg__19190036', name: '欧美榜', bangid: '19190036', webId: 'eur_usa' },
|
||||
{ id: 'mg__23189813', name: '日韩榜', bangid: '23189813', webId: 'jpn_kor' },
|
||||
{ id: 'mg__23190126', name: '彩铃榜', bangid: '23190126', webId: 'coloring' },
|
||||
{ id: 'mg__15140045', name: 'KTV榜', bangid: '15140045', webId: 'ktv' },
|
||||
{ id: 'mg__15140034', name: '网络榜', bangid: '15140034', webId: 'network' },
|
||||
{ id: 'mg__23217754', name: 'MV榜', bangid: '23217754', webId: 'mv' },
|
||||
{ id: 'mg__23218151', name: '新专辑榜', bangid: '23218151', webId: 'newalbum' },
|
||||
{ id: 'mg__21958042', name: '美国iTunes榜', bangid: '21958042', webId: 'itunes' },
|
||||
{ id: 'mg__21975570', name: '美国billboard榜', bangid: '21975570', webId: 'billboard' },
|
||||
{ id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815', webId: 'hito' },
|
||||
{ id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' },
|
||||
{ id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943', webId: 'mnet' },
|
||||
{ id: 'mg__22273437', name: '英国UK榜', bangid: '22273437', webId: 'uk' }
|
||||
]
|
||||
// const boardList = [
|
||||
// { id: 'mg__jianjiao_newsong', bangid: 'jianjiao_newsong', name: '尖叫新歌榜' },
|
||||
// { id: 'mg__jianjiao_hotsong', bangid: 'jianjiao_hotsong', name: '尖叫热歌榜' },
|
||||
// { id: 'mg__jianjiao_original', bangid: 'jianjiao_original', name: '尖叫原创榜' },
|
||||
// { id: 'mg__migumusic', bangid: 'migumusic', name: '音乐榜' },
|
||||
// { id: 'mg__movies', bangid: 'movies', name: '影视榜' },
|
||||
// { id: 'mg__mainland', bangid: 'mainland', name: '内地榜' },
|
||||
// { id: 'mg__hktw', bangid: 'hktw', name: '港台榜' },
|
||||
// { id: 'mg__eur_usa', bangid: 'eur_usa', name: '欧美榜' },
|
||||
// { id: 'mg__jpn_kor', bangid: 'jpn_kor', name: '日韩榜' },
|
||||
// { id: 'mg__coloring', bangid: 'coloring', name: '彩铃榜' },
|
||||
// { id: 'mg__ktv', bangid: 'ktv', name: 'KTV榜' },
|
||||
// { id: 'mg__network', bangid: 'network', name: '网络榜' },
|
||||
// { id: 'mg__newalbum', bangid: 'newalbum', name: '新专辑榜' },
|
||||
// { id: 'mg__mv', bangid: 'mv', name: 'MV榜' },
|
||||
// { id: 'mg__itunes', bangid: 'itunes', name: '美国iTunes榜' },
|
||||
// { id: 'mg__billboard', bangid: 'billboard', name: '美国billboard榜' },
|
||||
// { id: 'mg__hito', bangid: 'hito', name: 'Hito中文榜' },
|
||||
// { id: 'mg__mnet', bangid: 'mnet', name: '韩国Melon榜' },
|
||||
// { id: 'mg__uk', bangid: 'uk', name: '英国UK榜' },
|
||||
// ]
|
||||
|
||||
export default {
|
||||
limit: 10000,
|
||||
getUrl(id, page) {
|
||||
const targetBoard = boardList.find((board) => board.bangid == id)
|
||||
return `https://music.migu.cn/v3/music/top/${targetBoard.webId}`
|
||||
// return `http://m.music.migu.cn/migu/remoting/cms_list_tag?nid=${id}&pageSize=${this.limit}&pageNo=${page - 1}`
|
||||
},
|
||||
successCode: '000000',
|
||||
requestBoardsObj: null,
|
||||
regExps: {
|
||||
listData: /var listData = (\{.+\})<\/script>/
|
||||
},
|
||||
getData(url) {
|
||||
const requestObj = httpFetch(url)
|
||||
return requestObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach((singer) => {
|
||||
arr.push(singer.name)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
getIntv(interval) {
|
||||
if (!interval) return 0
|
||||
let intvArr = interval.split(':')
|
||||
let intv = 0
|
||||
let unit = 1
|
||||
while (intvArr.length) {
|
||||
intv += intvArr.pop() * unit
|
||||
unit *= 60
|
||||
}
|
||||
return parseInt(intv)
|
||||
},
|
||||
formateIntv() {},
|
||||
filterData(rawData) {
|
||||
// console.log(JSON.stringify(rawData))
|
||||
// console.log(rawData)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawData.forEach((item) => {
|
||||
if (ids.has(item.copyrightId)) return
|
||||
ids.add(item.copyrightId)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
const size = null
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
|
||||
if (item.hq) {
|
||||
const size = null
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = { size }
|
||||
}
|
||||
if (item.sq) {
|
||||
const size = null
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = { size }
|
||||
}
|
||||
|
||||
list.push({
|
||||
singer: this.getSinger(item.singers),
|
||||
name: item.name,
|
||||
albumName: item.album && item.album.albumName,
|
||||
albumId: item.album && item.album.albumId,
|
||||
songmid: item.id,
|
||||
copyrightId: item.copyrightId,
|
||||
source: 'mg',
|
||||
interval: item.duration ? formatPlayTime(this.getIntv(item.duration)) : null,
|
||||
img: item.mediumPic ? `https:${item.mediumPic}` : null,
|
||||
lrc: null,
|
||||
// lrcUrl: item.lrcUrl,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
for (const board of rawList) {
|
||||
if (board.template != 'group1') continue
|
||||
for (const item of board.itemList) {
|
||||
if (
|
||||
(item.template != 'row1' && item.template != 'grid1' && !item.actionUrl) ||
|
||||
!item.actionUrl.includes('rank-info')
|
||||
)
|
||||
continue
|
||||
|
||||
let data = item.displayLogId.param
|
||||
list.push({
|
||||
id: 'mg__' + data.rankId,
|
||||
name: data.rankName,
|
||||
bangid: String(data.rankId)
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// // console.log(response.body.data.contentItemList)
|
||||
// if (response.statusCode !== 200 || response.body.code !== this.successCode) return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.data.contentItemList)
|
||||
// // console.log(list)
|
||||
// // console.log(JSON.stringify(list))
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'mg',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'mg'
|
||||
}
|
||||
},
|
||||
getList(bangid, page, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
return this.getData(this.getUrl(bangid, page)).then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200) return this.getList(bangid, page, retryNum)
|
||||
let listData = body.match(this.regExps.listData)
|
||||
if (!listData) return this.getList(bangid, page, retryNum)
|
||||
const datas = JSON.parse(RegExp.$1)
|
||||
// console.log(datas)
|
||||
listData = this.filterData(datas.songs.items)
|
||||
return {
|
||||
total: datas.songs.itemTotal,
|
||||
list: this.filterData(datas.songs.items),
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'mg'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
28
src/main/utils/musicSdk/mg/tipSearch.js
Normal file
28
src/main/utils/musicSdk/mg/tipSearch.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { createHttpFetch } from './utils'
|
||||
|
||||
export default {
|
||||
requestObj: null,
|
||||
cancelTipSearch() {
|
||||
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
|
||||
},
|
||||
tipSearchBySong(str) {
|
||||
this.cancelTipSearch()
|
||||
this.requestObj = createHttpFetch(
|
||||
`https://music.migu.cn/v3/api/search/suggest?keyword=${encodeURIComponent(str)}`,
|
||||
{
|
||||
headers: {
|
||||
referer: 'https://music.migu.cn/v3'
|
||||
}
|
||||
}
|
||||
)
|
||||
return this.requestObj.then((body) => {
|
||||
return body.songs
|
||||
})
|
||||
},
|
||||
handleResult(rawData) {
|
||||
return rawData.map((info) => `${info.name} - ${info.singerName}`)
|
||||
},
|
||||
async search(str) {
|
||||
return this.tipSearchBySong(str).then((result) => this.handleResult(result))
|
||||
}
|
||||
}
|
||||
29
src/main/utils/musicSdk/mg/utils/index.js
Normal file
29
src/main/utils/musicSdk/mg/utils/index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { httpFetch } from '../../../request'
|
||||
|
||||
/**
|
||||
* 创建一个适用于MG的Http请求
|
||||
* @param {*} url
|
||||
* @param {*} options
|
||||
* @param {*} retryNum
|
||||
*/
|
||||
export const createHttpFetch = async (url, options, retryNum = 0) => {
|
||||
if (retryNum > 2) throw new Error('try max num')
|
||||
let result
|
||||
try {
|
||||
result = await httpFetch(url, options).promise
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return createHttpFetch(url, options, ++retryNum)
|
||||
}
|
||||
if (
|
||||
result.statusCode !== 200 ||
|
||||
(result.body.code !== undefined
|
||||
? result.body.code
|
||||
: result.body.returnCode !== undefined
|
||||
? result.body.returnCode
|
||||
: result.body.code) !== '000000'
|
||||
)
|
||||
return createHttpFetch(url, options, ++retryNum)
|
||||
if (result.body.data) return result.body.data
|
||||
return result.body
|
||||
}
|
||||
116
src/main/utils/musicSdk/mg/utils/mrc.js
Normal file
116
src/main/utils/musicSdk/mg/utils/mrc.js
Normal file
@@ -0,0 +1,116 @@
|
||||
// const key = 'karakal@123Qcomyidongtiantianhaoting'
|
||||
const DELTA = 2654435769n
|
||||
const MIN_LENGTH = 32
|
||||
// const SPECIAL_CHAR = '0'
|
||||
const keyArr = [
|
||||
27303562373562475n,
|
||||
18014862372307051n,
|
||||
22799692160172081n,
|
||||
34058940340699235n,
|
||||
30962724186095721n,
|
||||
27303523720101991n,
|
||||
27303523720101998n,
|
||||
31244139033526382n,
|
||||
28992395054481524n
|
||||
]
|
||||
|
||||
const teaDecrypt = (data, key) => {
|
||||
const length = data.length
|
||||
const lengthBitint = BigInt(length)
|
||||
if (length >= 1) {
|
||||
// let j = data[data.length - 1];
|
||||
let j2 = data[0]
|
||||
let j3 = toLong((6n + 52n / lengthBitint) * DELTA)
|
||||
while (true) {
|
||||
let j4 = j3
|
||||
if (j4 == 0n) break
|
||||
let j5 = toLong(3n & toLong(j4 >> 2n))
|
||||
let j6 = lengthBitint
|
||||
while (true) {
|
||||
j6--
|
||||
if (j6 > 0n) {
|
||||
let j7 = data[j6 - 1n]
|
||||
let i = j6
|
||||
j2 = toLong(
|
||||
data[i] -
|
||||
(toLong(toLong(j2 ^ j4) + toLong(j7 ^ key[toLong(toLong(3n & j6) ^ j5)])) ^
|
||||
toLong(
|
||||
toLong(toLong(j7 >> 5n) ^ toLong(j2 << 2n)) +
|
||||
toLong(toLong(j2 >> 3n) ^ toLong(j7 << 4n))
|
||||
))
|
||||
)
|
||||
data[i] = j2
|
||||
} else break
|
||||
}
|
||||
let j8 = data[lengthBitint - 1n]
|
||||
j2 = toLong(
|
||||
data[0n] -
|
||||
toLong(
|
||||
toLong(toLong(key[toLong(toLong(j6 & 3n) ^ j5)] ^ j8) + toLong(j2 ^ j4)) ^
|
||||
toLong(
|
||||
toLong(toLong(j8 >> 5n) ^ toLong(j2 << 2n)) +
|
||||
toLong(toLong(j2 >> 3n) ^ toLong(j8 << 4n))
|
||||
)
|
||||
)
|
||||
)
|
||||
data[0] = j2
|
||||
j3 = toLong(j4 - DELTA)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const longArrToString = (data) => {
|
||||
const arrayList = []
|
||||
for (const j of data) arrayList.push(longToBytes(j).toString('utf16le'))
|
||||
return arrayList.join('')
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/29132118
|
||||
const longToBytes = (l) => {
|
||||
const result = Buffer.alloc(8)
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result[i] = parseInt(l & 0xffn)
|
||||
l >>= 8n
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const toBigintArray = (data) => {
|
||||
const length = Math.floor(data.length / 16)
|
||||
const jArr = Array(length)
|
||||
for (let i = 0; i < length; i++) {
|
||||
jArr[i] = toLong(data.substring(i * 16, i * 16 + 16))
|
||||
}
|
||||
return jArr
|
||||
}
|
||||
|
||||
// https://github.com/lyswhut/lx-music-desktop/issues/445#issuecomment-1139338682
|
||||
const MAX = 9223372036854775807n
|
||||
const MIN = -9223372036854775808n
|
||||
const toLong = (str) => {
|
||||
const num = typeof str == 'string' ? BigInt('0x' + str) : str
|
||||
if (num > MAX) return toLong(num - (1n << 64n))
|
||||
else if (num < MIN) return toLong(num + (1n << 64n))
|
||||
return num
|
||||
}
|
||||
|
||||
export const decrypt = (data) => {
|
||||
// console.log(data.length)
|
||||
// -3551594764563790630
|
||||
// console.log(toLongArrayFromArr(Buffer.from(key)))
|
||||
// console.log(teaDecrypt(toBigintArray(data), keyArr))
|
||||
// console.log(longArrToString(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
// console.log(toByteArray(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
return data == null || data.length < MIN_LENGTH
|
||||
? data
|
||||
: longArrToString(teaDecrypt(toBigintArray(data), keyArr))
|
||||
}
|
||||
|
||||
// console.log(14895149309145760986n - )
|
||||
// console.log(toLong('14895149309145760986'))
|
||||
// console.log(decrypt(str))
|
||||
// console.log(decrypt(str))
|
||||
// console.log(toByteArray([6048138644744000495n]))
|
||||
// console.log(toByteArray([16325999628386395n]))
|
||||
// console.log(toLong(90994076459972177136n))
|
||||
16
src/main/utils/musicSdk/options.js
Normal file
16
src/main/utils/musicSdk/options.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export const bHh = '624868746c'
|
||||
|
||||
export const headers = {
|
||||
'User-Agent': 'lx-music request',
|
||||
[bHh]: [bHh]
|
||||
}
|
||||
|
||||
export const timeout = 15000
|
||||
|
||||
// 添加 getOptions 函数
|
||||
export const getOptions = () => {
|
||||
return {
|
||||
headers,
|
||||
timeout
|
||||
}
|
||||
}
|
||||
33
src/main/utils/musicSdk/tx/api-test.js
Normal file
33
src/main/utils/musicSdk/tx/api-test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/url/tx/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(requestMsg.fail))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
return Promise.resolve(
|
||||
`https://y.gtimg.cn/music/photo_new/T002R500x500M000${songInfo.albumId}.jpg`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default api_messoer
|
||||
289
src/main/utils/musicSdk/tx/comment.js
Normal file
289
src/main/utils/musicSdk/tx/comment.js
Normal file
@@ -0,0 +1,289 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { dateFormat2 } from '../index'
|
||||
import getMusicInfo from './musicInfo'
|
||||
|
||||
const emojis = {
|
||||
e400846: '😘',
|
||||
e400874: '😴',
|
||||
e400825: '😃',
|
||||
e400847: '😙',
|
||||
e400835: '😍',
|
||||
e400873: '😳',
|
||||
e400836: '😎',
|
||||
e400867: '😭',
|
||||
e400832: '😊',
|
||||
e400837: '😏',
|
||||
e400875: '😫',
|
||||
e400831: '😉',
|
||||
e400855: '😡',
|
||||
e400823: '😄',
|
||||
e400862: '😨',
|
||||
e400844: '😖',
|
||||
e400841: '😓',
|
||||
e400830: '😈',
|
||||
e400828: '😆',
|
||||
e400833: '😋',
|
||||
e400822: '😀',
|
||||
e400843: '😕',
|
||||
e400829: '😇',
|
||||
e400824: '😂',
|
||||
e400834: '😌',
|
||||
e400877: '😷',
|
||||
e400132: '🍉',
|
||||
e400181: '🍺',
|
||||
e401067: '☕️',
|
||||
e400186: '🥧',
|
||||
e400343: '🐷',
|
||||
e400116: '🌹',
|
||||
e400126: '🍃',
|
||||
e400613: '💋',
|
||||
e401236: '❤️',
|
||||
e400622: '💔',
|
||||
e400637: '💣',
|
||||
e400643: '💩',
|
||||
e400773: '🔪',
|
||||
e400102: '🌛',
|
||||
e401328: '🌞',
|
||||
e400420: '👏',
|
||||
e400914: '🙌',
|
||||
e400408: '👍',
|
||||
e400414: '👎',
|
||||
e401121: '✋',
|
||||
e400396: '👋',
|
||||
e400384: '👉',
|
||||
e401115: '✊',
|
||||
e400402: '👌',
|
||||
e400905: '🙈',
|
||||
e400906: '🙉',
|
||||
e400907: '🙊',
|
||||
e400562: '👻',
|
||||
e400932: '🙏',
|
||||
e400644: '💪',
|
||||
e400611: '💉',
|
||||
e400185: '🎁',
|
||||
e400655: '💰',
|
||||
e400325: '🐥',
|
||||
e400612: '💊',
|
||||
e400198: '🎉',
|
||||
e401685: '⚡️',
|
||||
e400631: '💝',
|
||||
e400768: '🔥',
|
||||
e400432: '👑'
|
||||
}
|
||||
|
||||
const songIdMap = new Map()
|
||||
const promises = new Map()
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
async getSongId({ songId, songmid }) {
|
||||
if (songId) return songId
|
||||
if (songIdMap.has(songmid)) return songIdMap.get(songmid)
|
||||
if (promises.has(songmid)) return (await promises.get(songmid)).songId
|
||||
const promise = getMusicInfo(songmid)
|
||||
promises.set(promise)
|
||||
const info = await promise
|
||||
songIdMap.set(songmid, info.songId)
|
||||
promises.delete(songmid)
|
||||
return info.songId
|
||||
},
|
||||
async getComment(mInfo, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
const songId = await this.getSongId(mInfo)
|
||||
|
||||
const _requestObj = httpFetch('http://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
},
|
||||
form: {
|
||||
uin: '0',
|
||||
format: 'json',
|
||||
cid: '205360772',
|
||||
reqtype: '2',
|
||||
biztype: '1',
|
||||
topid: songId,
|
||||
cmd: '8',
|
||||
needmusiccrit: '1',
|
||||
pagenum: page - 1,
|
||||
pagesize: limit
|
||||
}
|
||||
})
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.code !== 0) throw new Error('获取评论失败')
|
||||
// console.log(body, statusCode)
|
||||
const comment = body.comment
|
||||
return {
|
||||
source: 'tx',
|
||||
comments: this.filterNewComment(comment.commentlist),
|
||||
total: comment.commenttotal,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(comment.commenttotal / limit) || 1
|
||||
}
|
||||
},
|
||||
async getHotComment(mInfo, page = 1, limit = 20) {
|
||||
// const _requestObj2 = httpFetch('http://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg', {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
|
||||
// },
|
||||
// form: {
|
||||
// uin: '0',
|
||||
// format: 'json',
|
||||
// cid: '205360772',
|
||||
// reqtype: '2',
|
||||
// biztype: '1',
|
||||
// topid: songId,
|
||||
// cmd: '9',
|
||||
// needmusiccrit: '1',
|
||||
// pagenum: page - 1,
|
||||
// pagesize: limit,
|
||||
// },
|
||||
// })
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
const songId = await this.getSongId(mInfo)
|
||||
|
||||
const _requestObj2 = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
comm: {
|
||||
cv: 4747474,
|
||||
ct: 24,
|
||||
format: 'json',
|
||||
inCharset: 'utf-8',
|
||||
outCharset: 'utf-8',
|
||||
notice: 0,
|
||||
platform: 'yqq.json',
|
||||
needNewCode: 1,
|
||||
uin: 0
|
||||
},
|
||||
req: {
|
||||
module: 'music.globalComment.CommentRead',
|
||||
method: 'GetHotCommentList',
|
||||
param: {
|
||||
BizType: 1,
|
||||
BizId: String(songId),
|
||||
LastCommentSeqNo: '',
|
||||
PageSize: limit,
|
||||
PageNum: page - 1,
|
||||
HotType: 1,
|
||||
WithAirborne: 0,
|
||||
PicEnable: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.0.0',
|
||||
referer: 'https://y.qq.com/',
|
||||
origin: 'https://y.qq.com'
|
||||
}
|
||||
})
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log('body', body)
|
||||
if (statusCode != 200 || body.code !== 0 || body.req.code !== 0)
|
||||
throw new Error('获取热门评论失败')
|
||||
const comment = body.req.data.CommentList
|
||||
return {
|
||||
source: 'tx',
|
||||
comments: this.filterHotComment(comment.Comments),
|
||||
total: comment.Total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(comment.Total / limit) || 1
|
||||
}
|
||||
},
|
||||
filterNewComment(rawList) {
|
||||
return rawList.map((item) => {
|
||||
let time = this.formatTime(item.time)
|
||||
let timeStr = time ? dateFormat2(time) : null
|
||||
if (item.middlecommentcontent) {
|
||||
let firstItem = item.middlecommentcontent[0]
|
||||
firstItem.avatarurl = item.avatarurl
|
||||
firstItem.praisenum = item.praisenum
|
||||
item.avatarurl = null
|
||||
item.praisenum = null
|
||||
item.middlecommentcontent.reverse()
|
||||
}
|
||||
return {
|
||||
id: `${item.rootcommentid}_${item.commentid}`,
|
||||
rootId: item.rootcommentid,
|
||||
text: item.rootcommentcontent
|
||||
? this.replaceEmoji(item.rootcommentcontent).replace(/\\n/g, '\n')
|
||||
: '',
|
||||
time: item.rootcommentid == item.commentid ? time : null,
|
||||
timeStr: item.rootcommentid == item.commentid ? timeStr : null,
|
||||
userName: item.rootcommentnick ? item.rootcommentnick.substring(1) : '',
|
||||
avatar: item.avatarurl,
|
||||
userId: item.encrypt_rootcommentuin,
|
||||
likedCount: item.praisenum,
|
||||
reply: item.middlecommentcontent
|
||||
? item.middlecommentcontent.map((c) => {
|
||||
// let index = c.subcommentid.lastIndexOf('_')
|
||||
return {
|
||||
id: `sub_${item.rootcommentid}_${c.subcommentid}`,
|
||||
text: this.replaceEmoji(c.subcommentcontent).replace(/\\n/g, '\n'),
|
||||
time: c.subcommentid == item.commentid ? time : null,
|
||||
timeStr: c.subcommentid == item.commentid ? timeStr : null,
|
||||
userName: c.replynick.substring(1),
|
||||
avatar: c.avatarurl,
|
||||
userId: c.encrypt_replyuin,
|
||||
likedCount: c.praisenum
|
||||
}
|
||||
})
|
||||
: []
|
||||
}
|
||||
})
|
||||
},
|
||||
filterHotComment(rawList) {
|
||||
return rawList.map((item) => {
|
||||
return {
|
||||
id: `${item.SeqNo}_${item.CmId}`,
|
||||
rootId: item.SeqNo,
|
||||
text: item.Content ? this.replaceEmoji(item.Content).replace(/\\n/g, '\n') : '',
|
||||
time: item.PubTime ? this.formatTime(item.PubTime) : null,
|
||||
timeStr: item.PubTime ? dateFormat2(this.formatTime(item.PubTime)) : null,
|
||||
userName: item.Nick ?? '',
|
||||
images: item.Pic ? [item.Pic] : [],
|
||||
avatar: item.Avatar,
|
||||
location: item.Location ? item.Location : '',
|
||||
userId: item.EncryptUin,
|
||||
likedCount: item.PraiseNum,
|
||||
reply: item.SubComments
|
||||
? item.SubComments.map((c) => {
|
||||
return {
|
||||
id: `sub_${c.SeqNo}_${c.CmId}`,
|
||||
text: this.replaceEmoji(c.Content).replace(/\\n/g, '\n'),
|
||||
time: c.PubTime ? this.formatTime(c.PubTime) : null,
|
||||
timeStr: c.PubTime ? dateFormat2(this.formatTime(c.PubTime)) : null,
|
||||
userName: c.Nick ?? '',
|
||||
avatar: c.Avatar,
|
||||
images: c.Pic ? [c.Pic] : [],
|
||||
userId: c.EncryptUin,
|
||||
likedCount: c.PraiseNum
|
||||
}
|
||||
})
|
||||
: []
|
||||
}
|
||||
})
|
||||
},
|
||||
replaceEmoji(msg) {
|
||||
let rxp = /^\[em\](e\d+)\[\/em\]$/
|
||||
let result = msg.match(/\[em\]e\d+\[\/em\]/g)
|
||||
if (!result) return msg
|
||||
result = Array.from(new Set(result))
|
||||
for (let item of result) {
|
||||
let code = item.replace(rxp, '$1')
|
||||
msg = msg.replace(
|
||||
new RegExp(item.replace('[em]', '\\[em\\]').replace('[/em]', '\\[\\/em\\]'), 'g'),
|
||||
emojis[code] || ''
|
||||
)
|
||||
}
|
||||
return msg
|
||||
},
|
||||
formatTime(time) {
|
||||
return String(time).length < 10 ? null : parseInt(time + '000')
|
||||
}
|
||||
}
|
||||
54
src/main/utils/musicSdk/tx/hotSearch.js
Normal file
54
src/main/utils/musicSdk/tx/hotSearch.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
// const _requestObj = httpFetch('https://c.y.qq.com/splcloud/fcgi-bin/gethotkey.fcg', {
|
||||
// method: 'get',
|
||||
// headers: {
|
||||
// Referer: 'https://y.qq.com/portal/player.html',
|
||||
// },
|
||||
// })
|
||||
const _requestObj = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
body: {
|
||||
comm: {
|
||||
ct: '19',
|
||||
cv: '1803',
|
||||
guid: '0',
|
||||
patch: '118',
|
||||
psrf_access_token_expiresAt: 0,
|
||||
psrf_qqaccess_token: '',
|
||||
psrf_qqopenid: '',
|
||||
psrf_qqunionid: '',
|
||||
tmeAppID: 'qqmusic',
|
||||
tmeLoginType: 0,
|
||||
uin: '0',
|
||||
wid: '0'
|
||||
},
|
||||
hotkey: {
|
||||
method: 'GetHotkeyForQQMusicPC',
|
||||
module: 'tencent_musicsoso_hotkey.HotkeyService',
|
||||
param: {
|
||||
search_id: '',
|
||||
uin: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
Referer: 'https://y.qq.com/portal/player.html'
|
||||
}
|
||||
})
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.code !== 0) throw new Error('获取热搜词失败')
|
||||
// console.log(body)
|
||||
return { source: 'tx', list: this.filterList(body.hotkey.data.vec_hotkey) }
|
||||
},
|
||||
filterList(rawList) {
|
||||
return rawList.map((item) => item.query)
|
||||
}
|
||||
}
|
||||
25
src/main/utils/musicSdk/tx/index.js
Normal file
25
src/main/utils/musicSdk/tx/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import leaderboard from './leaderboard'
|
||||
import lyric from './lyric'
|
||||
import songList from './songList'
|
||||
import musicSearch from './musicSearch'
|
||||
import hotSearch from './hotSearch'
|
||||
import comment from './comment'
|
||||
// import tipSearch from './tipSearch'
|
||||
|
||||
const tx = {
|
||||
// tipSearch,
|
||||
leaderboard,
|
||||
songList,
|
||||
musicSearch,
|
||||
hotSearch,
|
||||
comment,
|
||||
getLyric(songInfo) {
|
||||
// let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer
|
||||
return lyric.getLyric(songInfo)
|
||||
},
|
||||
getMusicDetailPageUrl(songInfo) {
|
||||
return `https://y.qq.com/n/yqq/song/${songInfo.songmid}.html`
|
||||
}
|
||||
}
|
||||
|
||||
export default tx
|
||||
279
src/main/utils/musicSdk/tx/leaderboard.js
Normal file
279
src/main/utils/musicSdk/tx/leaderboard.js
Normal file
@@ -0,0 +1,279 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
let boardList = [
|
||||
{ id: 'tx__4', name: '流行指数榜', bangid: '4' },
|
||||
{ id: 'tx__26', name: '热歌榜', bangid: '26' },
|
||||
{ id: 'tx__27', name: '新歌榜', bangid: '27' },
|
||||
{ id: 'tx__62', name: '飙升榜', bangid: '62' },
|
||||
{ id: 'tx__58', name: '说唱榜', bangid: '58' },
|
||||
{ id: 'tx__57', name: '喜力电音榜', bangid: '57' },
|
||||
{ id: 'tx__28', name: '网络歌曲榜', bangid: '28' },
|
||||
{ id: 'tx__5', name: '内地榜', bangid: '5' },
|
||||
{ id: 'tx__3', name: '欧美榜', bangid: '3' },
|
||||
{ id: 'tx__59', name: '香港地区榜', bangid: '59' },
|
||||
{ id: 'tx__16', name: '韩国榜', bangid: '16' },
|
||||
{ id: 'tx__60', name: '抖快榜', bangid: '60' },
|
||||
{ id: 'tx__29', name: '影视金曲榜', bangid: '29' },
|
||||
{ id: 'tx__17', name: '日本榜', bangid: '17' },
|
||||
{ id: 'tx__52', name: '腾讯音乐人原创榜', bangid: '52' },
|
||||
{ id: 'tx__36', name: 'K歌金曲榜', bangid: '36' },
|
||||
{ id: 'tx__61', name: '台湾地区榜', bangid: '61' },
|
||||
{ id: 'tx__63', name: 'DJ舞曲榜', bangid: '63' },
|
||||
{ id: 'tx__64', name: '综艺新歌榜', bangid: '64' },
|
||||
{ id: 'tx__65', name: '国风热歌榜', bangid: '65' },
|
||||
{ id: 'tx__67', name: '听歌识曲榜', bangid: '67' },
|
||||
{ id: 'tx__72', name: '动漫音乐榜', bangid: '72' },
|
||||
{ id: 'tx__73', name: '游戏音乐榜', bangid: '73' },
|
||||
{ id: 'tx__75', name: '有声榜', bangid: '75' },
|
||||
{ id: 'tx__131', name: '校园音乐人排行榜', bangid: '131' }
|
||||
]
|
||||
|
||||
export default {
|
||||
limit: 300,
|
||||
list: [
|
||||
{
|
||||
id: 'txlxzsb',
|
||||
name: '流行榜',
|
||||
bangid: 4
|
||||
},
|
||||
{
|
||||
id: 'txrgb',
|
||||
name: '热歌榜',
|
||||
bangid: 26
|
||||
},
|
||||
{
|
||||
id: 'txwlhgb',
|
||||
name: '网络榜',
|
||||
bangid: 28
|
||||
},
|
||||
{
|
||||
id: 'txdyb',
|
||||
name: '抖音榜',
|
||||
bangid: 60
|
||||
},
|
||||
{
|
||||
id: 'txndb',
|
||||
name: '内地榜',
|
||||
bangid: 5
|
||||
},
|
||||
{
|
||||
id: 'txxgb',
|
||||
name: '香港榜',
|
||||
bangid: 59
|
||||
},
|
||||
{
|
||||
id: 'txtwb',
|
||||
name: '台湾榜',
|
||||
bangid: 61
|
||||
},
|
||||
{
|
||||
id: 'txoumb',
|
||||
name: '欧美榜',
|
||||
bangid: 3
|
||||
},
|
||||
{
|
||||
id: 'txhgb',
|
||||
name: '韩国榜',
|
||||
bangid: 16
|
||||
},
|
||||
{
|
||||
id: 'txrbb',
|
||||
name: '日本榜',
|
||||
bangid: 17
|
||||
},
|
||||
{
|
||||
id: 'txtybb',
|
||||
name: 'YouTube榜',
|
||||
bangid: 128
|
||||
}
|
||||
],
|
||||
listDetailRequest(id, period, limit) {
|
||||
// console.log(id, period, limit)
|
||||
return httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
},
|
||||
body: {
|
||||
toplist: {
|
||||
module: 'musicToplist.ToplistInfoServer',
|
||||
method: 'GetDetail',
|
||||
param: {
|
||||
topid: id,
|
||||
num: limit,
|
||||
period
|
||||
}
|
||||
},
|
||||
comm: {
|
||||
uin: 0,
|
||||
format: 'json',
|
||||
ct: 20,
|
||||
cv: 1859
|
||||
}
|
||||
}
|
||||
}).promise
|
||||
},
|
||||
regExps: {
|
||||
periodList:
|
||||
/<i class="play_cover__btn c_tx_link js_icon_play" data-listkey=".+?" data-listname=".+?" data-tid=".+?" data-date=".+?" .+?<\/i>/g,
|
||||
period: /data-listname="(.+?)" data-tid=".*?\/(.+?)" data-date="(.+?)" .+?<\/i>/
|
||||
},
|
||||
periods: {},
|
||||
periodUrl: 'https://c.y.qq.com/node/pc/wk_v15/top.html',
|
||||
_requestBoardsObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch(
|
||||
'https://c.y.qq.com/v8/fcg-bin/fcg_myqq_toplist.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&uin=0&needNewCode=1&platform=h5'
|
||||
)
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
return rawList.map((item) => {
|
||||
let types = []
|
||||
let _types = {}
|
||||
if (item.file.size_128mp3 !== 0) {
|
||||
let size = sizeFormate(item.file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(item.file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_flac !== 0) {
|
||||
let size = sizeFormate(item.file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_hires !== 0) {
|
||||
let size = sizeFormate(item.file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
return {
|
||||
singer: formatSingerName(item.singer, 'name'),
|
||||
name: item.title,
|
||||
albumName: item.album.name,
|
||||
albumId: item.album.mid,
|
||||
source: 'tx',
|
||||
interval: formatPlayTime(item.interval),
|
||||
songId: item.id,
|
||||
albumMid: item.album.mid,
|
||||
strMediaMid: item.file.media_mid,
|
||||
songmid: item.mid,
|
||||
img:
|
||||
item.album.name === '' || item.album.name === '空'
|
||||
? item.singer?.length
|
||||
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
|
||||
: ''
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.album.mid}.jpg`,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
getPeriods(bangid) {
|
||||
return this.getData(this.periodUrl).then(({ body: html }) => {
|
||||
let result = html.match(this.regExps.periodList)
|
||||
if (!result) return Promise.reject(new Error('get data failed'))
|
||||
result.forEach((item) => {
|
||||
let result = item.match(this.regExps.period)
|
||||
if (!result) return
|
||||
this.periods[result[2]] = {
|
||||
name: result[1],
|
||||
bangid: result[2],
|
||||
period: result[3]
|
||||
}
|
||||
})
|
||||
const info = this.periods[bangid]
|
||||
return info && info.period
|
||||
})
|
||||
},
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
for (const board of rawList) {
|
||||
// 排除 MV榜
|
||||
if (board.id == 201) continue
|
||||
|
||||
if (board.topTitle.startsWith('巅峰榜·')) {
|
||||
board.topTitle = board.topTitle.substring(4, board.topTitle.length)
|
||||
}
|
||||
if (!board.topTitle.endsWith('榜')) board.topTitle += '榜'
|
||||
list.push({
|
||||
id: 'tx__' + board.id,
|
||||
name: board.topTitle,
|
||||
bangid: String(board.id)
|
||||
})
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// // console.log(response.body)
|
||||
// if (response.statusCode !== 200 || response.body.code !== 0) return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.data.topList)
|
||||
// console.log(list)
|
||||
// console.log(JSON.stringify(list))
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'tx',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'tx'
|
||||
}
|
||||
},
|
||||
getList(bangid, page, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
bangid = parseInt(bangid)
|
||||
let info = this.periods[bangid]
|
||||
let p = info ? Promise.resolve(info.period) : this.getPeriods(bangid)
|
||||
return p.then((period) => {
|
||||
return this.listDetailRequest(bangid, period, this.limit).then((resp) => {
|
||||
if (resp.body.code !== 0) return this.getList(bangid, page, retryNum)
|
||||
return {
|
||||
total: resp.body.toplist.data.songInfoList.length,
|
||||
list: this.filterData(resp.body.toplist.data.songInfoList),
|
||||
limit: this.limit,
|
||||
page: 1,
|
||||
source: 'tx'
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getDetailPageUrl(id) {
|
||||
if (typeof id == 'string') id = id.replace('tx__', '')
|
||||
return `https://y.qq.com/n/ryqq/toplist/${id}`
|
||||
}
|
||||
}
|
||||
70
src/main/utils/musicSdk/tx/lyric.js
Normal file
70
src/main/utils/musicSdk/tx/lyric.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import getMusicInfo from './musicInfo'
|
||||
|
||||
const songIdMap = new Map()
|
||||
const promises = new Map()
|
||||
|
||||
export default {
|
||||
successCode: 0,
|
||||
async getSongId({ songId, songmid }) {
|
||||
if (songId) return songId
|
||||
if (songIdMap.has(songmid)) return songIdMap.get(songmid)
|
||||
if (promises.has(songmid)) return (await promises.get(songmid)).songId
|
||||
const promise = getMusicInfo(songmid)
|
||||
promises.set(promise)
|
||||
const info = await promise
|
||||
songIdMap.set(songmid, info.songId)
|
||||
promises.delete(songmid)
|
||||
return info.songId
|
||||
},
|
||||
getLyric(mInfo, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('Get lyric failed'))
|
||||
|
||||
return {
|
||||
promise: this.getSongId(mInfo).then((songId) => {
|
||||
const requestObj = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
referer: 'https://y.qq.com',
|
||||
'user-agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
|
||||
},
|
||||
body: {
|
||||
comm: {
|
||||
ct: '19',
|
||||
cv: '1859',
|
||||
uin: '0'
|
||||
},
|
||||
req: {
|
||||
method: 'GetPlayLyricInfo',
|
||||
module: 'music.musichallSong.PlayLyricInfo',
|
||||
param: {
|
||||
format: 'json',
|
||||
crypt: 1,
|
||||
ct: 19,
|
||||
cv: 1873,
|
||||
interval: 0,
|
||||
lrc_t: 0,
|
||||
qrc: 1,
|
||||
qrc_t: 0,
|
||||
roma: 1,
|
||||
roma_t: 0,
|
||||
songID: songId,
|
||||
trans: 1,
|
||||
trans_t: 0,
|
||||
type: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code != this.successCode || body.req.code != this.successCode)
|
||||
return this.getLyric(songId, ++retryNum)
|
||||
const data = body.req.data
|
||||
return this.parseLyric(data.lyric, data.trans, data.roma)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
100
src/main/utils/musicSdk/tx/musicInfo.js
Normal file
100
src/main/utils/musicSdk/tx/musicInfo.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../index'
|
||||
|
||||
const getSinger = (singers) => {
|
||||
let arr = []
|
||||
singers.forEach((singer) => {
|
||||
arr.push(singer.name)
|
||||
})
|
||||
return arr.join('、')
|
||||
}
|
||||
|
||||
export default (songmid) => {
|
||||
const requestObj = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
},
|
||||
body: {
|
||||
comm: {
|
||||
ct: '19',
|
||||
cv: '1859',
|
||||
uin: '0'
|
||||
},
|
||||
req: {
|
||||
module: 'music.pf_song_detail_svr',
|
||||
method: 'get_song_detail_yqq',
|
||||
param: {
|
||||
song_type: 0,
|
||||
song_mid: songmid
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code != 0 || body.req.code != 0) return Promise.reject(new Error('获取歌曲信息失败'))
|
||||
const item = body.req.data.track_info
|
||||
if (!item.file?.media_mid) return null
|
||||
|
||||
let types = []
|
||||
let _types = {}
|
||||
const file = item.file
|
||||
if (file.size_128mp3 != 0) {
|
||||
let size = sizeFormate(file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_flac !== 0) {
|
||||
let size = sizeFormate(file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_hires !== 0) {
|
||||
let size = sizeFormate(file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
let albumId = ''
|
||||
let albumName = ''
|
||||
if (item.album) {
|
||||
albumName = item.album.name
|
||||
albumId = item.album.mid
|
||||
}
|
||||
return {
|
||||
singer: getSinger(item.singer),
|
||||
name: item.title,
|
||||
albumName,
|
||||
albumId,
|
||||
source: 'tx',
|
||||
interval: formatPlayTime(item.interval),
|
||||
songId: item.id,
|
||||
albumMid: item.album?.mid ?? '',
|
||||
strMediaMid: item.file.media_mid,
|
||||
songmid: item.mid,
|
||||
img:
|
||||
albumId === '' || albumId === '空'
|
||||
? item.singer?.length
|
||||
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
|
||||
: ''
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${albumId}.jpg`,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
}
|
||||
141
src/main/utils/musicSdk/tx/musicSearch.js
Normal file
141
src/main/utils/musicSdk/tx/musicSearch.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
export default {
|
||||
limit: 50,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
successCode: 0,
|
||||
musicSearch(str, page, limit, retryNum = 0) {
|
||||
if (retryNum > 5) return Promise.reject(new Error('搜索失败'))
|
||||
// searchRequest = httpFetch(`https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=sizer.yqq.song_next&searchid=49252838123499591&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=${page}&n=${limit}&w=${encodeURIComponent(str)}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0`)
|
||||
// const searchRequest = httpFetch(`https://shc.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&remoteplace=txt.yqq.top&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=${page}&n=${limit}&w=${encodeURIComponent(str)}&cv=4747474&ct=24&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&uin=0&hostUin=0&loginUin=0`)
|
||||
const searchRequest = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
},
|
||||
body: {
|
||||
comm: {
|
||||
ct: 11,
|
||||
cv: '1003006',
|
||||
v: '1003006',
|
||||
os_ver: '12',
|
||||
phonetype: '0',
|
||||
devicelevel: '31',
|
||||
tmeAppID: 'qqmusiclight',
|
||||
nettype: 'NETWORK_WIFI'
|
||||
},
|
||||
req: {
|
||||
module: 'music.search.SearchCgiService',
|
||||
method: 'DoSearchForQQMusicLite',
|
||||
param: {
|
||||
query: str,
|
||||
search_type: 0,
|
||||
num_per_page: limit,
|
||||
page_num: page,
|
||||
nqc_flag: 0,
|
||||
grp: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// searchRequest = httpFetch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${this.limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
return searchRequest.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code != this.successCode || body.req.code != this.successCode)
|
||||
return this.musicSearch(str, page, limit, ++retryNum)
|
||||
return body.req.data
|
||||
})
|
||||
},
|
||||
handleResult(rawList) {
|
||||
// console.log(rawList)
|
||||
const list = []
|
||||
rawList.forEach((item) => {
|
||||
if (!item.file?.media_mid) return
|
||||
|
||||
let types = []
|
||||
let _types = {}
|
||||
const file = item.file
|
||||
if (file.size_128mp3 != 0) {
|
||||
let size = sizeFormate(file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_flac !== 0) {
|
||||
let size = sizeFormate(file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (file.size_hires !== 0) {
|
||||
let size = sizeFormate(file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
let albumId = ''
|
||||
let albumName = ''
|
||||
if (item.album) {
|
||||
albumName = item.album.name
|
||||
albumId = item.album.mid
|
||||
}
|
||||
list.push({
|
||||
singer: formatSingerName(item.singer, 'name'),
|
||||
name: item.name + (item.title_extra ?? ''),
|
||||
albumName,
|
||||
albumId,
|
||||
source: 'tx',
|
||||
interval: formatPlayTime(item.interval),
|
||||
songId: item.id,
|
||||
albumMid: item.album?.mid ?? '',
|
||||
strMediaMid: item.file.media_mid,
|
||||
songmid: item.mid,
|
||||
img:
|
||||
albumId === '' || albumId === '空'
|
||||
? item.singer?.length
|
||||
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
|
||||
: ''
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${albumId}.jpg`,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
// console.log(list)
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, limit) {
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then(({ body, meta }) => {
|
||||
let list = this.handleResult(body.item_song)
|
||||
|
||||
this.total = meta.estimate_sum
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'tx'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
252
src/main/utils/musicSdk/tx/singer.js
Normal file
252
src/main/utils/musicSdk/tx/singer.js
Normal file
@@ -0,0 +1,252 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
export const filterMusicInfoItem = (item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.file.size_128mp3 != 0) {
|
||||
let size = sizeFormate(item.file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(item.file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_flac !== 0) {
|
||||
let size = sizeFormate(item.file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_hires !== 0) {
|
||||
let size = sizeFormate(item.file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
const albumId = item.album.id ?? ''
|
||||
const albumMid = item.album.mid ?? ''
|
||||
const albumName = item.album.name ?? ''
|
||||
return {
|
||||
source: 'tx',
|
||||
singer: formatSingerName(item.singer, 'name'),
|
||||
name: item.title,
|
||||
albumName,
|
||||
albumId,
|
||||
albumMid,
|
||||
interval: formatPlayTime(item.interval),
|
||||
songId: item.id,
|
||||
songmid: item.mid,
|
||||
strMediaMid: item.file.media_mid,
|
||||
img:
|
||||
albumId === '' || albumId === '空'
|
||||
? item.singer?.length
|
||||
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
|
||||
: ''
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${albumMid}.jpg`,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个适用于TX的Http请求
|
||||
* @param {*} url
|
||||
* @param {*} options
|
||||
* @param {*} retryNum
|
||||
*/
|
||||
const createMusicuFetch = async (data, options, retryNum = 0) => {
|
||||
if (retryNum > 2) throw new Error('try max num')
|
||||
|
||||
let result
|
||||
try {
|
||||
result = await httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
comm: {
|
||||
cv: 4747474,
|
||||
ct: 24,
|
||||
format: 'json',
|
||||
inCharset: 'utf-8',
|
||||
outCharset: 'utf-8',
|
||||
uin: 0
|
||||
},
|
||||
...data
|
||||
},
|
||||
headers: {
|
||||
'User-Angent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
}
|
||||
}).promise
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return createMusicuFetch(data, options, ++retryNum)
|
||||
}
|
||||
if (result.statusCode !== 200 || result.body.code != 0)
|
||||
return createMusicuFetch(data, options, ++retryNum)
|
||||
|
||||
return result.body
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 获取歌手信息
|
||||
* @param {*} id
|
||||
*/
|
||||
getInfo(id) {
|
||||
return createMusicuFetch({
|
||||
req_1: {
|
||||
module: 'music.musichallSinger.SingerInfoInter',
|
||||
method: 'GetSingerDetail',
|
||||
param: {
|
||||
singer_mid: [id],
|
||||
ex_singer: 1,
|
||||
wiki_singer: 1,
|
||||
group_singer: 0,
|
||||
pic: 1,
|
||||
photos: 0
|
||||
}
|
||||
},
|
||||
req_2: {
|
||||
module: 'music.musichallAlbum.AlbumListServer',
|
||||
method: 'GetAlbumList',
|
||||
param: {
|
||||
singerMid: id,
|
||||
order: 0,
|
||||
begin: 0,
|
||||
num: 1,
|
||||
songNumTag: 0,
|
||||
singerID: 0
|
||||
}
|
||||
},
|
||||
req_3: {
|
||||
module: 'musichall.song_list_server',
|
||||
method: 'GetSingerSongList',
|
||||
param: {
|
||||
singerMid: id,
|
||||
order: 1,
|
||||
begin: 0,
|
||||
num: 1
|
||||
}
|
||||
}
|
||||
}).then((body) => {
|
||||
if (body.req_1.code != 0 || body.req_2 != 0 || body.req_3 != 0)
|
||||
throw new Error('get singer info faild.')
|
||||
|
||||
const info = body.req_1.data.singer_list[0]
|
||||
const music = body.req_3.data
|
||||
const album = body.req_3.data
|
||||
return {
|
||||
source: 'tx',
|
||||
id: info.basic_info.singer_mid,
|
||||
info: {
|
||||
name: info.basic_info.name,
|
||||
desc: info.ex_info.desc,
|
||||
avatar: info.pic.pic,
|
||||
gender: info.ex_info.genre === 1 ? 'man' : 'woman'
|
||||
},
|
||||
count: {
|
||||
music: music.totalNum,
|
||||
album: album.total
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取歌手专辑列表
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
* @param {*} limit
|
||||
*/
|
||||
getAlbumList(id, page = 1, limit = 10) {
|
||||
if (page === 1) page = 0
|
||||
return createMusicuFetch({
|
||||
req: {
|
||||
module: 'music.musichallAlbum.AlbumListServer',
|
||||
method: 'GetAlbumList',
|
||||
param: {
|
||||
singerMid: id,
|
||||
order: 0,
|
||||
begin: page * limit,
|
||||
num: limit,
|
||||
songNumTag: 0,
|
||||
singerID: 0
|
||||
}
|
||||
}
|
||||
}).then((body) => {
|
||||
if (body.req.code != 0) throw new Error('get singer album faild.')
|
||||
|
||||
const list = this.filterAlbumList(body.req.data.albumList)
|
||||
return {
|
||||
source: 'tx',
|
||||
list,
|
||||
limit,
|
||||
page,
|
||||
total: body.req.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取歌手歌曲列表
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
* @param {*} limit
|
||||
*/
|
||||
async getSongList(id, page = 1, limit = 100) {
|
||||
if (page === 1) page = 0
|
||||
return createMusicuFetch({
|
||||
req: {
|
||||
module: 'musichall.song_list_server',
|
||||
method: 'GetSingerSongList',
|
||||
param: {
|
||||
singerMid: id,
|
||||
order: 1,
|
||||
begin: page * limit,
|
||||
num: limit
|
||||
}
|
||||
}
|
||||
}).then((body) => {
|
||||
if (body.req.code != 0) throw new Error('get singer song list faild.')
|
||||
|
||||
const list = this.filterSongList(body.req.data.songList)
|
||||
return {
|
||||
source: 'tx',
|
||||
list,
|
||||
limit,
|
||||
page,
|
||||
total: body.req.data.totalNum
|
||||
}
|
||||
})
|
||||
},
|
||||
filterAlbumList(raw) {
|
||||
return raw.map((item) => {
|
||||
return {
|
||||
id: item.albumID,
|
||||
mid: item.albumMid,
|
||||
count: item.totalNum,
|
||||
info: {
|
||||
name: item.albumName,
|
||||
author: item.singerName,
|
||||
img: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.albumMid}.jpg`,
|
||||
desc: null
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
filterSongList(raw) {
|
||||
raw.map((item) => {
|
||||
return filterMusicInfoItem(item.songInfo)
|
||||
})
|
||||
}
|
||||
}
|
||||
351
src/main/utils/musicSdk/tx/songList.js
Normal file
351
src/main/utils/musicSdk/tx/songList.js
Normal file
@@ -0,0 +1,351 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
limit_list: 36,
|
||||
limit_song: 100000,
|
||||
successCode: 0,
|
||||
sortList: [
|
||||
{
|
||||
name: '最热',
|
||||
id: 5
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: 2
|
||||
}
|
||||
],
|
||||
regExps: {
|
||||
hotTagHtml: /class="c_bg_link js_tag_item" data-id="\w+">.+?<\/a>/g,
|
||||
hotTag: /data-id="(\w+)">(.+?)<\/a>/,
|
||||
|
||||
// https://y.qq.com/n/yqq/playlist/7217720898.html
|
||||
// https://i.y.qq.com/n2/m/share/details/taoge.html?platform=11&appshare=android_qq&appversion=9050006&id=7217720898&ADTAG=qfshare
|
||||
listDetailLink: /\/playlist\/(\d+)/,
|
||||
listDetailLink2: /id=(\d+)/
|
||||
},
|
||||
tagsUrl:
|
||||
'https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=%7B%22tags%22%3A%7B%22method%22%3A%22get_all_categories%22%2C%22param%22%3A%7B%22qq%22%3A%22%22%7D%2C%22module%22%3A%22playlist.PlaylistAllCategoriesServer%22%7D%7D',
|
||||
hotTagUrl: 'https://c.y.qq.com/node/pc/wk_v15/category_playlist.html',
|
||||
getListUrl(sortId, id, page) {
|
||||
if (id) {
|
||||
id = parseInt(id)
|
||||
return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(
|
||||
JSON.stringify({
|
||||
comm: { cv: 1602, ct: 20 },
|
||||
playlist: {
|
||||
method: 'get_category_content',
|
||||
param: {
|
||||
titleid: id,
|
||||
caller: '0',
|
||||
category_id: id,
|
||||
size: this.limit_list,
|
||||
page: page - 1,
|
||||
use_page: 1
|
||||
},
|
||||
module: 'playlist.PlayListCategoryServer'
|
||||
}
|
||||
})
|
||||
)}`
|
||||
}
|
||||
return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(
|
||||
JSON.stringify({
|
||||
comm: { cv: 1602, ct: 20 },
|
||||
playlist: {
|
||||
method: 'get_playlist_by_tag',
|
||||
param: {
|
||||
id: 10000000,
|
||||
sin: this.limit_list * (page - 1),
|
||||
size: this.limit_list,
|
||||
order: sortId,
|
||||
cur_page: page
|
||||
},
|
||||
module: 'playlist.PlayListPlazaServer'
|
||||
}
|
||||
})
|
||||
)}`
|
||||
},
|
||||
getListDetailUrl(id) {
|
||||
return `https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&new_format=1&disstid=${id}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0`
|
||||
},
|
||||
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2849349915&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
// 获取标签
|
||||
getTag(tryNum = 0) {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_tags = httpFetch(this.tagsUrl)
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
return this.filterTagInfo(body.tags.data.v_group)
|
||||
})
|
||||
},
|
||||
// 获取标签
|
||||
getHotTag(tryNum = 0) {
|
||||
if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_hotTags = httpFetch(this.hotTagUrl)
|
||||
return this._requestObj_hotTags.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200) return this.getHotTag(++tryNum)
|
||||
return this.filterInfoHotTag(body)
|
||||
})
|
||||
},
|
||||
filterInfoHotTag(html) {
|
||||
let hotTag = html.match(this.regExps.hotTagHtml)
|
||||
const hotTags = []
|
||||
if (!hotTag) return hotTags
|
||||
|
||||
hotTag.forEach((tagHtml) => {
|
||||
let result = tagHtml.match(this.regExps.hotTag)
|
||||
if (!result) return
|
||||
hotTags.push({
|
||||
id: parseInt(result[1]),
|
||||
name: result[2],
|
||||
source: 'tx'
|
||||
})
|
||||
})
|
||||
return hotTags
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return rawList.map((type) => ({
|
||||
name: type.group_name,
|
||||
list: type.v_item.map((item) => ({
|
||||
parent_id: type.group_id,
|
||||
parent_name: type.group_name,
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
source: 'tx'
|
||||
}))
|
||||
}))
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(this.getListUrl(sortId, tagId, page))
|
||||
// console.log(this.getListUrl(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return tagId
|
||||
? this.filterList2(body.playlist.data, page)
|
||||
: this.filterList(body.playlist.data, page)
|
||||
})
|
||||
},
|
||||
|
||||
filterList(data, page) {
|
||||
return {
|
||||
list: data.v_playlist.map((item) => ({
|
||||
play_count: formatPlayCount(item.access_num),
|
||||
id: String(item.tid),
|
||||
author: item.creator_info.nick,
|
||||
name: item.title,
|
||||
time: item.modify_time ? dateFormat(item.modify_time * 1000, 'Y-M-D') : '',
|
||||
img: item.cover_url_medium,
|
||||
// grade: item.favorcnt / 10,
|
||||
total: item.song_ids?.length,
|
||||
desc: decodeName(item.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
})),
|
||||
total: data.total,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'tx'
|
||||
}
|
||||
},
|
||||
filterList2({ content }, page) {
|
||||
// console.log(content.v_item)
|
||||
return {
|
||||
list: content.v_item.map(({ basic }) => ({
|
||||
play_count: formatPlayCount(basic.play_cnt),
|
||||
id: String(basic.tid),
|
||||
author: basic.creator.nick,
|
||||
name: basic.title,
|
||||
// time: basic.publish_time,
|
||||
img: basic.cover.medium_url || basic.cover.default_url,
|
||||
// grade: basic.favorcnt / 10,
|
||||
desc: decodeName(basic.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
})),
|
||||
total: content.total_cnt,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'tx'
|
||||
}
|
||||
},
|
||||
|
||||
async handleParseId(link, retryNum = 0) {
|
||||
if (retryNum > 2) return Promise.reject(new Error('link try max num'))
|
||||
|
||||
const requestObj_listDetailLink = httpFetch(link)
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode
|
||||
} = await requestObj_listDetailLink.promise
|
||||
// console.log(headers)
|
||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||
return location == null ? link : location
|
||||
},
|
||||
|
||||
async getListId(id) {
|
||||
if (/[?&:/]/.test(id)) {
|
||||
if (!this.regExps.listDetailLink.test(id)) {
|
||||
id = await this.handleParseId(id)
|
||||
}
|
||||
let result = this.regExps.listDetailLink.exec(id)
|
||||
if (!result) {
|
||||
result = this.regExps.listDetailLink2.exec(id)
|
||||
if (!result) throw new Error('failed')
|
||||
}
|
||||
id = result[1]
|
||||
// console.log(id)
|
||||
}
|
||||
return id
|
||||
},
|
||||
// 获取歌曲列表内的音乐
|
||||
async getListDetail(id, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
id = await this.getListId(id)
|
||||
|
||||
const requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
||||
headers: {
|
||||
Origin: 'https://y.qq.com',
|
||||
Referer: `https://y.qq.com/n/yqq/playsquare/${id}.html`
|
||||
}
|
||||
})
|
||||
const { body } = await requestObj_listDetail.promise
|
||||
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
|
||||
const cdlist = body.cdlist[0]
|
||||
return {
|
||||
list: this.filterListDetail(cdlist.songlist),
|
||||
page: 1,
|
||||
limit: cdlist.songlist.length + 1,
|
||||
total: cdlist.songlist.length,
|
||||
source: 'tx',
|
||||
info: {
|
||||
name: cdlist.dissname,
|
||||
img: cdlist.logo,
|
||||
desc: decodeName(cdlist.desc).replace(/<br>/g, '\n'),
|
||||
author: cdlist.nickname,
|
||||
play_count: formatPlayCount(cdlist.visitnum)
|
||||
}
|
||||
}
|
||||
},
|
||||
filterListDetail(rawList) {
|
||||
// console.log(rawList)
|
||||
return rawList.map((item) => {
|
||||
let types = []
|
||||
let _types = {}
|
||||
if (item.file.size_128mp3 !== 0) {
|
||||
let size = sizeFormate(item.file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(item.file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_flac !== 0) {
|
||||
let size = sizeFormate(item.file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_hires !== 0) {
|
||||
let size = sizeFormate(item.file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
return {
|
||||
singer: formatSingerName(item.singer, 'name'),
|
||||
name: item.title,
|
||||
albumName: item.album.name,
|
||||
albumId: item.album.mid,
|
||||
source: 'tx',
|
||||
interval: formatPlayTime(item.interval),
|
||||
songId: item.id,
|
||||
albumMid: item.album.mid,
|
||||
strMediaMid: item.file.media_mid,
|
||||
songmid: item.mid,
|
||||
img:
|
||||
item.album.name === '' || item.album.name === '空'
|
||||
? item.singer?.length
|
||||
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
|
||||
: ''
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.album.mid}.jpg`,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
getTags() {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({
|
||||
tags,
|
||||
hotTag,
|
||||
source: 'tx'
|
||||
}))
|
||||
},
|
||||
|
||||
async getDetailPageUrl(id) {
|
||||
id = await this.getListId(id)
|
||||
|
||||
return `https://y.qq.com/n/ryqq/playlist/${id}`
|
||||
},
|
||||
|
||||
search(text, page, limit = 20, retryNum = 0) {
|
||||
if (retryNum > 5) throw new Error('max retry')
|
||||
return httpFetch(
|
||||
`http://c.y.qq.com/soso/fcgi-bin/client_music_search_songlist?page_no=${page - 1}&num_per_page=${limit}&format=json&query=${encodeURIComponent(text)}&remoteplace=txt.yqq.playlist&inCharset=utf8&outCharset=utf-8`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
|
||||
Referer: 'http://y.qq.com/portal/search.html'
|
||||
}
|
||||
}
|
||||
).promise.then(({ body }) => {
|
||||
if (body.code != 0) return this.search(text, page, limit, ++retryNum)
|
||||
// console.log(body.data.list)
|
||||
return {
|
||||
list: body.data.list.map((item) => {
|
||||
return {
|
||||
play_count: formatPlayCount(item.listennum),
|
||||
id: String(item.dissid),
|
||||
author: decodeName(item.creator.name),
|
||||
name: decodeName(item.dissname),
|
||||
time: dateFormat(item.createtime, 'Y-M-D'),
|
||||
img: item.imgurl,
|
||||
// grade: item.favorcnt / 10,
|
||||
total: item.song_count,
|
||||
desc: decodeName(decodeName(item.introduction)).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: body.data.sum,
|
||||
source: 'tx'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
32
src/main/utils/musicSdk/tx/tipSearch.js
Normal file
32
src/main/utils/musicSdk/tx/tipSearch.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { httpFetch } from '../../request'
|
||||
|
||||
export default {
|
||||
// regExps: {
|
||||
// relWord: /RELWORD=(.+)/,
|
||||
// },
|
||||
requestObj: null,
|
||||
tipSearch(str) {
|
||||
this.cancelTipSearch()
|
||||
this.requestObj = httpFetch(
|
||||
`https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?is_xml=0&format=json&key=${encodeURIComponent(str)}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0`,
|
||||
{
|
||||
headers: {
|
||||
Referer: 'https://y.qq.com/portal/player.html'
|
||||
}
|
||||
}
|
||||
)
|
||||
return this.requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode != 200 || body.code != 0) return Promise.reject(new Error('请求失败'))
|
||||
return body.data
|
||||
})
|
||||
},
|
||||
handleResult(rawData) {
|
||||
return rawData.map((info) => `${info.name} - ${info.singer}`)
|
||||
},
|
||||
cancelTipSearch() {
|
||||
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
|
||||
},
|
||||
async search(str) {
|
||||
return this.tipSearch(str).then((result) => this.handleResult(result.song.itemlist))
|
||||
}
|
||||
}
|
||||
52
src/main/utils/musicSdk/utils.js
Normal file
52
src/main/utils/musicSdk/utils.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import crypto from 'crypto'
|
||||
import dns from 'dns'
|
||||
import { decodeName } from '../utils'
|
||||
|
||||
export const toMD5 = (str) => crypto.createHash('md5').update(str).digest('hex')
|
||||
|
||||
const ipMap = new Map()
|
||||
export const getHostIp = (hostname) => {
|
||||
const result = ipMap.get(hostname)
|
||||
if (typeof result === 'object') return result
|
||||
if (result === true) return
|
||||
ipMap.set(hostname, true)
|
||||
// console.log(hostname)
|
||||
dns.lookup(
|
||||
hostname,
|
||||
{
|
||||
// family: 4,
|
||||
all: false
|
||||
},
|
||||
(err, address, family) => {
|
||||
if (err) return console.log(err)
|
||||
// console.log(address, family)
|
||||
ipMap.set(hostname, { address, family })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const dnsLookup = (hostname, options, callback) => {
|
||||
const result = getHostIp(hostname)
|
||||
if (result) return callback(null, result.address, result.family)
|
||||
|
||||
dns.lookup(hostname, options, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化歌手
|
||||
* @param singers 歌手数组
|
||||
* @param nameKey 歌手名键值
|
||||
* @param join 歌手分割字符
|
||||
*/
|
||||
export const formatSingerName = (singers, nameKey = 'name', join = '、') => {
|
||||
if (Array.isArray(singers)) {
|
||||
const singer = []
|
||||
singers.forEach((item) => {
|
||||
let name = item[nameKey]
|
||||
if (!name) return
|
||||
singer.push(name)
|
||||
})
|
||||
return decodeName(singer.join(join))
|
||||
}
|
||||
return decodeName(String(singers ?? ''))
|
||||
}
|
||||
52
src/main/utils/musicSdk/wy/api-test.js
Normal file
52
src/main/utils/musicSdk/wy/api-test.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
import { dnsLookup } from '../utils'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusics.tk/url/wy/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
lookup: dnsLookup,
|
||||
family: 4
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode == 429) return Promise.reject(new Error(requestMsg.tooManyRequests))
|
||||
switch (body.code) {
|
||||
case 0:
|
||||
return Promise.resolve({ type, url: body.data })
|
||||
default:
|
||||
return Promise.reject(new Error(requestMsg.fail))
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
/* getPic(songInfo) {
|
||||
const requestObj = httpFetch(`http://localhost:3100/pic/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
family: 4,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFetch(`http://localhost:3100/lrc/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
family: 4,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
}, */
|
||||
}
|
||||
|
||||
export default api_test
|
||||
224
src/main/utils/musicSdk/wy/comment.js
Normal file
224
src/main/utils/musicSdk/wy/comment.js
Normal file
@@ -0,0 +1,224 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { weapi } from './utils/crypto'
|
||||
import { dateFormat2 } from '../index'
|
||||
|
||||
const emojis = [
|
||||
['大笑', '😃'],
|
||||
['可爱', '😊'],
|
||||
['憨笑', '☺️'],
|
||||
['色', '😍'],
|
||||
['亲亲', '😙'],
|
||||
['惊恐', '😱'],
|
||||
['流泪', '😭'],
|
||||
['亲', '😚'],
|
||||
['呆', '😳'],
|
||||
['哀伤', '😔'],
|
||||
['呲牙', '😁'],
|
||||
['吐舌', '😝'],
|
||||
['撇嘴', '😒'],
|
||||
['怒', '😡'],
|
||||
['奸笑', '😏'],
|
||||
['汗', '😓'],
|
||||
['痛苦', '😖'],
|
||||
['惶恐', '😰'],
|
||||
['生病', '😨'],
|
||||
['口罩', '😷'],
|
||||
['大哭', '😂'],
|
||||
['晕', '😵'],
|
||||
['发怒', '👿'],
|
||||
['开心', '😄'],
|
||||
['鬼脸', '😜'],
|
||||
['皱眉', '😞'],
|
||||
['流感', '😢'],
|
||||
['爱心', '❤️'],
|
||||
['心碎', '💔'],
|
||||
['钟情', '💘'],
|
||||
['星星', '⭐️'],
|
||||
['生气', '💢'],
|
||||
['便便', '💩'],
|
||||
['强', '👍'],
|
||||
['弱', '👎'],
|
||||
['拜', '🙏'],
|
||||
['牵手', '👫'],
|
||||
['跳舞', '👯♀️'],
|
||||
['禁止', '🙅♀️'],
|
||||
['这边', '💁♀️'],
|
||||
['爱意', '💏'],
|
||||
['示爱', '👩❤️👨'],
|
||||
['嘴唇', '👄'],
|
||||
['狗', '🐶'],
|
||||
['猫', '🐱'],
|
||||
['猪', '🐷'],
|
||||
['兔子', '🐰'],
|
||||
['小鸡', '🐤'],
|
||||
['公鸡', '🐔'],
|
||||
['幽灵', '👻'],
|
||||
['圣诞', '🎅'],
|
||||
['外星', '👽'],
|
||||
['钻石', '💎'],
|
||||
['礼物', '🎁'],
|
||||
['男孩', '👦'],
|
||||
['女孩', '👧'],
|
||||
['蛋糕', '🎂'],
|
||||
['18', '🔞'],
|
||||
['圈', '⭕'],
|
||||
['叉', '❌']
|
||||
]
|
||||
|
||||
const applyEmoji = (text) => {
|
||||
for (const e of emojis) text = text.replaceAll(`[${e[0]}]`, e[1])
|
||||
return text
|
||||
}
|
||||
|
||||
let cursorTools = {
|
||||
cache: {},
|
||||
getCursor(id, page, limit) {
|
||||
let cacheData = this.cache[id]
|
||||
if (!cacheData) cacheData = this.cache[id] = {}
|
||||
let orderType
|
||||
let cursor
|
||||
let offset
|
||||
if (page == 1) {
|
||||
cacheData.page = 1
|
||||
cursor = cacheData.cursor = cacheData.prevCursor = Date.now()
|
||||
orderType = 1
|
||||
offset = 0
|
||||
} else if (cacheData.page) {
|
||||
cursor = cacheData.cursor
|
||||
if (page > cacheData.page) {
|
||||
orderType = 1
|
||||
offset = (page - cacheData.page - 1) * limit
|
||||
} else if (page < cacheData.page) {
|
||||
orderType = 0
|
||||
offset = (cacheData.page - page - 1) * limit
|
||||
} else {
|
||||
cursor = cacheData.cursor = cacheData.prevCursor
|
||||
offset = cacheData.offset
|
||||
orderType = cacheData.orderType
|
||||
}
|
||||
}
|
||||
return {
|
||||
orderType,
|
||||
cursor,
|
||||
offset
|
||||
}
|
||||
},
|
||||
setCursor(id, cursor, orderType, offset, page) {
|
||||
let cacheData = this.cache[id]
|
||||
if (!cacheData) cacheData = this.cache[id] = {}
|
||||
cacheData.prevCursor = cacheData.cursor
|
||||
cacheData.cursor = cursor
|
||||
cacheData.orderType = orderType
|
||||
cacheData.offset = offset
|
||||
cacheData.page = page
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
async getComment({ songmid }, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
|
||||
const id = 'R_SO_4_' + songmid
|
||||
|
||||
const cursorInfo = cursorTools.getCursor(songmid, page, limit)
|
||||
|
||||
const _requestObj = httpFetch('https://music.163.com/weapi/comment/resource/comments/get', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
origin: 'https://music.163.com',
|
||||
Refere: 'http://music.163.com/'
|
||||
},
|
||||
form: weapi({
|
||||
cursor: cursorInfo.cursor,
|
||||
offset: cursorInfo.offset,
|
||||
orderType: cursorInfo.orderType,
|
||||
pageNo: page,
|
||||
pageSize: limit,
|
||||
rid: id,
|
||||
threadId: id
|
||||
})
|
||||
})
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.code !== 200) throw new Error('获取评论失败')
|
||||
cursorTools.setCursor(songmid, body.data.cursor, cursorInfo.orderType, cursorInfo.offset, page)
|
||||
return {
|
||||
source: 'wy',
|
||||
comments: this.filterComment(body.data.comments),
|
||||
total: body.data.totalCount,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(body.data.totalCount / limit) || 1
|
||||
}
|
||||
},
|
||||
async getHotComment({ songmid }, page = 1, limit = 100) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
|
||||
const id = 'R_SO_4_' + songmid
|
||||
page = page - 1
|
||||
|
||||
const _requestObj2 = httpFetch(`https://music.163.com/weapi/v1/resource/hotcomments/${id}`, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
origin: 'https://music.163.com',
|
||||
Refere: 'http://music.163.com/'
|
||||
},
|
||||
form: weapi({
|
||||
rid: id,
|
||||
limit,
|
||||
offset: limit * page,
|
||||
beforeTime: Date.now().toString()
|
||||
})
|
||||
})
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
if (statusCode != 200 || body.code !== 200) throw new Error('获取热门评论失败')
|
||||
const total = body.total ?? 0
|
||||
return {
|
||||
source: 'wy',
|
||||
comments: this.filterComment(body.hotComments),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
maxPage: Math.ceil(total / limit) || 1
|
||||
}
|
||||
},
|
||||
filterComment(rawList) {
|
||||
return rawList.map((item) => {
|
||||
let data = {
|
||||
id: item.commentId,
|
||||
text: item.content ? applyEmoji(item.content) : '',
|
||||
time: item.time ? item.time : '',
|
||||
timeStr: item.time ? dateFormat2(item.time) : '',
|
||||
location: item.ipLocation?.location,
|
||||
userName: item.user.nickname,
|
||||
avatar: item.user.avatarUrl,
|
||||
userId: item.user.userId,
|
||||
likedCount: item.likedCount,
|
||||
reply: []
|
||||
}
|
||||
|
||||
let replyData = item.beReplied && item.beReplied[0]
|
||||
return replyData
|
||||
? {
|
||||
id: item.commentId,
|
||||
rootId: replyData.beRepliedCommentId,
|
||||
text: replyData.content ? applyEmoji(replyData.content) : '',
|
||||
time: item.time,
|
||||
timeStr: null,
|
||||
location: replyData.ipLocation?.location,
|
||||
userName: replyData.user.nickname,
|
||||
avatar: replyData.user.avatarUrl,
|
||||
userId: replyData.user.userId,
|
||||
likedCount: null,
|
||||
reply: [data]
|
||||
}
|
||||
: data
|
||||
})
|
||||
}
|
||||
}
|
||||
20
src/main/utils/musicSdk/wy/hotSearch.js
Normal file
20
src/main/utils/musicSdk/wy/hotSearch.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { eapiRequest } from './utils/index'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const _requestObj = eapiRequest('/api/search/chart/detail', {
|
||||
id: 'HOT_SEARCH_SONG#@#'
|
||||
})
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
if (statusCode != 200 || body.code !== 200) throw new Error('获取热搜词失败')
|
||||
|
||||
return { source: 'wy', list: this.filterList(body.data.itemList) }
|
||||
},
|
||||
filterList(rawList) {
|
||||
return rawList.map((item) => item.searchWord)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user