annotate WinampLibrary.py @ 1:a7bd26076340 default tip

Remove test file
author brad
date Fri, 09 Nov 2012 19:24:36 -0600
parents af65171c2294
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
1 import os
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
2 import struct
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
3 import Media
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
4 import time
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
5 from datetime import datetime
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
6
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
7 class WinampLibrary:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
8
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
9 base_dir = ''
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
10 # Fields mappings in the format:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
11 # <MLMedia attribute>: {'name': <Winamp internal name>, 'type': <Winamp data type>, 'winamp_id': <Winamp field ID>}
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
12 field_encode = {
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
13 'file_name': {'name': 'filename', 'type': 12, 'winamp_id': 0},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
14 'title': {'name': 'title', 'type': 3, 'winamp_id': 1},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
15 'artist': {'name': 'artist', 'type': 3, 'winamp_id': 2},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
16 'album': {'name': 'album', 'type': 3, 'winamp_id': 3},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
17 'year': {'name': 'year', 'type': 4, 'winamp_id': 4},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
18 'genre': {'name': 'genre', 'type': 3, 'winamp_id': 5},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
19 'comment': {'name': 'comment', 'type': 3, 'winamp_id': 6},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
20 'album_artist': {'name': 'albumartist', 'type': 3, 'winamp_id': 20},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
21 'composer': {'name': 'composer', 'type': 3, 'winamp_id': 24},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
22 'publisher': {'name': 'publisher', 'type': 3, 'winamp_id': 23},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
23 'category': {'name': 'category', 'type': 3, 'winamp_id': 34},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
24 'track': {'name': 'trackno', 'type': 4, 'winamp_id': 7},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
25 'length': {'name': 'length', 'type': 11, 'winamp_id': 8},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
26 'type': {'name': 'type', 'type': 4, 'winamp_id': 9},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
27 'last_update': {'name': 'lastupd', 'type': 10, 'winamp_id': 10},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
28 'last_play': {'name': 'lastplay', 'type': 10, 'winamp_id': 11},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
29 'rating': {'name': 'rating', 'type': 4, 'winamp_id': 12},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
30 'play_count': {'name': 'playcount', 'type': 4, 'winamp_id': 15},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
31 'file_time': {'name': 'filetime', 'type': 10, 'winamp_id': 16},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
32 'file_size': {'name': 'filesize', 'type': 4, 'winamp_id': 17},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
33 'bit_rate': {'name': 'bitrate', 'type': 4, 'winamp_id': 18},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
34 'disc': {'name': 'disc', 'type': 4, 'winamp_id': 19},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
35 'replaygain_album_gain': {'name': 'replaygain_album_gain', 'type': 3, 'winamp_id': 21},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
36 'replaygain_track_gain': {'name': 'replaygain_track_gain', 'type': 3, 'winamp_id': 22},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
37 'bpm': {'name': 'bpm', 'type': 4, 'winamp_id': 25},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
38 'discs': {'name': 'discs', 'type': 4, 'winamp_id': 26},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
39 'tracks': {'name': 'tracks', 'type': 4, 'winamp_id': 27},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
40 'is_podcast': {'name': 'ispodcast', 'type': 4, 'winamp_id': 28},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
41 'podcast_channel': {'name': 'podcastchannel', 'type': 3, 'winamp_id': 29},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
42 'podcast_pub_date': {'name': 'podcastpubdate', 'type': 10, 'winamp_id': 30},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
43 'gracenote_file_id': {'name': 'GracenoteFileID', 'type': 3, 'winamp_id': 31},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
44 'gracenote_ext_data': {'name': 'GracenoteExtData', 'type': 3, 'winamp_id': 32},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
45 'lossless': {'name': 'lossless', 'type': 4, 'winamp_id': 33},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
46 'codec': {'name': 'codec', 'type': 3, 'winamp_id': 35},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
47 'director': {'name': 'director', 'type': 3, 'winamp_id': 36},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
48 'producer': {'name': 'producer', 'type': 3, 'winamp_id': 37},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
49 'width': {'name': 'width', 'type': 4, 'winamp_id': 38},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
50 'height': {'name': 'height', 'type': 4, 'winamp_id': 39},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
51 'tuid2': {'name': 'tuid2', 'type': 3, 'winamp_id': 14},
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
52 }
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
53 field_decode = dict((v['name'], k) for k, v in field_encode.iteritems())
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
54 medias = []
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
55
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
56 #def __init__(self):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
57 # self.base_dir = base_dir
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
58
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
59 def files_from_path(self, path):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
60 path = os.path.normpath(path)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
61 if not os.path.isdir(path):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
62 path = os.path.dirname(path)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
63 idxfile = os.path.join(path, 'main.idx')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
64 datfile = os.path.join(path, 'main.dat')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
65 return idxfile, datfile
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
66
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
67 def read(self, path):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
68 self.fields = {}
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
69 idxfile, datfile = self.files_from_path(path)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
70 if not os.path.isfile(idxfile):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
71 raise IOError('Could not find Winamp library index file ' + idxfile)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
72 if not os.path.isfile(idxfile):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
73 raise IOError('Could not find Winamp library data file ' + datfile)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
74
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
75 idx = open(idxfile, 'rb')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
76 if idx.read(8) != 'NDEINDEX':
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
77 idx.close()
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
78 raise Exception(idxfile + ' does not appear to be a valid Winamp library index file')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
79 num_records, = struct.unpack('<i', idx.read(4))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
80 idx.read(4) # no one seems to know what these four bytes are for
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
81 dat = open(datfile, 'rb')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
82 for _ in range(0, num_records):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
83 data = idx.read(8)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
84 if len(data) < 8:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
85 break
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
86 offset, media_id = struct.unpack('ii', data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
87 print offset, media_id
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
88 media = self.read_media(dat, offset)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
89 if media is not None:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
90 self.medias.append(media)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
91 idx.close()
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
92 dat.close()
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
93
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
94 def write(self, path):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
95 fields_sorted = sorted(self.field_encode.itervalues(), key = lambda field: field['winamp_id'])
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
96 self.fields = list(self.field_decode[i['name']] for i in fields_sorted)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
97
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
98 idxfile, datfile = self.files_from_path(path)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
99 idx = open(idxfile, 'wb')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
100 dat = open(datfile, 'wb')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
101 idx.write('NDEINDEX')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
102 dat.write('NDETABLE')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
103 self.last_write_offset = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
104 self.current_write_offset = 8
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
105 # Number of actual media files, plus the column and index records
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
106 num_records = len(self.medias) + 2
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
107 # Write the number of records plus four mystery bytes to the index
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
108 idx.write(struct.pack('<i', num_records) + '\xFF\x00\x00\x00')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
109
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
110 self.write_column_record(dat)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
111 self.write_mystery_record(dat)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
112
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
113 for media in self.medias:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
114 self.write_media_record(dat, media)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
115
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
116 def write_column_record(self, dat):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
117 position = 'first'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
118 n = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
119 for field in self.fields:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
120 if n == len(self.fields) - 1:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
121 position = 'last'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
122 self.write_field(dat, field, self.field_encode[field]['name'], position, header_record = True)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
123 n += 1
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
124 if n == 1:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
125 position = 'middle'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
126
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
127 # Who knows what this is for?
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
128 def write_mystery_record(self, dat):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
129 data_packed = '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x04\x4E\x6F\x6E\x65\xAE'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
130 offset_next = self.current_write_offset + len(data_packed) + 14
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
131 header = struct.pack('<BBiii', 255, 1, len(data_packed), offset_next, 0)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
132
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
133 write_data = header + data_packed
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
134 dat.write(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
135
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
136 self.last_write_offset = self.current_write_offset
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
137 self.current_write_offset += len(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
138
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
139 data_packed = '\x00\x00\x00\x00\x0C\x00\x00\x00\x08\x66\x69\x6C\x65\x6E\x61\x6D\x65\x00'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
140 offset_prev = self.last_write_offset
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
141 header = struct.pack('<BBiii', 0, 1, len(data_packed), 0, offset_prev)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
142
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
143 write_data = header + data_packed
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
144 dat.write(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
145
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
146 self.last_write_offset = self.current_write_offset
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
147 self.current_write_offset += len(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
148
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
149 def write_media_record(self, dat, media):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
150 position = 'first'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
151 n = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
152 for field in self.fields:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
153 if n == len(self.fields) - 1:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
154 position = 'last'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
155 self.write_field(dat, field, getattr(media, field), position)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
156 n += 1
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
157 if n == 1:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
158 position = 'middle'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
159
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
160 def write_field(self, dat, field, data, position, header_record = False):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
161 if data is None:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
162 return
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
163
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
164 field_id = self.field_encode[field]['winamp_id']
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
165 data_type = self.field_encode[field]['type']
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
166
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
167 if header_record:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
168 data_packed = struct.pack('<BBB', data_type, 0, len(data))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
169 data_packed += data
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
170 data_type = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
171 else:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
172 # String field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
173 if data_type == 3 or data_type == 12:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
174 data_encoded = data.encode('utf-16')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
175 data_packed = struct.pack('<H', len(data_encoded)) + data_encoded
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
176
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
177 # Integer field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
178 elif data_type == 4 or data_type == 11:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
179 data_packed = struct.pack('<i', data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
180
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
181 # Date field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
182 elif data_type == 10:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
183 timestamp = int(time.mktime(data.timetuple()))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
184 data_packed = struct.pack('<i', timestamp)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
185
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
186 else:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
187 print 'Warning: unsupported data type ' + str(data_type) + ' for field ' + field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
188
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
189 offset_prev = self.last_write_offset
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
190 offset_next = self.current_write_offset + len(data_packed) + 14
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
191 if position == 'first':
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
192 offset_prev = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
193 elif position == 'last':
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
194 offset_next = 0
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
195
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
196 header = struct.pack('<BBiii', field_id, data_type, len(data_packed), offset_next, offset_prev)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
197 write_data = header + data_packed
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
198 dat.write(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
199
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
200 self.last_write_offset = self.current_write_offset
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
201 self.current_write_offset += len(write_data)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
202
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
203 def read_media(self, dat, offset):
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
204 dat.seek(offset)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
205 media = Media.Media()
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
206 while True:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
207 field_id, data_type, size, offset_next, offset_prev = struct.unpack('<BBiii', dat.read(14))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
208 print 'data', field_id, data_type, size, offset_next, offset_prev
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
209 # Column field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
210 if data_type == 0:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
211 # The column name is always a string, and the middle byte appears to be unused
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
212 _, _, data_size = struct.unpack('<BBB', dat.read(3))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
213 field_name = dat.read(data_size)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
214 if field_name in self.field_decode:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
215 self.fields[field_id] = field_name
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
216 else:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
217 print 'Warning: unknown field name ' + field_name
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
218
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
219 elif field_id in self.fields:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
220 prop = self.field_decode[self.fields[field_id]]
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
221 value = None
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
222
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
223 # String field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
224 if data_type == 3 or data_type == 12:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
225 data_size, = struct.unpack('<H', dat.read(2))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
226 data = dat.read(data_size)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
227 enc = 'utf-16' if data.find('\xff\xfe') == 0 else 'ascii'
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
228 value = unicode(data, encoding=enc, errors='ignore')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
229
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
230 # Integer field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
231 elif data_type == 4 or data_type == 11:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
232 value, = struct.unpack('<i', dat.read(4))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
233
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
234 # Date field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
235 elif data_type == 10:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
236 timestamp, = struct.unpack('<i', dat.read(4))
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
237 value = datetime.fromtimestamp(timestamp)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
238
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
239 # Index field? Not actually a media
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
240 elif data_type == 1:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
241 return
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
242
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
243 else:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
244 print 'Warning: unsupported data type ' + str(data_type) + ' for field ' + self.fields[field_id]
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
245
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
246 if value is not None:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
247 setattr(media, prop, value)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
248
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
249 else:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
250 print '?' + str(field_id)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
251 if offset_next == 0:
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
252 break
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
253 dat.seek(offset_next)
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
254
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
255 if data_type > 1: # not column or index field
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
256 return media
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
257
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
258 lib = WinampLibrary()
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
259 lib.read('C:\\Users\\Brad\\AppData\\Roaming\\Winamp\\Plugins\\ml')
af65171c2294 Read support, experimental write support (.dat only)
brad
parents:
diff changeset
260 lib.write('C:\\Users\\Brad\\AppData\\Roaming\\Winamp\\Plugins\\ml\\out')