Skip to content

Commit

Permalink
Merge pull request #28 from kingosticks/fix-remove-StreamPlaybackProv…
Browse files Browse the repository at this point in the history
…ider

Stop inheriting from StreamPlaybackProvider
  • Loading branch information
Nick Steel committed Feb 16, 2016
2 parents e3a8c32 + 7c6c5d5 commit d8398c5
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 15 deletions.
6 changes: 6 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ Project resources
Changelog
=========

v0.4.0 (2016-02-16)
-------------------

- Borrow Mopidy's internal stream unwrapping to avoid incompatibilities with Mopidy v2.0.0 (PR: #28)
- Improved handling of malformed pls playlists.

v0.3.0 (2016-02-06)
-------------------

Expand Down
2 changes: 1 addition & 1 deletion mopidy_tunein/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from mopidy import config, ext

__version__ = '0.3.0'
__version__ = '0.4.0'


class Extension(ext.Extension):
Expand Down
101 changes: 90 additions & 11 deletions mopidy_tunein/actor.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import unicode_literals

import logging
import time

from mopidy import backend, httpclient
from mopidy import backend, exceptions, httpclient
from mopidy.audio import scan
# TODO: Something else, using internal APIs is not cool.
from mopidy.internal import http, playlists
from mopidy.models import Ref, SearchResult
from mopidy.stream.actor import StreamPlaybackProvider

import pykka

Expand Down Expand Up @@ -34,20 +36,20 @@ class TuneInBackend(pykka.ThreadingActor, backend.Backend):
def __init__(self, config, audio):
super(TuneInBackend, self).__init__()

session = get_requests_session(
self._session = get_requests_session(
proxy_config=config['proxy'],
user_agent='%s/%s' % (
mopidy_tunein.Extension.dist_name,
mopidy_tunein.__version__))

self._timeout = config['tunein']['timeout']

self._scanner = scan.Scanner(
timeout=config['tunein']['timeout'],
proxy_config=config['proxy'])
self.tunein = tunein.TuneIn(config['tunein']['timeout'], session)
self.tunein = tunein.TuneIn(config['tunein']['timeout'], self._session)
self.library = TuneInLibrary(self)
self.playback = TuneInPlayback(audio=audio,
backend=self,
config=config)
self.playback = TuneInPlayback(audio=audio, backend=self)


class TuneInLibrary(backend.LibraryProvider):
Expand Down Expand Up @@ -123,9 +125,7 @@ def search(self, query=None, uris=None, exact=False):
return SearchResult(uri='tunein:search', tracks=tracks)


class TuneInPlayback(StreamPlaybackProvider):
def __init__(self, audio, backend, config):
super(TuneInPlayback, self).__init__(audio, backend, config)
class TuneInPlayback(backend.PlaybackProvider):

def translate_uri(self, uri):
variant, identifier = translator.parse_uri(uri)
Expand All @@ -136,7 +136,7 @@ def translate_uri(self, uri):
while stream_uris:
uri = stream_uris.pop(0)
logger.debug('Looking up URI: %s.' % uri)
new_uri = super(TuneInPlayback, self).translate_uri(uri)
new_uri = self.unwrap_stream(uri)
if new_uri:
return new_uri
else:
Expand All @@ -149,3 +149,82 @@ def translate_uri(self, uri):
stream_uris.extend(new_uris)
logger.debug('TuneIn lookup failed.')
return None

def unwrap_stream(self, uri):
unwrapped_uri, _ = _unwrap_stream(
uri, timeout=self.backend._timeout, scanner=self.backend._scanner,
requests_session=self.backend._session)
return unwrapped_uri


# Shamelessly taken from mopidy.stream.actor
def _unwrap_stream(uri, timeout, scanner, requests_session):
"""
Get a stream URI from a playlist URI, ``uri``.
Unwraps nested playlists until something that's not a playlist is found or
the ``timeout`` is reached.
"""

original_uri = uri
seen_uris = set()
deadline = time.time() + timeout

while time.time() < deadline:
if uri in seen_uris:
logger.info(
'Unwrapping stream from URI (%s) failed: '
'playlist referenced itself', uri)
return None, None
else:
seen_uris.add(uri)

logger.debug('Unwrapping stream from URI: %s', uri)

try:
scan_timeout = deadline - time.time()
if scan_timeout < 0:
logger.info(
'Unwrapping stream from URI (%s) failed: '
'timed out in %sms', uri, timeout)
return None, None
scan_result = scanner.scan(uri, timeout=scan_timeout)
except exceptions.ScannerError as exc:
logger.debug('GStreamer failed scanning URI (%s): %s', uri, exc)
scan_result = None

if scan_result is not None:
if scan_result.playable or (
not scan_result.mime.startswith('text/') and
not scan_result.mime.startswith('application/')
):
logger.debug(
'Unwrapped potential %s stream: %s', scan_result.mime, uri)
return uri, scan_result

download_timeout = deadline - time.time()
if download_timeout < 0:
logger.info(
'Unwrapping stream from URI (%s) failed: timed out in %sms',
uri, timeout)
return None, None
content = http.download(
requests_session, uri, timeout=download_timeout)

if content is None:
logger.info(
'Unwrapping stream from URI (%s) failed: '
'error downloading URI %s', original_uri, uri)
return None, None

uris = playlists.parse(content)
if not uris:
logger.debug(
'Failed parsing URI (%s) as playlist; found potential stream.',
uri)
return uri, None

# TODO Test streams and return first that seems to be playable
logger.debug(
'Parsed playlist (%s) and found new URI: %s', uri, uris[0])
uri = uris[0]
6 changes: 3 additions & 3 deletions mopidy_tunein/tunein.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def parse_pls(data):
if cp.get(section, 'length%d' % (i+1)) == '-1':
yield cp.get(section, 'file%d' % (i+1))
else:
yield cp.get(section, 'file%d' % (i+1))
yield cp.get(section, 'file%d' % (i+1))
except configparser.NoOptionError:
return

Expand Down Expand Up @@ -308,11 +308,11 @@ def parse_stream_url(self, url):
parser = find_playlist_parser(extension, content_type)
if parser:
playlist_data = StringIO.StringIO(playlist)
try:
try:
results = [u for u in parser(playlist_data)
if u and u != url]
except Exception as e:
logger.error('TuneIn playlist parsing failed %s' % e)
logger.error('TuneIn playlist parsing failed %s' % e)
if not results:
logger.debug('Parsing failure, '
'malformed playlist: %s' % playlist)
Expand Down

0 comments on commit d8398c5

Please sign in to comment.