Skip to content

Commit

Permalink
feat: add coverart support
Browse files Browse the repository at this point in the history
  • Loading branch information
mgoltzsche committed Mar 27, 2024
1 parent 4bc641e commit d2e77f5
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 1 deletion.
5 changes: 5 additions & 0 deletions mopidy_subidy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@ def get_config_schema(self):

def setup(self, registry):
from .backend import SubidyBackend
from .web import image_proxy_factory

registry.add("backend", SubidyBackend)
registry.add("http:app", {
"name": self.ext_name,
"factory": image_proxy_factory,
})
12 changes: 11 additions & 1 deletion mopidy_subidy/library.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

from mopidy import backend
from mopidy.models import Ref, SearchResult
from mopidy.models import Image, Ref, SearchResult
from mopidy_subidy import uri

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -208,3 +208,13 @@ def search(self, query=None, uris=None, exact=False):
if "any" in query:
return self.subsonic_api.find_as_search_result(query.get("any")[0])
return SearchResult(artists=self.subsonic_api.get_artists_as_artists())

def get_images(self, uris):
images = {}
for uri in uris:
# TODO: derive hostname
if uri.startswith("subidy:album:"):
images[uri] = [Image(uri=f"http://localhost:6680/subidy/coverart/2{uri[14:]}")]
elif uri.startswith("subidy:song:"):
images[uri] = [Image(uri=f"http://localhost:6680/subidy/coverart/3{uri[13:]}")]
return images
88 changes: 88 additions & 0 deletions mopidy_subidy/web.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import os
import logging

import tornado.web
import tornado.httpclient

from urllib.parse import urlparse

logger = logging.getLogger('subidy-web')


def image_proxy_factory(config, core):
return [
(r"/coverart/(?P<id>.+)", ImageProxyHandler, {"core": core, "config": config})
]

class ImageProxyHandler(tornado.web.RequestHandler):
def initialize(self, core, config):
self.core = core

subidy_config = config["subidy"]
self._subsonic_url=subidy_config["url"]
self._subsonic_username=subidy_config["username"]
self._subsonic_password=subidy_config["password"]

async def get(self, **kwargs):
id = kwargs.get('id')

logger.debug('Handle coverart %s request', id)

def handle_response(response):
if (response.error and not
isinstance(response.error, tornado.httpclient.HTTPError)):
self.set_status(500)
self.write('Internal server error:\n' + str(response.error))
else:
self.set_status(response.code, response.reason)
self._headers = tornado.httputil.HTTPHeaders() # clear tornado default header

for header, v in response.headers.get_all():
if header not in ('Content-Length', 'Transfer-Encoding', 'Content-Encoding', 'Connection'):
self.add_header(header, v) # some header appear multiple times, eg 'Set-Cookie'

if response.body:
self.set_header('Content-Length', len(response.body))
self.write(response.body)
self.finish()

try:
if 'Proxy-Connection' in self.request.headers:
del self.request.headers['Proxy-Connection']
resp = await fetch_request(
f"{self._subsonic_url}/rest/getCoverArt?id={id}",
method=self.request.method, headers=self.request.headers,
follow_redirects=False, allow_nonstandard_methods=False)
handle_response(resp)
except tornado.httpclient.HTTPError as e:
if hasattr(e, 'response') and e.response:
handle_response(e.response)
else:
self.set_status(500)
self.write('Internal server error:\n' + str(e))
self.finish()

def get_proxy(url):
url_parsed = urlparse(url, scheme='http')
proxy_key = '%s_proxy' % url_parsed.scheme
return os.environ.get(proxy_key)


def parse_proxy(proxy):
proxy_parsed = urlparse(proxy, scheme='http')
return proxy_parsed.hostname, proxy_parsed.port


def fetch_request(url, **kwargs):
proxy = get_proxy(url)
if proxy:
logger.debug('Forward request via upstream proxy %s', proxy)
tornado.httpclient.AsyncHTTPClient.configure(
'tornado.curl_httpclient.CurlAsyncHTTPClient')
host, port = parse_proxy(proxy)
kwargs['proxy_host'] = host
kwargs['proxy_port'] = port

req = tornado.httpclient.HTTPRequest(url, **kwargs)
client = tornado.httpclient.AsyncHTTPClient()
return client.fetch(req, raise_error=False)

0 comments on commit d2e77f5

Please sign in to comment.