Created
April 3, 2021 05:16
-
-
Save dogtopus/b2598a5c2adaa4c34ad19d7927795c17 to your computer and use it in GitHub Desktop.
Old Taiko no Tatsujin iOS song pack tool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
import yaml | |
import struct | |
import os | |
SUFFIX = ( | |
'.m4a', | |
'_e.sht', | |
'_n.sht', | |
'_h.sht', | |
'_m.sht', | |
'.ipk', | |
'.lm' | |
) | |
ALTFN_KEY = ( | |
'sound', | |
'easy', | |
'normal', | |
'hard', | |
'oni', | |
'texture', | |
'animation' | |
) | |
GENRES = ( | |
'jpop', | |
'anime', | |
'variety', | |
'classic', | |
'original', | |
'download', | |
'game', | |
'folk', | |
'vocaloid' | |
) | |
def dat_unpack(datfile, dest_dir): | |
song_id = os.path.basename(datfile).split('.')[0] | |
datinfo = {'level':[0, 0, 0, 0], 'song_id':song_id} | |
fd_dat = open(datfile, 'rb') | |
(datinfo['version'], | |
datinfo['genre'], | |
datinfo['u1'], | |
datinfo['level'][0], | |
datinfo['level'][1], | |
datinfo['level'][2], | |
datinfo['level'][3]) = struct.unpack('<I2H4b', fd_dat.read(12)) | |
offsets = struct.unpack('<16I4x', fd_dat.read(68)) | |
fd_dat.seek(offsets[0]) | |
datinfo['song_name'] = unicode(fd_dat.read(offsets[1] - 1).decode('utf8')) | |
for i in range(2, len(offsets), 2): | |
if offsets[i+1] != 0: | |
fd_subfile = open('%s/%s%s' % (dest_dir, song_id, SUFFIX[i/2-1]), 'wb') | |
fd_dat.seek(offsets[i]) | |
fd_subfile.write(fd_dat.read((offsets[i+1]))) | |
fd_subfile.close() | |
if GENRES[datinfo['genre']]: | |
datinfo['genre'] = GENRES[datinfo['genre']] | |
fd_config = open('%s/config.yml' % (dest_dir), 'w') | |
yaml.dump(datinfo, fd_config, allow_unicode = True) | |
fd_config.close() | |
fd_dat.close() | |
def dat_pack(src_dir, datfile): | |
fd_config = open('%s/config.yml' % (src_dir), 'r') | |
datinfo = yaml.load(fd_config) | |
fd_config.close() | |
try: | |
altfn = datinfo['files'] | |
except KeyError: | |
altfn = None | |
if type(datinfo['genre']) == str: | |
datinfo['genre'] = GENRES.index(datinfo['genre']) | |
header = '' | |
header += struct.pack('<I2H4b', | |
datinfo['version'], | |
datinfo['genre'], | |
datinfo['u1'], | |
datinfo['level'][0], | |
datinfo['level'][1], | |
datinfo['level'][2], | |
datinfo['level'][3]) | |
offsets = [] | |
offset = 80 | |
sn = datinfo['song_name'].encode('utf-8') + "\0" | |
sn_len = len(sn) | |
offsets.append(offset) | |
offsets.append(sn_len) | |
offset += sn_len | |
if altfn: | |
flist = []#altfn[i] for i in ALTFN_KEY] | |
for i in ALTFN_KEY: | |
try: | |
flist.append(altfn[i]) | |
except KeyError: | |
flist.append(None) | |
else: | |
flist = [("%s%s" % (datinfo['song_id'], i)) for i in SUFFIX] | |
fdlist = [] | |
for fn in flist: | |
try: | |
if fn: | |
f_len = os.path.getsize("%s/%s" % (src_dir, fn)) | |
fdlist.append(open("%s/%s" % (src_dir, fn), 'rb')) | |
else: | |
f_len = 0 | |
fdlist.append(None) | |
except: | |
print "Cannot read %s, skipping" % (fn) | |
f_len = 0 | |
fdlist.append(None) | |
offsets.append(offset) | |
offsets.append(f_len) | |
offset += f_len | |
header += struct.pack('<16I4x', *offsets) | |
fd_dat = open(datfile, 'wb') | |
fd_dat.write(header) | |
fd_dat.write(sn) | |
for fd in fdlist: | |
if fd: | |
for chunk in iter(lambda: fd.read(65535), ''): | |
fd_dat.write(chunk) | |
fd.close() | |
fd_dat.close() | |
if __name__ == '__main__': | |
import sys | |
try: | |
p, s, d = sys.argv[1:4] | |
except: | |
p = '' | |
if p == '-e': | |
dat_unpack(s, d) | |
elif p == '-b': | |
dat_pack(s, d) | |
else: | |
print 'Usage: datutil [-e|-b] <src> <dest>' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment