Browse Source

Begin abstracting api responses

podcasts
dave 5 years ago
parent
commit
73f0ff1201
  1. 102
      pysonic/api.py

102
pysonic/api.py

@ -1,11 +1,11 @@
import sys
import json
import logging
import cherrypy
import subprocess
from time import time
from random import shuffle
from threading import Thread
from time import sleep
import cherrypy
from collections import defaultdict
from bs4 import BeautifulSoup
from pysonic.library import LETTER_GROUPS
from pysonic.types import MUSIC_TYPES
@ -14,6 +14,65 @@ from pysonic.types import MUSIC_TYPES
logging = logging.getLogger("api")
class ApiResponse(object):
def __init__(self, status="ok", version="1.15.0", top=None, **kwargs):
self.status = status
self.version = version
self.data = {}
self.top = top
if self.top:
self.data[self.top] = kwargs ## kwargs unused TODO
def add_child(self, _type, **kwargs):
if not self.top:
raise Exception("You can't do this?")
if _type not in self.data[self.top]:
self.data[self.top][_type] = []
self.data[self.top][_type].append(kwargs)
def render_json(self):
return json.dumps({"subsonic-response": dict(status=self.status, version="1.15.0", **self.data)}, indent=4)
def render_xml(self):
doc = BeautifulSoup('', features='lxml-xml')
root = doc.new_tag("subsonic-response", xmlns="http://subsonic.org/restapi",
status=self.status,
version=self.version)
doc.append(root)
if self.top:
top = doc.new_tag(self.top)
root.append(top)
# TODO top_attrs ?
for top_child_type, top_child_instances in self.data[self.top].items():
for top_child_attrs in top_child_instances:
child = doc.new_tag(top_child_type)
child.attrs.update(top_child_attrs)
top.append(child)
albumlist = doc.new_tag("albumList")
doc.append(albumlist)
return doc.prettify()
response_formats = defaultdict(lambda: "render_xml")
response_formats["json"] = "render_json"
response_headers = defaultdict(lambda: "text/xml; charset=utf-8")
response_headers["json"] = "text/json" #TODO is this right?
def formatresponse(func):
"""
Decorator for rendering ApiResponse responses
"""
def wrapper(*args, **kwargs):
response = func(*args, **kwargs)
cherrypy.response.headers['Content-Type'] = response_headers[kwargs.get("f", "xml")]
return getattr(response, response_formats[kwargs.get("f", "xml")])()
return wrapper
class PysonicApi(object):
def __init__(self, db, library, options):
self.db = db
@ -104,6 +163,7 @@ class PysonicApi(object):
print("TODO save playlist with items {} current {} position {}".format(id, current, position))
@cherrypy.expose
@formatresponse
def getAlbumList_view(self, type, size=50, offset=0, **kwargs):
albums = self.library.get_albums()
if type == "random":
@ -114,31 +174,27 @@ class PysonicApi(object):
raise NotImplemented()
albumset = albums[0 + int(offset):int(size) + int(offset)]
cherrypy.response.headers['Content-Type'] = 'text/xml; charset=utf-8'
doc, root = self.response()
albumlist = doc.new_tag("albumList")
doc.append(albumlist)
response = ApiResponse(top="albumList")
for album in albumset:
album_meta = album['metadata']
tag = doc.new_tag("album",
id=album["id"],
parent=album["parent"],
isDir="true" if album['isdir'] else "false",
title=album_meta.get("id3_title", album["name"]), #TODO these cant be blank or dsub gets mad
album=album_meta.get("id3_album", album["album"]),
artist=album_meta.get("id3_artist", album["artist"]),
# X year="2014"
# X coverArt="3228"
# playCount="0"
# created="2016-05-08T05:31:31.000Z"/>
)
album_kw = dict(id=album["id"],
parent=album["parent"],
isDir="true" if album['isdir'] else "false",
title=album_meta.get("id3_title", album["name"]), #TODO these cant be blank or dsub gets mad
album=album_meta.get("id3_album", album["album"]),
artist=album_meta.get("id3_artist", album["artist"]),
# X year="2014"
# X coverArt="3228"
# playCount="0"
# created="2016-05-08T05:31:31.000Z"/>)
)
if 'cover' in album_meta:
tag.attrs["coverArt"] = album_meta["cover"]
album_kw["coverArt"] = album_meta["cover"]
if 'id3_year' in album_meta:
tag.attrs["year"] = album_meta['id3_year']
albumlist.append(tag)
yield doc.prettify()
album_kw["year"] = album_meta['id3_year']
response.add_child("album", **album_kw)
return response
@cherrypy.expose
def getMusicDirectory_view(self, id, **kwargs):

Loading…
Cancel
Save