Comments added and methods of class MCGClient reordered
This commit is contained in:
parent
c2eb40c317
commit
cd711efa4a
2 changed files with 145 additions and 98 deletions
235
mcg.py
235
mcg.py
|
@ -1,6 +1,9 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Author: coderkun <olli@coderkun.de>
|
||||
|
||||
|
||||
|
||||
|
||||
import mpd
|
||||
|
@ -8,17 +11,26 @@ import os
|
|||
from hashlib import md5
|
||||
from threading import Thread
|
||||
|
||||
|
||||
|
||||
|
||||
class MCGClient:
|
||||
"""Client library for handling the connection to the Music Player Daemon.
|
||||
|
||||
This class implements an album-based MPD client.
|
||||
It offers a non-blocking threaded worker model for use in graphical
|
||||
environments and is based on python-mpd2.
|
||||
"""
|
||||
# Signal: connect/disconnect event
|
||||
SIGNAL_CONNECT = 'connect'
|
||||
# Signal: general idle event
|
||||
SIGNAL_IDLE = 'idle'
|
||||
# Signal: player idle event
|
||||
SIGNAL_IDLE_PLAYER = 'idle_player'
|
||||
# Signal: update event
|
||||
SIGNAL_UPDATE = 'update'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
"""Sets class variables and instantiates the MPDClient.
|
||||
"""
|
||||
self._connected = False
|
||||
self._albums = {}
|
||||
self._callbacks = {}
|
||||
|
@ -29,6 +41,9 @@ class MCGClient:
|
|||
|
||||
|
||||
def connect(self, host="localhost", port="6600", password=None):
|
||||
"""Connects to MPD with the given host, port and password or
|
||||
with standard values.
|
||||
"""
|
||||
# TODO als Parameter an _add_action() übergeben, nicht speichern
|
||||
self._host = host
|
||||
self._port = port
|
||||
|
@ -36,42 +51,22 @@ class MCGClient:
|
|||
self._add_action(self._connect)
|
||||
|
||||
|
||||
def _connect(self):
|
||||
try:
|
||||
self._client.connect(self._host, self._port)
|
||||
if self._password:
|
||||
self._client.password(self._password)
|
||||
# TODO Verbindung testen
|
||||
self._connected = True
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, None)
|
||||
self.update()
|
||||
self.idle_player()
|
||||
except IOError as e:
|
||||
self._connected = False
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, e)
|
||||
|
||||
|
||||
def is_connected(self):
|
||||
"""Returns the connection status.
|
||||
"""
|
||||
return self._connected
|
||||
|
||||
|
||||
def disconnect(self):
|
||||
"""Disconnects from the connected MPD.
|
||||
"""
|
||||
self._add_action(self._disconnect)
|
||||
|
||||
|
||||
def _disconnect(self):
|
||||
if not self.is_connected():
|
||||
return
|
||||
try:
|
||||
#self._client.close()
|
||||
self._client.disconnect()
|
||||
except:
|
||||
self._client = mpd.MPDClient()
|
||||
self._connected = False
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, None)
|
||||
|
||||
|
||||
def close(self):
|
||||
"""Closes the connection and stops properly the worker thread.
|
||||
This method is to stop the whole appliction.
|
||||
"""
|
||||
if not self.is_connected():
|
||||
return
|
||||
try:
|
||||
|
@ -83,32 +78,81 @@ class MCGClient:
|
|||
|
||||
|
||||
def update(self):
|
||||
"""Updates the album list.
|
||||
"""
|
||||
self._add_action(self._update)
|
||||
|
||||
|
||||
def _update(self):
|
||||
for song in self._client.listallinfo():
|
||||
try:
|
||||
if song['album'] not in self._albums:
|
||||
album = MCGAlbum(song['artist'], song['album'], song['date'], os.path.dirname(song['file']))
|
||||
self._albums[album.get_hash()] = album
|
||||
else:
|
||||
album = self._albums[MCGAlbum.hash(song['artist'], song['album'])]
|
||||
|
||||
track = MCGTrack(song['title'], song['track'], song['time'], song['file'])
|
||||
album.add_track(track)
|
||||
except KeyError:
|
||||
pass
|
||||
# TODO Alben sortieren
|
||||
self._callback(self.SIGNAL_UPDATE, self._albums)
|
||||
|
||||
|
||||
def play(self, album):
|
||||
"""Plays the given album.
|
||||
"""
|
||||
# TODO play()
|
||||
# mpd-Befehle: add, play
|
||||
# https://github.com/Mic92/python-mpd2/blob/master/mpd.py
|
||||
print("play: ", self._albums[album].get_title())
|
||||
|
||||
|
||||
def connect_signal(self, signal, callback):
|
||||
"""Connects a callback function to a signal (event).
|
||||
"""
|
||||
self._callbacks[signal] = callback
|
||||
|
||||
|
||||
def _has_callback(self, signal):
|
||||
"""Checks if there is a registered callback function for a
|
||||
signal.
|
||||
"""
|
||||
return signal in self._callbacks
|
||||
|
||||
|
||||
def _callback(self, signal, *args):
|
||||
"""Calls the callback function for a signal.
|
||||
"""
|
||||
if self._has_callback(signal):
|
||||
callback = self._callbacks[signal]
|
||||
callback(*args)
|
||||
|
||||
|
||||
def _add_action(self, method):
|
||||
"""Adds an action to the action list.
|
||||
"""
|
||||
self._actions.append(method)
|
||||
self._start_worker()
|
||||
|
||||
|
||||
def _start_worker(self):
|
||||
"""Starts the worker thread which waits for action to be
|
||||
performed.
|
||||
"""
|
||||
if self._worker is None or not self._worker.is_alive():
|
||||
self._worker = Thread(target=self._work, name='worker', args=())
|
||||
self._worker.start()
|
||||
else:
|
||||
try:
|
||||
self._client.noidle()
|
||||
except TypeError as e:
|
||||
pass
|
||||
|
||||
|
||||
def _work(self):
|
||||
"""Performs the next action or waits for an idle event.
|
||||
"""
|
||||
while True:
|
||||
if self._actions:
|
||||
action = self._actions.pop(0)
|
||||
action()
|
||||
else:
|
||||
if not self.is_connected():
|
||||
break
|
||||
modules = self._client.idle()
|
||||
if not self._go:
|
||||
break
|
||||
self._idle(modules)
|
||||
|
||||
|
||||
def _idle(self, modules):
|
||||
"""Reacts to idle events from MPD.
|
||||
"""
|
||||
if not modules:
|
||||
return
|
||||
|
||||
|
@ -125,11 +169,59 @@ class MCGClient:
|
|||
pass
|
||||
|
||||
|
||||
def idle_player(self):
|
||||
self._add_action(self._idle_player)
|
||||
def _connect(self):
|
||||
"""Action: Performs the real connect to MPD.
|
||||
"""
|
||||
try:
|
||||
self._client.connect(self._host, self._port)
|
||||
if self._password:
|
||||
self._client.password(self._password)
|
||||
# TODO Verbindung testen
|
||||
self._connected = True
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, None)
|
||||
self.update()
|
||||
self._add_action(self._idle_player)
|
||||
except IOError as e:
|
||||
self._connected = False
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, e)
|
||||
|
||||
|
||||
def _disconnect(self):
|
||||
"""Action: Performs the real disconnect from MPD.
|
||||
"""
|
||||
if not self.is_connected():
|
||||
return
|
||||
try:
|
||||
#self._client.close()
|
||||
self._client.disconnect()
|
||||
except:
|
||||
self._client = mpd.MPDClient()
|
||||
self._connected = False
|
||||
self._callback(self.SIGNAL_CONNECT, self._connected, None)
|
||||
|
||||
|
||||
def _update(self):
|
||||
"""Action: Performs the real update.
|
||||
"""
|
||||
for song in self._client.listallinfo():
|
||||
try:
|
||||
if song['album'] not in self._albums:
|
||||
album = MCGAlbum(song['artist'], song['album'], song['date'], os.path.dirname(song['file']))
|
||||
self._albums[album.get_hash()] = album
|
||||
else:
|
||||
album = self._albums[MCGAlbum.hash(song['artist'], song['album'])]
|
||||
|
||||
track = MCGTrack(song['title'], song['track'], song['time'], song['file'])
|
||||
album.add_track(track)
|
||||
except KeyError:
|
||||
pass
|
||||
# TODO Alben sortieren
|
||||
self._callback(self.SIGNAL_UPDATE, self._albums)
|
||||
|
||||
|
||||
def _idle_player(self):
|
||||
"""Reacts on the player idle event.
|
||||
"""
|
||||
if not self._has_callback(self.SIGNAL_IDLE_PLAYER):
|
||||
return
|
||||
status = self._client.status()
|
||||
|
@ -140,51 +232,6 @@ class MCGClient:
|
|||
|
||||
|
||||
|
||||
def connect_signal(self, signal, callback):
|
||||
self._callbacks[signal] = callback
|
||||
|
||||
|
||||
def _has_callback(self, signal):
|
||||
return signal in self._callbacks
|
||||
|
||||
|
||||
def _callback(self, signal, *args):
|
||||
if self._has_callback(signal):
|
||||
callback = self._callbacks[signal]
|
||||
callback(*args)
|
||||
|
||||
|
||||
def _add_action(self, method):
|
||||
self._actions.append(method)
|
||||
self._start_worker()
|
||||
|
||||
|
||||
def _start_worker(self):
|
||||
if self._worker is None or not self._worker.is_alive():
|
||||
self._worker = Thread(target=self._work, name='worker', args=())
|
||||
self._worker.start()
|
||||
else:
|
||||
try:
|
||||
self._client.noidle()
|
||||
except TypeError as e:
|
||||
pass
|
||||
|
||||
|
||||
def _work(self):
|
||||
while True:
|
||||
if self._actions:
|
||||
action = self._actions.pop(0)
|
||||
action()
|
||||
else:
|
||||
if not self.is_connected():
|
||||
break
|
||||
modules = self._client.idle()
|
||||
if not self._go:
|
||||
break
|
||||
self._idle(modules)
|
||||
|
||||
|
||||
|
||||
|
||||
class MCGAlbum:
|
||||
_file_names = ['folder', 'cover']
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Author: coderkun <olli@coderkun.de>
|
||||
|
||||
|
||||
|
||||
|
||||
from gi.repository import Gtk, Gdk, GdkPixbuf, GObject
|
||||
import mcg
|
||||
|
||||
|
||||
|
||||
|
||||
class MCGGtk(Gtk.Window):
|
||||
|
||||
def __init__(self):
|
||||
|
@ -292,7 +292,6 @@ class ConnectionPanel(Gtk.Box):
|
|||
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class CoverPanel(Gtk.HPaned):
|
||||
SIGNAL_UPDATE_START = 'update-start'
|
||||
SIGNAL_UPDATE_END = 'update-end'
|
||||
|
@ -443,6 +442,7 @@ class CoverPanel(Gtk.HPaned):
|
|||
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import configparser
|
||||
|
||||
|
|
Loading…
Reference in a new issue