# # Copyright (C) 2009 Anton Khirnov # # Nephilim is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Nephilim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Nephilim. If not, see . # from PyQt4 import QtCore import os from common import sec2min class Song(dict): """Song provides a dictionary-like wrapper around song metadata. Its instances _shouldn't_ be stored, use SongRef or PlaylistEntryRef for that.""" def __init__(self, data): # decode all strings to unicode for tag in data: if isinstance(data[tag], list): data[tag] = ','.join(data[tag]) if isinstance(data[tag], str): data[tag] = data[tag].decode('utf-8') dict.__init__(self, data) def __eq__(self, other): if not isinstance(other, Song): return NotImplemented return self['file'] == other['file'] def __ne__(self, other): if not isinstance(other, Song): return NotImplemented return self['file'] != other['file'] def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: if key == 'tracknum': try: return int(self['track']) except ValueError: try: return int(self['track'].split('/')[0]) except ValueError: return 0 elif key == 'length': return sec2min(int(self['time'])) elif key == 'id': return '-1' elif key == 'title': return self['file'] elif key == 'albumartist': return self['artist'] return '' def __nonzero__(self): return bool(self['file']) def expand_tags(self, str): """Expands tags in form $tag in str.""" ret = str ret = ret.replace('$title', self['title']) #to ensure that it is set to at least filename for tag in self.keys() + ['tracknum', 'length', 'id']: ret = ret.replace('$' + tag, unicode(self[tag])) ret = ret.replace('$songdir', os.path.dirname(self['file'])) return ret class SongRef: """SongRef stores only a reference to the song (uri) instead of full metadata to conserve memory. Song's tags can be accessed as in Song, but it requires a call to MPD for each tag. """ path = None mpclient = None def __init__(self, mpclient, path): self.mpclient = mpclient self.path = path def __getitem__(self, key): return self.song()[key] def __nonzero__(self): return bool(self.path) def song(self): try: return Song(self.mpclient.find('file', self.path)[0]) except IndexError: return Song({}) class PlaylistEntryRef: """This class stores a reference to a playlist entry instead of full metadata to conserve memory. Song's tags can be accessed as in Song, but it requires a call to MPD for each tag. """ plid = None mpclient = None def __init__(self, mpclient, plid): self.mpclient = mpclient self.plid = plid def __getitem__(self, key): return self.plid if key == 'id' else self.song()[key] def __nonzero__(self): return self.plid != '-1' def song(self): try: return self.mpclient.playlistid(self.plid) except IndexError: return Song({})