音频ncm格式转mp3格式

做个笔记,ncm格式转mp3格式
参考:传送门

import os
import json
import base64
import struct
import logging
import binascii
from glob import glob
from tqdm.auto import tqdm
from textwrap import dedent
from Crypto.Cipher import AES
from multiprocessing import Pool


class TqdmLoggingHandler(logging.StreamHandler):
    """Avoid tqdm progress bar interruption by logger's output to console"""
    # see logging.StreamHandler.eval method:
    # https://github.com/python/cpython/blob/d2e2534751fd675c4d5d3adc208bf4fc984da7bf/Lib/logging/__init__.py#L1082-L1091
    # and tqdm.write method:
    # https://github.com/tqdm/tqdm/blob/f86104a1f30c38e6f80bfd8fb16d5fcde1e7749f/tqdm/std.py#L614-L620

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.write(msg, end=self.terminator)
        except RecursionError:
            raise
        except Exception:
            self.handleError(record)


log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
handler = TqdmLoggingHandler()
fmt = '%(levelname)7s [%(asctime)s] %(message)s'
datefmt = '%Y-%m-%d %H:%M:%S'
handler.setFormatter(logging.Formatter(fmt, datefmt))
log.addHandler(handler)


def dump_single_file(filepath):
    try:

        filename = filepath.split('/')[-1]
        if not filename.endswith('.ncm'): return
        filename = filename[:-4]
        for ftype in ['mp3', 'flac']:
            fname = f'{filename}.{ftype}'
            if os.path.isfile(fname):
                log.warning(f'Skipping "{filepath}" due to existing file "{fname}"')
                return

        log.info(f'Converting "{filepath}"')

        # hex to str
        core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857')
        meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728')
        unpad = lambda s: s[0:-(s[-1] if isinstance(s[-1], int) else ord(s[-1]))]
        with open(filepath, 'rb') as f:
            header = f.read(8)
            
            # str to hex
            assert binascii.b2a_hex(header) == b'4354454e4644414d'
            f.seek(2, 1)
            key_length = f.read(4)
            key_length = struct.unpack('<I', bytes(key_length))[0]
            key_data = f.read(key_length)
            key_data_array = bytearray(key_data)
            for i in range(0, len(key_data_array)):
                key_data_array[i] ^= 0x64
            key_data = bytes(key_data_array)
            cryptor = AES.new(core_key, AES.MODE_ECB)
            key_data = unpad(cryptor.decrypt(key_data))[17:]
            key_length = len(key_data)
            key_data = bytearray(key_data)
            key_box = bytearray(range(256))

            c = 0
            last_byte = 0
            key_offset = 0
            for i in range(256):
                swap = key_box[i]
                c = (swap + last_byte + key_data[key_offset]) & 0xff
                key_offset += 1
                if key_offset >= key_length:
                    key_offset = 0
                key_box[i] = key_box[c]
                key_box[c] = swap
                last_byte = c

            meta_length = f.read(4)
            meta_length = struct.unpack('<I', bytes(meta_length))[0]
            meta_data = f.read(meta_length)
            meta_data_array = bytearray(meta_data)
            for i in range(0, len(meta_data_array)):
                meta_data_array[i] ^= 0x63
            meta_data = bytes(meta_data_array)
            meta_data = base64.b64decode(meta_data[22:])
            cryptor = AES.new(meta_key, AES.MODE_ECB)
            meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:]
            meta_data = json.loads(meta_data)

            crc32 = f.read(4)
            crc32 = struct.unpack('<I', bytes(crc32))[0]
            f.seek(5, 1)
            image_size = f.read(4)
            image_size = struct.unpack('<I', bytes(image_size))[0]
            image_data = f.read(image_size)
            target_filename = filename + '.' + meta_data['format']

            with open(target_filename, 'wb') as m:
                chunk = bytearray()
                while True:
                    chunk = bytearray(f.read(0x8000))
                    chunk_length = len(chunk)
                    if not chunk:
                        break
                    for i in range(1, chunk_length + 1):
                        j = i & 0xff
                        chunk[i - 1] ^= key_box[(key_box[j] + key_box[(key_box[j] + j) & 0xff]) & 0xff]
                    m.write(chunk)
        log.info(f'Converted file saved at "{target_filename}"')
        return target_filename

    except KeyboardInterrupt:
        log.warning('Aborted')
        quit()


def list_filepaths(path):
    if os.path.isfile(path):
        return [path]
    elif os.path.isdir(path):
        return [fp for p in glob(f'{path}/*') for fp in list_filepaths(p)]
    else:
        raise ValueError(f'path not recognized: {path}')


def dump(*paths, n_workers=None):
    header = dedent(r'''
                   _  _  ___ __  __ ___  _   _ __  __ ___
         _ __ _  _| \| |/ __|  \/  |   \| | | |  \/  | _ \
        | '_ \ || | .` | (__| |\/| | |) | |_| | |\/| |  _/
        | .__/\_, |_|\_|\___|_|  |_|___/ \___/|_|  |_|_|  
        |_|   |__/                                        
                            pyNCMDUMP                     
            https://github.com/allenfrostline/pyNCMDUMP  
    ''')
    for line in header.split('\n'):
        log.info(line)

    all_filepaths = [fp for p in paths for fp in list_filepaths(p)]
    if n_workers > 1:
        log.info(f'Running pyNCMDUMP with up to {n_workers} parallel workers')
        with Pool(processes=n_workers) as p:
            list(p.map(dump_single_file, all_filepaths))
    else:
        log.info('Running pyNCMDUMP on single-worker mode')
        for fp in tqdm(all_filepaths, leave=False): dump_single_file(fp)
    log.info('All finished')


if __name__ == '__main__':
    from argparse import ArgumentParser

    parser = ArgumentParser(description='pyNCMDUMP command-line interface')
    parser.add_argument(
        'paths',
        metavar='paths',
        type=str,
        nargs='+',
        help='one or more paths to source files'
    )
    parser.add_argument(
        '-w', '--workers',
        metavar='',
        type=int,
        help=f'parallel convertion when set to more than 1 workers (default: 1)',
        default=1
    )
    args = parser.parse_args()
    dump(*args.paths, n_workers=args.workers)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/248536.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙开发ArkTS语言-XML解析

XML概述 XML&#xff08;可扩展标记语言&#xff09;是一种用于描述数据的标记语言&#xff0c;旨在提供一种通用的方式来传输和存储数据&#xff0c;特别是Web应用程序中经常使用的数据。XML并不预定义标记。因此&#xff0c;XML更加灵活&#xff0c;并且可以适用于广泛的应用…

深入理解 hash 和 history:网页导航的基础(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

C语言——输出魔方阵

目录 一、前言&#xff1a; 二、算法设计&#xff1a; 三、代码实现&#xff1a; 五、效果展示&#xff1a; 一、前言&#xff1a; 魔方矩阵又称幻方&#xff0c;是有相同的行数和列数&#xff0c;并在每行每列、对角线上的和都相等的矩阵。魔方矩阵中的每个元素不能相同。你…

华为数通——网络参考模型

OSI参考模型 七层 应用层&#xff1a;最靠近用户的一层&#xff0c;为应用程序提供网络服务。 六层 表示层&#xff1a;数据格式转换编码格式UTF-8。 五层 会话层&#xff1a;双方之间建立、管理和终止会话。 四层 传输层&#xff1a;建立、维护和取消端到端的数据传输过…

七. 使用ts写一个贪吃蛇小游戏

之前学习了几篇的ts基础&#xff0c;今天我们就使用ts来完成一个贪吃蛇的小游戏。 游戏拆解 我们将我们的任务进行简单拆解分析。 首先我们应该有一个窗口&#xff0c;我们叫做屏幕。让蛇在里面移动&#xff0c;所有我们应该想到要设计一个大盒子当作地图。考虑到食物以及蛇…

Spark编程实验一:Spark和Hadoop的安装使用

一、目的与要求 1、掌握在Linux虚拟机中安装Hadoop和Spark的方法&#xff1b; 2、熟悉HDFS的基本使用方法&#xff1b; 3、掌握使用Spark访问本地文件和HDFS文件的方法。 二、实验内容 1、安装Hadoop和Spark 进入Linux系统&#xff0c;完成Hadoop伪分布式模式的安装。完成Ha…

字符串——OJ题

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、字符串相加1、题目讲解2、思路讲解3、代码实现 二、仅仅反转字母1、题目讲解2、思路讲解3…

DSP的ADC简单笔记

DSP不需要复用GPIO&#xff0c;是单独的ADC引脚&#xff0c;与GPIO不共用 ADC时钟在PCLKCR0寄存器 所以还要配置HSPCLK HISPCP/HSPCLK寄存器 所以ADC的输入时钟&#xff0c;有固定公式&#xff1b; 控制寄存器1 简单配置3个东西&#xff1b; 控制寄存器2 设置为1软件触发 控…

如何使用ArcGIS Pro拼接影像

为了方便数据的存储和传输&#xff0c;我们在网上获取到的影像一般都是分块的&#xff0c;正式使用之前需要对这些影像进行拼接&#xff0c;这里为大家介绍一下ArcGIS Pro中拼接影像的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的…

GZ015 机器人系统集成应用技术样题2-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题2 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

【Qt QML 入门】TextField

TextField 是一个单行文本编辑器&#xff0c;它继承自TextInput&#xff0c;具备TextInput的所有功能&#xff0c;同时扩展了 TextInput 并增加了占位符文本功能和装饰选项。 自定义文本输入框&#xff1a; import QtQuick import QtQuick.Window import QtQuick.ControlsWindo…

【Android】MVC与MVP的区别,MVP网络请求实践

一、MVC模式 目录 一、MVC模式二、MVP模式 1、MVP的简单应用 1.1 导入相关依赖包并设置权限1.2 实现Model1.2 实现Presenter1.3 实现View1.4分析项目结构和绑定过程1.5效果展示 2、MVP结合RxJava 一、MVC模式 MVC&#xff08;Model(模型)——View(视图)——Controller(控制…

QT-坦克大战游戏

QT-坦克大战游戏 一、演示效果二、关键程序三、下载链接 一、演示效果 二、关键程序 #include "score.h" Score::Score(){health30; maxHealthhealth;QLabel *label1 new QLabel(this);label1->setFrameStyle(QFrame::Plain | QFrame::Box);label1->setStyle…

element-plus 结合Vue Router时出现的问题及解决方法之一

1、单文件应用element-plus中的Menu 侧边栏 <template><el-row class"tac"><el-col :span"12"><!-- <h5 class"mb-2">Custom colors</h5> --><el-menuactive-text-color"#ffd04b"background-…

Leetcode—2414.最长的字母序连续子字符串的长度【中等】

2023每日刷题&#xff08;六十&#xff09; Leetcode—2414.最长的字母序连续子字符串的长度 实现代码 class Solution { public:int longestContinuousSubstring(string s) {int ans 1;int t 1;for(int i 1; i < s.size(); i) {if(s[i] - s[i - 1] 1) {t;ans max(an…

大数据生态圈kafka在物联网中的应用测试

背景 由物联网项目中使用到了Tbox应用管理车辆&#xff0c;在上报数据的过程中&#xff0c;需要将终端产生的数据通过kafka的produce topic customer对数据进行处理后&#xff0c;放置到mysql中。完成数据二进制到json转换工作。 Kafka的使用 查看kafka的topic ./kafka-topi…

直角三角形判断_分支结构 C语言xdoj56

问题描述 设直角三角形两条直角边长度为a和b&#xff0c;斜边长度为c&#xff0c;则a&#xff0c;b&#xff0c;c满足a^2b^2c^2&#xff0c; 输入三个整数a&#xff0c;b&#xff0c;c&#xff0c;判断对应的三角形是不是直角三角形&#xff0c;不是则输出“no”&#xff0…

docker consul容器自动与注册

微服务&#xff08;容器&#xff09;注册与发现&#xff1a;是一种分布式的管理系统&#xff0c;定位服务的方法。 在传统架构当中&#xff0c;应用程序之间直连到已知服务&#xff0c;设备提供的网络&#xff1a;IP地址&#xff0c;基于tcp/ip&#xff0c;端口&#x…

Apache Flume(4):日志文件监控

1 案例说明 企业中应用程序部署后会将日志写入到文件中&#xff0c;可以使用Flume从各个日志文件将日志收集到日志中心以便于查找和分析。 2 使用Exec Soucre Exec Source Exec Source通过指定命令监控文件的变化&#xff0c;加粗属性为必须设置的。 属性名默认值说明chan…

借助文档控件Aspose.Words,在Java中比较 Word、PDF 和 PPT 文档

文档比较是各个领域的一项关键任务&#xff0c;包括法律、出版和内容管理。它确保准确跟踪和审查对合同、报告或法律协议等文档的更改。Java 开发人员经常寻求高效可靠的方法来执行文档比较&#xff0c;而Aspose提供了强大的解决方案。在这篇博文中&#xff0c;我们将探讨如何高…