shuffle with lists
[riffle.git] / shuffle.py
blob8b73988fce9f315a9a355050f55cd197857774fd
1 """
2 iPod Shuffle database access
4 File format documentation:
5 - http://ipodlinux.org/ITunesDB#iTunesSD_file and further
7 Author: Artem Baguinski
8 """
10 from __future__ import with_statement
11 import os, sys
12 from records import *
14 READ = 'rb'
15 WRITE = 'w+b'
17 iTunesSD = Record([
18 Field(Uint24(), 'len(tracks)'),
19 Field(Uint24(), const = 0x010800),
20 Field(Uint24(), '%reclen%', check = True),
21 Skip(9),
22 ListField('tracks', Record([
23 Field(Uint24(), '%reclen%', check = True),
24 Skip(3),
25 Field(Uint24(), 'starttime', default = 0),
26 Skip(6),
27 Field(Uint24(), 'stoptime', default = 0),
28 Skip(6),
29 Field(Uint24(), 'volume', default = 0x64),
30 # for the following fileds there is no sensible default
31 Field(Uint24(), 'file_type'),
32 Skip(3),
33 Field(ZeroPaddedString(522, 'UTF-16-LE'), 'filename'),
34 Field(Bool8(), 'shuffleflag'),
35 Field(Bool8(), 'bookmarkflag'),
36 Skip(1)],
37 BIG_ENDIAN))],
38 BIG_ENDIAN)
40 iTunesStats = Record([
41 Field( Uint24(), 'len(tracks)'),
42 Skip(3),
43 ListField('tracks', Record([
44 Field( Uint24(), '%reclen%', check = True),
45 Field( Int24(), 'bookmarktime', default = -1),
46 Skip(6),
47 Field( Uint24(), 'playcount', default = 0),
48 Field( Uint24(), 'skippedcount', default = 0)],
49 LITTLE_ENDIAN))],
50 LITTLE_ENDIAN)
52 # Here I disagree with the format from URL, but I'm not sure about nothing
53 iTunesPState = Record([
54 Field( Uint8(), 'volume', default = 29 ),
55 Field( Uint24(), 'shufflepos', default = 0 ),
56 Field( Uint24(), 'trackno', default = 0 ),
57 Field( Bool24(), 'shuffleflag', default = False),
58 Field( Uint24(), 'trackpos', default = 0),
59 Skip(19)],
60 LITTLE_ENDIAN)
62 class ShuffleDB:
63 supported_file_types = (".mp3", ".aa", ".m4a", ".m4b", ".m4p", ".wav")
65 def write_iTunesSD(self, tracks):
66 with open('iTunesSD', WRITE) as file:
67 iTunesSD.write(file, {'tracks':tracks})
68 file.truncate()
70 def read_iTunesSD(self):
71 with open('iTunesSD', READ) as file:
72 return iTunesSD.read(file)['tracks']
74 def write_iTunesStats(self, tracks):
75 with open('iTunesStats', WRITE) as file:
76 iTunesStats.write(file, {'tracks':tracks})
77 file.truncate()
79 def read_iTunesStats(self, tracks):
80 with open('iTunesStats', READ) as file:
81 iTunesStats.read(file,{'tracks':tracks})['tracks']
83 def write_iTunesPState(self, pstate):
84 with open('iTunesPState', WRITE) as file:
85 iTunesPState.write(file, pstate)
86 file.truncate()
88 def read_iTunesPState(self):
89 with open('iTunesPState', READ) as file:
90 return iTunesPState.read(file)
92 def read_all(self):
93 tracks = self.read_iTunesSD()
94 self.read_iTunesStats(tracks)
95 pstate = self.read_iTunesPState()
96 return (tracks, pstate)
98 def write_all(self, tracks, pstate):
99 self.write_iTunesSD(tracks)
100 self.write_iTunesStats(tracks)
101 self.write_iTunesPState(pstate)
103 def set_old_tracks(self, lst):
104 self.old_tracks = {}
105 for i in xrange(len(lst)):
106 t = lst[i]
107 self.old_tracks[t['filename']] = t
108 self.old_tracks[i] = t
110 def make_track_record(self, filename):
111 if self.old_tracks.has_key(filename):
112 return self.old_tracks[filename]
113 else:
114 dict = {}
115 iTunesSD_track.make_default(dict)
116 iTunesStats_track.make_default(dict)
118 dict['filename'] = filename
119 if filename.endswith((".mp3",".aa")):
120 dict['file_type'] = 1
121 elif filename.endswith((".m4a", ".m4b", ".m4p")):
122 dict['file_type'] = 2
123 elif filename.endswith(".wav"):
124 dict['file_type'] = 4
125 else:
126 raise "%s: unsupported file type" % (filename)
127 dict['bookmarkflag'] = filename.endswith((".aa",".m4b"))
128 dict['shuffleflag'] = not dict['bookmarkflag']
129 return dict
131 #####################################################################
132 if __name__ == '__main__':
133 def print_list(xs):
134 for x in xs:
135 print x
137 if len(sys.argv) > 1:
138 # try reading
139 start_dir = os.getcwd()
140 os.chdir(sys.argv[1])
141 db = ShuffleDB()
142 tracks, pstate = db.read_all()
143 print_list( tracks )
144 print pstate
146 if len(sys.argv) > 2:
147 # try writing
148 os.chdir(start_dir)
149 os.chdir(sys.argv[2])
150 db.write_all(tracks, pstate)