# # 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 string import Template 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. Access '?tag' to get always at least an empty string. """ def __init__(self, data = {}): dict.__init__(self) for key in data: dict.__setitem__(self, key.lower(), data[key]) if not 'file' in self: self['file'] = '' 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): key = key.lower() try: return dict.__getitem__(self, key) except KeyError: if key and key[0] == '?': key = key[1:] return self[key] if key in self else '' 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'] elif key == 'songdir': return os.path.dirname(self['file']) raise KeyError def __contains__(self, item): if dict.__contains__(self, item.lower()): return True try: self[item] return True except KeyError: return False def __nonzero__(self): return bool(self['file']) def expand_tags(self, s): """Expands tags in form ${tag} in string s.""" ret = Template(s) ret = ret.safe_substitute(self) 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): return list(self.mpclient.find_sync('file', self.path))[0] 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): return self.mpclient.get_plist_song(self.plid)