Giter VIP home page Giter VIP logo

ximalaya-xm-decrypt's Introduction

Hi there

  • 🏫 I'm currently a passionate student pursuing my studies.
  • 🌱 I love exploring new technologies and learning new skills.
  • 💻 My primary programming language is Python.
  • 🎯 My main focus is on Machine Learning and Data Science.
  • 🌱 I'm always eager to grow and learn from others in the field.
  • 🤝 I'm open to collaboration on interesting projects.

Feel free to drop me an email at [email protected]!

Diaoxiaozhang's GitHub stats

ximalaya-xm-decrypt's People

Contributors

diaoxiaozhang avatar moxuec avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ximalaya-xm-decrypt's Issues

decryption

from mutagen.easyid3 import ID3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
import io,sys,pathlib
import re,base64,magic
import mutagen



class XMInfo:
    '''
    const {
        title: s,
        artist: l,
        subtitle: c,
        length: d,
        comment: {
            language: u,
            text: p
        },
        album: h,
        trackNumber: b,
        size: g,
        encodingTechnology: v,
        ISRC: _,
        fileType: y,
        encodedBy: w,
        publisher: k,
        composer: x,
        mediaType: S
    }
    '''
    def __init__(self):
        self.title = ""
        self.artist = ""
        self.album = ""
        self.tracknumber = 0
        self.size = 0
        self.header_size = 0
        self.ISRC = ""
        self.encodedby = ""
        self.encoding_technology = ""

    def iv(self):
        if (self.ISRC != ""):
            return bytes.fromhex(self.ISRC)
        return bytes.fromhex(self.encodedby)

def get_str(x):
    if x is None:
        return ""
    return x

def read_file(x):
    with open(x,"rb") as f:
        return f.read()

# return number of id3 bytes
def get_xm_info(data:bytes):
    # print(EasyID3(io.BytesIO(data)))
    id3 = ID3(io.BytesIO(data),v2_version=3)
    id3value = XMInfo()
    id3value.title = str(id3["TIT2"])
    id3value.album = str(id3["TALB"])
    id3value.artist = str(id3["TPE1"])
    id3value.tracknumber = int(str(id3["TRCK"]))
    id3value.ISRC = "" if id3.get("TSRC") is None else str(id3["TSRC"])
    id3value.encodedby = "" if id3.get("TENC") is None else str(id3["TENC"])
    id3value.size = int(str(id3["TSIZ"]))
    id3value.header_size = id3.size
    id3value.encoding_technology = str(id3["TSSE"])
    return id3value

def get_printable_count(x:bytes):
    i = 0
    for i,c in enumerate(x):
        # all pritable
        if c < 0x20 or c > 0x7e:
            return i
    return i

def get_printable_bytes(x:bytes):
    return x[:get_printable_count(x)]

def xm_decrypt(raw_data):
    # decode id3
    xm_info = get_xm_info(raw_data)
    print("id3 header size: ",hex(xm_info.header_size))
    encrypted_data = raw_data[xm_info.header_size:xm_info.header_size+xm_info.size:]

    # Stage 1 aes-256-cbc
    xm_key = b"ximalayaximalayaximalayaximalaya"
    print(f"decrypt stage 1 (aes-256-cbc):\n"
          f"    data length = {len(encrypted_data)},\n"
          f"    key = {xm_key},\n"
          f"    iv = {xm_info.iv().hex()}")
    cipher = AES.new(xm_key, AES.MODE_CBC, xm_info.iv())
    de_data = cipher.decrypt(pad(encrypted_data, 16))
    # Stage 2 xmDecrypt = (base64 decode => aes-192-cbc => base64 encode)
    print(f"decrypt stage 2 (xmDecrypt):\n"
          f"    data length = {len(de_data)},\n"
          f"    key = {str(xm_info.tracknumber)}")
    stage_2_data = base64.b64decode(get_printable_bytes(de_data))
    assert len(stage_2_data) % 16 == 0
    key = str(xm_info.tracknumber).encode()
    key = (b'12345678'*3)[:0x18-len(key)] + key
    cipher = AES.new(key, AES.MODE_CBC, key[:16])
    stage_2_data = unpad(cipher.decrypt(stage_2_data),16).decode() # idk but workround
    # Stage 3 combine
    print(f"Stage 3 (base64 combination):\n"
          f"    technology = {xm_info.encoding_technology}")
    decrypted_data = base64.b64decode(xm_info.encoding_technology+stage_2_data)
    final_data = decrypted_data + raw_data[xm_info.header_size+xm_info.size::]
    return xm_info,final_data

def xm_decrypt_v12():
    pass

def find_ext(data):
    exts = ["m4a","mp3","flac","wav"]
    value = magic.from_buffer(data).lower()
    for ext in exts:
        if ext in value:
            return ext
    raise Exception(f"unexpected format {value}")

def decrypt_xm_file(from_file,output=''):
    print(f"decrypting {from_file}")
    data = read_file(from_file)
    info, audio_data = xm_decrypt(data)
    if output == "":
        output = re.sub(r'[^\w\-_\. ]', '_', info.title)+"."+find_ext(audio_data[:0xff])
    buffer = io.BytesIO(audio_data)
    tags = mutagen.File(buffer,easy=True)
    tags["title"] = info.title
    tags["album"] = info.album
    tags["artist"] = info.artist
    print(tags.pprint())
    tags.save(buffer)
    with open(output,"wb") as f:
        buffer.seek(0)
        f.write(buffer.read())
    print(f"decrypt succeed, file write to {output}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python decrypt_xm.py [<filename> ...]")
    for filename in sys.argv[1::]:
        decrypt_xm_file(filename)

如果加密没变过的话

请问一下源码环境如何配置

我这边本地配置python一直有一个包导进来显示不可用,导致没法自己修改一下,想把转换后的文件直接转成mp3,请问可以教一下吗?万分感谢

新增了一下,由于我这边有转mp3的需求,修改了一下源码,可以多线程ffmpeg转mp3,我给的是8个

import base64
import concurrent.futures
import glob
import io
import os
import pathlib
import subprocess
import sys
import mutagen
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from mutagen.easyid3 import ID3
from wasmer import Store, Module, Instance, Uint8Array, Int32Array, engine
from wasmer_compiler_cranelift import Compiler

class XMInfo:
def init(self):
self.title = ""
self.artist = ""
self.album = ""
self.tracknumber = 0
self.size = 0
self.header_size = 0
self.ISRC = ""
self.encodedby = ""
self.encoding_technology = ""

def iv(self):
    if self.ISRC != "":
        return bytes.fromhex(self.ISRC)
    return bytes.fromhex(self.encodedby)

def get_str(x):
if x is None:
return ""
return x

def read_file(x):
with open(x, "rb") as f:
return f.read()

return number of id3 bytes

def get_xm_info(data: bytes):
# print(EasyID3(io.BytesIO(data)))
id3 = ID3(io.BytesIO(data), v2_version=3)
id3value = XMInfo()
id3value.title = str(id3["TIT2"])
id3value.album = str(id3["TALB"])
id3value.artist = str(id3["TPE1"])
id3value.tracknumber = int(str(id3["TRCK"]))
id3value.ISRC = "" if id3.get("TSRC") is None else str(id3["TSRC"])
id3value.encodedby = "" if id3.get("TENC") is None else str(id3["TENC"])
id3value.size = int(str(id3["TSIZ"]))
id3value.header_size = id3.size
id3value.encoding_technology = str(id3["TSSE"])
return id3value

def get_printable_count(x: bytes):
i = 0
for i, c in enumerate(x):
# all pritable
if c < 0x20 or c > 0x7e:
return i
return i

def get_printable_bytes(x: bytes):
return x[:get_printable_count(x)]

def xm_decrypt(raw_data):
# load xm encryptor
# print("loading xm encryptor")
xm_encryptor = Instance(Module(
Store(engine.Universal(Compiler)),
pathlib.Path("./xm_encryptor.wasm").read_bytes()
))
# decode id3
xm_info = get_xm_info(raw_data)
# print("id3 header size: ", hex(xm_info.header_size))
encrypted_data = raw_data[xm_info.header_size:xm_info.header_size + xm_info.size:]

# Stage 1 aes-256-cbc
xm_key = b"ximalayaximalayaximalayaximalaya"
# print(f"decrypt stage 1 (aes-256-cbc):\n"
#       f"    data length = {len(encrypted_data)},\n"
#       f"    key = {xm_key},\n"
#       f"    iv = {xm_info.iv().hex()}")
cipher = AES.new(xm_key, AES.MODE_CBC, xm_info.iv())
de_data = cipher.decrypt(pad(encrypted_data, 16))
# print("success")
# Stage 2 xmDecrypt
de_data = get_printable_bytes(de_data)
track_id = str(xm_info.tracknumber).encode()
stack_pointer = xm_encryptor.exports.a(-16)
assert isinstance(stack_pointer, int)
de_data_offset = xm_encryptor.exports.c(len(de_data))
assert isinstance(de_data_offset, int)
track_id_offset = xm_encryptor.exports.c(len(track_id))
assert isinstance(track_id_offset, int)
memory_i = xm_encryptor.exports.i
memview_unit8: Uint8Array = memory_i.uint8_view(offset=de_data_offset)
for i, b in enumerate(de_data):
    memview_unit8[i] = b
memview_unit8: Uint8Array = memory_i.uint8_view(offset=track_id_offset)
for i, b in enumerate(track_id):
    memview_unit8[i] = b
# print(bytearray(memory_i.buffer)[track_id_offset:track_id_offset + len(track_id)].decode())
# print(f"decrypt stage 2 (xmDecrypt):\n"
#       f"    stack_pointer = {stack_pointer},\n"
#       f"    data_pointer = {de_data_offset}, data_length = {len(de_data)},\n"
#       f"    track_id_pointer = {track_id_offset}, track_id_length = {len(track_id)}")
# print("success")
xm_encryptor.exports.g(stack_pointer, de_data_offset, len(de_data), track_id_offset, len(track_id))
memview_int32: Int32Array = memory_i.int32_view(offset=stack_pointer // 4)
result_pointer = memview_int32[0]
result_length = memview_int32[1]
assert memview_int32[2] == 0, memview_int32[3] == 0
result_data = bytearray(memory_i.buffer)[result_pointer:result_pointer + result_length].decode()
# Stage 3 combine
# print(f"Stage 3 (base64)")
decrypted_data = base64.b64decode(xm_info.encoding_technology + result_data)
final_data = decrypted_data + raw_data[xm_info.header_size + xm_info.size::]
# print("success")
return xm_info, final_data

def replace_invalid_chars(name):
invalid_chars = ['/', '\', ':', '*', '?', '"', '<', '>', '|']
for char in invalid_chars:
if char in name:
name = name.replace(char, " ")
return name

def convert_to_mp3(input_file, output_file, bitrate='24k'):
command = ['ffmpeg', '-i', input_file, '-acodec', 'libmp3lame', '-b:a', bitrate, output_file]
subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def decrypt_xm_file_to_aac(from_file, output_path='./output'):
data = read_file(from_file)
info, audio_data = xm_decrypt(data)

album_path = f"{output_path}/{replace_invalid_chars(info.album)}"
temp_output = f"{album_path}/{replace_invalid_chars(info.title)}.aac"

if not os.path.exists(album_path):
    os.makedirs(album_path)

buffer = io.BytesIO(audio_data)
tags = mutagen.File(buffer, easy=True)
tags["title"] = info.title
tags["album"] = info.album
tags["artist"] = info.artist
tags.save(buffer)

with open(temp_output, "wb") as f:
    buffer.seek(0)
    f.write(buffer.read())

return temp_output

def convert_to_mp3_in_thread(aac_file, mp3_file, bitrate='24k'):
convert_to_mp3(aac_file, mp3_file, bitrate)
os.remove(aac_file) # 删除临时AAC文件

def batch_decrypt_and_convert(directory, output_path='./output'):
xm_files = glob.glob(os.path.join(directory, "*.xm"))
aac_files = []

for xm_file in xm_files:
    print(f"正在解密文件: {xm_file}")
    aac_file = decrypt_xm_file_to_aac(xm_file, output_path)
    aac_files.append(aac_file)

with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
    futures = []
    for aac_file in aac_files:
        mp3_file = aac_file.replace(".aac", ".mp3")
        futures.append(executor.submit(convert_to_mp3_in_thread, aac_file, mp3_file, '24k'))

    for future in concurrent.futures.as_completed(futures):
        print("文件转换完成:", future.result())

def get_output_path():
print("请选择是否需要设置输出路径:(不设置默认为本程序目录下的output文件夹)")
print("1. 设置输出路径")
print("2. 不设置输出路径")
choice = input()
if choice == "1":
print("请输入输出路径:")
output_path = input()
if not os.path.exists(output_path):
os.makedirs(output_path)
return output_path
else:
return "./output"

if name == "main":
while True:
print("欢迎使用喜马拉雅音频解密工具")
print("本工具仅供学习交流使用,严禁用于商业用途")
print("请选择您想要使用的功能:")
print("1. 解密单个文件")
print("2. 批量解密文件")
print("3. 退出")
choice = input()
if choice == "1":
print("请输入需要解密的文件路径:")
file_to_decrypt = input()
if os.path.exists(file_to_decrypt) and os.path.isfile(file_to_decrypt):
output_path = get_output_path()
decrypt_xm_file_to_aac(file_to_decrypt, output_path)
else:
print("您输入的不是一个有效的文件路径,请重新输入!")
elif choice == "2":
print("请输入包含需要解密的文件的文件夹路径:")
dir_to_decrypt = input()
if os.path.exists(dir_to_decrypt) and os.path.isdir(dir_to_decrypt):
output_path = get_output_path()
batch_decrypt_and_convert(dir_to_decrypt, output_path)
else:
print("您输入的不是一个有效的文件夹路径,请重新输入!")
elif choice == "3":
print("退出程序。")
sys.exit()
else:
print("输入错误,请重新输入!")

您好,我为我的无知感到抱歉,我无法直接对xm解密为mp3

之前在您issue下面发布代码实属不对,并且我发现,解密xm再用ffmpeg转为mp3实在有点蠢,请问您可以给我提供点建议以直接将解密后的文件输出为mp3/wav吗?家里老人使用收音机,m4a无法播放,万分感谢,我再喜马拉雅APP下载的均为低音质,感谢您,祝您生活愉快

部分专辑居然解密失败

正在解密D:/喜马拉雅/另一部分\第4260集 真正的通天指!【搜:一觉醒来】.xm
Traceback (most recent call last):
File "main.py", line 220, in
File "main.py", line 146, in decrypt_xm_file
File "main.py", line 85, in xm_decrypt
File "main.py", line 50, in get_xm_info
File "mutagen\id3_file.py", line 76, in init
File "mutagen\id3_tags.py", line 172, in init
File "mutagen_util.py", line 533, in init
File "mutagen_tags.py", line 110, in init
File "mutagen_util.py", line 184, in wrapper
File "mutagen_util.py", line 155, in wrapper
File "mutagen\id3_file.py", line 151, in load
File "mutagen_util.py", line 184, in wrapper
File "mutagen\id3_tags.py", line 58, in init
mutagen.id3._util.ID3NoHeaderError: : too small
[3712] Failed to execute script 'main' due to unhandled exception!

感谢!

非常棒,解密有效而且速度快!

转换格式问题

我是用大佬这个工具用来下载喜马拉雅的,xm格式转换后是m4a格式,希望可以增加转换成mp3格式的选项。这样可以方便我放在收音机里面。谢谢大佬

新增了一下,由于我这边有转mp3的需求,修改了一下源码,可以多线程ffmpeg转mp3,我给的是8个

import base64
import concurrent.futures
import glob
import io
import os
import pathlib
import subprocess
import sys
import mutagen
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from mutagen.easyid3 import ID3
from wasmer import Store, Module, Instance, Uint8Array, Int32Array, engine
from wasmer_compiler_cranelift import Compiler

class XMInfo:
    def __init__(self):
        self.title = ""
        self.artist = ""
        self.album = ""
        self.tracknumber = 0
        self.size = 0
        self.header_size = 0
        self.ISRC = ""
        self.encodedby = ""
        self.encoding_technology = ""

    def iv(self):
        if self.ISRC != "":
            return bytes.fromhex(self.ISRC)
        return bytes.fromhex(self.encodedby)


def get_str(x):
    if x is None:
        return ""
    return x


def read_file(x):
    with open(x, "rb") as f:
        return f.read()


# return number of id3 bytes
def get_xm_info(data: bytes):
    # print(EasyID3(io.BytesIO(data)))
    id3 = ID3(io.BytesIO(data), v2_version=3)
    id3value = XMInfo()
    id3value.title = str(id3["TIT2"])
    id3value.album = str(id3["TALB"])
    id3value.artist = str(id3["TPE1"])
    id3value.tracknumber = int(str(id3["TRCK"]))
    id3value.ISRC = "" if id3.get("TSRC") is None else str(id3["TSRC"])
    id3value.encodedby = "" if id3.get("TENC") is None else str(id3["TENC"])
    id3value.size = int(str(id3["TSIZ"]))
    id3value.header_size = id3.size
    id3value.encoding_technology = str(id3["TSSE"])
    return id3value


def get_printable_count(x: bytes):
    i = 0
    for i, c in enumerate(x):
        # all pritable
        if c < 0x20 or c > 0x7e:
            return i
    return i


def get_printable_bytes(x: bytes):
    return x[:get_printable_count(x)]

def xm_decrypt(raw_data):
    xm_encryptor = Instance(Module(
        Store(engine.Universal(Compiler)),
        pathlib.Path("./xm_encryptor.wasm").read_bytes()
    ))
    xm_info = get_xm_info(raw_data)
    encrypted_data = raw_data[xm_info.header_size:xm_info.header_size + xm_info.size:]
    xm_key = b"ximalayaximalayaximalayaximalaya"
    cipher = AES.new(xm_key, AES.MODE_CBC, xm_info.iv())
    de_data = cipher.decrypt(pad(encrypted_data, 16))
    de_data = get_printable_bytes(de_data)
    track_id = str(xm_info.tracknumber).encode()
    stack_pointer = xm_encryptor.exports.a(-16)
    assert isinstance(stack_pointer, int)
    de_data_offset = xm_encryptor.exports.c(len(de_data))
    assert isinstance(de_data_offset, int)
    track_id_offset = xm_encryptor.exports.c(len(track_id))
    assert isinstance(track_id_offset, int)
    memory_i = xm_encryptor.exports.i
    memview_unit8: Uint8Array = memory_i.uint8_view(offset=de_data_offset)
    for i, b in enumerate(de_data):
        memview_unit8[i] = b
    memview_unit8: Uint8Array = memory_i.uint8_view(offset=track_id_offset)
    for i, b in enumerate(track_id):
        memview_unit8[i] = b
    xm_encryptor.exports.g(stack_pointer, de_data_offset, len(de_data), track_id_offset, len(track_id))
    memview_int32: Int32Array = memory_i.int32_view(offset=stack_pointer // 4)
    result_pointer = memview_int32[0]
    result_length = memview_int32[1]
    assert memview_int32[2] == 0, memview_int32[3] == 0
    result_data = bytearray(memory_i.buffer)[result_pointer:result_pointer + result_length].decode()
    decrypted_data = base64.b64decode(xm_info.encoding_technology + result_data)
    final_data = decrypted_data + raw_data[xm_info.header_size + xm_info.size::]
    return xm_info, final_data

def replace_invalid_chars(name):
    invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
    for char in invalid_chars:
        if char in name:
            name = name.replace(char, " ")
    return name

def convert_to_mp3(input_file, output_file, bitrate='24k'):
    command = ['ffmpeg', '-i', input_file, '-acodec', 'libmp3lame', '-b:a', bitrate, output_file]
    subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def decrypt_xm_file_to_aac(from_file, output_path='./output'):
    data = read_file(from_file)
    info, audio_data = xm_decrypt(data)

    album_path = f"{output_path}/{replace_invalid_chars(info.album)}"
    temp_output = f"{album_path}/{replace_invalid_chars(info.title)}.aac"

    if not os.path.exists(album_path):
        os.makedirs(album_path)

    buffer = io.BytesIO(audio_data)
    tags = mutagen.File(buffer, easy=True)
    tags["title"] = info.title
    tags["album"] = info.album
    tags["artist"] = info.artist
    tags.save(buffer)

    with open(temp_output, "wb") as f:
        buffer.seek(0)
        f.write(buffer.read())

    return temp_output

def convert_to_mp3_in_thread(aac_file, mp3_file, bitrate='24k'):
    convert_to_mp3(aac_file, mp3_file, bitrate)
    os.remove(aac_file)  # 删除临时AAC文件

def batch_decrypt_and_convert(directory, output_path='./output'):
    xm_files = glob.glob(os.path.join(directory, "*.xm"))
    aac_files = []

    for xm_file in xm_files:
        print(f"正在解密文件: {xm_file}")
        aac_file = decrypt_xm_file_to_aac(xm_file, output_path)
        aac_files.append(aac_file)

    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        futures = []
        for aac_file in aac_files:
            mp3_file = aac_file.replace(".aac", ".mp3")
            futures.append(executor.submit(convert_to_mp3_in_thread, aac_file, mp3_file, '24k'))

        for future in concurrent.futures.as_completed(futures):
            print("文件转换完成:", future.result())


def get_output_path():
    print("请选择是否需要设置输出路径:(不设置默认为本程序目录下的output文件夹)")
    print("1. 设置输出路径")
    print("2. 不设置输出路径")
    choice = input()
    if choice == "1":
        print("请输入输出路径:")
        output_path = input()
        if not os.path.exists(output_path):
            os.makedirs(output_path)
        return output_path
    else:
        return "./output"

if __name__ == "__main__":
    while True:
        print("欢迎使用喜马拉雅音频解密工具")
        print("本工具仅供学习交流使用,严禁用于商业用途")
        print("请选择您想要使用的功能:")
        print("1. 解密单个文件")
        print("2. 批量解密文件")
        print("3. 退出")
        choice = input()
        if choice == "1":
            print("请输入需要解密的文件路径:")
            file_to_decrypt = input()
            if os.path.exists(file_to_decrypt) and os.path.isfile(file_to_decrypt):
                output_path = get_output_path()
                decrypt_xm_file_to_aac(file_to_decrypt, output_path)
            else:
                print("您输入的不是一个有效的文件路径,请重新输入!")
        elif choice == "2":
            print("请输入包含需要解密的文件的文件夹路径:")
            dir_to_decrypt = input()
            if os.path.exists(dir_to_decrypt) and os.path.isdir(dir_to_decrypt):
                output_path = get_output_path()
                batch_decrypt_and_convert(dir_to_decrypt, output_path)
            else:
                print("您输入的不是一个有效的文件夹路径,请重新输入!")
        elif choice == "3":
            print("退出程序。")
            sys.exit()
        else:
            print("输入错误,请重新输入!")

python-magic-bin 无法安装

ERROR: Could not find a version that satisfies the requirement python-magic-bin (from versions: none)
ERROR: No matching distribution found for python-magic-bin

环境:mac, Python 3.11.4

一個小錯誤

Hello

剛發現一個小錯誤,第 147 行建立文件夾的 if 區塊,應該放在 if output == "" 裡面,因為當 decrypt_xm_file 函數未設置輸出文件夾且輸出的子文件夾又不存在的時候才需要建立,這樣理解應該沒錯吧,若無誤再煩請修改囉!

    if output == "":
        output = f"./output/{replace_invalid_chars(info.album)}/{replace_invalid_chars(info.title)}.{find_ext(audio_data[:0xff])}"
        # 下面的部分
        if not os.path.exists(f"./output/{replace_invalid_chars(info.album)}"):
            os.makedirs(f"./output/{replace_invalid_chars(info.album)}")

报错无法解密

image
放了一个单文件进去解密练手,提示如上图。不管是否自定义导出路径,会直接很快显示完上图后退出程序,也没有解密完的文件生成。
专辑ID为5691565,顺手放进去的其中一个文件,所以不知道具体是哪一集。但随机放了两个文件去尝试,结果都一样。

id3 != b'ID3'

解密单个文件
不设置输出路径
raise ID3NoHeaderError("%r doesn't start with an ID3 tag" % fn)
mutagen.id3._util.ID3NoHeaderError: '' doesn't start with an ID3 tag

求助:解密部分专辑时,会出现部分文件无法解密的情况

1716573253371
1716573235045
使用v0.1.3版本,系统windows 10。
图中专辑发布上传于2020-2021年。
从第498集开始解密失败,将xm文件删除,重新下载本地,解密依然失败。
除了这个专辑以外,还有其他的也出现过此类问题,譬如《不让江山》《我的女鬼大人》等。

0.13版本,解密最新喜马拉雅客户端下载的xm音频时闪退

0.13版本,解密最新喜马拉雅客户端下载的xm音频时闪退,Ximalaya-XM-Decrypt-v0.1.3.exe和xm_encryptor.wasm在同一文件夹,exe可以正常打开,但按照指引选择文件解密时,会百分百闪退,批量和单文件,指定和不指定路径都尝试过了,全部闪退

请问一下,这个错误是为什么

File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen\id3_file.py", line 76, in init
super(ID3, self).init(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen\id3_tags.py", line 175, in init
super(ID3Tags, self).init(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen_util.py", line 534, in init
super(DictProxy, self).init(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen_tags.py", line 110, in init
self.load(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen_util.py", line 185, in wrapper
return func(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen_util.py", line 156, in wrapper
return func(self, h, *args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen\id3_file.py", line 151, in load
self._header = ID3Header(fileobj)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen_util.py", line 185, in wrapper
return func(*args, **kwargs)
File "D:\soft\anaocanda\envs\xmly\lib\site-packages\mutagen\id3_tags.py", line 66, in init
raise ID3NoHeaderError("%r doesn't start with an ID3 tag" % fn)
mutagen.id3._util.ID3NoHeaderError: '' doesn't start with an ID3 tag

提示以下错误,请问是版本问题么

Traceback (most recent call last):
File "E:\Python\Pycharm\PyCharm_workspace\量化\ximalayajiemi\main.py", line 221, in
decrypt_xm_file(file, output_path)
File "E:\Python\Pycharm\PyCharm_workspace\量化\ximalayajiemi\main.py", line 145, in decrypt_xm_file
output = f"{output_path}/{replace_invalid_chars(info.album)}/{replace_invalid_chars(info.title)}.{find_ext(audio_data[:0xff])}"
File "E:\Python\Pycharm\PyCharm_workspace\量化\ximalayajiemi\main.py", line 134, in find_ext
value = magic.from_buffer(data).lower()
File "E:\Python\Pycharm\PyCharm_workspace\量化\lib\site-packages\magic\magic.py", line 146, in from_buffer
m = _get_magic_type(mime)
File "E:\Python\Pycharm\PyCharm_workspace\量化\lib\site-packages\magic\magic.py", line 122, in _get_magic_type
i = _instances[mime] = Magic(mime=mime)
File "E:\Python\Pycharm\PyCharm_workspace\量化\lib\site-packages\magic\magic.py", line 71, in init
magic_load(self.cookie, magic_file)
File "E:\Python\Pycharm\PyCharm_workspace\量化\lib\site-packages\magic\magic.py", line 272, in magic_load
return _magic_load(cookie, coerce_filename(filename))
File "E:\Python\Pycharm\PyCharm_workspace\量化\lib\site-packages\magic\magic.py", line 203, in errorcheck_negative_one
raise MagicException(err)
magic.magic.MagicException: b'could not find any valid magic files!'

使用的 python_magic_bin 不支持 Mac M 系列芯片

当前使用 Macbook Pro M芯片(M3Max),安装 Requirements 时,发现 python_magic_bin 无法安装,查看 pipy 官方页面,发现不支持 Mac 的 M 系列芯片,请问是否考虑更换这个依赖包?

[Bug] 喜马拉雅是文件格式可能发生变更

Traceback (most recent call last):
File "main.py", line 220, in
File "main.py", line 146, in decrypt_xm_file
File "main.py", line 85, in xm_decrypt
File "main.py", line 50, in get_xm_info
File "mutagen\id3_file.py", line 76, in init
File "mutagen\id3_tags.py", line 172, in init
File "mutagen_util.py", line 533, in init
File "mutagen_tags.py", line 110, in init
File "mutagen_util.py", line 184, in wrapper
File "mutagen_util.py", line 155, in wrapper
File "mutagen\id3_file.py", line 151, in load
File "mutagen_util.py", line 184, in wrapper
File "mutagen\id3_tags.py", line 66, in init
mutagen.id3._util.ID3NoHeaderError: '' doesn't start with an ID3 tag
[16084] Failed to execute script 'main' due to unhandled exception!

无法清除缓存,文件改名后重新转换依旧是原始文件名

如果对某目录下的文件转换过一次后,需要增加删除一些文件,同时把部分旧文件改名。
再次转换该目录,则无法识别新文件,也无法识别改名后的旧文件,重新生成的还是原始文件。
应该是缓存没有清除,希望改进。
感谢

闪退

解密路径和输出路径都设置好了 运行就闪退 然后什么都没有了
输出路径不设置也是一样的 不知道这是为什么
以管理员身份运行也是同样闪退

Exception: unexpected format audio file with id3 version 2.4.0, contains:mpeg adts, layer iii, v2, 160 kbps, 24 khz, monaural

运行时出现下面这个错误,请问是怎么回事?

Traceback (most recent call last):
File "/Users/Documents/Ximalaya-XM-Decrypt-main/main.py", line 221, in
decrypt_xm_file(file, output_path)
File "/Users/Documents/Ximalaya-XM-Decrypt-main/main.py", line 145, in decrypt_xm_file
output = f"{output_path}/{replace_invalid_chars(info.album)}/{replace_invalid_chars(info.title)}.{find_ext(audio_data[:0xff])}"
File "/Users/Documents/Ximalaya-XM-Decrypt-main/main.py", line 138, in find_ext
raise Exception(f"unexpected format {value}")
Exception: unexpected format audio file with id3 version 2.4.0, contains:mpeg adts, layer iii, v2, 160 kbps, 24 khz, monaural

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.