I have attached a new plugin for LAST FM play. This plugin uses the
shell-fm command line program to interface with the LAST FM servers.
I have tested this plugin against the new 1.9.2beta1 release.
I hope others find this useful.
Regards,
Jim
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
# Simple plug-in to listen to last fm radio using shell-fm deamon
# -----------------------------------------------------------------------
# $Id: shellfm.py 11408 2009-04-11 14:58:01Z duncan $
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2003 Krister Lagerstrom, et al.
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY 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 this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------
"""
Simple plugin to listen to Last FM Radio.
Download and install shell-fm application from here:
https://github.com/jkramer/shell-fm
To activate put the following in your local_conf.py::
plugin.activate('audio.shellfm')
SHELLFM_CMD = '/usr/local/bin/shell-fm'
LASTFM_USER = 'myLastFmAccount'
LASTFM_PASS = 'myLastFmPassword'
LASTFM_LOCATIONS = [
('Last FM - Neighbours', 'lastfm://user/%s/neighbours' % LASTFM_USER),
('Last FM - My Library', 'lastfm://user/%s/personal' % LASTFM_USER),
('Last FM - Recommended', 'lastfm://user/%s/recommended' % LASTFM_USER),
('Last FM - Rock', 'lastfm://globaltags/rock'),
('Last FM - Hard Rock', 'lastfm://globaltags/hard rock')
('Last FM - Train', 'lastfm://artist/train')
]
Use the "1" key for Last FM BAN function.
Use the "3" key for Last FM LOVE function.
"""
#python modules
import os, popen2, fcntl, select, time
import glob
import thread
import traceback
from socket import *
import errno
import kaa.imlib2 as imlib2
import config, menu, rc, plugin, util
from audio.player import PlayerGUI
from item import Item
from menu import MenuItem
from gui import AlertBox
import skin
from event import *
class PluginInterface(plugin.MainMenuPlugin):
"""
This plugin uses the command line shellfm programto tune to
a lastfm station using the shellfm program running in damon
mode. The shellfm deamon is controlled using the socket interface.
to activate put the following in your local_conf.py:
| plugin.activate('audio.shellfm')
| SHELLFM_CMD = '/usr/local/bin/shell-fm'
| LASTFM_USER = 'myLastFmAccount'
| LASTFM_LOCATIONS = [
| ('Last FM - Neighbours', 'lastfm://user/%s/neighbours' % LASTFM_USER),
| ('Last FM - My Library', 'lastfm://user/%s/personal' % LASTFM_USER),
| ('Last FM - Recommended', 'lastfm://user/%s/recommended' % LASTFM_USER),
| ('Last FM - Rock', 'lastfm://globaltags/rock'),
| ('Last FM - Hard Rock', 'lastfm://globaltags/hard rock')
| ('Last FM - Train', 'lastfm://artist/train')
| ]
|
"""
def __init__(self):
_debug_('PluginInterface.__init__()')
if not config.SHELLFM_CMD or not config.LASTFM_USER or not config.LASTFM_PASS or not config.LASTFM_LOCATIONS:
self.reason = 'SHELLFM_CMD or LASTFM_USER or LASTFM_PASS or LASTFM_LOCATIONS not set'
_debug_('PluginInterface.__init__() failed!')
return
plugin.MainMenuPlugin.__init__(self)
self.plugin_name = 'shellfm'
def config(self):
"""
Configuration method for lastfm items
"""
_debug_('%s.config()' % (self.__class__))
return [
('LASTFM_USER', None, 'User name for www.last.fm'),
('LASTFM_PASS', None, 'Password for www.last.fm'),
('LASTFM_LOCATIONS', [], 'LastFM locations'),
('SHELLFM_CMD', 'shell-fm', 'System command to execute the shell-fm program'),
('SHELLFM_PORT', 54311, 'The listening port for shell-fm program'),
]
def items(self, parent):
_debug_('%s.items()' % (self.__class__))
return [ ShellFmMainMenuItem(parent) ]
class ShellFmMainMenuItem(MenuItem):
"""
this is the item for the main menu and creates the list
of commands in a submenu.
"""
def __init__(self, parent):
_debug_('ShellFmMainMenuItem.__init__(parent=%r)' % (parent))
MenuItem.__init__(self, parent, skin_type='audio')
self.name = _('Last FM Radio')
self.image = util.getimage(os.path.join(config.SKIN_DIR, 'plugins/lastfm'))
def actions(self):
_debug_('%s.actions()' % (self.__class__,))
"""
Get a list of actions for this menu item
"""
return [ (self.create_stations_menu, 'stations') ]
def create_stations_menu(self, arg=None, menuw=None):
_debug_('%s.create_stations_menu()' % (self.__class__,))
station_items = []
for station in config.LASTFM_LOCATIONS:
shellfm_item = ShellFmItem()
shellfm_item.name = station[0]
shellfm_item.station = station[1]
shellfm_item.url = station[1]
shellfm_item.type = 'audio'
shellfm_item.station_index = config.LASTFM_LOCATIONS.index(station)
shellfm_item.length = 0
shellfm_item.remain = 0
shellfm_item.tags = ''
shellfm_item.info = {'album':'', 'artist':'', 'length': '', 'title':'','elapsed':''}
station_items += [ shellfm_item ]
if (len(station_items) == 0):
station_items += [menu.MenuItem(_('No Last FM Stations found'), menwu.goto_prev_page, 0)]
station_menu = menu.Menu(_
('Last FM Stations'), station_items)
menuw.pushmenu(station_menu)
menuw.refresh()
_debug_('%s.create_stations_menu() done' % (self.__class__,))
class ShellFmItem(Item):
"""
This is the class that actually runs the commands. Eventually hope to add
actions for different ways of running commands and for displaying stdout
and stderr of last command run.
"""
def __init__(self):
Item.__init__(self)
self.title = None
self.artist = None
self.album = None
self.image = None
self.length = 0
def actions(self):
""" Get a list of actions for this item """
items = [ (self.play, _('Listen to Last FM Station')) ]
return items
def play(self, arg=None, menuw=None):
_debug_('%s.play()' % (self.__class__,))
_debug_('station=%r station_index=%r name=%r' % (self.station, self.station_index, self.name))
if not self.menuw:
self.menuw = menuw
self.player = shellfmGUI(self, menuw)
error = self.player.play()
if error and menuw:
AlertBox(text=error).show()
rc.post_event(rc.PLAY_END)
def stop(self, arg=None, menuw=None):
_debug_('%s.stop()' % (self.__class__,))
""" Stop the current playing """
self.player.stop()
class shellfmGUI(PlayerGUI):
"""
ShellFm Player user interface
"""
def __init__(self, item, menuw=None):
""" Create an instance of a shellfmGUI """
_debug_('shellfmGUI.__init__(item=%r, menuw=%r)' % (item, menu), 2)
PlayerGUI.__init__(self, item, menuw)
self.item = item
self.item.starttime = time.time()
self.image = util.getimage(os.path.join(config.SKIN_DIR, 'plugins/lastfm'))
self.item.image = self.image
self.tags = ''
if not config.SHELLFM_PORT:
self.lastfm_port = 54311
else:
self.lastfm_port = config.SHELLFM_PORT
self.event_context = 'audio'
self.mode = 'idle'
self.name = 'shellfmGUI'
self.app_mode = 'audio'
self.app = None
self.starttime = 0
def refresh(self):
""" Give information to the skin """
_debug_('refresh()')
if not self.visible:
_debug_('not visible')
return
if not self.mode == 'play':
_debug_( 'not playing')
return
elapsed = int(time.time() - self.item.starttime + 0.5)
hr = elapsed / (60 * 60)
mn = elapsed % (60 * 60) / 60
sc = elapsed % (60 * 60) % 60
# Is there any point is having elapsed?
if hr > 0:
self.item.elapsed = '%d:%02d:%02d' % (hr, mn, sc)
else:
self.item.elapsed = '%d:%02d' % (mn, sc)
skin.draw('player', self.item)
data = []
try:
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.settimeout(1)
sockobj.send("info %a:%t:%l:%d\n")
tags = sockobj.recv(1024)
sockobj.close()
if not tags == self.tags:
self.tags = tags
data = tags.split(":")
self.item.info['artist'] = data[0]
self.item.info['title'] = data[1]
self.item.info['album'] = data[2]
self.item.info['length'] = data[3]
_debug_('item.__dict__=%r' % (self.item.__dict__))
self.item.starttime = time.time()
skin.draw('player', self.item)
except timeout:
_debug_('timeout')
except Exception, why:
self.reason = '%s: %s' % (self.item.name, why)
traceback.print_exc()
_debug_('%s.refresh() finished' % (self.__class__))
def play(self):
"""
play a lastfmitem with shellfm
"""
_debug_('%s.play()',self.__class__ )
self.item.elapsed = ''
self.item.starttime = time.time()
try:
_debug_('play %r' % self.item.station)
except AttributeError:
return 'Cannot play with shellfmGUI - no station'
pathname = os.path.expanduser('~/.shell-fm/shell-fm.rc')
try:
os.makedirs(os.path.basename(pathname), 0777)
except OSError, e:
if e.errno == errno.EEXIST:
_debug_('Directory %s already exists' % os.path.basename(pathname))
try:
f = open(pathname, 'w')
f.write('username=%s\n' % config.LASTFM_USER)
f.write('password=%s\n' % config.LASTFM_PASS)
f.write('bind=localhost\n')
f.write('port=%s\n' % self.lastfm_port)
f.close( )
except Exception, why:
self.reason = '%s: %s' % (self.item.name, why)
traceback.print_exc()
_debug_('starting the player')
try:
os.system('%s -d' % config.SHELLFM_CMD)
except Exception, why:
self.reason = '%s: %s' % (self.item.name, why)
traceback.print_exc()
time.sleep(0.3)
_debug_('starting %s station %s' % (self.item.name,self.item.url))
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.send('play %s\n' % self.item.url )
sockobj.close()
self.mode = 'play'
thread.start_new_thread(self.__update_thread, ())
rc.add_app(self)
rc.post_event(PLAY_START)
_debug_('%s.run(%s) finished' % (self.__class__, self.name))
return None
def stop(self):
"""
Stop mplayer and set thread to idle
"""
_debug_('%s.stop()' % (self.__class__,))
self.mode = 'stop'
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.send('quit\n')
sockobj.close()
rc.post_event(PLAY_END)
rc.remove_app(self)
def is_playing(self):
_debug_('%s.is_playing()' % (self.__class__,))
return self.mode == 'play'
def ban(self):
_debug_('%s.ban()' % (self.__class__,))
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.send('ban\n')
sockobj.close()
self.item.starttime = time.time()
def love(self):
_debug_('%s.love()' % (self.__class__,))
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.send('love\n')
sockobj.close()
def skip(self):
_debug_('%s.skip()' % (self.__class__,))
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.connect(('localhost',self.lastfm_port))
sockobj.send('skip\n')
sockobj.close()
self.item.starttime = time.time()
def eventhandler(self, event, menuw=None):
"""
eventhandler for mplayer control. If an event is not bound in this
function it will be passed over to the items eventhandler
"""
_debug_('shellfmGUI event handler %s' % event)
if event in (STOP, PLAY_END, USER_END):
self.item.stop()
return self.item.eventhandler(event)
elif event in (PLAYLIST_NEXT,SEEK):
self.skip()
return True
elif event == INPUT_1:
self.ban()
return True
elif event == INPUT_3:
self.love()
return True
else:
# everything else: give event to the items eventhandler
return self.item.eventhandler(event)
def __update_thread(self):
"""
OSD update thread
"""
_debug_('%s.update_thread()' % (self.__class__,))
while self.is_playing():
self.refresh()
time.sleep(1)
------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and,
should the need arise, upgrade to a full multi-node Oracle RAC database
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Freevo-users mailing list
Freevo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-users