1
# -*- coding: utf-8 -*-
2
# Licensed under the MIT license
3
# http://opensource.org/licenses/mit-license.php
5
# Copyright 2007, Philippe Normand <phil at base-art dot net>
7
from elisa.core.base_plugins import DataAccessPlugin, PlayerPlugin, DataAccessFile
8
from elisa.core.base_plugins import TreePlugin
9
from elisa.core.interfaces import IDataAccess, IMediaPlayer
10
from elisa.core import media_uri, common, menu
11
from elisa.core.signals.application import application_started
12
from elisa.core.gst.lastfm_src import LastFMSource
20
class LastFMPlayer(DataAccessPlugin, PlayerPlugin):
22
__implements__ = (IMediaPlayer, IDataAccess)
26
menu_name = _('Last.FM radios')
31
default_config = {'locations': ['lastfm://globaltags/rock',
32
'lastfm://globaltags/jazz']}
34
folder_icon_path = 'folder-radios.png'
35
item_icon_path = 'radio.png'
39
icons = ['lastfm_love', 'lastfm_ban'] + PlayerPlugin.icons
41
provides = [ "uri:lastfm" ]
42
uncacheable_uri_schemes = ['lastfm']
46
DataAccessPlugin.__init__(self)
47
PlayerPlugin.__init__(self)
48
#self.set_icon_path('radios.png')
49
self.login, self.password = '', ''
51
self.gst_pipeline = None
52
application_started.connect(self._application_started)
54
def _application_started(self):
55
plugin_manager = common.get_plugin_manager()
56
audioscrobbler = plugin_manager.get_plugin_with_name('audioscrobbler')
57
if audioscrobbler and audioscrobbler.enabled:
58
config = audioscrobbler.get_config()
59
self.login = config.get('user')
60
self.password = config.get('password')
62
self.unload("Audioscrobbler plugin is required by the LastFM plugin")
65
return PlayerPlugin.get_parent(self)
67
def add_wizard_shortcuts(self):
70
def play_item(self, menu_item):
74
music_file = str(media_uri.Uri(location=menu_item.get_target_path()))
75
player = self.get_player()
78
self.logger.info('Playing radio %s' % music_file)
79
player.play(start=True)
81
PlayerPlugin.play_item(self, menu_item)
84
dfr = player.set_uri(music_file)
86
dfr.addCallback(launch)
90
item_action = play_item
92
def item_action_menu(self, menu_item):
93
play_pause = menu.MenuItem(short_name=_("Play"))
94
play_pause.set_target_path("play/pause")
95
play_pause.set_icon_path(self.play_icon)
96
play_pause.set_action_callback(self.play_parent_item)
98
love = menu.MenuItem(short_name=_("Love"))
99
love.set_target_path("love")
100
love.set_icon_path(self.lastfm_love_icon)
101
love.set_action_callback(self.love_parent_item)
104
ban = menu.MenuItem(short_name=_("Ban"))
105
ban.set_target_path("ban")
106
ban.set_icon_path(self.lastfm_ban_icon)
107
ban.set_action_callback(self.ban_parent_item)
110
skip = menu.MenuItem(short_name=_("Skip"))
111
skip.set_target_path("skip")
112
skip.set_icon_path(self.seekf_icon)
113
skip.set_action_callback(self.skip_parent_item)
116
stop = menu.MenuItem(short_name=_("Stop"))
117
stop.set_target_path("stop")
118
stop.set_icon_path(self.stop_icon)
119
stop.set_action_callback(self.stop_parent_item)
122
volp = menu.MenuItem(short_name=_("Volume+"))
123
volp.set_target_path("vol+")
124
volp.set_icon_path(self.volume_up_icon)
125
volp.set_action_callback(self.volp_parent_item)
128
volm = menu.MenuItem(short_name=_("Volume-"))
129
volm.set_target_path("vol-")
130
volm.set_icon_path(self.volume_down_icon)
131
volm.set_action_callback(self.volm_parent_item)
134
menu_item.add_item(stop)
135
menu_item.add_item(love)
136
menu_item.add_item(ban)
137
menu_item.add_item(play_pause)
138
menu_item.add_item(skip)
139
menu_item.add_item(volm)
140
menu_item.add_item(volp)
142
TreePlugin.item_action_menu(self, menu_item)
144
player = self.get_player()
145
if player and str(menu_item.get_target_path()) == \
146
str(player.get_playing_uri()):
147
self.playing(menu_item)
149
def playing(self, menu_item):
150
PlayerPlugin.playing(self, menu_item)
151
for target in ("love", "ban", "skip"):
152
item = menu_item.get_item_with_target(target)
156
#common.get_application().get_task_manager().add_task(task.Task(menu_item))
158
def love_parent_item(self, menu_item):
160
self.lastfmsrc.love()
162
def ban_parent_item(self, menu_item):
166
def skip_parent_item(self, menu_item):
168
self.lastfmsrc.skip()
170
# IDataAccess implementation
172
def is_dir(self, uri):
175
def get_direct_children(self, uri):
179
def has_children(self, uri):
182
def next_location(self, from_uri, item_filter=None, root=None):
184
Return the uri just next to `from_uri`.
188
return (next_uri, short_name)
190
def open(self, uri, mode=None):
193
handle = DataAccessFile(self, DummyFD())
196
def remove_location(self, uri):
202
def get_gst_pipeline(self):
203
if not self.gst_pipeline:
204
self.gst_pipeline = gst.Pipeline('pipeline')
206
self.lastfmsrc = LastFMSource('src', self.login, self.password)
207
decoder = gst.element_factory_make('decodebin')
208
queue = gst.element_factory_make('queue')
209
convert = gst.element_factory_make('audioconvert')
211
def on_new_decoded_pad(element, pad, last):
212
caps = pad.get_caps()
213
name = caps[0].get_name()
214
apad = convert.get_pad('sink')
216
if not apad.is_linked(): # Only link once
219
decoder.connect('new-decoded-pad', on_new_decoded_pad)
221
volume = gst.element_factory_make('volume', 'vlm')
222
sink = gst.element_factory_make('autoaudiosink', 'audio-sink')
224
self.gst_pipeline.add(self.lastfmsrc, decoder, queue, convert,
227
self.lastfmsrc.link(decoder)
231
return self.gst_pipeline