修复 vipsong.py 多处错误

1. 修复 Line 277 语法错误:output_path")" 多余引号导致的 SyntaxError
2. 添加缺失的 META_KEY 常量(NCM 元数据 AES 密钥,16 字节)
3. 添加缺失的 KUGOU_KEY_PATH 常量(指向 kugou_key.xz)
4. 添加缺失的 stats 和 kgm_decoder 模块级初始化
5. 添加缺失的 import io(用于 _convert_audio 的 BytesIO)
6. 添加缺失的 _sniff_container 函数(音频容器魔术字节检测)
7. 添加缺失的 _extension_for 函数(格式到扩展名映射)
8. 添加缺失的 _convert_audio 函数(原始音频转码)
9. 修复 print("\n") 为 print()(恢复更清洁的输出格式)
This commit is contained in:
ypshidifu
2026-09-17 13:22:49 +08:00
parent 430e7156b8
commit 3af7501b47
+55 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os, sys, glob, struct, base64, json import os, sys, glob, struct, base64, json, io
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from Crypto.Cipher import AES from Crypto.Cipher import AES
@@ -12,11 +12,53 @@ from pydub import AudioSegment
NCM_MAGIC = b"CTENFDAM" NCM_MAGIC = b"CTENFDAM"
CORE_KEY = b"hzHRAmso5kInbaxW" CORE_KEY = b"hzHRAmso5kInbaxW"
META_KEY = bytes.fromhex("2331346C6A6B5F215C5D2630553C2728")
META_PREFIX = b"163 key(D't modify):" META_PREFIX = b"163 key(D't modify):"
KUGOU_KEY_PATH = Path(__file__).parent / "kugou_key.xz"
_FORMAT_MAP = {
"mp3": "mp3",
"flac": "flac",
"wav": "wav",
"ogg": "ogg",
"m4a": "mp4",
"mp4": "mp4",
}
stats = {"success": 0, "failed": 0, "files": []}
kgm_decoder = None
def _u32le(data, pos): def _u32le(data, pos):
return struct.unpack(b"<I", data[pos:pos+4])[0] return struct.unpack(b"<I", data[pos:pos+4])[0]
def _sniff_container(header):
"""从魔术字节检测音频容器类型。"""
if len(header) >= 3 and header[:3] == b"ID3":
return "mp3"
if len(header) >= 2 and header[0] == 0xFF and (header[1] & 0xE0) == 0xE0:
return "mp3"
if len(header) >= 4 and header[:4] == b"fLaC":
return "flac"
if len(header) >= 4 and header[:4] == b"OggS":
return "ogg"
if len(header) >= 12 and header[:4] == b"RIFF" and header[8:12] == b"WAVE":
return "wav"
if len(header) >= 12 and header[4:8] == b"ftyp":
return "mp4"
return None
def _extension_for(fmt):
"""将格式名称映射为文件后缀。"""
mapping = {
"mp3": "mp3",
"flac": "flac",
"wav": "wav",
"ogg": "ogg",
"m4a": "m4a",
"mp4": "m4a",
}
return mapping.get(fmt, "mp3")
def ncm_stream_bytes(key): def ncm_stream_bytes(key):
sbox = bytearray(range(256)) sbox = bytearray(range(256))
j = 0 j = 0
@@ -210,6 +252,16 @@ def _add_tags(output_path, tags, cover=None):
except Exception: except Exception:
pass pass
def _convert_audio(raw, container, out_fmt, output_path):
"""将解密后的原始音频转码为目标格式。"""
src_fmt = _FORMAT_MAP.get(container, container)
dst_fmt = _FORMAT_MAP.get(out_fmt, out_fmt)
if src_fmt == dst_fmt:
Path(output_path).write_bytes(raw)
else:
audio = AudioSegment.from_file(io.BytesIO(raw), format=src_fmt)
audio.export(output_path, format=dst_fmt)
def convert_file(file_path, output_fmt, delete_flag): def convert_file(file_path, output_fmt, delete_flag):
global stats, kgm_decoder global stats, kgm_decoder
file_path = str(Path(file_path).resolve()) file_path = str(Path(file_path).resolve())
@@ -339,11 +391,11 @@ def main():
convert_file(f, output_fmt, delete_flag) convert_file(f, output_fmt, delete_flag)
print_stats() print_stats()
return return
print("=* 50") print("=" * 50)
print(" vipsong - Music Format Converter") print(" vipsong - Music Format Converter")
print(" Support: .ncm (NetEase) .kgm/.vpr (KuGou)") print(" Support: .ncm (NetEase) .kgm/.vpr (KuGou)")
print(" Output: mp3 / flac / wav / ogg / m4a") print(" Output: mp3 / flac / wav / ogg / m4a")
print("=* 50") print("=" * 50)
print("Commands:") print("Commands:")
print(" <filepath> Convert file or glob pattern (e.g. *.ncm)") print(" <filepath> Convert file or glob pattern (e.g. *.ncm)")
print(" -f <format> Output format (default: mp3)") print(" -f <format> Output format (default: mp3)")