remove some useless conversions to unicode
[nephilim.git] / nephilim / song.py
blob6d8cc391e8c4353defa50a2b0d87e63282fff562
2 # Copyright (C) 2009 Anton Khirnov <wyskas@gmail.com>
4 # Nephilim is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # Nephilim is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Nephilim. If not, see <http://www.gnu.org/licenses/>.
18 from PyQt4 import QtCore
19 import os
21 from common import sec2min
23 class Song(dict):
24 """Song provides a dictionary-like wrapper around song metadata.
25 Its instances _shouldn't_ be stored, use SongRef or PlaylistEntryRef for that."""
27 def __init__(self, data):
28 for tag in data:
29 if isinstance(data[tag], list):
30 data[tag] = ','.join(data[tag])
32 dict.__init__(self, data)
34 def __eq__(self, other):
35 if not isinstance(other, Song):
36 return NotImplemented
37 return self['file'] == other['file']
39 def __ne__(self, other):
40 if not isinstance(other, Song):
41 return NotImplemented
42 return self['file'] != other['file']
44 def __getitem__(self, key):
45 try:
46 return dict.__getitem__(self, key)
47 except KeyError:
48 if key == 'tracknum':
49 try:
50 return int(self['track'])
51 except ValueError:
52 try:
53 return int(self['track'].split('/')[0])
54 except ValueError:
55 return 0
56 elif key == 'length':
57 return sec2min(int(self['time']))
58 elif key == 'id':
59 return '-1'
60 elif key == 'title':
61 return self['file']
62 elif key == 'albumartist':
63 return self['artist']
64 return ''
66 def __nonzero__(self):
67 return bool(self['file'])
69 def expand_tags(self, str):
70 """Expands tags in form $tag in str."""
71 ret = str
72 ret = ret.replace('$title', self['title']) #to ensure that it is set to at least filename
73 for tag in self.keys() + ['tracknum', 'length', 'id']:
74 ret = ret.replace('$' + tag, unicode(self[tag]))
75 ret = ret.replace('$songdir', os.path.dirname(self['file']))
76 return ret
78 class SongRef:
79 """SongRef stores only a reference to the song (uri) instead
80 of full metadata to conserve memory. Song's tags can be accessed
81 as in Song, but it requires a call to MPD for each tag. """
82 path = None
83 mpclient = None
85 def __init__(self, mpclient, path):
86 self.mpclient = mpclient
87 self.path = path
89 def __getitem__(self, key):
90 return self.song()[key]
92 def __nonzero__(self):
93 return bool(self.path)
95 def song(self):
96 try:
97 return Song(self.mpclient.find('file', self.path)[0])
98 except IndexError:
99 return Song({})
101 class PlaylistEntryRef:
102 """This class stores a reference to a playlist entry instead of full
103 metadata to conserve memory. Song's tags can be accessed
104 as in Song, but it requires a call to MPD for each tag. """
105 plid = None
106 mpclient = None
108 def __init__(self, mpclient, plid):
109 self.mpclient = mpclient
110 self.plid = plid
112 def __getitem__(self, key):
113 return self.plid if key == 'id' else self.song()[key]
115 def __nonzero__(self):
116 return self.plid != '-1'
118 def song(self):
119 try:
120 return self.mpclient.playlistid(self.plid)
121 except IndexError:
122 return Song({})