Browse Source

fit png format cover & empty meta data #14

pull/16/head
Nzix 6 years ago
parent
commit
cd9201d7f8
  1. 49
      ncmdump.py

49
ncmdump.py

@ -5,11 +5,10 @@ Created on Sun Jul 15 01:05:58 2018
@author: Nzix
"""
import binascii
import struct
import base64
import json
import os
import binascii, struct
import base64, json
import os, traceback
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor as XOR
from mutagen import mp3, flac, id3
@ -17,6 +16,8 @@ from mutagen import mp3, flac, id3
def dump(input_path, output_path = None, skip = True):
output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta['format']) if not output_path else output_path
output_path = (lambda path, meta: path) if not callable(output_path) else output_path
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]))]
@ -52,6 +53,7 @@ def dump(input_path, output_path = None, skip = True):
meta_length = f.read(4)
meta_length = struct.unpack('<I', bytes(meta_length))[0]
if meta_length:
meta_data = bytearray(f.read(meta_length))
meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data]))
meta_data = base64.b64decode(meta_data[22:])
@ -59,6 +61,8 @@ def dump(input_path, output_path = None, skip = True):
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)
else:
meta_data = {'format': 'flac' if os.fstat(f.fileno()).st_size > 1024 ** 2 * 16 else 'mp3'}
# crc32
crc32 = f.read(4)
@ -68,7 +72,7 @@ def dump(input_path, output_path = None, skip = True):
f.seek(5, 1)
image_size = f.read(4)
image_size = struct.unpack('<I', bytes(image_size))[0]
image_data = f.read(image_size)
image_data = f.read(image_size) if image_size else None
# media data
output_path = output_path(input_path, meta_data)
@ -78,15 +82,6 @@ def dump(input_path, output_path = None, skip = True):
f.close()
# stream cipher (modified RC4 Pseudo-random generation algorithm)
# data = bytearray(data)
# i = 0
# j = 0
# for k, _ in enumerate(data):
# i = (i + 1) % 256
# j = (i + S[i]) % 256 # in RC4, is j = (j + S[i]) % 256
# # S[i], S[j] = S[j], S[i] # no swapping
# data[k] ^= S[(S[i] + S[j]) % 256]
stream = [S[(S[i] + S[(i + S[i]) & 0xFF]) & 0xFF] for i in range(256)]
stream = bytes(bytearray(stream * (len(data) // 256 + 1))[1:1 + len(data)])
data = XOR(data, stream)
@ -96,28 +91,28 @@ def dump(input_path, output_path = None, skip = True):
m.close()
# media tag
def embed(item, content):
item.encoding = 0
item.type = 3
item.mime = 'image/png' if content[0:4] == binascii.a2b_hex('89504E47') else 'image/jpeg'
item.data = content
if image_data:
if meta_data['format'] == 'flac':
audio = flac.FLAC(output_path)
# audio.delete()
image = flac.Picture()
image.encoding = 0
image.type = 3
image.mime = 'image/jpeg'
image.data = image_data
embed(image, image_data)
audio.clear_pictures()
audio.add_picture(image)
elif meta_data['format'] == 'mp3':
audio = mp3.MP3(output_path)
# audio.delete()
image = id3.APIC()
image.encoding = 0
image.type = 3
image.mime = 'image/jpeg'
image.data = image_data
embed(image, image_data)
audio.tags.add(image)
audio.save()
audio = mp3.EasyMP3(output_path)
if meta_length:
audio = flac.FLAC(output_path) if meta_data['format'] == 'flac' else mp3.EasyMP3(output_path)
audio['title'] = meta_data['musicName']
audio['album'] = meta_data['album']
audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']])
@ -143,5 +138,5 @@ if __name__ == '__main__':
dump(path)
print(os.path.split(path)[-1])
except Exception as e:
print(e)
print(traceback.format_exc())
pass
Loading…
Cancel
Save