mirror of
https://github.com/MeoProject/lx-music-api-server.git
synced 2025-05-23 19:17:41 +08:00
feat: 支持NeteaseCloudMusicApi
This commit is contained in:
parent
56d19ee671
commit
ed47e928dd
13
Dockerfile
13
Dockerfile
@ -1,13 +0,0 @@
|
|||||||
FROM python:3.10-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY ./main.py .
|
|
||||||
COPY ./common ./common
|
|
||||||
COPY ./modules ./modules
|
|
||||||
COPY ./requirements.txt .
|
|
||||||
|
|
||||||
# 指定源, 如果后期源挂了, 更换个源就可以.
|
|
||||||
RUN pip install --no-cache -i https://pypi.mirrors.ustc.edu.cn/simple/ -r requirements.txt
|
|
||||||
|
|
||||||
CMD [ "python", "main.py" ]
|
|
@ -141,13 +141,16 @@ module:
|
|||||||
use_vkey_api: false
|
use_vkey_api: false
|
||||||
vkey_api_url: "xxx"
|
vkey_api_url: "xxx"
|
||||||
|
|
||||||
wy: # 网易云音乐相关配置
|
wy: # 网易云音乐相关配置, proto支持值: ['offcial', 'ncmapi']
|
||||||
enable: true # 是否开启本平台服务
|
enable: true # 是否开启本平台服务
|
||||||
|
proto: offcial
|
||||||
user:
|
user:
|
||||||
cookie: "" # 账号cookie数据,可以通过浏览器获取,需要vip账号来获取会员歌曲,如果没有请留为空值
|
cookie: "" # 账号cookie数据,可以通过浏览器获取,需要vip账号来获取会员歌曲,如果没有请留为空值
|
||||||
refresh_login:
|
refresh_login:
|
||||||
enable: false
|
enable: false
|
||||||
interval: 86400
|
interval: 86400
|
||||||
|
ncmapi:
|
||||||
|
api_url: "" # NeteaseCloudMusicApi的URL, 自行参考https://gitlab.com/Binaryify/neteasecloudmusicapi搭建
|
||||||
|
|
||||||
mg: # 咪咕音乐相关配置
|
mg: # 咪咕音乐相关配置
|
||||||
enable: true # 是否开启本平台服务
|
enable: true # 是否开启本平台服务
|
||||||
|
@ -8,36 +8,34 @@
|
|||||||
# This file is part of the "lx-music-api-server" project.
|
# This file is part of the "lx-music-api-server" project.
|
||||||
|
|
||||||
import os as _os
|
import os as _os
|
||||||
import ujson as _json
|
import ruamel.yaml as _yaml
|
||||||
|
|
||||||
|
yaml = _yaml.YAML()
|
||||||
|
|
||||||
|
|
||||||
def _read_config_file():
|
def _read_config_file():
|
||||||
try:
|
try:
|
||||||
with open("./config/config.json", "r", encoding="utf-8") as f:
|
with open(f"./config/config.yml", "r", encoding="utf-8") as f:
|
||||||
return _json.load(f)
|
return yaml.load(f.read())
|
||||||
except:
|
except:
|
||||||
return {}
|
return []
|
||||||
|
|
||||||
|
|
||||||
def _read_config(key):
|
def _read_config(key):
|
||||||
try:
|
config = _read_config_file()
|
||||||
config = _read_config_file()
|
keys = key.split('.')
|
||||||
keys = key.split('.')
|
value = config
|
||||||
value = config
|
for k in keys:
|
||||||
for k in keys:
|
if isinstance(value, dict):
|
||||||
if isinstance(value, dict):
|
if k not in value and keys.index(k) != len(keys) - 1:
|
||||||
if k not in value and keys.index(k) != len(keys) - 1:
|
value[k] = []
|
||||||
value[k] = {}
|
elif k not in value and keys.index(k) == len(keys) - 1:
|
||||||
elif k not in value and keys.index(k) == len(keys) - 1:
|
|
||||||
value = None
|
|
||||||
value = value[k]
|
|
||||||
else:
|
|
||||||
value = None
|
value = None
|
||||||
break
|
value = value[k]
|
||||||
|
else:
|
||||||
return value
|
value = None
|
||||||
except:
|
break
|
||||||
return None
|
return value
|
||||||
|
|
||||||
|
|
||||||
_dm = _read_config("common.debug_mode")
|
_dm = _read_config("common.debug_mode")
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
lx:
|
|
||||||
container_name: lx-server
|
|
||||||
build: .
|
|
||||||
ports:
|
|
||||||
- "9763:9763"
|
|
||||||
volumes:
|
|
||||||
- .:/app
|
|
||||||
environment:
|
|
||||||
TZ: 'Asia/Shanghai'
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
|
|
@ -15,6 +15,9 @@ from .encrypt import eapiEncrypt
|
|||||||
import ujson as json
|
import ujson as json
|
||||||
from . import refresh_login
|
from . import refresh_login
|
||||||
|
|
||||||
|
PROTO = config.read_config("module.wy.proto")
|
||||||
|
API_URL = config.read_config("module.wy.ncmapi.api_url")
|
||||||
|
|
||||||
tools = {
|
tools = {
|
||||||
'qualityMap': {
|
'qualityMap': {
|
||||||
'128k': 'standard',
|
'128k': 'standard',
|
||||||
@ -45,56 +48,56 @@ tools = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def url(songId, quality):
|
async def url(songId, quality):
|
||||||
path = '/api/song/enhance/player/url/v1'
|
if PROTO == "offcial":
|
||||||
requestUrl = 'https://interface.music.163.com/eapi/song/enhance/player/url/v1'
|
path = '/api/song/enhance/player/url/v1'
|
||||||
requestBody = {
|
requestUrl = 'https://interface.music.163.com/eapi/song/enhance/player/url/v1'
|
||||||
"ids": json.dumps([songId]),
|
requestBody = {
|
||||||
"level": tools["qualityMap"][quality],
|
"ids": json.dumps([songId]),
|
||||||
"encodeType": "flac",
|
"level": tools["qualityMap"][quality],
|
||||||
}
|
"encodeType": "flac",
|
||||||
if (quality == "sky"):
|
}
|
||||||
requestBody["immerseType"] = "c51"
|
if (quality == "sky"):
|
||||||
req = await Httpx.AsyncRequest(requestUrl, {
|
requestBody["immerseType"] = "c51"
|
||||||
'method': 'POST',
|
req = await Httpx.AsyncRequest(requestUrl, {
|
||||||
'headers': {
|
'method': 'POST',
|
||||||
'Cookie': config.read_config('module.wy.user.cookie') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.wy'))['cookie'],
|
'headers': {
|
||||||
},
|
'Cookie': config.read_config('module.wy.user.cookie') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.wy'))['cookie'],
|
||||||
'form': eapiEncrypt(path, json.dumps(requestBody))
|
},
|
||||||
})
|
'form': eapiEncrypt(path, json.dumps(requestBody))
|
||||||
|
})
|
||||||
|
body = req.json()
|
||||||
|
if (not body.get("data") or (not body.get("data")) or (not body.get("data")[0].get("url"))):
|
||||||
|
raise FailedException("失败")
|
||||||
|
|
||||||
|
data = body["data"][0]
|
||||||
|
if (data['level'] != tools['qualityMap'][quality]):
|
||||||
|
raise FailedException("reject unmatched quality")
|
||||||
|
|
||||||
# 发 GET 请求给第三方 Netease Cloud Music API 服务器获取链接(多此一举)|| 其实是我个人莫名其妙拿不到 Hires 以上音质的一种无奈替代方案
|
return {
|
||||||
# 想自建服务器?可以参考这份教程:https://github.com/kirakirai8023/NeteaseCloudMusicApi
|
'url': data["url"].split("?")[0],
|
||||||
# 总之,在我的测试环境下很神奇,这个版本的 /song/url/v1 接口才能获取到最高音质,最新版本的 NeteaseCloudMusicApi 也不行
|
'quality': tools['qualityMapReverse'][data['level']]
|
||||||
# 我懒得抓包了,等有缘人来改吧,哈哈
|
}
|
||||||
|
elif (PROTO == "ncmapi") and (API_URL):
|
||||||
|
requestUrl = f"{API_URL}/song/url/v1"
|
||||||
|
requestBody = {
|
||||||
|
"ids": songId,
|
||||||
|
"level": tools["qualityMap"][quality],
|
||||||
|
"cookie": config.read_config('module.wy.user.cookie') if (not variable.use_cookie_pool) else random.choice(config.read_config('module.cookiepool.wy'))['cookie']
|
||||||
|
}
|
||||||
|
req = await Httpx.AsyncRequest(requestUrl, {
|
||||||
|
"method": "GET",
|
||||||
|
"params": requestBody
|
||||||
|
})
|
||||||
|
body = req.json()
|
||||||
|
if (body["code"] != 200) or (not body.get(data, "")):
|
||||||
|
raise FailedException("失败")
|
||||||
|
data = body["data"][0]
|
||||||
|
if (data['level'] != tools['qualityMap'][quality]):
|
||||||
|
raise FailedException("reject unmatched quality")
|
||||||
|
|
||||||
'''
|
return {
|
||||||
async def url(songId, quality):
|
'url': data["url"].split("?")[0],
|
||||||
requestUrl = 'https://your-netease-api-server.com/song/url/v1'
|
'quality': tools['qualityMapReverse'][data['level']]
|
||||||
params = {
|
}
|
||||||
"id": songId,
|
|
||||||
"level": tools["qualityMap"][quality],
|
|
||||||
"cookie": config.read_config('module.wy.user.cookie')
|
|
||||||
if not variable.use_cookie_pool
|
|
||||||
else random.choice(config.read_config('module.cookiepool.wy'))['cookie']
|
|
||||||
}
|
|
||||||
|
|
||||||
req = await Httpx.AsyncRequest(requestUrl, {
|
|
||||||
'method': 'GET',
|
|
||||||
'params': params,
|
|
||||||
})
|
|
||||||
'''
|
|
||||||
|
|
||||||
body = req.json()
|
|
||||||
if (not body.get("data") or (not body.get("data")) or (not body.get("data")[0].get("url"))):
|
|
||||||
raise FailedException("failed")
|
|
||||||
|
|
||||||
data = body["data"][0]
|
|
||||||
if (data['level'] != tools['qualityMap'][quality]):
|
|
||||||
raise FailedException("reject unmatched quality")
|
|
||||||
|
|
||||||
return {
|
|
||||||
'url': data["url"].split("?")[0],
|
|
||||||
'quality': tools['qualityMapReverse'][data['level']]
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Loading…
x
Reference in New Issue
Block a user