From 0d8e86265f74ee36503bbcec445dcefdea208df0 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Mon, 13 Feb 2012 22:09:11 +0100 Subject: Initial import. --- directory.py | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 directory.py (limited to 'directory.py') diff --git a/directory.py b/directory.py new file mode 100644 index 0000000..67db83f --- /dev/null +++ b/directory.py @@ -0,0 +1,134 @@ +import os, mimetypes, cuesheet, mutagen, db + +from config import config + +class DirectoryEntry(object): + '''Base class for directory entries.''' + + def __init__(self, path, track = None, metadata = {}): + self.path = path + self.track = track + self.metadata = metadata + + if '..' in path.split(): + raise Exception('Invalid path') + + self.rel_path = os.path.relpath(path, config.get('music_root')) + + def __cmp__(self, other): + return cmp(self.path, other.path) + + def __lt__(self, other): + return self.path < other.path + + def __str__(self): + return '{name}
'.format(path = self.rel_path, name = os.path.basename(self.path)) + + def json(self): + return {'type': self.entry_type, 'name': self.rel_path, 'track': self.track, 'metadata': self.metadata} + +class Directory(DirectoryEntry): + '''A directory entry inside a directory.''' + + entry_type = 'dir' + + def listdir(self): + directories = [] + files = [] + + for f in os.listdir(self.path): + path = os.path.join(self.path, f) + if os.path.isdir(path): + directories.append(Directory(path)) + elif os.path.isfile(path): + if os.path.splitext(f)[1] == '.cue': + cue = cuesheet.Cuesheet(path) + for t in cue.tracks: + metadata = {} + info = cue.info[0] + if info.performer: + metadata['artist'] = info.performer + if info.title: + metadata['album'] = info.title + if t.title: + metadata['title'] = t.title + files.append(File(path, track = t.track[0], metadata = metadata)) + else: + metadata = {} + tags = mutagen.File(path) or [] + if isinstance(tags, mutagen.mp3.MP3): + for id3, tn in (('TPE1', 'artist'), ('TALB', 'album'), ('TIT2', 'title')): + if id3 in tags: + metadata[tn] = tags[id3].text[0] + else: + for tn in ('artist', 'album', 'title'): + if tn in tags: + metadata[tn] = tags[tn][0].encode('utf-8') + files.append(File(path, metadata = metadata)) + return sorted(directories) + sorted(files) + +class File(DirectoryEntry): + '''A file entry inside a directory.''' + + entry_type = 'file' + + def send(self, environ, start_response): + do_range = 'HTTP_RANGE' in environ + if do_range: + file_range = environ['HTTP_RANGE'].split('bytes=')[1] + + mime = mimetypes.guess_type(self.path, strict = False)[0] or 'application/octet-stream' + size = os.path.getsize(self.path) + if do_range: + start, end = [int(x or 0) for x in file_range.split('-')] + if end == 0: + end = size-1 + + write_out = start_response('206 Partial Content', [ + ('Content-Type', mime), + ('Content-Range', 'bytes {start}-{end}/{size}'.format(start = start, end = end, size = size)), + ('Content-Length', str(end - start + 1))]) + + f = open(self.path, 'rb') + f.seek(start) + remaining = end-start+1 + s = f.read(min(remaining, 1024)) + while s: + write_out(s) + remaining -= len(s) + s = f.read(min(remaining, 1024)) + return [] + + start_response('200 OK', [ + ('Content-Type', mime), + ('Content-Length', str(size))]) + return open(self.path, 'rb') + +def rec_scan(session, root, parent_id = None): + directory = db.Directory.get(session, root, parent_id) + + d = Directory(root) + for de in d.listdir(): + if isinstance(de, Directory): + print 'id:', directory.id + rec_scan(session, de.path, directory.id) + else: + print de.metadata + artist = db.Artist.get(session, de.metadata['artist']) if 'artist' in de.metadata else None + album = db.Album.get(session, de.metadata['album'], artist.id if artist else None) if 'album' in de.metadata else None + track = db.Track.get(session, de.metadata['title'] if 'title' in de.metadata else None, None, + os.path.basename(de.path), de.track, directory.id, artist.id if artist else None, album.id if album else None) + +def scan(root = None): + if not root: + root = config.get('music_root') + + try: + session = db.Session() + rec_scan(session, root) + session.commit() + finally: + session.close() + +if __name__ == '__main__': + scan() -- cgit v1.2.3