Skip to content

Commit

Permalink
Version 1.6.9.2
Browse files Browse the repository at this point in the history
# 新设定
* `--use-download-api` (Issue #44)
使用官方下载 API 进行下载,而不使用播放 API 下载
* `--user-bookmarks` (Issue #43)
在下载用户所有歌单时(提供用户主页分享链接),同时下载其收藏的所有歌单
# Bugfix
* `--save` 等不进行下载的操作不再需要提供分享链接
  • Loading branch information
mos9527 committed Aug 9, 2023
1 parent 1ba7561 commit c4bc68d
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 75 deletions.
123 changes: 63 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,73 +11,76 @@

**Windows 用户**: 在 [Releases](https://github.com/mos9527/pyncm/releases) 可下载已打包 `.exe` 版本
# 命令行使用
positional arguments:
链接 网易云音乐分享链接
positional arguments:
链接 网易云音乐分享链接

options:
-h, --help show this help message and exit
options:
-h, --help show this help message and exit

下载:
--max-workers 最多同时下载任务数, -m 最多同时下载任务数
--output-name 保存文件名模板, --template 保存文件名模板, -t 保存文件名模板
保存文件名模板
参数:
id - 网易云音乐资源 ID
year - 出版年份
no - 专辑中编号
album - 专辑标题
track - 单曲标题
title - 完整标题
artists- 艺术家名
例:
{track} - {artists} 等效于 {title}
-o 输出, --output 输出 输出文件夹
注:该参数也可使用模板,格式同 保存文件名模板
--quality 音质 音频音质(高音质需要 CVIP)
参数:
hires - Hi-Res
lossless- “无损”
exhigh - 较高
standard- 标准
--no-overwrite 不重复下载已经存在的音频文件
下载:
--max-workers 最多同时下载任务数, -m 最多同时下载任务数
--output-name 保存文件名模板, --template 保存文件名模板, -t 保存文件名模板
保存文件名模板
参数:
id - 网易云音乐资源 ID
year - 出版年份
no - 专辑中编号
album - 专辑标题
track - 单曲标题
title - 完整标题
artists- 艺术家名
例:
{track} - {artists} 等效于 {title}
-o 输出, --output 输出 输出文件夹
注:该参数也可使用模板,格式同 保存文件名模板
--quality 音质 音频音质(高音质需要 CVIP)
参数:
hires - Hi-Res
lossless- “无损”
exhigh - 较高
standard- 标准
-dl, --use-download-api
调用下载API,而非播放API进行下载。如此可能允许更高高音质音频的下载。
【注意】此API有额度限制,参考 https://music.163.com/member/downinfo
--no-overwrite 不重复下载已经存在的音频文件

歌词:
--lyric-no 跳过歌词 跳过某些歌词类型的下载
参数:
lrc - 源语言歌词 (合并到 .lrc)
tlyric - 翻译后歌词 (合并到 .lrc)
romalrc- 罗马音歌词 (合并到 .lrc)
yrc - 逐词滚动歌词 (保存到 .ass)
none - 下载所有歌词
例:
--lyric-no tlyric romalrc yrc 将只下载源语言歌词
--lyric-no none 将下载所有歌词
注:
默认不下载 *逐词滚动歌词*
歌词:
--lyric-no 跳过歌词 跳过某些歌词类型的下载
参数:
lrc - 源语言歌词 (合并到 .lrc)
tlyric - 翻译后歌词 (合并到 .lrc)
romalrc- 罗马音歌词 (合并到 .lrc)
yrc - 逐词滚动歌词 (保存到 .ass)
none - 下载所有歌词
例:
--lyric-no tlyric romalrc yrc 将只下载源语言歌词
--lyric-no none 将下载所有歌词
注:
默认不下载 *逐词滚动歌词*


登陆:
--phone 手机 网易账户手机号
--pwd 密码, --password 密码
网易账户密码
--save [保存到] 写本次登录信息于文件
--load [保存的登陆信息文件] 从文件读取登录信息供本次登陆使用
--http 优先使用 HTTP,不保证不被升级
--log-level LOG_LEVEL
日志等级
登陆:
--phone 手机 网易账户手机号
--pwd 密码, --password 密码
网易账户密码
--save [保存到] 写本次登录信息于文件
--load [保存的登陆信息文件] 从文件读取登录信息供本次登陆使用
--http 优先使用 HTTP,不保证不被升级
--log-level LOG_LEVEL
日志等级

限量及过滤(注:只适用于*每单个*链接 / ID):
-n 下载总量, --count 下载总量
限制下载歌曲总量,n=0即不限制(注:过大值可能导致限流)
--sort-by 歌曲排序 【限制总量时】歌曲排序方式 (default: 默认排序 hot: 热度高(相对于其所在专辑)在前 time: 发行时间新在前)
--reverse-sort 【限制总量时】倒序排序歌曲

工具:
--save-m3u 保存M3U播放列表文件名
将本次下载的歌曲文件名依一定顺序保存在M3U文件中;写入的文件目录相对于该M3U文件
文件编码为 UTF-8
顺序为:链接先后优先——每个连接的所有歌曲依照歌曲排序设定 (--sort-by)排序
限量及过滤(注:只适用于*每单个*链接 / ID):
-n 下载总量, --count 下载总量
限制下载歌曲总量,n=0即不限制(注:过大值可能导致限流)
--sort-by 歌曲排序 【限制总量时】歌曲排序方式 (default: 默认排序 hot: 热度高(相对于其所在专辑)在前 time: 发行时间新在前)
--reverse-sort 【限制总量时】倒序排序歌曲
--user-bookmarks 【下载用户歌单时】在下载用户创建的歌单的同时,也下载其收藏的歌单

工具:
--save-m3u 保存M3U播放列表文件名
将本次下载的歌曲文件名依一定顺序保存在M3U文件中;写入的文件目录相对于该M3U文件
文件编码为 UTF-8
顺序为:链接先后优先——每个链接的所有歌曲依照歌曲排序设定 (--sort-by)排序
## 环境变量
|变量名|说明|
|-|-|
Expand Down
2 changes: 1 addition & 1 deletion pyncm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
# 注意事项
- (PR#11) 海外用户可能经历 460 "Cheating" 问题,可通过添加以下 Header 解决: `X-Real-IP = 118.88.88.88`
"""
__version__ = "1.6.9.1"
__version__ = "1.6.9.2"

from threading import current_thread
from typing import Text, Union
Expand Down
38 changes: 25 additions & 13 deletions pyncm/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,12 @@ def execute(task: BaseKeyValueClass):
if type(task) == TrackDownloadTask:
try:
# Downloding source audio
dAudio = track.GetTrackAudioV1(task.audio.id, level=task.audio.level)
dAudio = dAudio.get("data", [{"url": ""}])[0] # Dummy fallback value
apiCall = track.GetTrackAudioV1 if not task.routine.args.use_download_api else track.GetTrackDownloadURLV1
if task.routine.args.use_download_api: logger.warn("使用下载 API,可能消耗 VIP 下载额度!")
dAudio = apiCall(task.audio.id, level=task.audio.level)
dAudio = dAudio.get("data", [{"url": ""}]) # Dummy fallback value
if type(dAudio) == list:
dAudio = dAudio[0]
if not dAudio['url']:
# Attempt to give some sort of explaination
# 来自 https://neteasecloudmusicapi-docs.4everland.app/#/?id=%e8%8e%b7%e5%8f%96%e6%ad%8c%e6%9b%b2%e8%af%a6%e6%83%85
Expand Down Expand Up @@ -476,8 +480,8 @@ def parse_sharelink(url):
rurl = re.findall("(?:http|https):\/\/.*", url)
if rurl:
url = rurl[0] # Use first URL found. Otherwise use value given as is.
numerics = re.findall("\d{4,}", url)
assert numerics, "未在链接中找到任何 ID"
numerics = re.findall("\d{4,}", url)
assert numerics != None, "未在链接中找到任何 ID"
ids = numerics[:1] # Only pick the first match
table = {
"song": ["trackId", "song"],
Expand All @@ -497,7 +501,6 @@ def parse_sharelink(url):

PLACEHOLDER_URL = "00000"


def parse_args():
"""Setting up __main__ argparser"""
parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -543,6 +546,12 @@ def parse_args():
standard- 标准""",
default="standard",
)
group.add_argument(
"-dl",
"--use-download-api",
action="store_true",
help="调用下载API,而非播放API进行下载。如此可能允许更高高音质音频的下载。\n【注意】此API有额度限制,参考 https://music.163.com/member/downinfo"
)
group.add_argument("--no-overwrite", action="store_true", help="不重复下载已经存在的音频文件")
group = parser.add_argument_group("歌词")
group.add_argument(
Expand Down Expand Up @@ -590,20 +599,24 @@ def parse_args():
default="",
help=r"""将本次下载的歌曲文件名依一定顺序保存在M3U文件中;写入的文件目录相对于该M3U文件
文件编码为 UTF-8
顺序为:链接先后优先——每个连接的所有歌曲依照歌曲排序设定 (--sort-by)排序"""
顺序为:链接先后优先——每个链接的所有歌曲依照歌曲排序设定 (--sort-by)排序"""
)
args = parser.parse_args()
# Clean up
args.lyric_no = args.lyric_no.lower()
args.lyric_no = args.lyric_no.split(' ')
if 'none' in args.lyric_no:
args.lyric_no = []
def print_help_and_exit():
sys.argv.append("-h") # If using placeholder, no argument is really passed
sys.exit(__main__()) # In which case, print help and exit
if args.url == PLACEHOLDER_URL and not args.save:
print_help_and_exit()
try:
return args , [parse_sharelink(url) for url in args.url]
except AssertionError:
if args.url == PLACEHOLDER_URL:
sys.argv.append("-h") # If using placeholder, no argument is really passed
return __main__() # In which case, print help and exit
print_help_and_exit()
assert args.save, "无效分享链接 %s" % ' '.join(args.url) # Allow invalid links for this one
return args , []

Expand Down Expand Up @@ -655,12 +668,11 @@ def write(__s):
open(args.save, "w").write(DumpSessionAsString(GetCurrentSession()))
return 0
if not GetCurrentSession().logged_in:
# deviceID doesn't seem to have a format,so to speak
# Meaning anything will work.
# What we're trying to do here is to generate a UUID for
# the current machine so pyncm users won't be sharing the same one (i.e. id=pyncm!)
# What even is with this thing???
# Does only a selected few deviceIds actually work?
# Nevertheless, no Issues has come to me yet so let's just leave this be lol
import uuid,base64
GetCurrentSession().deviceId = 'ahahahaman'
GetCurrentSession().deviceId = base64.b64encode(uuid.getnode().to_bytes(48,"little")).decode()[:10]
login.LoginViaAnonymousAccount()
logger.info("以匿名身份登陆成功,deviceId=%s, UID: %s" % (GetCurrentSession().deviceId,GetCurrentSession().uid))
executor = TaskPoolExecutorThread(max_workers=args.max_workers)
Expand Down
20 changes: 19 additions & 1 deletion pyncm/apis/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def GetTrackAudioV1(song_ids: list, level='standard', encodeType="flac"):

@EapiCryptoRequest
def GetTrackDownloadURL(song_ids: list, bitrate=320000, encodeType="aac"):
"""PC 端 - 以计费下载方式,获取资源URL
"""PC 端 - 获取资源URL
Args:
song_ids (list): 歌曲 ID
Expand All @@ -91,6 +91,24 @@ def GetTrackDownloadURL(song_ids: list, bitrate=320000, encodeType="aac"):
"br": str(bitrate),
}

@EapiCryptoRequest
def GetTrackDownloadURLV1(song_id:int, level='standard'):
"""PC 端 - 获取资源URL V1
Args:
song_ids (list): 歌曲 ID
level (str, optional): 音质 standard / exhigh / lossless / hires
Notes:
song_ids 项目数应 <= 1000
Returns:
dict
"""

return "/eapi/song/enhance/download/url/v1", {
"id": '%s_0' % song_id,
"level": str(level),
}

@WeapiCryptoRequest
def GetTrackLyrics(song_id: str, lv=-1, tv=-1, rv=-1):
Expand Down

0 comments on commit c4bc68d

Please sign in to comment.