summaryrefslogtreecommitdiff
path: root/src/load_itunes.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/load_itunes.py')
-rw-r--r--src/load_itunes.py326
1 files changed, 326 insertions, 0 deletions
diff --git a/src/load_itunes.py b/src/load_itunes.py
new file mode 100644
index 0000000..f4131b1
--- /dev/null
+++ b/src/load_itunes.py
@@ -0,0 +1,326 @@
1import sqlite3
2import plistlib
3
4library = plistlib.readPlist('iTunes-Music-Library.xml')
5
6
7class BasicLibraryItem(object):
8
9 def get_insert_query(self):
10 return 'INSERT INTO {} VALUES ({})'.format(
11 self.TABLE_NAME, self.get_bind_string(self.COLUMN_COUNT))
12
13 @staticmethod
14 def get_bind_string(count):
15 return ('?,' * count)[:-1]
16
17 @staticmethod
18 def as_data_string(value):
19 if not value:
20 return None
21 else:
22 return value.asBase64()
23
24 @staticmethod
25 def as_boolean(value):
26 return 1 if value else 0
27
28 @staticmethod
29 def format_name(name):
30 return name.lower().replace(' ', '_')
31
32 @classmethod
33 def from_plist_entry(cls, entry):
34 self = cls()
35
36 for key, value in entry.items():
37 name = cls.format_name(key)
38
39 if not hasattr(self, name):
40 raise Exception("No attribute named %r" % name)
41
42 setattr(self, name, value)
43
44 return self
45
46
47class Playlist(BasicLibraryItem):
48
49 COLUMN_COUNT = 21
50 TABLE_NAME = 'playlist'
51
52 def __init__(self):
53 self.playlist_id = None
54 self.playlist_persistent_id = None
55 self.parent_persistent_id = None
56 self.distinguished_kind = None
57 self.genius_track_id = None
58 self.name = None
59
60 self.master = False
61 self.visible = False
62 self.all_items = False
63 self.folder = False
64
65 self.music = False
66 self.movies = False
67 self.tv_shows = False
68 self.podcasts = False
69 self.itunesu = False
70 self.audiobooks = False
71 self.books = False
72 self.purchased_music = False
73
74 self.smart_info = None
75 self.smart_criteria = None
76
77 self.items = []
78
79 def as_dbrow_tuple(self):
80 return (
81 self.playlist_id, #int
82 1, # user_id
83 self.playlist_persistent_id,
84 self.parent_persistent_id,
85 self.distinguished_kind, #int
86 self.genius_track_id, #int
87 self.name,
88
89 self.as_boolean(self.master),
90 self.as_boolean(self.visible),
91 self.as_boolean(self.all_items),
92 self.as_boolean(self.folder),
93 self.as_boolean(self.music),
94 self.as_boolean(self.movies),
95 self.as_boolean(self.tv_shows),
96 self.as_boolean(self.podcasts),
97 self.as_boolean(self.itunesu),
98 self.as_boolean(self.audiobooks),
99 self.as_boolean(self.books),
100 self.as_boolean(self.purchased_music),
101
102 self.as_data_string(self.smart_info),
103 self.as_data_string(self.smart_criteria)
104 )
105
106 @classmethod
107 def from_plist_entry(cls, entry):
108 self = cls()
109
110 for key, value in entry.items():
111 if key == 'Playlist Items':
112 for item in value:
113 self.items.append(item['Track ID'])
114
115 continue
116
117 name = cls.format_name(key)
118
119 if not hasattr(self, name):
120 raise Exception("No attribute named %r" % name)
121
122 setattr(self, name, value)
123
124 return self
125
126
127class Track(BasicLibraryItem):
128
129 COLUMN_COUNT = 53
130 TABLE_NAME = 'track'
131
132 def __init__(self):
133 self.album_rating = None
134 self.album_rating_computed = False
135 self.comments = None
136 self.volume_adjustment = None
137 self.unplayed = False
138 self.date_added = None
139 self.date_modified = None
140 self.disabled = False
141 self.play_count = None
142 self.play_date = None
143 self.play_date_utc = None
144 self.rating = None
145 self.skip_count = None
146 self.skip_date = None
147 self.track_id = None
148 self.persistent_id = None
149 self.library_folder_count = None
150 self.file_folder_count = None
151 self.location = None
152 self.track_type = None
153 self.file_type = None
154 self.artwork_count = None
155 self.hd = False
156 self.has_video = False
157 self.itunesu = False
158 self.tv_show = False
159 self.podcast = False
160 self.protected = False
161 self.purchased = False
162 self.movie = False
163 self.music_video = False
164 self.bpm = None
165 self.bit_rate = None
166 self.sample_rate = None
167 self.size = None
168 self.total_time = None
169 self.kind = None
170 self.video_height = None
171 self.video_width = None
172 self.sort_album = None
173 self.sort_album_artist = None
174 self.sort_artist = None
175 self.sort_composer = None
176 self.sort_name = None
177 self.sort_series = None
178 self.album = None
179 self.album_artist = None
180 self.artist = None
181 self.clean = False
182 self.compilation = False
183 self.composer = None
184 self.content_rating = None
185 self.disc_count = None
186 self.disc_number = None
187 self.episode = None
188 self.episode_order = None
189 self.explicit = False
190 self.genre = None
191 self.grouping = None
192 self.name = None
193 self.part_of_gapless_album = False
194 self.release_date = None
195 self.season = None
196 self.series = None
197 self.track_count = None
198 self.track_number = None
199 self.year = None
200
201 def as_dbrow_tuple(self):
202 return (
203 self.track_id,
204 self.persistent_id,
205 self.library_folder_count,
206 self.file_folder_count,
207 self.location,
208 self.track_type,
209 self.file_type,
210 self.artwork_count,
211 self.as_boolean(self.hd),
212 self.as_boolean(self.has_video),
213 self.as_boolean(self.itunesu),
214 self.as_boolean(self.tv_show),
215 self.as_boolean(self.podcast),
216 self.as_boolean(self.protected),
217 self.as_boolean(self.purchased),
218 self.as_boolean(self.movie),
219 self.as_boolean(self.music_video),
220 self.bpm,
221 self.bit_rate,
222 self.sample_rate,
223 self.size,
224 self.total_time,
225 self.kind,
226 self.video_height,
227 self.video_width,
228 self.sort_album,
229 self.sort_album_artist,
230 self.sort_artist,
231 self.sort_composer,
232 self.sort_name,
233 self.sort_series,
234 self.album,
235 self.album_artist,
236 self.artist,
237 self.as_boolean(self.clean),
238 self.as_boolean(self.compilation),
239 self.composer,
240 self.content_rating,
241 self.disc_count,
242 self.disc_number,
243 self.episode,
244 self.episode_order,
245 self.as_boolean(self.explicit),
246 self.genre,
247 self.grouping,
248 self.name,
249 self.as_boolean(self.part_of_gapless_album),
250 self.release_date,
251 self.season,
252 self.series,
253 self.track_count,
254 self.track_number,
255 self.year
256 )
257
258 def usermeta_as_dbrow_tuple(self):
259 return (
260 1,
261 self.track_id,
262 self.album_rating,
263 self.as_boolean(self.album_rating_computed),
264 self.comments,
265 self.volume_adjustment,
266 self.as_boolean(self.unplayed),
267 self.date_added,
268 self.date_modified,
269 self.as_boolean(self.disabled),
270 self.play_count,
271 self.play_date,
272 self.play_date_utc,
273 self.rating,
274 self.skip_count,
275 self.skip_date
276 )
277
278 USERMETA_COLUMN_COUNT = 16
279 USERMETA_TABLE_NAME = 'user_track_metadata'
280
281 def get_usermeta_insert_query(self):
282 return 'INSERT INTO {} VALUES ({})'.format(
283 self.USERMETA_TABLE_NAME,
284 self.get_bind_string(self.USERMETA_COLUMN_COUNT))
285
286
287assert library['Major Version'] == 1, "Invalid major version"
288assert library['Minor Version'] == 1, "Invalid minor version"
289
290def insert_playlists(db, library):
291 playlists = [Playlist.from_plist_entry(entry)
292 for entry in library['Playlists']]
293
294 curs = db.cursor()
295 track_insert_query = playlists[0].get_insert_query()
296
297 for playlist in playlists:
298 curs.execute(track_insert_query, playlist.as_dbrow_tuple())
299
300 for item in playlist.items:
301 curs.execute('INSERT INTO playlist_track VALUES (?, ?)',
302 (playlist.playlist_id, item))
303
304 db.commit()
305
306
307def insert_tracks(db, library):
308 music_folder = library['Music Folder']
309 tracks = [Track.from_plist_entry(entry)
310 for entry in library['Tracks'].values()]
311
312 curs = db.cursor()
313 track_insert_query = tracks[0].get_insert_query()
314 usermeta_insert_query = tracks[0].get_usermeta_insert_query()
315
316 for track in tracks:
317 curs.execute(track_insert_query, track.as_dbrow_tuple())
318 curs.execute(usermeta_insert_query, track.usermeta_as_dbrow_tuple())
319
320 db.commit()
321
322
323db = sqlite3.connect('iTunesLibrary.db')
324#insert_playlists(db, library)
325insert_tracks(db, library)
326db.close()