forked from ipatix/agbplay
-
Notifications
You must be signed in to change notification settings - Fork 1
/
playlist_from_gsf.py
executable file
·72 lines (63 loc) · 2.62 KB
/
playlist_from_gsf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python3
# GSF spec: https://www.caitsith2.com/gsf/gsf%20spec.txt
# PSF spec: https://web.archive.org/web/20031018001256/http://www.neillcorlett.com/psf/psf_format.txt
import zlib
import sys
import json
def parse_songname_from_tags(filename, data):
try:
tag_data = data.split(b'[TAG]')[1]
tag_strings = tag_data.decode("utf-8").splitlines()
# now look for a tag called "title"
for tag in tag_strings:
if not tag.lower().startswith("title="):
continue
return tag[6:]
except:
pass
# default song name to filename if not found
return filename.replace('.minigsf', '').replace('\\', '/').split('/')[-1]
def add_minigsf_to_playlist(minigsf_file, playlist):
with open(minigsf_file, "rb") as minigsf_handle:
# load data from minigsf
minigsf_data = minigsf_handle.read()
if minigsf_data[0:3].decode("ascii") != "PSF":
raise Exception("Illegal file magic")
reserved_data_size = (
(minigsf_data[4]) |
(minigsf_data[5] << 8) |
(minigsf_data[6] << 16) |
(minigsf_data[7] << 24))
program_data_size = (
(minigsf_data[8]) |
(minigsf_data[9] << 8) |
(minigsf_data[10] << 16) |
(minigsf_data[11] << 24))
# I am too lazy to implement CRC32 check at the time
program_data = zlib.decompress(minigsf_data[0x10 + reserved_data_size : 0x10 + reserved_data_size + program_data_size])
if len(program_data) != 14 and len(program_data) != 13:
raise Exception("This converter only supports GSF with 14 bytes program data")
# get song num
if len(program_data) >= 14:
song_num = (program_data[12] | (program_data[13] << 8))
else:
song_num = program_data[12]
# get song name from tags
song_name = parse_songname_from_tags(minigsf_file, minigsf_data)
playlist.append({ "index" : song_num, "name" : song_name })
# MAIN PROGRAM STARTS HERE
if len(sys.argv) <= 1:
print("This program generates an agbplay JSON playlist from a set of minigsf files")
print("")
print("Usage:")
print("$ playlist_from_gsf.py <input minigsfs...>")
sys.exit(0)
# GSF often have the track order encoded in the file name
minigsfs = sorted(sys.argv[1:])
# remove all non minigsf files
minigsfs = [n for n in minigsfs if n.lower().endswith(".minigsf")]
# generate playlist in sorted order
playlist = []
for minigsf in minigsfs:
add_minigsf_to_playlist(minigsf, playlist)
print(json.dumps(playlist, indent=2))