4.2.0r3
[enigma2.git] / usr / lib / enigma2 / python / Plugins / Extensions / MediaCenter / DatabasePlaylist.py
1 from enigma import eMediaDatabase, eServiceReference, StringMap, StringMapVector
2 from Screens.ChoiceBox import ChoiceBox
3 from Screens.InputBox import InputBox
4 from Tools.Log import Log
5
6 from MediaCore import MediaCore
7 from Playlist import Playlist, PlayListEntry, AudioPlaylistEntry, DefaultCoverArt
8
9 from os import path as os_path
10
11 class DatabasePlaylistEntry(PlayListEntry):
12         @staticmethod
13         def get(ref, state, data):
14                 artist = data.get(eMediaDatabase.FIELD_ARTIST, "")
15                 title = data.get(eMediaDatabase.FIELD_TITLE, "")
16                 album = data.get(eMediaDatabase.FIELD_ALBUM, "")
17                 seconds = int(data.get(eMediaDatabase.FIELD_DURATION, 0))
18
19                 if seconds > 0:
20                         minutes, seconds = divmod(seconds, 60)
21                         duration = "%02d:%02d" % (minutes, seconds)
22                 else:
23                         duration = "--:--"
24
25                 entry = (data, "", title, artist, album, duration, DefaultCoverArt)
26                 entry = AudioPlaylistEntry.updateState(entry, state)
27
28                 return entry
29
30 class DatabasePlaylist(Playlist):
31         FEATURE_LISTABLE = True
32
33         class PlaylistChoice(ChoiceBox):
34                 def __init__(self, session, type=MediaCore.TYPE_AUDIO):
35                         menu = []
36                         playlists = DatabasePlaylist.getPlaylists(type)
37                         for playlist in playlists:
38                                 menu.append( (playlist.name, playlist) )
39                         ChoiceBox.__init__(self, session, list=menu)
40                         self.setTitle(_("Playlists"))
41
42         class PlaylistCreate:
43                 def __init__(self, session, type, callback):
44                         self._callback = callback
45                         self._type = type
46                         inputbox = session.openWithCallback(self._onInput, InputBox, title="Playlist name")
47                         inputbox.setTitle("Create New Playlist")
48
49                 def _onInput(self, name):
50                         Log.i(name)
51                         if name != None:
52                                 p = DatabasePlaylist.create(name, type=self._type)
53                                 self._callback(p)
54
55         def __init__(self, id, name=_("Default"), type=MediaCore.TYPE_AUDIO, enableWrapAround=True, entryHelper=DatabasePlaylistEntry):
56                 Playlist.__init__(self, name, type, enableWrapAround=enableWrapAround, entryHelper=entryHelper)
57                 self._id = id
58
59         @staticmethod
60         def getPlaylists(type=MediaCore.TYPE_AUDIO):
61                 Log.i("")
62                 res = eMediaDatabase.getInstance().getPlaylists(type)
63                 playlists = []
64                 if res:
65                         for item in res.data():
66                                 playlists.append((
67                                         DatabasePlaylist( int(item[eMediaDatabase.FIELD_ID]), name=item[eMediaDatabase.FIELD_PLAYLIST_NAME], type=int(item[eMediaDatabase.FIELD_TYPE]) )
68                                 ))
69                 return playlists
70
71         @staticmethod
72         def get(id=-1, name=None, type=MediaCore.TYPE_AUDIO, create=False):
73                 # If we'er called with only the name given we'll try to get the id.
74                 # If we cannot find a matching playlist, we return None
75                 db = eMediaDatabase.getInstance()
76                 if id < 0:
77                         res = db.getPlaylistByName(name, type)
78                 else:
79                         res = db.getPlaylist(id)
80                 if res.error() or not res.data(): #Playlist unkown (not yet saved/created!)
81                         Log.w("%s / %s" %(res.errorDatabaseText(), res.errorDriverText()))
82                         if create:
83                                 Log.i("creating new playlist")
84                                 return DatabasePlaylist.create(name, type)
85                         else:
86                                 Log.w("Unkown Playlist for id=%s, name=%s and type=%s" %(id, name, type))
87                                 return None
88
89                 data = res.data()[0]
90                 id = int(data[eMediaDatabase.FIELD_ID])
91                 name = data[eMediaDatabase.FIELD_NAME]
92                 Log.i("Playlist %s found. Id is %s" %(name, id))
93                 playlist = DatabasePlaylist(id, name=name, type=type)
94                 playlist.reload()
95                 return playlist
96
97         @staticmethod
98         def create(name, type=MediaCore.TYPE_AUDIO):
99                 Log.i("name=%s, type=%s" %(name, type))
100                 db = eMediaDatabase.getInstance()
101                 res = db.getPlaylistByName(name, type)
102                 if not res or res.error() or res.data():
103                         Log.w("%s / %s / %s" %(res.data(), res.errorDatabaseText(), res.errorDriverText()))
104                         return None
105
106                 playlist = DatabasePlaylist(-1, name=name, type=type)
107                 playlist.save()
108                 return playlist
109
110         def add(self, ref, extra=None, isBatch=False):
111                 data = extra
112                 if extra is None or extra.get(eMediaDatabase.FIELD_FILE_ID, 0) <= 0:
113                         data = self.getDetailsByRef(ref) or data
114                 if data is None:
115                         path, filename = os_path.split(ref.getPath())
116                         data = { "file_uri" : ref.getPath(), "title" : filename, }
117                 Playlist.add(self, ref, data, isBatch)
118
119         def getDetailsByRef(self, ref):
120                 path = ref.getPath()
121                 #if we get only a reference or an entry with "extra data" but no file id yet we ask the database to enrich the data
122                 if path.startswith("/"):
123                         Log.i("Asking database for details!")
124                         db = eMediaDatabase.getInstance()
125                         res = db.getFileByPath(path)
126                         if res and res.data() and not res.error() :
127                                 return dict(res.data()[0])
128                         else:
129                                 Log.i("ERROR: %s :: %s" %(res.errorDatabaseText(), res.errorDriverText()))
130                 else:
131                         Log.i("%s is not an absolute local path, skip querying the database" % path)
132
133                 return None
134
135         def load(self, id, name):
136                 Log.i("Loading playlist with id=%s and name=%s" %(id, name))
137                 self._id = id
138                 self._name = name
139                 self.reload()
140
141         def reload(self):
142                 self._list = []
143                 db = eMediaDatabase.getInstance()
144                 res = None
145                 if self._id < 0: #no @staticmethod get() used, probably....
146                         self._valid = False
147                         self.listChanged()
148                         Log.w("A Playlist with the name/id %s/%s does not exist!" %(self._name, self._id))
149                         return
150
151                 res = db.getPlaylistItemsById(self._id)
152                 if res and not res.error():
153                         for data in res.data():
154                                 data = dict(data)
155                                 file_uri = data.get(eMediaDatabase.FIELD_FILE_URI, None)
156                                 if not file_uri:
157                                         Log.w("Playlist entry invalid, %s" % data)
158                                         continue
159                                 ref = eServiceReference(4097, 0, file_uri)
160                                 self.add(ref, data, True)
161                         self._valid = True
162                 else:
163                         Log.i("Error loading playlist %s:%s\n%s\n%s" % (self._id, self._name, res.errorDatabaseText(), res.errorDriverText()))
164                         self._valid = False
165                 self.listChanged()
166
167         def save(self):
168                 #c-ify
169                 vector = StringMapVector()
170                 pos = 1
171                 for item in self._list:
172                         item = item[2]
173                         stringMap = StringMap()
174                         for k, v in item.iteritems():
175                                 stringMap[k] = str(v)
176                         stringMap[eMediaDatabase.FIELD_POS] = str(pos)
177                         pos += 1
178                         vector.append(stringMap)
179                 db = eMediaDatabase.getInstance()
180                 res = db.savePlaylist(self._id, self._name, self._type, vector)
181                 error = res.error()
182                 if error:
183                         Log.w("Error saving playlist %s\n%s\n%s" % (self._id, res.errorDatabaseText(), res.errorDriverText()))
184                         return not error
185                 #if self._id <= 0:
186                 data = res.data()
187                 self._id = -1
188                 if data and len(data) > 0:
189                         self._id = int(res.data()[0].get(eMediaDatabase.FIELD_ID, -1))
190                 if self._id == -1:
191                         error = True
192                 self._valid = not error
193                 if not error:
194                         Log.i("Playlist '%s (%s)' saved" %(self._name, self._id))
195                 else:
196                         Log.w("Error saving playlist!")
197                 return not error
198
199         def _getId(self):
200                 return self._id
201         id = property(_getId)