Skip to content

Commit

Permalink
Implement Media Serving!
Browse files Browse the repository at this point in the history
Abstract out songs/playlists to make managing the MPD library easier.  The refresh needs to
become asynchronous and in a thread.
  • Loading branch information
Zach Goldberg committed Feb 16, 2010
1 parent e45f785 commit 8a7fce2
Show file tree
Hide file tree
Showing 13 changed files with 1,385 additions and 30 deletions.
79 changes: 79 additions & 0 deletions library.py
@@ -0,0 +1,79 @@
from mpdobjects.playlist import MPDPlaylist
from mpdobjects.song import MPDSong

class MPDLibrary(object):
def __init__(self, client, credentials):
self.client = client
self.creds = credentials

def clear(self):
self.playlists = []
self.songs = []
self.songs_by_file = {}
self.id_inc = 0
self.items_by_id = {}


def connect(self):
self.client.connect(**self.creds)

def disconnect(self):
self.client.disconnect()

def refresh(self):
self.connect()

self.clear()

print "Downloading MPD Playlists / Library"
for p in self.client.listplaylists():
print "Loading %s" % p['playlist']
songs = self.client.listplaylistinfo(p['playlist'])
mpdsongs = []
for song in songs:
if not song['file'] in self.songs_by_file:
self.songs_by_file[song['file']] = MPDSong(song['file'], song.get('artist', 'Unknown'),
song.get('album', 'Unknown'), song.get('title', 'Unknown')
)

self.register_song(self.songs_by_file[song['file']])

mpdsongs.append(self.songs_by_file[song['file']])

playlist = MPDPlaylist(p['playlist'], mpdsongs)
self.register_playlist(playlist)

cursongs = self.client.playlistinfo()
self.disconnect()

curmpdsongs = []
for song in cursongs:
if not song['file'] in self.songs_by_file:
self.songs_by_file[song['file']] = MPDSong(song['file'], song.get('artist', 'Unknown'),
song.get('album', 'Unknown'), song.get('title', 'Unknown'))
self.register_song(self.songs_by_file[song['file']])
curmpdsongs.append(self.songs_by_file[song['file']])

self.register_playlist(MPDPlaylist('Current Playlist', curmpdsongs))
self.register_playlist(MPDPlaylist('All Songs', self.songs))
self.playlists.reverse()

def get_by_id(self, id):
return self.items_by_id.get(id, None)


def next_id(self):
self.id_inc += 1
return self.id_inc

def register_item(self, obj, list):
obj.set_id(self.next_id())
self.items_by_id[obj.get_id()] = obj
list.append(obj)

def register_playlist(self, playlist):
self.register_item(playlist, self.playlists)

def register_song(self, song):
self.register_item(song, self.songs)

Empty file added mpdobjects/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions mpdobjects/mpdobject.py
@@ -0,0 +1,9 @@
class MPDObject(object):
def __init__(self):
self.id = None

def set_id(self, id):
self.id = id

def get_id(self):
return self.id
16 changes: 16 additions & 0 deletions mpdobjects/playlist.py
@@ -0,0 +1,16 @@
from mpdobjects.mpdobject import MPDObject

class MPDPlaylist(MPDObject):
def __init__(self, name, songs):
self.name = name
self.songs = songs

def writeself(self, writer):
container = writer.add_container()
container.set_title(self.name)
container.set_child_count(len(self.songs))
container.set_id(str(self.get_id()))

def writeall(self, writer):
for song in self.songs:
song.writeself(writer)
18 changes: 18 additions & 0 deletions mpdobjects/song.py
@@ -0,0 +1,18 @@
from mpdobjects.mpdobject import MPDObject

class MPDSong(MPDObject):
def __init__(self, file, artist, album, title):
self.file = file
self.artist = artist
self.album = album
self.title = title

def writeself(self, writer):
item = writer.add_item()
item.set_title(self.title)
item.set_artist(self.artist)
item.set_album(self.album)
item.set_id(str(self.get_id()))

res = item.add_resource()
res.set_uri("mpd://%s" % self.get_id())
80 changes: 50 additions & 30 deletions server.py
@@ -1,43 +1,41 @@
from gi.repository import GUPnP, GUPnPAV, GObject, GLib
from library import MPDLibrary
from mpdobjects.playlist import MPDPlaylist
from mpdobjects.song import MPDSong
import mpd

CON_ID = None
MPDCLIENT = None

LIBRARY = None
GObject.threads_init()

PLAYLISTS = []

def setup_server():

ctx = GUPnP.Context(interface="eth0")

ctx.host_path("device.xml", "/device.xml")
ctx.host_path("AVTransport2.xml", "/AVTransport2.xml")
ctx.host_path("ContentDirectory.xml", "/ContentDirectory.xml")
ctx.host_path("xml/device.xml", "/device.xml")
ctx.host_path("xml/AVTransport2.xml", "/AVTransport2.xml")
ctx.host_path("xml/ContentDirectory.xml", "/ContentDirectory.xml")

desc = "device.xml"
desc_loc = "./"
desc_loc = "./xml/"

rd = GUPnP.RootDevice.new(ctx, desc, desc_loc)
rd.set_available(True)

return rd

def setup_mpd():
global CON_ID, MPDCLIENT, PLAYLISTS
global CON_ID, MPDCLIENT, LIBRARY
HOST = 'localhost'
PORT = '6600'
CON_ID = {'host':HOST, 'port':PORT}

MPDCLIENT = mpd.MPDClient()
MPDCLIENT.connect(**CON_ID)

print "Downloading MPD Playlists / Library"
PLAYLISTS = MPDCLIENT.listplaylists()

MPDCLIENT.disconnect()

LIBRARY = MPDLibrary(MPDCLIENT, CON_ID)
LIBRARY.refresh()

print "Scheduling MPD Database refresh every 60 seconds..."


Expand All @@ -57,30 +55,52 @@ def wrapper(service, action):
MPDCLIENT.connect(**CON_ID)
getattr(MPDCLIENT, function_name.lower())(*args)
MPDCLIENT.disconnect()
getattr(action, "return")()
getattr(action, "return")()


return wrapper

def set_mpd_uri(service, action):
print action.get_value_type("CurrentURI", GObject.TYPE_STRING)
import pdb
pdb.set_trace()

uri = action.get_value_type("CurrentURI", GObject.TYPE_STRING)
itemid = int(uri.replace("mpd://", ""))

song = LIBRARY.get_by_id(itemid)

def browse_action(service, action):
w = GUPnPAV.GUPnPDIDLLiteWriter.new("English")
if not isinstance(song, MPDSong):
action.return_error()
return

MPDCLIENT.connect(**CON_ID)
songdata = MPDCLIENT.playlistfind('file', song.file)

if songdata:
# If the song is in the current playlist move to it and play it
MPDCLIENT.seek(songdata[0]['pos'], 0)
else:
# Else add it to the playlist then play it
MPDCLIENT.add(song.file)
songdata = MPDCLIENT.playlistfind('file', song.file)
if not songdata:
action.return_error()
return
MPDCLIENT.seek(songdata[0]['pos'], 0)

container = w.add_container()
container.set_title("All Songs")
MPDCLIENT.disconnect()
getattr(action, "return")()

container = w.add_container()
container.set_title("Current Playlist")
def browse_action(service, action):
global LIBRARY
itemid = action.get_value_type('ObjectID', GObject.TYPE_INT)

for p in PLAYLISTS:
container = w.add_container()
container.set_title(p["playlist"])

w = GUPnPAV.GUPnPDIDLLiteWriter.new("English")
if itemid == 0:
for playlist in LIBRARY.playlists:
playlist.writeself(w)
else:
obj = LIBRARY.get_by_id(itemid)
if not isinstance(obj, MPDPlaylist):
action.return_error()
return
obj.writeall(w)

action.set_value("Result", w.get_string())
action.set_value("NumberReturned", 1)
Expand Down
File renamed without changes.

0 comments on commit 8a7fce2

Please sign in to comment.