feat(logger}: 支持更好的日志输出, 完善了文档

This commit is contained in:
ImFurina 2025-08-24 15:01:05 +08:00
parent 11e1c62cc3
commit ceb2044500
27 changed files with 915 additions and 832 deletions

View File

@ -1,4 +1,7 @@
# 更新日志 # 更新日志
## 二开作者注: 这些`commit`记录为原版网易云音乐API的记录, 本项目不会对其进行添加以及修改
### 4.25.0 | 2024.11.16 ### 4.25.0 | 2024.11.16
- feat: 增加副歌时间、相关歌单推荐接口原有相关歌单接口已废弃fix: 将部分易盾白名单接口替换为eapi [#30](https://gitlab.com/Binaryify/neteasecloudmusicapi/-/merge_requests/30) - feat: 增加副歌时间、相关歌单推荐接口原有相关歌单接口已废弃fix: 将部分易盾白名单接口替换为eapi [#30](https://gitlab.com/Binaryify/neteasecloudmusicapi/-/merge_requests/30)
- fix: 播客上传接口 [#32](https://gitlab.com/Binaryify/neteasecloudmusicapi/-/merge_requests/32) - fix: 播客上传接口 [#32](https://gitlab.com/Binaryify/neteasecloudmusicapi/-/merge_requests/32)

View File

@ -1,4 +1,4 @@
# 网易云音乐 API Enhanced(Reborn) # 网易云音乐 API Enhanced
--- ---
@ -34,16 +34,18 @@ set PORT=4000 && node app.js # Windows
### 重要提示 ### 重要提示
- 调用前请务必阅读文档的“调用前须知”部分。 - 调用前请务必阅读文档的 [调用前须知](https://music-api.focalors.ltd/#/?id=%e8%b0%83%e7%94%a8%e5%89%8d%e9%a1%bb%e7%9f%a5) 部分。
- 推荐将敏感信息(如 cookie通过部署平台的环境变量进行配置。 - 推荐将敏感信息(如 cookie通过部署平台的环境变量进行配置。
## 在线体验与文档 ## 在线体验与文档
- [在线文档](https://music-api.focalors.ltd/docs/#) - [在线文档](https://music-api.focalors.ltd/)
- [NPM 包地址](https://www.npmjs.com/package/@neteaseapireborn/api) - [NPM 包地址](https://www.npmjs.com/package/@neteaseapireborn/api)
## 常见部署方式 ## 常见部署方式
- 推荐参考[在线文档](https://music-api.focalors.ltd/)
### Vercel 一键部署 ### Vercel 一键部署
1. fork 本项目 1. fork 本项目
@ -114,4 +116,3 @@ pnpm test
## License ## License
[MIT License](https://github.com/IamFurina/NeteaseCloudMusicApiReborn/blob/main/LICENSE) [MIT License](https://github.com/IamFurina/NeteaseCloudMusicApiReborn/blob/main/LICENSE)
console.log(error)

View File

@ -1,6 +1,7 @@
const fsPromises = require('fs/promises') const fsPromises = require('fs/promises')
const path = require('path') const path = require('path')
const server = require('../server') const server = require('../server')
const logger = require('../util/logger.js')
const exportFile = path.join(__dirname, 'moddef.json') const exportFile = path.join(__dirname, 'moddef.json')
@ -16,7 +17,7 @@ async function main() {
) )
fsPromises.writeFile(exportFile, JSON.stringify(def, null, 4)) fsPromises.writeFile(exportFile, JSON.stringify(def, null, 4))
console.log(`👍 Get your own definition at: ${exportFile}`) logger.info(`👍 Get your own definition at: ${exportFile}`)
} }
main() main()

View File

@ -4,6 +4,7 @@
// 可按需修改此 API 的代码 // 可按需修改此 API 的代码
/* {"extInfo":"{\"lastRequestTimestamp\":1692358373509,\"lbsInfoList\":[{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692358543},{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692055283}],\"listenedTs\":false,\"noAidjToAidj\":true}","header":"{}"} */ /* {"extInfo":"{\"lastRequestTimestamp\":1692358373509,\"lbsInfoList\":[{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692358543},{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692055283}],\"listenedTs\":false,\"noAidjToAidj\":true}","header":"{}"} */
const logger = require('../util/logger.js')
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
module.exports = (query, request) => { module.exports = (query, request) => {
var extInfo = {} var extInfo = {}
@ -22,6 +23,6 @@ module.exports = (query, request) => {
const data = { const data = {
extInfo: JSON.stringify(extInfo), extInfo: JSON.stringify(extInfo),
} }
// console.log(data) // logger.info(data)
return request(`/api/aidj/content/rcmd/info`, data, createOption(query)) return request(`/api/aidj/content/rcmd/info`, data, createOption(query))
} }

View File

@ -2,6 +2,7 @@ const mm = require('music-metadata')
const uploadPlugin = require('../plugins/songUpload') const uploadPlugin = require('../plugins/songUpload')
const md5 = require('md5') const md5 = require('md5')
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
let ext = 'mp3' let ext = 'mp3'
// if (query.songFile.name.indexOf('flac') > -1) { // if (query.songFile.name.indexOf('flac') > -1) {
@ -65,7 +66,7 @@ module.exports = async (query, request) => {
} }
// if (metadata.native.ID3v1) { // if (metadata.native.ID3v1) {
// metadata.native.ID3v1.forEach((item) => { // metadata.native.ID3v1.forEach((item) => {
// // console.log(item.id, item.value) // // logger.info(item.id, item.value)
// if (item.id === 'title') { // if (item.id === 'title') {
// songName = item.value // songName = item.value
// } // }
@ -76,19 +77,19 @@ module.exports = async (query, request) => {
// album = item.value // album = item.value
// } // }
// }) // })
// // console.log({ // // logger.info({
// // songName, // // songName,
// // album, // // album,
// // songName, // // songName,
// // }) // // })
// } // }
// console.log({ // logger.info({
// songName, // songName,
// album, // album,
// songName, // songName,
// }) // })
} catch (error) { } catch (error) {
console.log(error) logger.info(error)
} }
const tokenRes = await request( const tokenRes = await request(
`/api/nos/token/alloc`, `/api/nos/token/alloc`,
@ -106,9 +107,9 @@ module.exports = async (query, request) => {
if (res.body.needUpload) { if (res.body.needUpload) {
const uploadInfo = await uploadPlugin(query, request) const uploadInfo = await uploadPlugin(query, request)
// console.log('uploadInfo', uploadInfo.body.result.resourceId) // logger.info('uploadInfo', uploadInfo.body.result.resourceId)
} }
// console.log(tokenRes.body.result) // logger.info(tokenRes.body.result)
const res2 = await request( const res2 = await request(
`/api/upload/cloud/info/v2`, `/api/upload/cloud/info/v2`,
{ {
@ -123,8 +124,8 @@ module.exports = async (query, request) => {
}, },
createOption(query), createOption(query),
) )
// console.log({ res2, privateCloud: res2.body.privateCloud }) // logger.info({ res2, privateCloud: res2.body.privateCloud })
// console.log(res.body.songId, 'songid') // logger.info(res.body.songId, 'songid')
const res3 = await request( const res3 = await request(
`/api/cloud/pub/v2`, `/api/cloud/pub/v2`,
{ {
@ -132,7 +133,7 @@ module.exports = async (query, request) => {
}, },
createOption(query), createOption(query),
) )
// console.log({ res3 }) // logger.info({ res3 })
return { return {
status: 200, status: 200,
body: { body: {

View File

@ -1,4 +1,5 @@
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
query.ids = query.ids || '' query.ids = query.ids || ''
const data = { const data = {
@ -9,7 +10,7 @@ module.exports = async (query, request) => {
}), }),
), ),
} }
console.log(data) logger.info(data)
return request(`/api/playlist/track/add`, data, createOption(query, 'weapi')) return request(`/api/playlist/track/add`, data, createOption(query, 'weapi'))
} }

View File

@ -2,7 +2,7 @@
// 支持qq音乐、酷狗音乐、酷我音乐、咪咕音乐、第三方网易云API等等(来自GD音乐台) // 支持qq音乐、酷狗音乐、酷我音乐、咪咕音乐、第三方网易云API等等(来自GD音乐台)
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
try { try {
@ -12,7 +12,7 @@ module.exports = async (query, request) => {
const server = query.server ? query.server.split(',') : query.server const server = query.server ? query.server.split(',') : query.server
const result = await match(query.id, !server? source : server) const result = await match(query.id, !server? source : server)
const proxy = process.env.PROXY_URL; const proxy = process.env.PROXY_URL;
console.log("[OK] 开始解灰", query.id, result) logger.info("开始解灰", query.id, result)
const useProxy = process.env.ENABLE_PROXY || "false" const useProxy = process.env.ENABLE_PROXY || "false"
if (result.url.includes('kuwo')) { result.proxyUrl = useProxy === 'true' ? proxy + result.url : result.url } if (result.url.includes('kuwo')) { result.proxyUrl = useProxy === 'true' ? proxy + result.url : result.url }
return { return {

View File

@ -2,7 +2,7 @@
// 支持qq音乐、酷狗音乐、酷我音乐、咪咕音乐、第三方网易云API等等(来自GD音乐台) // 支持qq音乐、酷狗音乐、酷我音乐、咪咕音乐、第三方网易云API等等(来自GD音乐台)
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
try { try {
@ -12,7 +12,7 @@ module.exports = async (query, request) => {
const server = query.server ? query.server.split(',') : query.server const server = query.server ? query.server.split(',') : query.server
const result = await match(query.id, !server? source : server) const result = await match(query.id, !server? source : server)
const proxy = process.env.PROXY_URL; const proxy = process.env.PROXY_URL;
console.log("[OK] 开始解灰", query.id, result) logger.info("开始解灰", query.id, result)
const useProxy = process.env.ENABLE_PROXY || "false" const useProxy = process.env.ENABLE_PROXY || "false"
if (result.url.includes('kuwo') && useProxy === "true") { result.proxyUrl = proxy + result.url } if (result.url.includes('kuwo') && useProxy === "true") { result.proxyUrl = proxy + result.url }
return { return {

View File

@ -3,6 +3,7 @@
// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断 // 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断
// 当unblock为true时, 会尝试使用unblockneteasemusic进行解锁, 同时音质设置不会生效, 但仍然为必须传入参数 // 当unblock为true时, 会尝试使用unblockneteasemusic进行解锁, 同时音质设置不会生效, 但仍然为必须传入参数
const logger = require('../util/logger.js')
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
const match = require('@unblockneteasemusic/server') const match = require('@unblockneteasemusic/server')
@ -16,7 +17,7 @@ module.exports = async (query, request) => {
if (query.unblock === 'true') { if (query.unblock === 'true') {
try { try {
const result = await match(query.id, source) const result = await match(query.id, source)
console.log('[OK] 开始解灰', query.id, result) logger.info('开始解灰', query.id, result)
if (result.url.includes('kuwo')) { if (result.url.includes('kuwo')) {
const useProxy = process.env.ENABLE_PROXY || 'false' const useProxy = process.env.ENABLE_PROXY || 'false'
var proxyUrl = useProxy === 'true' ? process.env.PROXY_URL + result.url : result.url var proxyUrl = useProxy === 'true' ? process.env.PROXY_URL + result.url : result.url

View File

@ -1,4 +1,5 @@
const { eapiResDecrypt, eapiReqDecrypt } = require('../util/crypto') const { eapiResDecrypt, eapiReqDecrypt } = require('../util/crypto')
const logger = require('../util/logger.js')
let reqParamsHex = let reqParamsHex =
'6E0B1C712DCB3648589D7C950C296204072A88C3E080C4CFFD0A71A553EC2533BA88E11B1E1C6DF3BE8EFA26177FCB6FCA34EB3FAFAB4671B2BBAFA9781AFDA2BF53A3DC423722493837B9BC6E80CED5BBD2DDC2856920E4D4E3E7F3EB77ECF265217A66AE677BE36F2D6FB203F721CA250E1453EA61A34904E33D5FCB9D483601D744BE0AE979AC911A00F25828538844F4B1C24F6C34880A4AB257F530C7FB10A81FED32B18D09D70C0B1B9D34A2E58A3C3FAD382C6F958077059C4F801AD7B3B248FDB9D7A59B6A9EEFF8C781A84315B33A7AFD48BE9FCFCBE1902CCC27949ACF2BDE3FA34D116E230C3597E8320B8C42BBBF371A00C03EC428E0440EB94C1540F3FD4173D29E310AFE43AB0EF449852904103EF305FC435AD43B7D8673642F74C89CCB2F1A6A79B3BE14F1235D3843C3B241D12C05DBDDF37B68CA8B5D0230AF1FCF2A9705886F4D126B33FFF6948DE1E4046DB6423D687E96C5B65122464D2E71AEC7722935FF2C3796FAE253A16AA3B102FBE7296AB0DB9EA5C46AD12B'.replaceAll( '6E0B1C712DCB3648589D7C950C296204072A88C3E080C4CFFD0A71A553EC2533BA88E11B1E1C6DF3BE8EFA26177FCB6FCA34EB3FAFAB4671B2BBAFA9781AFDA2BF53A3DC423722493837B9BC6E80CED5BBD2DDC2856920E4D4E3E7F3EB77ECF265217A66AE677BE36F2D6FB203F721CA250E1453EA61A34904E33D5FCB9D483601D744BE0AE979AC911A00F25828538844F4B1C24F6C34880A4AB257F530C7FB10A81FED32B18D09D70C0B1B9D34A2E58A3C3FAD382C6F958077059C4F801AD7B3B248FDB9D7A59B6A9EEFF8C781A84315B33A7AFD48BE9FCFCBE1902CCC27949ACF2BDE3FA34D116E230C3597E8320B8C42BBBF371A00C03EC428E0440EB94C1540F3FD4173D29E310AFE43AB0EF449852904103EF305FC435AD43B7D8673642F74C89CCB2F1A6A79B3BE14F1235D3843C3B241D12C05DBDDF37B68CA8B5D0230AF1FCF2A9705886F4D126B33FFF6948DE1E4046DB6423D687E96C5B65122464D2E71AEC7722935FF2C3796FAE253A16AA3B102FBE7296AB0DB9EA5C46AD12B'.replaceAll(
@ -10,6 +11,6 @@ const resHex =
' ', ' ',
'', '',
) )
console.log(reqParamsHex) logger.info(reqParamsHex)
console.log(eapiReqDecrypt(reqParamsHex)) logger.info(eapiReqDecrypt(reqParamsHex))
console.log(eapiResDecrypt(resHex)) logger.info(eapiResDecrypt(resHex))

View File

@ -2,6 +2,7 @@ const { cloud, login_cellphone } = require('../main')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const yargs = require('yargs') const yargs = require('yargs')
const logger = require('../util/logger.js')
const MUSIC_FILE_EXTENSIONS = new Set(['.mp3', '.flac']) const MUSIC_FILE_EXTENSIONS = new Set(['.mp3', '.flac'])
@ -37,11 +38,11 @@ async function uploadArrayOfFile(token, arrayOfFiles) {
cookie: token.body.cookie, cookie: token.body.cookie,
}) })
} catch (error) { } catch (error) {
console.log(error) logger.info(error)
failed += 1 failed += 1
failedFiles.push(file) failedFiles.push(file)
} }
console.log(`Uploaded ${k + 1}/${fileCount} songs`) logger.info(`Uploaded ${k + 1}/${fileCount} songs`)
} }
return { failedFiles, failed } return { failedFiles, failed }
} }
@ -86,19 +87,19 @@ async function main() {
const files = args.file ? [args.file] : getAllMusicFiles(args.dir) const files = args.file ? [args.file] : getAllMusicFiles(args.dir)
const fileCount = files.length const fileCount = files.length
console.log(`Found ${fileCount} files, uploading...`) logger.info(`Found ${fileCount} files, uploading...`)
let res = await uploadArrayOfFile(token, files) let res = await uploadArrayOfFile(token, files)
if (res.failed) { if (res.failed) {
console.log(`Failed to upload ${res.failed} songs, retrying...`) logger.info(`Failed to upload ${res.failed} songs, retrying...`)
res = await uploadArrayOfFile(token, res.failedFiles) res = await uploadArrayOfFile(token, res.failedFiles)
} }
console.log(`Uploaded ${fileCount - res.failed} songs`) logger.info(`Uploaded ${fileCount - res.failed} songs`)
console.log( logger.info(
`Failed to upload ${res.failed} songs, you can reupload the files below`, `Failed to upload ${res.failed} songs, you can reupload the files below`,
) )
for (let k in res.failedFiles) { for (let k in res.failedFiles) {
console.log(res.failedFiles[k]) logger.info(res.failedFiles[k])
} }
} }
main() main()

View File

@ -1,6 +1,7 @@
const { cloud, login_cellphone } = require('../main') const { cloud, login_cellphone } = require('../main')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const logger = require('../util/logger.js')
async function main() { async function main() {
const result = await login_cellphone({ const result = await login_cellphone({
@ -17,7 +18,7 @@ async function main() {
cookie: result.body.cookie, cookie: result.body.cookie,
}) })
} catch (error) { } catch (error) {
console.log(error, 'error') logger.info(error, 'error')
} }
} }
main() main()

View File

@ -1,3 +1,4 @@
const logger = require('../util/logger.js')
const { const {
login_cellphone, login_cellphone,
user_cloud, user_cloud,
@ -10,22 +11,22 @@ async function test() {
phone: '手机号', phone: '手机号',
password: '密码', password: '密码',
}) })
console.log(result) logger.info(result)
const result2 = await user_cloud({ const result2 = await user_cloud({
cookie: result.body.cookie, cookie: result.body.cookie,
}) })
console.log(result2.body) logger.info(result2.body)
const result3 = await album_sublist({ const result3 = await album_sublist({
cookie: result.body.cookie, cookie: result.body.cookie,
}) })
console.log(result3.body) logger.info(result3.body)
const result4 = await song_url({ const result4 = await song_url({
cookie: result.body.cookie, cookie: result.body.cookie,
id: 33894312, id: 33894312,
}) })
console.log(result4.body) logger.info(result4.body)
} catch (error) { } catch (error) {
console.log(error) logger.info(error)
} }
} }
test() test()

View File

@ -1,9 +1,10 @@
import { banner, lyric } from '@neteaseapireborn/api' import { banner, lyric } from '@neteaseapireborn/api'
import { logger } from '../util/logger.js'
banner({ type: 0 }).then((res) => { banner({ type: 0 }).then((res) => {
console.log(res) logger.info(res)
}) })
lyric({ lyric({
id: '33894312', id: '33894312',
}).then((res) => { }).then((res) => {
console.log(res) logger.info(res)
}) })

View File

@ -1,5 +1,6 @@
const { default: axios } = require('axios') const { default: axios } = require('axios')
const createOption = require('../util/option.js') const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => { module.exports = async (query, request) => {
let ext = 'mp3' let ext = 'mp3'
// if (query.songFile.name.indexOf('flac') > -1) { // if (query.songFile.name.indexOf('flac') > -1) {
@ -51,7 +52,7 @@ module.exports = async (query, request) => {
maxBodyLength: Infinity, maxBodyLength: Infinity,
}) })
} catch (error) { } catch (error) {
console.log('error', error.response) logger.info('error', error.response)
throw error.response throw error.response
} }
return { return {

View File

@ -1,5 +1,6 @@
'use strict' 'use strict'
const WASM_BINARY_PLACEHOLDER = 'WASM_BINARY_PLACEHOLDER'; const WASM_BINARY_PLACEHOLDER = 'WASM_BINARY_PLACEHOLDER';
const logger = require('../../util/logger.js')
// See https://github.com/Distributive-Network/PythonMonkey/issues/266 // See https://github.com/Distributive-Network/PythonMonkey/issues/266
if (typeof globalThis.setInterval != 'function'){ if (typeof globalThis.setInterval != 'function'){
globalThis.setInterval = function pm$$setInterval(fn, timeout) { globalThis.setInterval = function pm$$setInterval(fn, timeout) {
@ -1611,9 +1612,9 @@ function instantiateRuntime(){
function GenerateFP(floatArray) { function GenerateFP(floatArray) {
let PCMBuffer = Float32Array.from(floatArray) let PCMBuffer = Float32Array.from(floatArray)
console.log('[afp] input samples n=', PCMBuffer.length) logger.info('[afp] input samples n=', PCMBuffer.length)
return instantiateRuntime().then((fpRuntime) => { return instantiateRuntime().then((fpRuntime) => {
console.log('[afp] begin fingerprinting') logger.info('[afp] begin fingerprinting')
let fp_vector = fpRuntime.ExtractQueryFP(PCMBuffer.buffer) let fp_vector = fpRuntime.ExtractQueryFP(PCMBuffer.buffer)
let result_buf = new Uint8Array(fp_vector.size()); let result_buf = new Uint8Array(fp_vector.size());
for (let t = 0; t < fp_vector.size(); t++) for (let t = 0; t < fp_vector.size(); t++)

View File

@ -1,99 +1,104 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh"> <html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>云盘上传</title>
</head>
<head> <body>
<meta charset="UTF-8" /> <div>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <a href="/qrlogin-nocookie.html"> 如果没登录,请先登录 </a>
<title>云盘上传</title> </div>
</head> <input id="file" type="file" multiple />
<div id="app">
<ul>
<li v-for="(item,index) in songs" :key="index">{{item.songName}}</li>
</ul>
</div>
<body> <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<div> <script src="https://fastly.jsdelivr.net/npm/vue"></script>
<a href="/qrlogin-nocookie.html"> <script>
如果没登录,请先登录 const logger = require('../util/logger.js')
</a> const app = Vue.createApp({
</div> data() {
<input id="file" type="file" multiple /> return {
<div id="app"> songs: [],
<ul>
<li v-for="(item,index) in songs" :key="index">
{{item.songName}}
</li>
</ul>
</div>
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<script src="https://fastly.jsdelivr.net/npm/vue"></script>
<script>
const app = Vue.createApp({
data() {
return {
songs: []
}
},
created() {
this.getData()
},
methods: {
getData() {
console.log('getdata');
const _this = this
axios({
url: `/user/cloud?time=${Date.now()}&cookie=${localStorage.getItem('cookie')}`,
}).then(res => {
console.log(res.data)
_this.songs = res.data.data
})
}
}
}).mount('#app')
const fileUpdateTime = {}
let fileLength = 0
function main() {
document
.querySelector('input[type="file"]')
.addEventListener('change', function (e) {
console.log(this.files)
let currentIndx = 0
fileLength = this.files.length
for (const item of this.files) {
currentIndx += 1
upload(item, currentIndx)
} }
})
}
main()
function upload(file, currentIndx) {
var formData = new FormData()
formData.append('songFile', file)
axios({
method: 'post',
url: `/cloud?time=${Date.now()}&cookie=${localStorage.getItem('cookie')}`,
headers: {
'Content-Type': 'multipart/form-data',
}, },
data: formData, created() {
}).then(res => { this.getData()
console.log(`${file.name} 上传成功`) },
if (currentIndx >= fileLength) { console.log('上传完毕') } methods: {
app.getData() getData() {
}).catch(async err => { logger.info('getdata')
console.log(err) const _this = this
console.log(fileUpdateTime) axios({
fileUpdateTime[file.name] ? fileUpdateTime[file.name] += 1 : fileUpdateTime[file.name] = 1 url: `/user/cloud?time=${Date.now()}&cookie=${localStorage.getItem(
if (fileUpdateTime[file.name] >= 4) { 'cookie',
console.error(`丢,这首歌怎么都传不上:${file.name}`) )}`,
return }).then((res) => {
} else { logger.info(res.data)
console.error(`${file.name} 失败 ${fileUpdateTime[file.name]} 次`) _this.songs = res.data.data
} })
// await login() },
upload(file, currentIndx) },
}) }).mount('#app')
} const fileUpdateTime = {}
</script> let fileLength = 0
</body>
function main() {
document
.querySelector('input[type="file"]')
.addEventListener('change', function (e) {
logger.info(this.files)
let currentIndx = 0
fileLength = this.files.length
for (const item of this.files) {
currentIndx += 1
upload(item, currentIndx)
}
})
}
main()
function upload(file, currentIndx) {
var formData = new FormData()
formData.append('songFile', file)
axios({
method: 'post',
url: `/cloud?time=${Date.now()}&cookie=${localStorage.getItem(
'cookie',
)}`,
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
})
.then((res) => {
logger.info(`${file.name} 上传成功`)
if (currentIndx >= fileLength) {
logger.info('上传完毕')
}
app.getData()
})
.catch(async (err) => {
logger.info(err)
logger.info(fileUpdateTime)
fileUpdateTime[file.name]
? (fileUpdateTime[file.name] += 1)
: (fileUpdateTime[file.name] = 1)
if (fileUpdateTime[file.name] >= 4) {
console.error(`丢,这首歌怎么都传不上:${file.name}`)
return
} else {
console.error(`${file.name} 失败 ${fileUpdateTime[file.name]} 次`)
}
// await login()
upload(file, currentIndx)
})
}
</script>
</body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
<script src="https://fastly.jsdelivr.net/npm/vue@3"></script> <script src="https://fastly.jsdelivr.net/npm/vue@3"></script>
<script> <script>
const logger = require('../util/logger.js')
const app = Vue.createApp({ const app = Vue.createApp({
data() { data() {
return { return {
@ -61,7 +62,7 @@
} }
}) })
this.result = JSON.stringify(res.data.data) this.result = JSON.stringify(res.data.data)
console.log(res.data); logger.info(res.data);
} catch (error) { } catch (error) {
console.error(error) console.error(error)
alert(error?.response?.data?.message || '解密失败,数据格式错误') alert(error?.response?.data?.message || '解密失败,数据格式错误')

View File

@ -1,44 +1,41 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh"> <html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>home</title>
</head>
<head> <body>
<meta charset="UTF-8" /> <div>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <a href="/qrlogin-nocookie.html"> 如果没登录,请先登录 </a>
<title>home</title> </div>
</head> <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<script>
<body> const logger = require('../util/logger.js')
<div> async function main() {
<a href="/qrlogin-nocookie.html"> const res = await axios({
如果没登录,请先登录 url: `/homepage/block/page`,
</a>
</div>
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<script>
async function main() {
const res = await axios({
url: `/homepage/block/page`,
data: {
cookie: localStorage.getItem('cookie'),
},
method: 'post',
})
let cursor = ''
console.log(res.data.data)
if (res.data.data.hasMore) {
cursor = res.data.data.cursor
const res2 = await axios({
url: `/homepage/block/page?time=${Date.now()}`,
data: { data: {
cookie: localStorage.getItem('cookie'), cookie: localStorage.getItem('cookie'),
cursor: cursor,
}, },
method: 'post', method: 'post',
}) })
let cursor = ''
logger.info(res.data.data)
if (res.data.data.hasMore) {
cursor = res.data.data.cursor
const res2 = await axios({
url: `/homepage/block/page?time=${Date.now()}`,
data: {
cookie: localStorage.getItem('cookie'),
cursor: cursor,
},
method: 'post',
})
}
} }
} main()
main() </script>
</script> </body>
</body>
</html> </html>

View File

@ -1,159 +1,253 @@
<!-- eslint-disable prettier/prettier --> <!-- eslint-disable prettier/prettier -->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh"> <html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>一起听</title>
<script src="https://unpkg.com/petite-vue"></script>
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/mdui@1.0.2/dist/css/mdui.min.css"
/>
<script src="https://unpkg.com/mdui@1.0.2/dist/js/mdui.min.js"></script>
</head>
<head> <body class="mdui-container">
<meta charset="UTF-8" /> <div>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <a href="/qrlogin.html"> 如果没登录,请先登录 </a>
<title>一起听</title> </div>
<script src="https://unpkg.com/petite-vue"></script> <h1>一起听 - 主机模式</h1>
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script> <div>消息: {{message}}</div>
<link rel="stylesheet" href="https://unpkg.com/mdui@1.0.2/dist/css/mdui.min.css" /> <audio id="player" autoplay controls></audio>
<script src="https://unpkg.com/mdui@1.0.2/dist/js/mdui.min.js"></script> <br />
</head> <br />
<button v-if="!account.login" @click="login">获取登录状态</button>
<div>您的当前登录账号为: {{account.nickname}}</div>
<br />
<div v-if="account.login">
<button v-if="!roomInfo.roomId" @click="createRoom">创建房间</button>
<details>
<summary>加入房间</summary>
<div><span>房间ID: </span><input v-model="roomInfo.roomId" /></div>
<div>
<span>邀请者 ID: </span><input v-model="roomInfo.inviterId" />
</div>
<button @click="joinRoom">点击加入</button>
</details>
<body class="mdui-container"> <div v-if="roomInfo.roomId">
<div> <div>
<a href="/qrlogin.html"> 分享链接为:
如果没登录,请先登录 https://st.music.163.com/listen-together/share/?songId=1372188635&roomId={{roomInfo.roomId}}&inviterId={{roomInfo.inviterId}}
</a> </div>
</div> <br />
<h1>一起听 - 主机模式</h1> <button @click="refreshRoom">刷新房间状态</button>
<div>消息: {{message}}</div> <div>在线用户:</div>
<audio id="player" autoplay controls> <ul class="mdui-list">
</audio> <li
<br /> v-for="user in roomInfo.roomUsers"
<br /> class="mdui-list-item mdui-ripple"
<button v-if="!account.login" @click="login">获取登录状态</button> >
<div>您的当前登录账号为: {{account.nickname}}</div> <div class="mdui-list-item-avatar">
<br /> <img :src="user.avatarUrl" />
<div v-if="account.login"> </div>
<button v-if="!roomInfo.roomId" @click="createRoom">创建房间</button> <div class="mdui-list-item-content">{{user.nickname}}</div>
<details> </li>
<summary>加入房间</summary> </ul>
<div><span>房间ID: </span><input v-model="roomInfo.roomId" /></div> <button v-if="roomInfo.roomId" @click="closeRoom">关闭房间</button>
<div><span>邀请者 ID: </span><input v-model="roomInfo.inviterId" /></div>
<button @click="joinRoom">点击加入</button>
</details>
<div v-if="roomInfo.roomId">
<div>分享链接为:
https://st.music.163.com/listen-together/share/?songId=1372188635&roomId={{roomInfo.roomId}}&inviterId={{roomInfo.inviterId}}
</div> </div>
</div>
<button @click="playTrack">播放</button>
<button @click="pauseTrack">暂停</button>
<button @click="seekTrack">同步进度</button>
<details>
<summary>播放列表</summary>
<br /> <br />
<button @click="refreshRoom">刷新房间状态</button> <div>
<div>在线用户: </div> <span>歌单ID: </span><input v-model="playlistInfo.playlistId" />
</div>
<button @click="loadPlaylist">加载歌单到播放列表</button>
<span>{{playlistInfo.playlistName}}</span>
<br />
<br />
<div>歌单内容:</div>
<ul class="mdui-list"> <ul class="mdui-list">
<li v-for="user in roomInfo.roomUsers" class="mdui-list-item mdui-ripple"> <li
@click="gotoTrack(track.id)"
v-for="track in playlistInfo.playlistTracks"
class="mdui-list-item mdui-ripple"
>
<div class="mdui-list-item-avatar"> <div class="mdui-list-item-avatar">
<img :src="user.avatarUrl" /> <img :src="track.al.picUrl" />
</div> </div>
<div class="mdui-list-item-content">{{user.nickname}}</div> <div class="mdui-list-item-content">{{track.name}}</div>
</li> </li>
</ul> </ul>
<button v-if="roomInfo.roomId" @click="closeRoom">关闭房间</button> </details>
</div> </body>
</div> <script>
<button @click="playTrack">播放</button> const logger = require('../util/logger.js')
<button @click="pauseTrack">暂停</button> PetiteVue.createApp({
<button @click="seekTrack">同步进度</button> message: '请点击获取登录状态',
<details> account: {
<summary>播放列表</summary> login: false,
<br /> userId: 0,
<div><span>歌单ID: </span><input v-model="playlistInfo.playlistId" /></div> nickname: '未登录',
<button @click="loadPlaylist">加载歌单到播放列表</button> },
<span>{{playlistInfo.playlistName}}</span> roomInfo: {
<br /> roomId: null,
<br /> inviterId: 0,
<div>歌单内容: </div> roomUsers: [],
<ul class="mdui-list"> },
<li @click="gotoTrack(track.id)" v-for="track in playlistInfo.playlistTracks" class="mdui-list-item mdui-ripple"> playlistInfo: {
<div class="mdui-list-item-avatar"> playlistId: 0,
<img :src="track.al.picUrl" /> playlistName: '未获取',
</div> playlistTrackIds: [],
<div class="mdui-list-item-content">{{track.name}}</div> playlistTracks: [],
</li> },
</ul> playingInfo: {
</details> trackId: 0,
status: 'PLAY',
progress: 1,
},
clientSeq: 1,
login: async function () {
const res = await axios({
url: `/login/status?timestamp=${new Date().getTime()}`,
method: 'get',
data: {
cookie: localStorage.getItem('cookie'),
},
})
if (res.data.data.code != 200) {
alert('请先使用登录 API 登录到网易云音乐')
} else {
this.account.userId = res.data.data.profile.userId
this.account.nickname = res.data.data.profile.nickname
this.account.login = true
this.message = '成功登录, 请创建房间'
}
},
joinRoom: async function () {
const res = await axios({
url: 'listentogether/accept',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
inviterId: this.roomInfo.inviterId,
cookie: localStorage.getItem('cookie'),
},
})
logger.info(res)
if (res.data.code != 200) {
this.message = '加入房间出现问题: ' + res.data.message
} else {
this.message = '加入房间成功: ' + this.roomInfo.roomId
const res2 = await axios({
url: 'listentogether/room/check',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
cookie: localStorage.getItem('cookie'),
},
})
logger.info(res2)
const res3 = await axios({
url: 'listentogether/sync/playlist/get',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
cookie: localStorage.getItem('cookie'),
},
})
</body> this.playlistInfo.playlistName = '其他人的歌单'
<script> this.playlistInfo.playlistTrackIds =
PetiteVue.createApp({ res3.data.data.playlist.displayList.result.join(',')
message: '请点击获取登录状态', const resa = await axios({
account: { url: '/song/detail',
login: false, method: 'post',
userId: 0, data: {
nickname: '未登录', ids: this.playlistInfo.playlistTrackIds,
}, cookie: localStorage.getItem('cookie'),
roomInfo: { },
roomId: null, })
inviterId: 0, logger.info(resa)
roomUsers: [], this.playlistInfo.playlistTracks = resa.data.songs
}, }
playlistInfo: { },
playlistId: 0, createRoom: async function () {
playlistName: '未获取', const res = await axios({
playlistTrackIds: [], url: 'listentogether/room/create',
playlistTracks: [], method: 'get',
}, data: {
playingInfo: { cookie: localStorage.getItem('cookie'),
trackId: 0, },
status: 'PLAY', })
progress: 1, logger.info(res)
}, if (res.data.code != 200) {
clientSeq: 1, this.message = '创建房间出现问题: ' + res.data.message
login: async function () { } else {
const res = await axios({ this.message = '创建房间成功: ' + res.data.data.roomInfo.roomId
url: `/login/status?timestamp=${new Date().getTime()}`, this.roomInfo.inviterId = this.account.userId
method: 'get', this.roomInfo.roomId = res.data.data.roomInfo.roomId
data: { const res2 = await axios({
cookie: localStorage.getItem('cookie'), url: 'listentogether/room/check',
}, method: 'post',
}) data: {
if (res.data.data.code != 200) { roomId: this.roomInfo.roomId,
alert('请先使用登录 API 登录到网易云音乐') cookie: localStorage.getItem('cookie'),
} else { },
this.account.userId = res.data.data.profile.userId })
this.account.nickname = res.data.data.profile.nickname logger.info(res2)
this.account.login = true }
this.message = '成功登录, 请创建房间' },
} refreshRoom: async function () {
}, const res = await axios({
joinRoom: async function () { url: '/listentogether/status',
const res = await axios({ data: {
url: 'listentogether/accept', cookie: localStorage.getItem('cookie'),
method: 'post', },
data: { })
roomId: this.roomInfo.roomId, logger.info(res)
inviterId: this.roomInfo.inviterId, if (res.data.code != 200 || !res.data.data.inRoom) {
cookie: localStorage.getItem('cookie'), this.message = '房间状态获取失败, 可能退出了房间'
}, } else {
}) this.roomInfo.roomUsers = res.data.data.roomInfo.roomUsers
console.log(res) }
if (res.data.code != 200) { },
this.message = '加入房间出现问题: ' + res.data.message closeRoom: async function () {
} else { const res = await axios({
this.message = '加入房间成功: ' + this.roomInfo.roomId url: '/listentogether/end',
const res2 = await axios({
url: 'listentogether/room/check',
method: 'post', method: 'post',
data: { data: {
roomId: this.roomInfo.roomId, roomId: this.roomInfo.roomId,
cookie: localStorage.getItem('cookie'), cookie: localStorage.getItem('cookie'),
}, },
}) })
console.log(res2) logger.info(res)
const res3 = await axios({ if (res.data.code != 200 || !res.data.data.success) {
url: 'listentogether/sync/playlist/get', this.message = '房间关闭失败'
} else {
this.message = '房间关闭成功'
this.roomInfo.roomId = null
}
},
loadPlaylist: async function () {
const res = await axios({
url: '/playlist/detail',
method: 'post', method: 'post',
data: { data: {
roomId: this.roomInfo.roomId, id: this.playlistInfo.playlistId,
cookie: localStorage.getItem('cookie'), cookie: localStorage.getItem('cookie'),
}, },
}) })
logger.info(res)
this.playlistInfo.playlistName = "其他人的歌单" this.playlistInfo.playlistName = res.data.playlist.name
this.playlistInfo.playlistTrackIds = res3.data.data.playlist.displayList.result this.playlistInfo.playlistTrackIds = res.data.playlist.trackIds
.map((track) => track.id)
.join(',') .join(',')
const resa = await axios({ const resa = await axios({
url: '/song/detail', url: '/song/detail',
@ -163,156 +257,68 @@
cookie: localStorage.getItem('cookie'), cookie: localStorage.getItem('cookie'),
}, },
}) })
console.log(resa) logger.info(resa)
this.playlistInfo.playlistTracks = resa.data.songs this.playlistInfo.playlistTracks = resa.data.songs
if (this.roomInfo.roomId) {
const resb = await axios({
} url: 'listentogether/sync/list/command',
method: 'post',
}, data: {
createRoom: async function () { roomId: this.roomInfo.roomId,
const res = await axios({ commandType: 'REPLACE',
url: 'listentogether/room/create', userId: this.account.userId,
method: 'get', version: this.clientSeq++,
data: { playMode: 'ORDER_LOOP',
cookie: localStorage.getItem('cookie'), displayList: this.playlistInfo.playlistTrackIds,
}, randomList: this.playlistInfo.playlistTrackIds,
}) cookie: localStorage.getItem('cookie'),
console.log(res) },
if (res.data.code != 200) { })
this.message = '创建房间出现问题: ' + res.data.message logger.info(resb)
} else { }
this.message = '创建房间成功: ' + res.data.data.roomInfo.roomId },
this.roomInfo.inviterId = this.account.userId gotoTrack: async function (trackId) {
this.roomInfo.roomId = res.data.data.roomInfo.roomId this.playingInfo.trackId = trackId
const res2 = await axios({ if (this.roomInfo.roomId) {
url: 'listentogether/room/check', await this.playCommand('GOTO')
}
document.getElementById('player').src =
'https://music.163.com/song/media/outer/url?id=' + trackId + '.mp3'
},
playTrack: async function () {
this.playingInfo.status = 'PLAY'
await this.playCommand('PLAY')
document.getElementById('player').play()
},
pauseTrack: async function () {
this.playingInfo.status = 'PAUSE'
await this.playCommand('PAUSE')
document.getElementById('player').pause()
},
seekTrack: async function () {
this.playingInfo.status = 'PLAY'
await this.playCommand('seek')
document.getElementById('player').play()
},
playCommand: async function (action) {
const res = await axios({
url: 'listentogether/play/command',
method: 'post', method: 'post',
data: { data: {
roomId: this.roomInfo.roomId, roomId: this.roomInfo.roomId,
progress: Math.floor(
document.getElementById('player').currentTime * 1000,
),
commandType: action,
formerSongId: '-1',
targetSongId: this.playingInfo.trackId,
clientSeq: this.clientSeq++,
playStatus: this.playingInfo.status,
cookie: localStorage.getItem('cookie'), cookie: localStorage.getItem('cookie'),
}, },
}) })
console.log(res2) logger.info(res)
} },
}, }).mount()
refreshRoom: async function () { </script>
const res = await axios({
url: '/listentogether/status',
data: {
cookie: localStorage.getItem('cookie'),
},
})
console.log(res)
if (res.data.code != 200 || !res.data.data.inRoom) {
this.message = '房间状态获取失败, 可能退出了房间'
} else {
this.roomInfo.roomUsers = res.data.data.roomInfo.roomUsers
}
},
closeRoom: async function () {
const res = await axios({
url: '/listentogether/end',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
cookie: localStorage.getItem('cookie'),
},
})
console.log(res)
if (res.data.code != 200 || !res.data.data.success) {
this.message = '房间关闭失败'
} else {
this.message = '房间关闭成功'
this.roomInfo.roomId = null
}
},
loadPlaylist: async function () {
const res = await axios({
url: '/playlist/detail',
method: 'post',
data: {
id: this.playlistInfo.playlistId,
cookie: localStorage.getItem('cookie'),
},
})
console.log(res)
this.playlistInfo.playlistName = res.data.playlist.name
this.playlistInfo.playlistTrackIds = res.data.playlist.trackIds
.map((track) => track.id)
.join(',')
const resa = await axios({
url: '/song/detail',
method: 'post',
data: {
ids: this.playlistInfo.playlistTrackIds,
cookie: localStorage.getItem('cookie'),
},
})
console.log(resa)
this.playlistInfo.playlistTracks = resa.data.songs
if (this.roomInfo.roomId) {
const resb = await axios({
url: 'listentogether/sync/list/command',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
commandType: 'REPLACE',
userId: this.account.userId,
version: this.clientSeq++,
playMode: 'ORDER_LOOP',
displayList: this.playlistInfo.playlistTrackIds,
randomList: this.playlistInfo.playlistTrackIds,
cookie: localStorage.getItem('cookie'),
},
})
console.log(resb)
}
},
gotoTrack: async function (trackId) {
this.playingInfo.trackId = trackId
if (this.roomInfo.roomId) {
await this.playCommand('GOTO')
}
document.getElementById('player').src =
'https://music.163.com/song/media/outer/url?id=' + trackId + '.mp3'
},
playTrack: async function () {
this.playingInfo.status = 'PLAY'
await this.playCommand('PLAY')
document.getElementById('player').play()
},
pauseTrack: async function () {
this.playingInfo.status = 'PAUSE'
await this.playCommand('PAUSE')
document.getElementById('player').pause()
},
seekTrack: async function () {
this.playingInfo.status = 'PLAY'
await this.playCommand('seek')
document.getElementById('player').play()
},
playCommand: async function (action) {
const res = await axios({
url: 'listentogether/play/command',
method: 'post',
data: {
roomId: this.roomInfo.roomId,
progress: Math.floor(
document.getElementById('player').currentTime * 1000,
),
commandType: action,
formerSongId: '-1',
targetSongId: this.playingInfo.trackId,
clientSeq: this.clientSeq++,
playStatus: this.playingInfo.status,
cookie: localStorage.getItem('cookie'),
},
})
console.log(res)
},
}).mount()
</script>
</html> </html>

View File

@ -1,125 +1,128 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh"> <html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>播客上传声音</title>
</head>
<head> <body>
<meta charset="UTF-8" /> <div>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <a href="/qrlogin-nocookie.html"> 如果没登录,请先登录 </a>
<title>播客上传声音</title> </div>
</head> <div id="app">
<ul>
<li
v-for="(item,index) in voicelist"
@click="currentVoiceIndex=index"
:class="{active:currentVoiceIndex===index}"
>
<img :src="item.coverUrl" style="width: 50px; width: 50px" />
<ul>
<li v-for="(item2,index) in item.voiceListData">
{{item2.voiceName}}
</li>
</ul>
{{item.voiceListName}}
</li>
</ul>
<input v-model="songName" placeholder="请输入声音名称" />
<input v-model="description" placeholder="请输入介绍" />
<input type="file" name="songFile" />
<button @click="submit">上传</button>
</div>
<body> <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<div> <script src="https://fastly.jsdelivr.net/npm/vue"></script>
<a href="/qrlogin-nocookie.html"> <script>
如果没登录,请先登录 const logger = require('../util/logger.js')
</a> Vue.createApp({
</div> data() {
<div id="app"> return {
<ul> songName: '',
<li v-for="(item,index) in voicelist" @click="currentVoiceIndex=index" description: '',
:class="{active:currentVoiceIndex===index}"> voicelist: [],
<img :src="item.coverUrl" style="width:50px;width:50px;" /> cookieToken: '',
<ul> currentVoiceIndex: 0,
<li v-for="(item2,index) in item.voiceListData"> }
{{item2.voiceName}}
</li>
</ul>
{{item.voiceListName}}
</li>
</ul>
<input v-model="songName" placeholder="请输入声音名称" />
<input v-model="description" placeholder="请输入介绍" />
<input type="file" name="songFile" />
<button @click="submit">上传</button>
</div>
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
<script src="https://fastly.jsdelivr.net/npm/vue"></script>
<script>
Vue.createApp({
data() {
return {
songName: '',
description: '',
voicelist: [],
cookieToken: '',
currentVoiceIndex: 0,
}
},
created() {
this.getData()
},
computed: {
currentVoice() {
// {
// voiceListId: '',
// coverImgId: '',
// categoryId: '',
// secondCategoryId: '',
// }
return this.voicelist[this.currentVoiceIndex]
}, },
}, created() {
methods: { this.getData()
submit() {
console.log('submit')
const file = document.querySelector('input[type=file]').files[0]
this.upload(file)
}, },
computed: {
currentVoice() {
// {
// voiceListId: '',
// coverImgId: '',
// categoryId: '',
// secondCategoryId: '',
// }
return this.voicelist[this.currentVoiceIndex]
},
},
methods: {
submit() {
logger.info('submit')
const file = document.querySelector('input[type=file]').files[0]
this.upload(file)
},
async getData() { async getData() {
const res = await axios({ const res = await axios({
url: `/voicelist/search?cookie=${localStorage.getItem('cookie')}`, url: `/voicelist/search?cookie=${localStorage.getItem('cookie')}`,
})
console.log(res.data.data)
this.voicelist = res.data.data.list
this.voicelist.map(async i => {
const res2 = await axios({
url: `/voicelist/list?voiceListId=${i.voiceListId}&limit=5`,
}) })
i.voiceListData = res2.data.data.list
console.log(res2); logger.info(res.data.data)
}) this.voicelist = res.data.data.list
}, this.voicelist.map(async (i) => {
upload(file) { const res2 = await axios({
var formData = new FormData() url: `/voicelist/list?voiceListId=${i.voiceListId}&limit=5`,
formData.append('songFile', file) })
axios({ i.voiceListData = res2.data.data.list
method: 'post', logger.info(res2)
url: `/voice/upload?time=${Date.now()}&cookie=${localStorage.getItem('cookie')
}&songName=${this.songName}&voiceListId=${this.currentVoice.voiceListId
}&categoryId=${this.currentVoice.categoryId}&coverImgId=${this.currentVoice.coverImgId
}&secondCategoryId=${this.currentVoice.secondCategoryId}&description=${this.description
}&privacy=1`,
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
})
.then((res) => {
alert(`${file.name} 上传成功`)
if (currentIndx >= fileLength) {
console.log('上传完毕')
}
}) })
.catch(async (err) => { },
console.log(err) upload(file) {
var formData = new FormData()
formData.append('songFile', file)
axios({
method: 'post',
url: `/voice/upload?time=${Date.now()}&cookie=${localStorage.getItem(
'cookie',
)}&songName=${this.songName}&voiceListId=${
this.currentVoice.voiceListId
}&categoryId=${this.currentVoice.categoryId}&coverImgId=${
this.currentVoice.coverImgId
}&secondCategoryId=${
this.currentVoice.secondCategoryId
}&description=${this.description}&privacy=1`,
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
}) })
.then((res) => {
alert(`${file.name} 上传成功`)
if (currentIndx >= fileLength) {
logger.info('上传完毕')
}
})
.catch(async (err) => {
logger.info(err)
})
},
}, },
}, }).mount('#app')
}).mount('#app') </script>
</script>
<style> <style>
ul li { ul li {
cursor: pointer; cursor: pointer;
} }
ul li.active {
color: red;
}
</style>
</body>
ul li.active {
color: red;
}
</style>
</body>
</html> </html>

View File

@ -9,6 +9,7 @@ const cache = require('./util/apicache').middleware
const { cookieToJson } = require('./util/index') const { cookieToJson } = require('./util/index')
const fileUpload = require('express-fileupload') const fileUpload = require('express-fileupload')
const decode = require('safe-decode-uri-component') const decode = require('safe-decode-uri-component')
const logger = require('./util/logger.js')
/** /**
* The version check result. * The version check result.
@ -237,14 +238,14 @@ async function consturctServer(moduleDefs) {
if (ip == '::1') { if (ip == '::1') {
ip = global.cnIp ip = global.cnIp
} }
// console.log(ip) // logger.info(ip)
obj[3] = { obj[3] = {
...obj[3], ...obj[3],
ip, ip,
} }
return request(...obj) return request(...obj)
}) })
console.log('[OK]', decode(req.originalUrl)) logger.info(`Request Success: ${decode(req.originalUrl)}`)
if ( if (
(req.baseUrl === '/song/url/v1' || req.baseUrl === '/song/url') && (req.baseUrl === '/song/url/v1' || req.baseUrl === '/song/url') &&
@ -254,11 +255,11 @@ async function consturctServer(moduleDefs) {
if (song.freeTrialInfo !== null || !song.url || [1, 4].includes(song.fee)) { if (song.freeTrialInfo !== null || !song.url || [1, 4].includes(song.fee)) {
const match = require('@unblockneteasemusic/server') const match = require('@unblockneteasemusic/server')
const source = process.env.UNBLOCK_SOURCE ? process.env.UNBLOCK_SOURCE.split(',') : ['pyncmd', 'kuwo', 'qq', 'migu', 'kugou'] const source = process.env.UNBLOCK_SOURCE ? process.env.UNBLOCK_SOURCE.split(',') : ['pyncmd', 'kuwo', 'qq', 'migu', 'kugou']
console.log("开始解灰", source) logger.info("开始解灰", source)
const { url } = await match(req.query.id, source) const { url } = await match(req.query.id, source)
song.url = url song.url = url
song.freeTrialInfo = 'null' song.freeTrialInfo = 'null'
console.log("解灰成功!") logger.info("解灰成功!")
} }
if (song.url.includes('kuwo')) { if (song.url.includes('kuwo')) {
const proxy = process.env.PROXY_URL; const proxy = process.env.PROXY_URL;
@ -285,7 +286,7 @@ async function consturctServer(moduleDefs) {
} }
res.status(moduleResponse.status).send(moduleResponse.body) res.status(moduleResponse.status).send(moduleResponse.body)
} catch (/** @type {*} */ moduleResponse) { } catch (/** @type {*} */ moduleResponse) {
console.log('[ERR]', decode(req.originalUrl), { logger.error(`${decode(req.originalUrl)}`, {
status: moduleResponse.status, status: moduleResponse.status,
body: moduleResponse.body, body: moduleResponse.body,
}) })
@ -324,7 +325,7 @@ async function serveNcmApi(options) {
options.checkVersion && options.checkVersion &&
checkVersion().then(({ npmVersion, ourVersion, status }) => { checkVersion().then(({ npmVersion, ourVersion, status }) => {
if (status == VERSION_CHECK_RESULT.NOT_LATEST) { if (status == VERSION_CHECK_RESULT.NOT_LATEST) {
console.log( logger.info(
`最新版本: ${npmVersion}, 当前版本: ${ourVersion}, 请及时更新`, `最新版本: ${npmVersion}, 当前版本: ${ourVersion}, 请及时更新`,
) )
} }
@ -339,9 +340,25 @@ async function serveNcmApi(options) {
/** @type {import('express').Express & ExpressExtension} */ /** @type {import('express').Express & ExpressExtension} */
const appExt = app const appExt = app
appExt.server = app.listen(port, host, () => { appExt.server = app.listen(port, host, () => {
console.log(`server running @ http://${host ? host : 'localhost'}:${port}`) console.log(`
_ _ _____ __ __ _ ____ ___
| \\ | |/ ____| \\/ | /\\ | | | _ \\_ |
| \\| | | | \\ / | / \\ | | | |_) | |
| . \` | | | |\\/| | / /\\ \\ | | | __/| |
| |\\ | |____| | | | / ____ \\| |__| | | |
|_| \\_|\\_____|_| |_| /_/ \\_\\____|_| |_|
`)
console.log(`
`)
logger.info(`
- Server started successfully @ http://${host ? host : 'localhost'}:${port}
- Environment: ${process.env.NODE_ENV || 'development'}
- Node Version: ${process.version}
- Process ID: ${process.pid}`)
}) })
return appExt return appExt
} }

View File

@ -1,2 +0,0 @@
const source = process.env.UNBLOCK_SOURCE ? process.env.UNBLOCK_SOURCE.split(',') : ['pyncmd', 'kuwo', 'qq', 'migu', 'kugou']
console.log("开始解灰", source)

View File

@ -1,5 +1,6 @@
var url = require('url') var url = require('url')
var MemoryCache = require('./memory-cache') var MemoryCache = require('./memory-cache')
const logger = require('./logger.js')
var t = { var t = {
ms: 1, ms: 1,
@ -349,7 +350,7 @@ function ApiCache() {
try { try {
redis.del(key) redis.del(key)
} catch (err) { } catch (err) {
console.log('[apicache] error in redis.del("' + key + '")') logger.info('[apicache] error in redis.del("' + key + '")')
} }
} }
index.all = index.all.filter(doesntMatch(key)) index.all = index.all.filter(doesntMatch(key))
@ -373,7 +374,7 @@ function ApiCache() {
try { try {
redis.del(target) redis.del(target)
} catch (err) { } catch (err) {
console.log('[apicache] error in redis.del("' + target + '")') logger.info('[apicache] error in redis.del("' + target + '")')
} }
} }
@ -404,7 +405,7 @@ function ApiCache() {
try { try {
redis.del(key) redis.del(key)
} catch (err) { } catch (err) {
console.log('[apicache] error in redis.del("' + key + '")') logger.info('[apicache] error in redis.del("' + key + '")')
} }
}) })
} }

29
util/logger.js Normal file
View File

@ -0,0 +1,29 @@
// ANSI 颜色代码
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
black: '\x1b[30m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
bgRed: '\x1b[41m',
bgGreen: '\x1b[42m',
bgYellow: '\x1b[43m'
};
const logger = {
debug: (msg, ...args) => console.info(`${colors.cyan}[DEBUG]${colors.reset}`, msg, ...args),
info: (msg, ...args) => console.info(`${colors.green}[INFO]${colors.reset}`, msg, ...args),
warn: (msg, ...args) => console.info(`${colors.yellow}[WARN]${colors.reset}`, msg, ...args),
error: (msg, ...args) => console.error(`${colors.red}[ERROR]${colors.reset}`, msg, ...args),
success: (msg, ...args) => console.log(`${colors.bright}${colors.green}[SUCCESS]${colors.reset}`, msg, ...args),
critical: (msg, ...args) => console.error(`${colors.bright}${colors.bgRed}[CRITICAL]${colors.reset}`, msg, ...args)
};
// 导出logger
module.exports = logger;

View File

@ -15,6 +15,7 @@ const anonymous_token = fs.readFileSync(
) )
const { URLSearchParams, URL } = require('url') const { URLSearchParams, URL } = require('url')
const { APP_CONF } = require('../util/config.json') const { APP_CONF } = require('../util/config.json')
const logger = require('./logger.js')
// request.debug = true // 开启可看到更详细信息 // request.debug = true // 开启可看到更详细信息
const WNMCID = (function () { const WNMCID = (function () {
@ -76,7 +77,7 @@ const createRequest = (uri, data, options) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let headers = options.headers || {} let headers = options.headers || {}
let ip = options.realIP || options.ip || '' let ip = options.realIP || options.ip || ''
// console.log(ip) // logger.info(ip)
if (ip) { if (ip) {
headers['X-Real-IP'] = ip headers['X-Real-IP'] = ip
headers['X-Forwarded-For'] = ip headers['X-Forwarded-For'] = ip
@ -201,11 +202,11 @@ const createRequest = (uri, data, options) => {
default: default:
// 未知的加密方式 // 未知的加密方式
console.log('[ERR]', 'Unknown Crypto:', crypto) logger.info('[ERR]', 'Unknown Crypto:', crypto)
break break
} }
const answer = { status: 500, body: {}, cookie: [] } const answer = { status: 500, body: {}, cookie: [] }
// console.log(headers, 'headers') // logger.info(headers, 'headers')
let settings = { let settings = {
method: 'POST', method: 'POST',
url: url, url: url,
@ -282,7 +283,7 @@ const createRequest = (uri, data, options) => {
answer.status = 200 answer.status = 200
} }
} catch (e) { } catch (e) {
// console.log(e) // logger.info(e)
// can't decrypt and can't parse directly // can't decrypt and can't parse directly
answer.body = body answer.body = body
answer.status = res.status answer.status = res.status