音频应用
CD抓轨
abcde -1 -o flac
参数说明:
-
-1
表示将整张cd抓为一个文件否则一个音轨一个文件, -
-o flac
中的-o
用于指定输出格式, -
-P
指定使用管道而不是临时的wav文件, -
其他常见的参数还有
-b
它大概是说平衡各个音轨的音量。
具体信息可以使用abcde --help
查看。
输出位置说明:
它不提供指定输出位置的功能(至少2.5.4还不提供),默认将文件输出到当前目录下。如果使用了临时的wav文件,那么它会创建一个临时文件夹“abcde.xxxxxx”其中xxxxx表示一个随机数。对于最终输出,它会以“艺术家-专辑名”创建一个文件夹,然后在其中以“专辑名”/“音轨号-曲目名”保存各个文件
音频文件分轨
linux下使用.cue
对flac/ape
分轨与转换
LinuxUbuntuF# 需要的工具有flac,mac,shntool,ubuntu下安装mac(monkeys audio codec)要添加ppa源:
sudo add-apt-repository ppa:robert-tari/main sudo apt-get update sudo apt-get install flac mac shntool
对cue索引的flac分轨:
shntool split example.flac -f example.cue -t "%n.%p-%t" -o flac -d output shntool split example.ape -f example.cue -t "%n.%p-%t" -o flac -d output
-
-f
:指定分轨的cue文件。 -
-t
:指定输出文件的文件名格式,%n
是音轨号,%p
是演奏者/艺术家,%t
标题 -
-o
:分出来的音乐格式,一般用开源的无损格式flac
-
-d
:指定分轨后的单曲文件的输出目录,不指定的话在当前目录生成
音频格式转换
ape与flac
将ape转换成flac:
shnconv -i ape -o flac example.ape
或者
mac example.ape temp.wav -d flac temp.wav example.flac
网易云音乐格式
转换目录下的网易云音乐加密文件*.ncm
,并下载图片:
# encoding=utf-8 import binascii import struct import base64 import json import os import re from Crypto.Cipher import AES import httplib2 from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB def dump(baseDir, fileName, filePostFix): core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857") meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728") unpad = lambda s : s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(os.path.join(baseDir, fileName),'rb') header = f.read(8) 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:] # print(meta_data) meta_data = json.loads(meta_data) # meta data albumName = meta_data['album'] musicName = re.sub(os.path.sep," ", meta_data['musicName']) artist = re.sub(os.path.sep," ", meta_data['artist'][0][0]) audioFileFormat = meta_data['format'] 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] imageData = f.read(image_size) audioFileName = artist + ' - ' + musicName + '.' + audioFileFormat musicFileNamePath = os.path.join(baseDir, audioFileName) print('----------------------------------------') print(' file: ' + musicFileNamePath) print(' album: ' + albumName) print(' title: ' + musicName) print('artist: ' + artist) print('----------------------------------------') m = open(musicFileNamePath,'wb') 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) m.close() f.close() # down album cover image # downImage(meta_data['albumPic'], '/home/jade/tmp/music', audioFileName) # f = open(musicFileNamePath + '.jpg','wb') f.write(imageData) f.close() # # set meta data id3 # setMp3Info(musicFileNamePath, albumName, musicName, artist, imageData) # def setMp3Info(fileNamePath, albumName, musicName, artist, imageData): # print('------------------1---------------------') # songFile = ID3(fileNamePath) # print('------------------2---------------------') # songFile['APIC'] = APIC( # 插入封面 # encoding=3, # mime='image/jpeg', # type=3, # desc=u'Cover', # data=imageData # ) # print('------------------3---------------------') # songFile['TIT2'] = TIT2( # 插入歌名 # encoding=3, # text=musicName # ) # print('------------------4---------------------') # songFile['TPE1'] = TPE1( # 插入第一演奏家、歌手、等 # encoding=3, # text=artist # ) # print('------------------5---------------------') # songFile['TALB'] = TALB( # 插入专辑名 # encoding=3, # text=albumName # ) # print('------------------6---------------------') # songFile.save() # print('------------------7---------------------') # if __name__ == '__main__': # picPath = '2.jpg' # with open(picPath, 'rb') as f: # picData = f.read() # info = {'picData': picData, 'title': '你的酒馆对我打了烊', # 'artist': '陈雪凝', 'album': '绿色'} # songPath = '你的酒馆对我打了烊.mp3' # SetMp3Info(songPath, info) # def downImage(imgUrl, baseDir, musicName): # print('-------------------- 1 --------------------------') # print(imgUrl) # img_ext = re.findall(r'\.[^.\\/:*?"<>|\r\n]+$', imgUrl)[0] # fileName = baseDir + '/' + musicName + img_ext # print(fileName) # resp, content = httplib2.Http().request(imgUrl) # print('-------------------- 2 --------------------------') # print(resp) # if resp['status'] == '200': # f = open(fileName, 'wb') # f.write(content) # f.close() if __name__ == '__main__': # baseDir = input("input path like : /user/music\n") baseDir = os.path.abspath(os.curdir) list = os.listdir(baseDir) for i in range(0,len(list)): fileName = list[i] filePathName = os.path.join(baseDir, fileName) filePostFix = os.path.splitext(filePathName)[1] if os.path.isfile(filePathName): if filePostFix == ".ncm": try: dump(baseDir, fileName, filePostFix) except: pass