Elizabeth Dodd wrote:
On Fri, 21 Dec 2007, Duncan Webb wrote:
Elizabeth Dodd wrote:
On Fri, 21 Dec 2007, Duncan Webb wrote:
Elizabeth Dodd wrote:
On Thu, 20 Dec 2007, Elizabeth Dodd wrote:
In Freevo 1.7-4 the mpd plugin crashes looking for OSD_OVERSCAN_LEFT
and OSD_OVERSCAN_RIGHT
so my will-code-for-food assistant has sorted this out for me
We haven't looked at svn to see if this is OK or not in svn
<redface>
don't trust the "paste as attachment" in kmail
</redface>
not a real diff, but close enough
mpd.py 204 <<<<<<
# set the multiplier to be used in all screen drawing
- self.xmult = float(osd.width - config.OSD_OVERSCAN_LEFT -
OSD_OVERSCAN_RIGHT) / 800
- self.ymult = float(osd.height - config.OSD_OVERSCAN_TOP -
OSD_OVERSCAN_BOTTOM) / 600
+ self.xmult = float(osd.width - config.OSD_OVERSCAN_LEFT -
config.OSD_OVERSCAN_RIGHT) / 800
+ self.ymult = float(osd.height - config.OSD_OVERSCAN_TOP -
config.OSD_OVERSCAN_BOTTOM) / 600
now it has the line wrap problem I was trying to be smart and avoid
Thanks for this, silly bug.
The whole system isn't actually operational yet; there may be more little
bugs and sometime over the silly season the report will be ready for the
wiki. There may be more bugs to find yet.
I like people to use the tracker to report bugs, this way there is a
history and they will be reported in the ChangeLog and you can attach a
unified diff to the report. If you're not sure what I'm talking about
see:
http://doc.freevo.org/Contributing?action=show#head-9ec333e919eefa9afe3b19d
417596d388a209b6d
To submit a new one, follow this link:
https://sourceforge.net/tracker/?func=add&group_id=46652&atid=446895
Duncan
Replacement MPD plugin has been coded (for about 2 weeks food).
It is on the tracker as graham put it there last night.
Can you test the attached patch, it changes the thread handling. This is
based on the page http://www.thescripts.com/forum/thread45247.html
I patch has been applied to svn, so hopefully it is working. The reason
is that kaa is a bit picky about threads not terminating.
Thanks
Duncan
Index: src/audio/plugins/mpdclient2.py
===================================================================
--- src/audio/plugins/mpdclient2.py (revision 10462)
+++ src/audio/plugins/mpdclient2.py (working copy)
@@ -11,7 +11,7 @@
import socket
from time import sleep
-import thread
+from threading import Thread, Event, Lock
# a line is either:
#
@@ -22,6 +22,7 @@
class socket_talker(object):
def __init__(self, host, port):
+ _debug_('socket_talker.__init__(host, port)', 2)
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -31,9 +32,10 @@
self.ack = ''
self.done = True
+
# this SUCKS
-
def get_line(self):
+ _debug_('get_line()', 2)
if not self.current_line:
self.current_line = self.file.readline().rstrip("\n")
if not self.current_line:
@@ -42,7 +44,9 @@
self.done = True
return self.current_line
+
def putline(self, line):
+ _debug_('putline(line)', 2)
self.file.write("%s\n" % line)
try:
self.file.flush()
@@ -50,7 +54,9 @@
pass
self.done = False
+
def get_pair(self):
+ _debug_('get_pair()', 2)
line = self.get_line()
self.ack = ''
@@ -152,21 +158,25 @@
}
def is_command(cmd):
+ _debug_('is_command(cmd)', 2)
return cmd in [ k[0] for k in commands.keys() ]
def escape(text):
+ _debug_('escape(text)', 2)
# join/split is faster than replace
text = '\\\\'.join(text.split('\\')) # \ -> \\
text = '\\"'.join(text.split('"')) # " -> \"
return text
def get_command(cmd, args):
+ _debug_('get_command(cmd, args)', 2)
try:
return commands[(cmd, len(args))]
except KeyError:
raise RuntimeError("no such command: %s (%d args)" % (cmd, len(args)))
def send_command(talker, cmd, args):
+ _debug_('send_command(talker, cmd, args)', 2)
args = list(args[:])
for i, arg in enumerate(args):
if not isinstance(arg, int):
@@ -175,15 +185,21 @@
talker.putline(format % tuple([cmd] + list(args)))
class sender_n_fetcher(object):
+ """ """
def __init__(self, sender, fetcher):
+ _debug_('sender_n_fetcher.__init__(sender, fetcher)', 2)
self.sender = sender
self.fetcher = fetcher
self.iterate = False
+
def __getattr__(self, cmd):
+ _debug_('sender_n_fetcher.__getattr__(cmd)', 2)
return lambda *args: self.send_n_fetch(cmd, args)
+
def send_n_fetch(self, cmd, args):
+ _debug_('send_n_fetch(cmd, args)', 2)
getattr(self.sender, cmd)(*args)
junk, howmany, type, keywords = get_command(cmd, args)
@@ -202,9 +218,11 @@
self.fetcher.clear()
return result
+
# stupid hack because you apparently can't return non-None and yield
# within the same function
def yield_then_clear(it):
+ _debug_('yield_then_clear(it)', 2)
for x in it:
yield x
self.fetcher.clear()
@@ -212,23 +230,36 @@
class command_sender(object):
+ """ """
def __init__(self, talker):
+ _debug_('command_sender.__init__(talker)', 2)
self.talker = talker
+
+
def __getattr__(self, cmd):
+ _debug_('command_sender.__getattr__(cmd)', 2)
return lambda *args: send_command(self.talker, cmd, args)
+
+
class response_fetcher(object):
+ """ """
def __init__(self, talker):
+ _debug_('response_fetcher.__init__(talker)', 2)
self.talker = talker
self.converters = {}
+
def clear(self):
+ _debug_('clear()', 2)
while not self.talker.done:
self.talker.current_line = ''
self.talker.get_line()
self.talker.current_line = ''
+
def one_object(self, keywords, type):
+ _debug_('one_object(keywords, type)', 2)
# if type isn't empty, then the object's type is set to it. otherwise
# the type is set to the key of the first key/val pair.
@@ -261,7 +292,9 @@
return entity
+
def all_objects(self, keywords, type):
+ _debug_('all_objects(keywords, type)', 2)
while 1:
obj = self.one_object(keywords, type)
if not obj:
@@ -270,14 +303,23 @@
if self.talker.done:
raise StopIteration
+
def convert(self, cmd, key, val):
+ _debug_('convert(cmd, key, val)', 2)
# if there's a converter, convert it, otherwise return it the same
return self.converters.get(cmd, {}).get(key, lambda x: x)(val)
+
+
class dictobj(dict):
+ """ """
def __getattr__(self, attr):
+ _debug_('dictobj.__getattr__(attr)', 2)
return self[attr]
+
+
def __repr__(self):
+ _debug_('dictobj.__repr__()', 2)
# <mpdclient2.dictobj at 0x12345678 ..
# {
# key: val,
@@ -288,8 +330,12 @@
',\n '.join([ '%s: %s' % (k, v) for k, v in self.items() ]) +
'\n }>')
+
+
class mpd_connection(object):
+ """ """
def __init__(self, host, port):
+ _debug_('mpd_connection.__init__(host, port)', 2)
self.talker = socket_talker(host, port)
self.send = command_sender(self.talker)
self.fetch = response_fetcher(self.talker)
@@ -297,25 +343,31 @@
self._hello()
+
def _hello(self):
+ _debug_('_hello()', 2)
line = self.talker.get_line()
if not line.startswith("OK MPD "):
raise RuntimeError("this ain't mpd")
self.mpd_version = line[len("OK MPD "):].strip()
self.talker.current_line = ''
+
# conn.foo() is equivalent to conn.do.foo(), but nicer
def __getattr__(self, attr):
+ _debug_('mpd_connection.__getattr__(attr)', 2)
if is_command(attr):
return getattr(self.do, attr)
raise AttributeError(attr)
def parse_host(host):
+ _debug_('parse_host(host)', 2)
if '@' in host:
return host.split('@', 1)
return '', host
def connect(**kw):
+ _debug_('connect(**kw)', 2)
import os
port = int(os.environ.get('MPD_PORT', 6600))
@@ -339,41 +391,71 @@
#
-# # Thread safe extenstion added by Graham Billiau <[EMAIL PROTECTED]>
+# Thread safe extenstion added by Graham Billiau <[EMAIL PROTECTED]>
#
-
-# TODO:
-# sometimes this hangs, probably a problem with the locking
-
-def MPD_Ping_Thread(conn):
+class MPD_Ping_Thread(Thread):
"""This should be run as a thread
It constantly loops, sending keepalive packets to the mpd server
it exits cleanly after the connection is closed"""
- while True:
- sleep(10)
- try:
- if not conn:
- return
- conn.ping()
- except socket.error:
- return
+ def __init__(self, conn):
+ _debug_('__init__(conn=%r)' % (conn,), 2)
+ self.conn = conn
+ self._stopevent = Event()
+ self._sleepperiod = 10.0
+ Thread.__init__(self, name="MPD_Ping_Thread")
+
+ def join(self, timeout=None):
+ _debug_('join(timeout=None)', 2)
+ """
+ Stop the thread
+ """
+ self._stopevent.set()
+ Thread.join(self, timeout)
+
+
+ def run(self):
+ _debug_('run()', 2)
+ while not self._stopevent.isSet():
+ try:
+ self.conn.ping()
+ except socket.error:
+ break
+ self._stopevent.wait(self._sleepperiod)
+
+
+
class Thread_MPD_Connection:
"""This is a wrapper around the mpdclient2 library to make it thread safe"""
- #conn
- def __init__ (self, host, port, keepalive=False, pword = None):
+ def __init__(self, host, port, keepalive=False, pword=None):
"""create the connection and locks,
- if keepalive is True the connection will not time out and must be explcitly closed"""
+ if keepalive is True the connection will not time out and must be explcitly closed
+ """
+ _debug_('Thread_MPD_Connection.__init__(host=%r, port=%r, keepalive=%r, pword=%r)' %
+ (host, port, keepalive, pword), 1)
self.conn = mpd_connection(host, port)
- if (pword is not None):
+ if pword is not None:
self.conn.password(pword)
- self.lock = thread.allocate_lock()
- if (keepalive == True):
- thread.start_new_thread(MPD_Ping_Thread, (self, ))
+ self.lock = Lock()
+ if keepalive:
+ self.ping_thread = MPD_Ping_Thread(self)
+ if self.ping_thread:
+ self.ping_thread.start()
+
+ def join(self):
+ """ stop the ping thread """
+ _debug_('Thread_MPD_Connection.join()', 2)
+ if self.ping_thread:
+ self.ping_thread.join()
+
+
def __getattr__(self, attr):
"""pass the request on to the connection object, while ensuring no conflicts"""
+ _debug_('__getattr__(attr)', 2)
self.lock.acquire()
- funct = self.conn.__getattr__(attr)
- self.lock.release()
+ try:
+ funct = self.conn.__getattr__(attr)
+ finally:
+ self.lock.release()
return funct
Index: src/audio/plugins/mpd_playlist.py
===================================================================
--- src/audio/plugins/mpd_playlist.py (revision 10462)
+++ src/audio/plugins/mpd_playlist.py (working copy)
@@ -100,6 +100,7 @@
def shutdown(self):
"""close the connection to the mpd server"""
+ self.conn.join()
try:
# this always throws EOFError, even though there isn't really an error
self.conn.close()
Index: src/audio/plugins/mpd_status.py
===================================================================
--- src/audio/plugins/mpd_status.py (revision 10462)
+++ src/audio/plugins/mpd_status.py (working copy)
@@ -72,7 +72,6 @@
__maintainer_email__ = __author_email__
__version__ = '2'
-
def __init__(self):
"""Initilise the plugin"""
if not config.MPD_MUSIC_BASE_PATH:
@@ -115,6 +114,7 @@
def shutdown(self):
"""close the connection to the MPD server"""
+ self.conn.join()
try:
self.conn.close()
except EOFError:
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Freevo-users mailing list
Freevo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-users