Mopidy-SomaFM-2.0.0rc1/ 0000755 0001750 0001751 00000000000 13571702175 016441 5 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/.circleci/ 0000755 0001750 0001751 00000000000 13571702175 020274 5 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/.circleci/config.yml 0000644 0001750 0001751 00000002065 13571702147 022266 0 ustar alexandre alexandre 0000000 0000000 version: 2.1
orbs:
codecov: codecov/codecov@1.0.5
workflows:
version: 2
test:
jobs:
- py38
- py37
- black
- check-manifest
- flake8
jobs:
py38: &test-template
docker:
- image: mopidy/ci-python:3.8
steps:
- checkout
- restore_cache:
name: Restoring tox cache
key: tox-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.cfg" }}
- run:
name: Run tests
command: |
tox -e $CIRCLE_JOB -- \
--junit-xml=test-results/pytest/results.xml \
--cov-report=xml
- save_cache:
name: Saving tox cache
key: tox-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.cfg" }}
paths:
- ./.tox
- ~/.cache/pip
- codecov/upload:
file: coverage.xml
- store_test_results:
path: test-results
py37:
<<: *test-template
docker:
- image: mopidy/ci-python:3.7
black: *test-template
check-manifest: *test-template
flake8: *test-template
Mopidy-SomaFM-2.0.0rc1/CHANGES.rst 0000644 0001750 0001751 00000003047 13571702147 020246 0 ustar alexandre alexandre 0000000 0000000 Changelog
=========
v2.0.0rc1 (2019-12-04)
----------------------
- #32 Migrate to Python 3.7
v1.1.0 (2017-10-14)
-------------------
- #24: Graceful fallback
- #28: Various fix (DJ as artist, station ordering)
v1.0.1 (2016-01-19)
-------------------
- Use httpclient helper from Mopidy >= 1.1
v0.8.0 (2015-11-09)
-------------------
- #20: Replace HTTP with HTTPS for channels.xml
v0.7.1 (2015-01-04)
-------------------
- #11: Add Low Bitrate encoding (aacp)
v0.7.0 (2014-07-29)
-------------------
- #10: Remove playlists provider
v0.6.0 (2014-03-15)
-------------------
- Directly show PLS in browser
- Add precision about 'quality' and 'encoding' couple
v0.5.1 (2014-03-09)
-------------------
- Fix doc typo
v0.5.0 (2014-03-03)
-------------------
- #5: Select prefered quality and format from config
- Add tests and Travis-CI support
v0.4.0 (2014-02-16)
-------------------
- Add browse support for LibraryController
v0.3.1 (2014-01-30)
-------------------
- #3: Correct wrong subclassing
v0.3.0 (2014-01-29)
-------------------
- Require Mopidy >= 0.18
- Add proxy support for downloading SomaFM content
- #1: handle 'requests' exceptions
- Use builtin Mopidy's .pls support
- Internal code cleanup
v0.2.0 (2013-09-22)
-------------------
- PLS files are downloaded to local temp directory
- Implement library::lookup to allow adding tracks from playlist uri
v0.1.1 (2013-09-14)
-------------------
- Update Licence information
v0.1.0 (2013-09-13)
-------------------
- Initial release
- Create SomaFM extension for Mopidy
Mopidy-SomaFM-2.0.0rc1/LICENSE 0000644 0001750 0001751 00000002076 13571702147 017452 0 ustar alexandre alexandre 0000000 0000000 The MIT License (MIT)
Copyright (c) 2019 Alexandre Petitjean
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Mopidy-SomaFM-2.0.0rc1/MANIFEST.in 0000644 0001750 0001751 00000000412 13571702147 020173 0 ustar alexandre alexandre 0000000 0000000 include *.py
include *.rst
include .mailmap
include LICENSE
include MANIFEST.in
include pyproject.toml
include tox.ini
recursive-include .circleci *
recursive-include .github *
include mopidy_*/ext.conf
recursive-include tests *.py
recursive-include tests/data *
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/ 0000755 0001750 0001751 00000000000 13571702175 022576 5 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/PKG-INFO 0000644 0001750 0001751 00000006545 13571702175 023705 0 ustar alexandre alexandre 0000000 0000000 Metadata-Version: 2.1
Name: Mopidy-SomaFM
Version: 2.0.0rc1
Summary: SomaFM extension for Mopidy
Home-page: https://github.com/AlexandrePTJ/mopidy-somafm
Author: Alexandre Petitjean
Author-email: alpetitjean@gmail.com
License: Apache License, Version 2.0
Description: *************
Mopidy-SomaFM
*************
.. image:: https://img.shields.io/pypi/v/Mopidy-SomaFM
:target: https://pypi.org/project/Mopidy-SomaFM/
:alt: Latest PyPI version
.. image:: https://img.shields.io/circleci/build/gh/AlexandrePTJ/mopidy-somafm
:target: https://circleci.com/gh/AlexandrePTJ/mopidy-somafm
:alt: CircleCI build status
.. image:: https://img.shields.io/codecov/c/gh/AlexandrePTJ/mopidy-somafm
:target: https://codecov.io/gh/AlexandrePTJ/mopidy-somafm
:alt: Test coverage
SomaFM extension for Mopidy
Installation
============
Debian/Ubuntu
-------------
Install by running::
python3 -m pip install Mopidy-SomaFM
Or, if available, install the Debian/Ubuntu package from
`apt.mopidy.com `_.
Configuration
=============
Before starting Mopidy, you must add configuration for
Mopidy-SomaFM to your Mopidy configuration file::
[somafm]
encoding = aac
quality = highest
- ``encoding`` must be either ``aac``, ``mp3`` or ``aacp``
- ``quality`` must be one of ``highest``, ``fast``, ``slow``, ``firewall``
If the preferred quality is not available for a channel, the extension will fallback
to ``fast``. And afterwards if the preferred encoding is not available for that
quality, it will fallback to using ``mp3``.
It seems that all channels support the combination ``fast`` + ``mp3``
You can also choose to use the channel DJ as the reported track artist (default behavior)::
[somafm]
dj_as_artist = true
Project resources
=================
- `Source code `_
- `Issue tracker `_
- `Changelog `_
Credits
=======
- Original author: `Alexandre Petitjean `__
- Current maintainer: `Alexandre Petitjean `__
- `Contributors `_
Platform: UNKNOWN
Classifier: Environment :: No Input/Output (Daemon)
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
Requires-Python: >=3.7
Provides-Extra: lint
Provides-Extra: release
Provides-Extra: test
Provides-Extra: dev
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/SOURCES.txt 0000644 0001750 0001751 00000001016 13571702175 024460 0 ustar alexandre alexandre 0000000 0000000 CHANGES.rst
LICENSE
MANIFEST.in
README.rst
pyproject.toml
setup.cfg
setup.py
tox.ini
.circleci/config.yml
Mopidy_SomaFM.egg-info/PKG-INFO
Mopidy_SomaFM.egg-info/SOURCES.txt
Mopidy_SomaFM.egg-info/dependency_links.txt
Mopidy_SomaFM.egg-info/entry_points.txt
Mopidy_SomaFM.egg-info/not-zip-safe
Mopidy_SomaFM.egg-info/requires.txt
Mopidy_SomaFM.egg-info/top_level.txt
mopidy_somafm/__init__.py
mopidy_somafm/backend.py
mopidy_somafm/ext.conf
mopidy_somafm/somafm.py
tests/__init__.py
tests/test_extension.py
tests/test_somafm.py Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/dependency_links.txt 0000644 0001750 0001751 00000000001 13571702175 026644 0 ustar alexandre alexandre 0000000 0000000
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/entry_points.txt 0000644 0001750 0001751 00000000057 13571702175 026076 0 ustar alexandre alexandre 0000000 0000000 [mopidy.ext]
somafm = mopidy_somafm:Extension
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/not-zip-safe 0000644 0001750 0001751 00000000001 13571666354 025034 0 ustar alexandre alexandre 0000000 0000000
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/requires.txt 0000644 0001750 0001751 00000000466 13571702175 025204 0 ustar alexandre alexandre 0000000 0000000 Mopidy>=3.0.0a4
Pykka>=2.0.1
requests>=2.0.0
setuptools
[dev]
black
check-manifest
flake8
flake8-bugbear
flake8-import-order
isort[pyproject]
twine
wheel
pytest
pytest-cov
[lint]
black
check-manifest
flake8
flake8-bugbear
flake8-import-order
isort[pyproject]
[release]
twine
wheel
[test]
pytest
pytest-cov
Mopidy-SomaFM-2.0.0rc1/Mopidy_SomaFM.egg-info/top_level.txt 0000644 0001750 0001751 00000000016 13571702175 025325 0 ustar alexandre alexandre 0000000 0000000 mopidy_somafm
Mopidy-SomaFM-2.0.0rc1/PKG-INFO 0000644 0001750 0001751 00000006545 13571702175 017550 0 ustar alexandre alexandre 0000000 0000000 Metadata-Version: 2.1
Name: Mopidy-SomaFM
Version: 2.0.0rc1
Summary: SomaFM extension for Mopidy
Home-page: https://github.com/AlexandrePTJ/mopidy-somafm
Author: Alexandre Petitjean
Author-email: alpetitjean@gmail.com
License: Apache License, Version 2.0
Description: *************
Mopidy-SomaFM
*************
.. image:: https://img.shields.io/pypi/v/Mopidy-SomaFM
:target: https://pypi.org/project/Mopidy-SomaFM/
:alt: Latest PyPI version
.. image:: https://img.shields.io/circleci/build/gh/AlexandrePTJ/mopidy-somafm
:target: https://circleci.com/gh/AlexandrePTJ/mopidy-somafm
:alt: CircleCI build status
.. image:: https://img.shields.io/codecov/c/gh/AlexandrePTJ/mopidy-somafm
:target: https://codecov.io/gh/AlexandrePTJ/mopidy-somafm
:alt: Test coverage
SomaFM extension for Mopidy
Installation
============
Debian/Ubuntu
-------------
Install by running::
python3 -m pip install Mopidy-SomaFM
Or, if available, install the Debian/Ubuntu package from
`apt.mopidy.com `_.
Configuration
=============
Before starting Mopidy, you must add configuration for
Mopidy-SomaFM to your Mopidy configuration file::
[somafm]
encoding = aac
quality = highest
- ``encoding`` must be either ``aac``, ``mp3`` or ``aacp``
- ``quality`` must be one of ``highest``, ``fast``, ``slow``, ``firewall``
If the preferred quality is not available for a channel, the extension will fallback
to ``fast``. And afterwards if the preferred encoding is not available for that
quality, it will fallback to using ``mp3``.
It seems that all channels support the combination ``fast`` + ``mp3``
You can also choose to use the channel DJ as the reported track artist (default behavior)::
[somafm]
dj_as_artist = true
Project resources
=================
- `Source code `_
- `Issue tracker `_
- `Changelog `_
Credits
=======
- Original author: `Alexandre Petitjean `__
- Current maintainer: `Alexandre Petitjean `__
- `Contributors `_
Platform: UNKNOWN
Classifier: Environment :: No Input/Output (Daemon)
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
Requires-Python: >=3.7
Provides-Extra: lint
Provides-Extra: release
Provides-Extra: test
Provides-Extra: dev
Mopidy-SomaFM-2.0.0rc1/README.rst 0000644 0001750 0001751 00000003766 13571702147 020143 0 ustar alexandre alexandre 0000000 0000000 *************
Mopidy-SomaFM
*************
.. image:: https://img.shields.io/pypi/v/Mopidy-SomaFM
:target: https://pypi.org/project/Mopidy-SomaFM/
:alt: Latest PyPI version
.. image:: https://img.shields.io/circleci/build/gh/AlexandrePTJ/mopidy-somafm
:target: https://circleci.com/gh/AlexandrePTJ/mopidy-somafm
:alt: CircleCI build status
.. image:: https://img.shields.io/codecov/c/gh/AlexandrePTJ/mopidy-somafm
:target: https://codecov.io/gh/AlexandrePTJ/mopidy-somafm
:alt: Test coverage
SomaFM extension for Mopidy
Installation
============
Debian/Ubuntu
-------------
Install by running::
python3 -m pip install Mopidy-SomaFM
Or, if available, install the Debian/Ubuntu package from
`apt.mopidy.com `_.
Configuration
=============
Before starting Mopidy, you must add configuration for
Mopidy-SomaFM to your Mopidy configuration file::
[somafm]
encoding = aac
quality = highest
- ``encoding`` must be either ``aac``, ``mp3`` or ``aacp``
- ``quality`` must be one of ``highest``, ``fast``, ``slow``, ``firewall``
If the preferred quality is not available for a channel, the extension will fallback
to ``fast``. And afterwards if the preferred encoding is not available for that
quality, it will fallback to using ``mp3``.
It seems that all channels support the combination ``fast`` + ``mp3``
You can also choose to use the channel DJ as the reported track artist (default behavior)::
[somafm]
dj_as_artist = true
Project resources
=================
- `Source code `_
- `Issue tracker `_
- `Changelog `_
Credits
=======
- Original author: `Alexandre Petitjean `__
- Current maintainer: `Alexandre Petitjean `__
- `Contributors `_
Mopidy-SomaFM-2.0.0rc1/mopidy_somafm/ 0000755 0001750 0001751 00000000000 13571702175 021304 5 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/mopidy_somafm/__init__.py 0000644 0001750 0001751 00000001556 13571702147 023423 0 ustar alexandre alexandre 0000000 0000000 import logging
import pathlib
import pkg_resources
from mopidy import config, ext
__version__ = pkg_resources.get_distribution("Mopidy-SomaFM").version
logger = logging.getLogger(__name__)
class Extension(ext.Extension):
dist_name = "Mopidy-SomaFM"
ext_name = "somafm"
version = __version__
def get_default_config(self):
return config.read(pathlib.Path(__file__).parent / "ext.conf")
def get_config_schema(self):
schema = super().get_config_schema()
schema["encoding"] = config.String(choices=("aac", "mp3", "aacp"))
schema["quality"] = config.String(
choices=("highest", "fast", "slow", "firewall")
)
schema["dj_as_artist"] = config.Boolean()
return schema
def setup(self, registry):
from .backend import SomaFMBackend
registry.add("backend", SomaFMBackend)
Mopidy-SomaFM-2.0.0rc1/mopidy_somafm/backend.py 0000644 0001750 0001751 00000005341 13571702147 023247 0 ustar alexandre alexandre 0000000 0000000 import logging
import mopidy_somafm
import pykka
from mopidy import backend
from mopidy.models import Album, Artist, Image, Ref, Track
from .somafm import SomaFMClient
logger = logging.getLogger(__name__)
class SomaFMBackend(pykka.ThreadingActor, backend.Backend):
def __init__(self, config, audio):
super().__init__()
self.somafm = SomaFMClient(
config["proxy"],
"{}/{}".format(
mopidy_somafm.Extension.dist_name, mopidy_somafm.__version__
),
)
self.library = SomaFMLibraryProvider(backend=self)
self.uri_schemes = ["somafm"]
self.quality = config["somafm"]["quality"]
self.encoding = config["somafm"]["encoding"]
self.dj_as_artist = config["somafm"]["dj_as_artist"]
def on_start(self):
self.somafm.refresh(self.encoding, self.quality)
class SomaFMLibraryProvider(backend.LibraryProvider):
root_directory = Ref.directory(uri="somafm:root", name="SomaFM")
def lookup(self, uri):
# Whatever the uri, it will always contains one track
# which is a url to a pls
if not uri.startswith("somafm:"):
return None
channel_name = uri[uri.index("/") + 1 :]
channel_data = self.backend.somafm.channels[channel_name]
# Artists
if self.backend.dj_as_artist:
artist = Artist(name=channel_data["dj"])
else:
artist = Artist()
# Build album (idem as playlist, but with more metada)
album = Album(
artists=[artist],
name=channel_data["title"],
uri="somafm:channel:/%s" % (channel_name),
)
track = Track(
artists=[artist],
album=album,
last_modified=channel_data["updated"],
comment=channel_data["description"],
genre=channel_data["genre"],
name=channel_data["title"],
uri=channel_data["pls"],
)
return [track]
def browse(self, uri):
if uri != "somafm:root":
return []
result = []
for channel in self.backend.somafm.channels:
result.append(
Ref.track(
uri="somafm:channel:/%s" % (channel),
name=self.backend.somafm.channels[channel]["title"],
)
)
result.sort(key=lambda ref: ref.name.lower())
return result
def get_images(self, uris):
images = []
for uri in uris:
if uri.startswith("somafm:"):
channel_name = uri[uri.index("/") + 1 :]
image = Image(uri=self.backend.somafm.images[channel_name])
images.append(image)
return images
Mopidy-SomaFM-2.0.0rc1/mopidy_somafm/ext.conf 0000644 0001750 0001751 00000000112 13571140522 022735 0 ustar alexandre alexandre 0000000 0000000 [somafm]
enabled = true
encoding = mp3
quality = fast
dj_as_artist = true
Mopidy-SomaFM-2.0.0rc1/mopidy_somafm/somafm.py 0000644 0001750 0001751 00000012052 13571702147 023137 0 ustar alexandre alexandre 0000000 0000000 import collections
import logging
import re
from urllib.parse import urlsplit
import requests
from mopidy import httpclient
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
logger = logging.getLogger(__name__)
#
# Channels are playlist and Album
# PLS are tracks
# PLS contents for internal use
#
class SomaFMClient:
CHANNELS_URI = "https://api.somafm.com/channels.xml"
# All channels seem to have this combination of quality/encoding available
FALLBACK_QUALITY = "fast"
FALLBACK_ENCODING = "mp3"
channels = {}
images = {}
def __init__(self, proxy_config=None, user_agent=None):
super().__init__()
# Build requests session
self.session = requests.Session()
if proxy_config is not None:
proxy = httpclient.format_proxy(proxy_config)
self.session.proxies.update({"http": proxy, "https": proxy})
full_user_agent = httpclient.format_user_agent(user_agent)
self.session.headers.update({"user-agent": full_user_agent})
def refresh(self, encoding, quality):
# clean previous data
self.channels = {}
# download channels xml file
channels_content = self._downloadContent(self.CHANNELS_URI)
if channels_content is None:
logger.error("Cannot fetch %s" % (self.CHANNELS_URI))
return
# parse XML
root = ET.fromstring(channels_content)
for child_channel in root:
pls_id = child_channel.attrib["id"]
channel_data = {}
channel_all_pls = collections.defaultdict(dict)
for child_detail in child_channel:
key = child_detail.tag
val = child_detail.text
if key in ["title", "image", "dj", "genre", "description"]:
channel_data[key] = val
elif key == "updated":
channel_data["updated"] = int(val)
elif "pls" in key:
pls_quality = key[:-3]
pls_format = child_detail.attrib["format"]
channel_all_pls[pls_quality][pls_format] = val
# firewall playlist are fastpls+mp3 but with fw path
if pls_quality == "fast" and pls_format == "mp3":
r1 = urlsplit(val)
channel_all_pls["firewall"][
"mp3"
] = "{}://{}/{}".format(
r1.scheme, r1.netloc, "fw" + r1.path
)
channel_pls = self._choose_pls(channel_all_pls, encoding, quality)
if channel_pls is not None:
channel_data["pls"] = channel_pls
self.channels[pls_id] = channel_data
self.images[pls_id] = channel_data["image"]
logger.info("Loaded %i SomaFM channels" % (len(self.channels)))
def extractStreamUrlFromPls(self, pls_uri):
pls_content = self._downloadContent(pls_uri)
if pls_content is None:
logger.error("Cannot fetch %s" % (pls_uri))
return pls_uri
# try to find FileX=
try:
m = re.search(r"^(File\d)=(?P\S+)", pls_content, re.M)
if m:
return m.group("stream_url")
else:
return pls_uri
except BaseException:
return pls_uri
def _choose_pls(self, all_pls, encoding, quality):
if not all_pls:
return None
if quality in all_pls:
quality_pls = all_pls[quality]
elif self.FALLBACK_QUALITY in all_pls:
quality_pls = all_pls[self.FALLBACK_QUALITY]
else:
quality_pls = all_pls[next(iter(all_pls))]
if not quality_pls:
return None
if encoding in quality_pls:
pls = quality_pls[encoding]
elif self.FALLBACK_ENCODING in all_pls:
pls = quality_pls[self.FALLBACK_ENCODING]
else:
pls = quality_pls[next(iter(quality_pls))]
return pls
def _downloadContent(self, url):
try:
r = self.session.get(url)
logger.debug("Get %s : %i", url, r.status_code)
if r.status_code != 200:
logger.error(
"SomaFM: %s is not reachable [http code:%i]",
url,
r.status_code,
)
return None
except requests.exceptions.RequestException as e:
logger.error("SomaFM RequestException: %s", e)
except requests.exceptions.ConnectionError as e:
logger.error("SomaFM ConnectionError: %s", e)
except requests.exceptions.URLRequired as e:
logger.error("SomaFM URLRequired: %s", e)
except requests.exceptions.TooManyRedirects as e:
logger.error("SomaFM TooManyRedirects: %s", e)
except Exception as e:
logger.error("SomaFM exception: %s", e)
else:
return r.text
return None
Mopidy-SomaFM-2.0.0rc1/pyproject.toml 0000644 0001750 0001751 00000000526 13571702147 021357 0 ustar alexandre alexandre 0000000 0000000 [build-system]
requires = ["setuptools >= 30.3.0", "wheel"]
[tool.black]
target-version = ["py37", "py38"]
line-length = 80
[tool.isort]
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
line_length = 88
known_tests = "tests"
sections = "FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,TESTS,LOCALFOLDER"
Mopidy-SomaFM-2.0.0rc1/setup.cfg 0000644 0001750 0001751 00000002657 13571702175 020274 0 ustar alexandre alexandre 0000000 0000000 [metadata]
name = Mopidy-SomaFM
version = 2.0.0rc1
url = https://github.com/AlexandrePTJ/mopidy-somafm
author = Alexandre Petitjean
author_email = alpetitjean@gmail.com
license = Apache License, Version 2.0
license_file = LICENSE
description = SomaFM extension for Mopidy
long_description = file: README.rst
classifiers =
Environment :: No Input/Output (Daemon)
Intended Audience :: End Users/Desktop
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Topic :: Multimedia :: Sound/Audio :: Players
[options]
zip_safe = False
include_package_data = True
packages = find:
python_requires = >= 3.7
install_requires =
Mopidy >= 3.0.0a4 # Change to >= 3.0 once final is released
Pykka >= 2.0.1
requests >= 2.0.0
setuptools
[options.extras_require]
lint =
black
check-manifest
flake8
flake8-bugbear
flake8-import-order
isort[pyproject]
release =
twine
wheel
test =
pytest
pytest-cov
dev =
%(lint)s
%(release)s
%(test)s
[options.packages.find]
exclude =
tests
tests.*
[options.entry_points]
mopidy.ext =
somafm = mopidy_somafm:Extension
[flake8]
application-import-names = mopidy_somafm, tests
max-line-length = 80
exclude = .git, .tox, build
select =
C, E, F, W
B
B950
N
ignore =
E203
E501
W503
B305
[wheel]
universal = 1
[egg_info]
tag_build =
tag_date = 0
Mopidy-SomaFM-2.0.0rc1/setup.py 0000644 0001750 0001751 00000000046 13571702147 020152 0 ustar alexandre alexandre 0000000 0000000 from setuptools import setup
setup()
Mopidy-SomaFM-2.0.0rc1/tests/ 0000755 0001750 0001751 00000000000 13571702175 017603 5 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/tests/__init__.py 0000644 0001750 0001751 00000000000 13571140522 021672 0 ustar alexandre alexandre 0000000 0000000 Mopidy-SomaFM-2.0.0rc1/tests/test_extension.py 0000644 0001750 0001751 00000000545 13571702147 023233 0 ustar alexandre alexandre 0000000 0000000 from mopidy_somafm import Extension
def test_get_default_config():
ext = Extension()
config = ext.get_default_config()
assert "[somafm]" in config
assert "enabled = true" in config
def test_get_config_schema():
ext = Extension()
schema = ext.get_config_schema()
assert "quality" in schema
assert "encoding" in schema
Mopidy-SomaFM-2.0.0rc1/tests/test_somafm.py 0000644 0001750 0001751 00000002655 13571702147 022505 0 ustar alexandre alexandre 0000000 0000000 import unittest
from mopidy_somafm.somafm import SomaFMClient
class SomaFMClientTest(unittest.TestCase):
def test_refresh(self):
sfmc = SomaFMClient()
sfmc.refresh("mp3", "fast")
self.assertIsNotNone(sfmc.channels)
self.assertNotEqual(len(sfmc.channels), 0)
def test_refresh_firewall(self):
sfmc = SomaFMClient()
sfmc.refresh("mp3", "firewall")
self.assertIsNotNone(sfmc.channels)
self.assertNotEqual(len(sfmc.channels), 0)
def test_refresh_no_channels(self):
sfmc = SomaFMClient()
sfmc.CHANNELS_URI = ""
sfmc.refresh("mp3", "fast")
self.assertDictEqual(sfmc.channels, {})
self.assertEqual(len(sfmc.channels), 0)
def test_downloadContent(self):
url = "http://api.somafm.com/channels.xml"
sfmc = SomaFMClient()
data = sfmc._downloadContent(url)
self.assertNotEqual(len(data), 0)
def test_extractStreamUrlFromPls(self):
url = "http://somafm.com/groovesalad.pls"
sfmc = SomaFMClient()
data = sfmc.extractStreamUrlFromPls(url)
self.assertNotEqual(len(data), 0)
self.assertNotEqual(data, url)
def test_extractStreamUrlFromPls_unknown(self):
url = "http://somafm.com/noneazerty.pls"
sfmc = SomaFMClient()
data = sfmc.extractStreamUrlFromPls(url)
self.assertNotEqual(len(data), 0)
self.assertEqual(data, url)
Mopidy-SomaFM-2.0.0rc1/tox.ini 0000644 0001750 0001751 00000000737 13571702147 017762 0 ustar alexandre alexandre 0000000 0000000 [tox]
envlist = py37, py38, black, check-manifest, flake8
[testenv]
sitepackages = true
deps = .[test]
commands =
python -m pytest \
--basetemp={envtmpdir} \
--cov=mopidy_somafm --cov-report=term-missing \
{posargs}
[testenv:black]
deps = .[lint]
commands = python -m black --check .
[testenv:check-manifest]
deps = .[lint]
commands = python -m check_manifest
[testenv:flake8]
deps = .[lint]
commands = python -m flake8 --show-source --statistics