root/deejayd/interfaces.py

Revision 1500, 14.8 kB (checked in by Mickael Royer <mickael.royer@…>, 9 days ago)

[deejayd] improve webradio mode

  • now, we can add multiple urls for a webradio
  • add shoutcast support as a deejayd plugin
Line 
1# Deejayd, a media player daemon
2# Copyright (C) 2007-2009 Mickael Royer <mickael.royer@gmail.com>
3#                         Alexandre Rossi <alexandre.rossi@gmail.com>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
20import locale
21
22
23class DeejaydError(Exception):
24    """General purpose error structure."""
25
26    # Handle unicode messages, what Exceptions cannot. See Python issue at
27    # http://bugs.python.org/issue2517
28    def __str__(self):
29        if type(self.message) is unicode:
30            return str(self.message.encode(locale.getpreferredencoding()))
31        else:
32            return str(self.message)
33
34    def __unicode__(self):
35        if type(self.message) is unicode:
36            return self.message
37        else:
38            return unicode(self.message)
39
40class DeejaydAnswer(object):
41    """General purpose core answer container."""
42
43    def __init__(self):
44        self.contents = None
45        self.error = False
46
47    def set_error(self, msg):
48        self.contents = msg
49        self.error = True
50
51    def get_contents(self):
52        if self.error:
53            raise DeejaydError(self.contents)
54        return self.contents
55
56
57class DeejaydKeyValue(DeejaydAnswer):
58    """Dictionnary answer."""
59
60    def __getitem__(self, name):
61        self.get_contents()
62        return self.contents[name]
63
64    def keys(self):
65        self.get_contents()
66        return self.contents.keys()
67
68    def items(self):
69        self.get_contents()
70        return self.contents.items()
71
72
73class DeejaydList(DeejaydAnswer):
74    """List answer."""
75
76    def __len__(self):
77        self.get_contents()
78        return len(self.contents)
79
80    def __iter__(self):
81        self.get_contents()
82        return self.contents.__iter__()
83
84
85class DeejaydFileList(DeejaydAnswer):
86    """File list answer."""
87
88    def __init__(self):
89        DeejaydAnswer.__init__(self)
90        self.root_dir = ""
91        self.files = []
92        self.directories = []
93
94    def set_rootdir(self, dir):
95        self.root_dir = dir
96
97    def add_file(self, file):
98        self.files.append(file)
99
100    def add_dir(self, dir):
101        self.directories.append(dir)
102
103    def set_files(self, files):
104        self.files = files
105
106    def set_directories(self, dirs):
107        self.directories = dirs
108
109    def get_files(self):
110        self.get_contents()
111        return self.files
112
113    def get_directories(self):
114        self.get_contents()
115        return self.directories
116
117
118class DeejaydMediaList(DeejaydAnswer):
119    """Media list answer."""
120
121    def __init__(self):
122        DeejaydAnswer.__init__(self)
123        self.medias = []
124        self.filter = None
125        self.sort = None
126        self.media_type = None
127
128    def add_media(self, media):
129        self.medias.append(media)
130
131    def get_medias(self):
132        self.get_contents()
133        return self.medias
134
135    def set_medias(self, medias):
136        self.medias = medias
137
138    def is_magic(self):
139        self.get_contents()
140        return self.filter != None
141
142    def set_media_type(self, media_type):
143        self.media_type = media_type
144
145    def get_media_type(self):
146        self.get_contents()
147        return self.media_type
148
149    def set_filter(self, filter):
150        self.filter = filter
151
152    def get_filter(self):
153        self.get_contents()
154        return self.filter
155
156    def set_sort(self, sort):
157        self.sort = sort
158
159    def get_sort(self):
160        self.get_contents()
161        return self.sort
162
163
164class DeejaydDvdInfo(DeejaydAnswer):
165    """Dvd information answer."""
166
167    def __init__(self):
168        DeejaydAnswer.__init__(self)
169        self.dvd_content = {}
170
171    def set_dvd_content(self, infos):
172        self.dvd_content.update(infos)
173
174    def add_track(self, track):
175        if "track" not in self.dvd_content.keys():
176            self.dvd_content['track'] = []
177        self.dvd_content['track'].append(track)
178
179    def set_tracks(self, tracks):
180        self.dvd_content['track'] = tracks
181
182    def get_dvd_contents(self):
183        self.get_contents()
184        if "track" not in self.dvd_content.keys():
185            self.dvd_content['track'] = []
186        return self.dvd_content
187
188
189class DeejaydStaticPlaylist(object):
190    """ Static playlist object """
191    type = "static"
192
193    def get(self, first=0, length=-1):
194        raise NotImplementedError
195
196    def add_path(self, path):
197        return self.add_paths([path])
198
199    def add_paths(self, paths):
200        raise NotImplementedError
201
202    def add_song(self, song_id):
203        return self.add_songs([song_id])
204
205    def add_songs(self, song_ids):
206        raise NotImplementedError
207
208
209class DeejaydMagicPlaylist(object):
210    """ Magic playlist object """
211    type = "magic"
212
213    def get(self, first=0, length=-1):
214        raise NotImplementedError
215
216    def add_filter(self, filter):
217        raise NotImplementedError
218
219    def remove_filter(self, filter):
220        raise NotImplementedError
221
222    def clear_filters(self):
223        raise NotImplementedError
224
225    def get_properties(self):
226        raise NotImplementedError
227
228    def set_property(self, key, value):
229        raise NotImplementedError
230
231
232class DeejaydWebradioList(object):
233    """Webradio list management."""
234
235    def get(self, first = 0, length = None):
236        raise NotImplementedError
237
238    def get_available_sources(self):
239        raise NotImplementedError
240
241    def get_source_categories(self, source_name):
242        raise NotImplementedError
243
244    def set_source(self, source_name):
245        raise NotImplementedError
246
247    def set_source_categorie(self, categorie):
248        raise NotImplementedError
249
250    def add_webradio(self, name, urls):
251        raise NotImplementedError
252
253    def delete_webradio(self, wr_id):
254        return self.delete_webradios([wr_id])
255
256    def delete_webradios(self, wr_ids):
257        raise NotImplementedError
258
259    def clear(self):
260        raise NotImplementedError
261
262
263class DeejaydQueue(object):
264    """Queue management."""
265
266    def get(self, first = 0, length = None):
267        raise NotImplementedError
268
269    def add_path(self, path, pos = None):
270        return self.add_paths([path], pos)
271
272    def add_paths(self, paths, pos = None):
273        raise NotImplementedError
274
275    def add_song(self, song_id, pos = None):
276        return self.add_songs([song_id], pos)
277
278    def add_songs(self, song_ids, pos = None):
279        raise NotImplementedError
280
281    def load_playlist(self, pl_id, pos = None):
282        return self.load_playlists([pl_id], pos)
283
284    def load_playlists(self, pl_ids, pos = None):
285        raise NotImplementedError
286
287    def move(self, ids, new_pos):
288        raise NotImplementedError
289
290    def clear(self):
291        raise NotImplementedError
292
293    def del_song(self, id):
294        return self.del_songs([id])
295
296    def del_songs(self, ids):
297        raise NotImplementedError
298
299
300class DeejaydPanel(object):
301
302    def get(self, first = 0, length = None):
303        raise NotImplementedError
304
305    def get_active_list(self):
306        raise NotImplementedError
307
308    def get_panel_tags(self):
309        raise NotImplementedError
310
311    def set_active_list(self, type, pl_id=""):
312        raise NotImplementedError
313
314    def set_panel_filters(self, tag, values):
315        raise NotImplementedError
316
317    def remove_panel_filters(self, tag):
318        raise NotImplementedError
319
320    def clear_panel_filters(self):
321        raise NotImplementedError
322
323    def set_search_filter(self, tag, value):
324        raise NotImplementedError
325
326    def clear_search_filter(self):
327        raise NotImplementedError
328
329    def set_sorts(self, sort):
330        raise NotImplementedError
331
332
333class DeejaydPlaylistMode(object):
334
335    def get(self, first = 0, length = None):
336        raise NotImplementedError
337
338    def save(self, name):
339        raise NotImplementedError
340
341    def add_path(self, path, pos = None):
342        return self.add_paths([path], pos)
343
344    def add_paths(self, paths, pos = None):
345        raise NotImplementedError
346
347    def add_song(self, song_id, pos = None):
348        return self.add_songs([song_id], pos)
349
350    def add_songs(self, song_ids, pos = None):
351        raise NotImplementedError
352
353    def load(self, pl_id, pos = None):
354        return self.loads([pl_id], pos)
355
356    def loads(self, pl_ids, pos = None):
357        raise NotImplementedError
358
359    def move(self, ids, new_pos):
360        raise NotImplementedError
361
362    def shuffle(self):
363        raise NotImplementedError
364
365    def clear(self):
366        raise NotImplementedError
367
368    def del_song(self, id):
369        return self.del_songs([id])
370
371    def del_songs(self, ids):
372        raise NotImplementedError
373
374
375class DeejaydVideo(object):
376    """Video management."""
377
378    def get(self, first = 0, length = None):
379        raise NotImplementedError
380
381    def set(self, value, type = "directory"):
382        raise NotImplementedError
383
384    def set_sorts(self, sorts):
385        raise NotImplementedError
386
387
388class DeejaydSignal(object):
389
390    SIGNALS = ('player.status',       # Player status change (play/pause/stop/
391                                      # random/repeat/volume/manseek)
392               'player.current',      # Currently played song change
393               'player.plupdate',     # The current playlist has changed
394               'playlist.listupdate', # The stored playlist list has changed
395                                      # (either a saved playlist has been saved
396                                      # or deleted).
397               'playlist.update',     # A recorded playlist (static or magic)
398                                      # has changed
399                                      # set id of playlist as attribute
400               'webradio.listupdate',
401               'panel.update',
402               'queue.update',
403               'video.update',
404               'dvd.update',
405               'mode',                # Mode change
406               'mediadb.aupdate',     # Media library audio update
407               'mediadb.vupdate',     # Media library video update
408               'mediadb.mupdate',     # a media has been updated
409                                      # set id and type of media as attribute
410                                      # set type of update as attribute
411              )
412
413    def __init__(self, name=None, attrs = {}):
414        self.name = name
415        self.attrs = attrs
416
417    def set_name(self, name):
418        self.name = name
419
420    def get_name(self):
421        return self.name
422
423    def get_attrs(self):
424        return self.attrs
425
426    def get_attr(self, key):
427        return self.attrs[key]
428
429    def set_attr(self, key, value):
430        self.attrs[key] = value
431
432
433class DeejaydCore(object):
434    """Abstract class for a deejayd core."""
435
436    def __init__(self):
437        self._clear_subscriptions()
438
439    def ping(self):
440        raise NotImplementedError
441
442    def play_toggle(self):
443        raise NotImplementedError
444
445    def stop(self):
446        raise NotImplementedError
447
448    def previous(self):
449        raise NotImplementedError
450
451    def next(self):
452        raise NotImplementedError
453
454    def seek(self, pos, relative = False):
455        raise NotImplementedError
456
457    def get_current(self):
458        raise NotImplementedError
459
460    def go_to(self, id, id_type = None, source = None):
461        raise NotImplementedError
462
463    def set_volume(self, volume_value):
464        raise NotImplementedError
465
466    def set_option(self, source, option_name, option_value):
467        raise NotImplementedError
468
469    def set_mode(self, mode_name):
470        raise NotImplementedError
471
472    def get_mode(self):
473        raise NotImplementedError
474
475    def set_player_option(self, option_name, option_value):
476        raise NotImplementedError
477
478    def get_status(self):
479        raise NotImplementedError
480
481    def get_stats(self):
482        raise NotImplementedError
483
484    def update_audio_library(self, force = False, sync = False):
485        raise NotImplementedError
486
487    def update_video_library(self, force = False, sync = False):
488        raise NotImplementedError
489
490    def create_recorded_playlist(self, name, type):
491        raise NotImplementedError
492
493    def get_recorded_playlist(self, pl_id):
494        raise NotImplementedError
495
496    def erase_playlist(self, pl_ids):
497        raise NotImplementedError
498
499    def get_playlist_list(self):
500        raise NotImplementedError
501
502    def get_playlist(self):
503        raise NotImplementedError
504
505    def get_webradios(self):
506        raise NotImplementedError
507
508    def get_queue(self):
509        raise NotImplementedError
510
511    def get_panel(self):
512        raise NotImplementedError
513
514    def get_video(self):
515        raise NotImplementedError
516
517    def set_media_rating(self, media_ids, rating, type = "audio"):
518        raise NotImplementedError
519
520    def get_audio_dir(self, dir=None):
521        raise NotImplementedError
522
523    def get_audio_cover(self, media_id):
524        raise NotImplementedError
525
526    def audio_search(self, search_txt, type = 'all'):
527        raise NotImplementedError
528
529    def get_video_dir(self, dir=None):
530        raise NotImplementedError
531
532    def dvd_reload(self):
533        raise NotImplementedError
534
535    def mediadb_list(self, taglist, filter):
536        raise NotImplementedError
537
538    def get_dvd_content(self):
539        raise NotImplementedError
540
541    def __get_next_sub_id(self):
542        sub_id = self.__sub_id_counter
543        self.__sub_id_counter = self.__sub_id_counter + 1
544        return sub_id
545
546    def subscribe(self, signal_name, callback):
547        """Subscribe to a signal with a callback. Returns an id."""
548        if signal_name not in DeejaydSignal.SIGNALS:
549            return DeejaydError('Unknown signal provided for subscription.')
550
551        sub_id = self.__get_next_sub_id()
552        self.__sig_subscriptions[sub_id] = (signal_name, callback)
553        return sub_id
554
555    def unsubscribe(self, sub_id):
556        """Unsubscribe using the provied id."""
557        try:
558            del self.__sig_subscriptions[sub_id]
559        except IndexError:
560            raise DeejaydError('Unknown subscription id')
561
562    def get_subscriptions(self):
563        """Get the list of currently subcribed signals for this instance."""
564        return dict([(sub_id, sub[0]) for (sub_id, sub)\
565                                      in self.__sig_subscriptions.items()])
566
567    def _clear_subscriptions(self):
568        self.__sig_subscriptions = {}
569        self.__sub_id_counter = 0
570
571    def _dispatch_signal(self, signal):
572        for cb in [sub[1] for sub in self.__sig_subscriptions.values()\
573                                  if sub[0] == signal.get_name()]:
574            cb(signal)
575
576    def _dispatch_signame(self, signal_name, attrs = {}):
577        self._dispatch_signal(DeejaydSignal(signal_name, attrs))
578
579
580# vim: ts=4 sw=4 expandtab
Note: See TracBrowser for help on using the browser.