# Buggy code
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 / 1000)

        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 = urllib.parse.urljoin(uri, uris[0])


# Traceback (AttributeError)
ERROR    StreamBackend backend caused an exception.
Traceback (most recent call last):
File "/usr/lib64/python2.7/site-packages/mopidy/core/library.py", line 19, in _backend_error_handling
yield
File "/usr/lib64/python2.7/site-packages/mopidy/core/library.py", line 237, in lookup
result = future.get()
File "/usr/lib64/python2.7/site-packages/pykka/threading.py", line 52, in get
compat.reraise(*self._data['exc_info'])
File "/usr/lib64/python2.7/site-packages/pykka/compat.py", line 12, in reraise
exec('raise tp, value, tb')
File "/usr/lib64/python2.7/site-packages/pykka/actor.py", line 201, in _actor_loop
response = self._handle_receive(message)
File "/usr/lib64/python2.7/site-packages/pykka/actor.py", line 295, in _handle_receive
return callee(*message['args'], **message['kwargs'])
File "/usr/lib64/python2.7/site-packages/mopidy/stream/actor.py", line 65, in lookup
requests_session=self.backend._session)
File "/usr/lib64/python2.7/site-packages/mopidy/stream/actor.py", line 131, in _unwrap_stream
not scan_result.mime.startswith('text/') and
AttributeError: 'NoneType' object has no attribute 'startswith'

# Fixed code
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:
            has_interesting_mime = (
                scan_result.mime is not None
                and not scan_result.mime.startswith("text/")
                and not scan_result.mime.startswith("application/")
            )
            if scan_result.playable or has_interesting_mime:
                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 / 1000)

        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 = urllib.parse.urljoin(uri, uris[0])