Initial commit
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*.egg-info
|
||||
*.pyc
|
||||
*.swp
|
||||
.cache/
|
||||
.coverage
|
||||
.tox/
|
||||
MANIFEST
|
||||
build/
|
||||
dist/
|
||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.14 (/usr/bin/python2.7)" project-jdk-type="Python SDK" />
|
||||
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||
<option name="version" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/mopidy-radionet.iml" filepath="$PROJECT_DIR$/.idea/mopidy-radionet.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
11
.idea/mopidy-radionet.iml
generated
Normal file
11
.idea/mopidy-radionet.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 2.7.14 (/usr/bin/python2.7)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
740
.idea/workspace.xml
generated
Normal file
740
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,740 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="a827305c-f450-4dd8-9234-28c4c187e3c8" name="Default" comment="">
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.gitignore" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/misc.xml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/modules.xml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/mopidy-radionet.iml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/vcs.xml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.travis.yml" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/LICENSE" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/MANIFEST.in" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/README.rst" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/mopidy_radionet/__init__.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/mopidy_radionet/backend.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/mopidy_radionet/ext.conf" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/mopidy_radionet/library.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/mopidy_radionet/radionet.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/setup.cfg" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/setup.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/tests/__init__.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/tests/test_extension.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/tests/test_radionet.py" />
|
||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/tox.ini" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FavoritesManager">
|
||||
<favorites_list name="mopidy-radionet" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||
<file leaf-file-name="library.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/library.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1395">
|
||||
<caret line="93" column="0" lean-forward="false" selection-start-line="93" selection-start-column="0" selection-end-line="93" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="__init__.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="backend.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/backend.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="330">
|
||||
<caret line="22" column="39" lean-forward="false" selection-start-line="22" selection-start-column="39" selection-end-line="22" selection-end-column="39" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="ext.conf" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/ext.conf">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="test_extension.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_extension.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="0" lean-forward="false" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="dependency_links.txt" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/Mopidy_RadioNet.egg-info/dependency_links.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="15">
|
||||
<caret line="1" column="0" lean-forward="false" selection-start-line="1" selection-start-column="0" selection-end-line="1" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="setup.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/setup.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="182">
|
||||
<caret line="24" column="30" lean-forward="true" selection-start-line="24" selection-start-column="30" selection-end-line="24" selection-end-column="30" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="radionet.py" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-4108">
|
||||
<caret line="13" column="36" lean-forward="true" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="36" />
|
||||
<folding>
|
||||
<element signature="e#48#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Python Script" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>channel</find>
|
||||
<find>fav_stations</find>
|
||||
<find>RadioNetClient</find>
|
||||
<find>bitrate</find>
|
||||
<find>get_sta</find>
|
||||
<find>get_top</find>
|
||||
</findStrings>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/radionetclient.py" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/listener.py" />
|
||||
<option value="/Buildout config Fragment (backend.py:827).cfg" />
|
||||
<option value="$PROJECT_DIR$/tests/test_radionet.py" />
|
||||
<option value="$PROJECT_DIR$/adhoctest.py" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/ext.conf" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/backend.py" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/__init__.py" />
|
||||
<option value="$PROJECT_DIR$/tests/test_extension.py" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/library.py" />
|
||||
<option value="$PROJECT_DIR$/.gitignore" />
|
||||
<option value="$PROJECT_DIR$/README.rst" />
|
||||
<option value="$PROJECT_DIR$/mopidy_radionet/radionet.py" />
|
||||
<option value="$PROJECT_DIR$/setup.py" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="169" />
|
||||
<option name="y" value="133" />
|
||||
<option name="width" value="1016" />
|
||||
<option name="height" value="605" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
<manualOrder />
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope" />
|
||||
<pane id="Scratches" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="mopidy-radionet" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="mopidy-radionet" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="mopidy-radionet" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="mopidy-radionet" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="mopidy_radionet" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="mopidy-radionet" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="mopidy-radionet" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="Mopidy_RadioNet.egg-info" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="mopidy-radionet" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="mopidy-radionet" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="tests" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
|
||||
<property name="last.edited.regexp" value="Sample Text" />
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.adhoctest">
|
||||
<configuration name="adhoctest" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<module name="mopidy-radionet" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/adhoctest.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
</configuration>
|
||||
<configuration name="test_extension" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<module name="mopidy-radionet" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/test_extension.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
</configuration>
|
||||
<configuration name="test_radionet" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<module name="mopidy-radionet" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/test_radionet.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
</configuration>
|
||||
<list size="3">
|
||||
<item index="0" class="java.lang.String" itemvalue="Python.test_extension" />
|
||||
<item index="1" class="java.lang.String" itemvalue="Python.test_radionet" />
|
||||
<item index="2" class="java.lang.String" itemvalue="Python.adhoctest" />
|
||||
</list>
|
||||
<recent_temporary>
|
||||
<list size="3">
|
||||
<item index="0" class="java.lang.String" itemvalue="Python.adhoctest" />
|
||||
<item index="1" class="java.lang.String" itemvalue="Python.test_radionet" />
|
||||
<item index="2" class="java.lang.String" itemvalue="Python.test_extension" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="ShelveChangesManager" show_recycled="false">
|
||||
<option name="remove_strategy" value="false" />
|
||||
</component>
|
||||
<component name="StructureViewFactory">
|
||||
<option name="ACTIVE_ACTIONS" value=",ALPHA_COMPARATOR" />
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="a827305c-f450-4dd8-9234-28c4c187e3c8" name="Default" comment="" />
|
||||
<created>1513805306740</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1513805306740</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TodoView">
|
||||
<todo-panel id="selected-file">
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
<todo-panel id="all">
|
||||
<are-packages-shown value="true" />
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="169" y="133" width="1366" height="739" extended-state="6" />
|
||||
<layout>
|
||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24963397" sideWeight="0.4944" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3296" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3296" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="true" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4672" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" x="0" y="367" width="1366" height="292" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24963397" sideWeight="0.4944" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3987034" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24963397" sideWeight="0.5056" order="2" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.328" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
</layout>
|
||||
<layout-to-restore>
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3296" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3296" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="true" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4672" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" x="0" y="367" width="1366" height="292" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24963397" sideWeight="0.4944" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.328" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24963397" sideWeight="0.4944" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3987034" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24963397" sideWeight="0.5056" order="2" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
</layout-to-restore>
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<option name="time" value="7" />
|
||||
</breakpoint-manager>
|
||||
<watches-manager />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/library.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="660">
|
||||
<caret line="48" column="19" lean-forward="false" selection-start-line="48" selection-start-column="19" selection-end-line="48" selection-end-column="19" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/backend.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="525">
|
||||
<caret line="41" column="41" lean-forward="false" selection-start-line="41" selection-start-column="41" selection-end-line="41" selection-end-column="41" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="120">
|
||||
<caret line="13" column="0" lean-forward="false" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/ext.conf">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="6" column="0" lean-forward="true" selection-start-line="0" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_extension.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="210">
|
||||
<caret line="15" column="0" lean-forward="false" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="855">
|
||||
<caret line="64" column="25" lean-forward="true" selection-start-line="64" selection-start-column="25" selection-end-line="64" selection-end-column="25" />
|
||||
<folding>
|
||||
<element signature="e#48#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/.gitignore">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="135">
|
||||
<caret line="9" column="0" lean-forward="false" selection-start-line="9" selection-start-column="0" selection-end-line="9" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.rst">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="645">
|
||||
<caret line="43" column="0" lean-forward="true" selection-start-line="43" selection-start-column="0" selection-end-line="43" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/library.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="645">
|
||||
<caret line="47" column="19" lean-forward="false" selection-start-line="47" selection-start-column="19" selection-end-line="47" selection-end-column="19" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/backend.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="525">
|
||||
<caret line="41" column="41" lean-forward="true" selection-start-line="41" selection-start-column="41" selection-end-line="41" selection-end-column="41" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/ext.conf">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="16" lean-forward="true" selection-start-line="5" selection-start-column="16" selection-end-line="5" selection-end-column="16" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="120">
|
||||
<caret line="13" column="0" lean-forward="true" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_extension.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="1" column="37" lean-forward="true" selection-start-line="1" selection-start-column="37" selection-end-line="1" selection-end-column="37" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/.gitignore">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="150">
|
||||
<caret line="10" column="0" lean-forward="true" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="540">
|
||||
<caret line="38" column="52" lean-forward="false" selection-start-line="38" selection-start-column="52" selection-end-line="38" selection-end-column="52" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2805">
|
||||
<caret line="194" column="21" lean-forward="true" selection-start-line="194" selection-start-column="21" selection-end-line="194" selection-end-column="35" />
|
||||
<folding>
|
||||
<element signature="e#48#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/library.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="342">
|
||||
<caret line="24" column="32" lean-forward="false" selection-start-line="24" selection-start-column="32" selection-end-line="24" selection-end-column="32" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_extension.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="234">
|
||||
<caret line="15" column="21" lean-forward="false" selection-start-line="15" selection-start-column="21" selection-end-line="15" selection-end-column="21" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1728">
|
||||
<caret line="103" column="60" lean-forward="false" selection-start-line="103" selection-start-column="60" selection-end-line="103" selection-end-column="60" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="558">
|
||||
<caret line="33" column="59" lean-forward="false" selection-start-line="33" selection-start-column="59" selection-end-line="33" selection-end-column="59" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file:///usr/lib/python2.7/site-packages/requests/utils.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="121">
|
||||
<caret line="740" column="0" lean-forward="false" selection-start-line="740" selection-start-column="0" selection-end-line="740" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file:///usr/lib/python2.7/site-packages/requests/sessions.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="103">
|
||||
<caret line="554" column="0" lean-forward="false" selection-start-line="554" selection-start-column="0" selection-end-line="554" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file:///usr/lib/python2.7/unittest/suite.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="229">
|
||||
<caret line="118" column="39" lean-forward="false" selection-start-line="118" selection-start-column="39" selection-end-line="118" selection-end-column="39" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file:///usr/lib/python2.7/unittest/case.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="103">
|
||||
<caret line="392" column="0" lean-forward="false" selection-start-line="392" selection-start-column="0" selection-end-line="392" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/listener.py" />
|
||||
<entry file="file://$PROJECT_DIR$/LICENSE">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/MANIFEST.in">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/setup.cfg">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/.travis.yml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="20" column="0" lean-forward="false" selection-start-line="20" selection-start-column="0" selection-end-line="20" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tox.ini">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-239">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/adhoctest.py" />
|
||||
<entry file="file://$PROJECT_DIR$/.gitignore">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="135">
|
||||
<caret line="9" column="0" lean-forward="false" selection-start-line="9" selection-start-column="0" selection-end-line="9" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="105">
|
||||
<caret line="9" column="0" lean-forward="true" selection-start-line="9" selection-start-column="0" selection-end-line="9" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.rst">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="197">
|
||||
<caret line="47" column="36" lean-forward="true" selection-start-line="47" selection-start-column="36" selection-end-line="47" selection-end-column="36" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/library.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1395">
|
||||
<caret line="93" column="0" lean-forward="false" selection-start-line="93" selection-start-column="0" selection-end-line="93" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/backend.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="330">
|
||||
<caret line="22" column="39" lean-forward="false" selection-start-line="22" selection-start-column="39" selection-end-line="22" selection-end-column="39" />
|
||||
<folding>
|
||||
<element signature="e#0#12#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/ext.conf">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="90">
|
||||
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/test_extension.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="0" lean-forward="false" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#39#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/Mopidy_RadioNet.egg-info/dependency_links.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="15">
|
||||
<caret line="1" column="0" lean-forward="false" selection-start-line="1" selection-start-column="0" selection-end-line="1" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/setup.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="182">
|
||||
<caret line="24" column="30" lean-forward="true" selection-start-line="24" selection-start-column="30" selection-end-line="24" selection-end-column="30" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/mopidy_radionet/radionet.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-4108">
|
||||
<caret line="13" column="36" lean-forward="true" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="36" />
|
||||
<folding>
|
||||
<element signature="e#48#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
||||
28
.travis.yml
Normal file
28
.travis.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
sudo: false
|
||||
|
||||
language: python
|
||||
|
||||
python:
|
||||
- "2.7_with_system_site_packages"
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- mopidy-stable
|
||||
packages:
|
||||
- mopidy
|
||||
|
||||
env:
|
||||
- TOX_ENV=py27
|
||||
- TOX_ENV=flake8
|
||||
|
||||
install:
|
||||
- "pip install tox"
|
||||
|
||||
script:
|
||||
- "tox -e $TOX_ENV"
|
||||
|
||||
after_success:
|
||||
- "if [ $TOX_ENV == 'py27' ]; then pip install coveralls; coveralls; fi"
|
||||
|
||||
|
||||
202
LICENSE
Normal file
202
LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
@@ -0,0 +1,8 @@
|
||||
include .travis.yml
|
||||
include LICENSE
|
||||
include MANIFEST.in
|
||||
include README.rst
|
||||
include mopidy_radionet/ext.conf
|
||||
include tox.ini
|
||||
|
||||
recursive-include tests *.py
|
||||
66
README.rst
Normal file
66
README.rst
Normal file
@@ -0,0 +1,66 @@
|
||||
****************************
|
||||
Mopidy-RadioNet
|
||||
****************************
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/Mopidy-RadioNet.svg?style=flat
|
||||
:target: https://pypi.python.org/pypi/Mopidy-RadioNet/
|
||||
:alt: Latest PyPI version
|
||||
|
||||
.. image:: https://img.shields.io/travis/blakberrymamba/mopidy-radionet/master.svg?style=flat
|
||||
:target: https://travis-ci.org/blakberrymamba/mopidy-radionet
|
||||
:alt: Travis CI build status
|
||||
|
||||
.. image:: https://img.shields.io/coveralls/blakberrymamba/mopidy-radionet/master.svg?style=flat
|
||||
:target: https://coveralls.io/r/blakberrymamba/mopidy-radionet
|
||||
:alt: Test coverage
|
||||
|
||||
Mopidy extension for radio.net
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Install by running::
|
||||
|
||||
pip install Mopidy-RadioNet
|
||||
|
||||
Or, if available, install the Debian/Ubuntu package from `apt.mopidy.com
|
||||
<http://apt.mopidy.com/>`_.
|
||||
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Before starting Mopidy, you must add configuration for
|
||||
Mopidy-RadioNet to your Mopidy configuration file::
|
||||
|
||||
[radionet]
|
||||
enabled = true
|
||||
username = alice666.9
|
||||
password = secret
|
||||
language = pl # or net, de, at, fr, pt, es, dk, se, it
|
||||
min_bitrate = 96
|
||||
|
||||
|
||||
Project resources
|
||||
=================
|
||||
|
||||
- `Source code <https://github.com/blakberrymamba/mopidy-radionet>`_
|
||||
- `Issue tracker <https://github.com/blakberrymamba/mopidy-radionet/issues>`_
|
||||
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
- Original author: `blakberrymamba <https://github.com/blakberrymamba`__
|
||||
- Current maintainer: `blakberrymamba <https://github.com/blakberrymamba`__
|
||||
- `Contributors <https://github.com/blakberrymamba/mopidy-radionet/graphs/contributors>`_
|
||||
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.1.0 (UNRELEASED)
|
||||
----------------------------------------
|
||||
|
||||
- Initial release.
|
||||
36
mopidy_radionet/__init__.py
Normal file
36
mopidy_radionet/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from mopidy import config, ext
|
||||
|
||||
|
||||
__version__ = '0.1.0'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Extension(ext.Extension):
|
||||
|
||||
dist_name = 'Mopidy-RadioNet'
|
||||
ext_name = 'radionet'
|
||||
version = __version__
|
||||
|
||||
def get_default_config(self):
|
||||
conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
|
||||
return config.read(conf_file)
|
||||
|
||||
def get_config_schema(self):
|
||||
schema = super(Extension, self).get_config_schema()
|
||||
schema['username'] = config.String()
|
||||
schema['password'] = config.Secret()
|
||||
schema['language'] = config.String()
|
||||
schema['min_bitrate'] = config.String()
|
||||
return schema
|
||||
|
||||
def setup(self, registry):
|
||||
from .backend import RadioNetBackend
|
||||
registry.add('backend', RadioNetBackend)
|
||||
|
||||
46
mopidy_radionet/backend.py
Normal file
46
mopidy_radionet/backend.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import pykka
|
||||
import time
|
||||
|
||||
from mopidy import backend
|
||||
import mopidy_radionet
|
||||
from .library import RadioNetLibraryProvider
|
||||
from .radionet import RadioNetClient
|
||||
|
||||
|
||||
class RadioNetBackend(pykka.ThreadingActor, backend.Backend):
|
||||
update_timeout = None
|
||||
|
||||
def __init__(self, config, audio):
|
||||
super(RadioNetBackend, self).__init__()
|
||||
self.radionet = RadioNetClient(
|
||||
config['proxy'],
|
||||
"%s/%s" % (
|
||||
mopidy_radionet.Extension.dist_name,
|
||||
mopidy_radionet.__version__))
|
||||
|
||||
self.library = RadioNetLibraryProvider(backend=self)
|
||||
|
||||
self.uri_schemes = ['radionet']
|
||||
self.username = config['radionet']['username']
|
||||
self.password = config['radionet']['password']
|
||||
|
||||
self.radionet.min_bitrate = int(config['radionet']['min_bitrate'])
|
||||
self.radionet.set_lang(str(config['radionet']['language']))
|
||||
|
||||
def set_update_timeout(self, minutes=2):
|
||||
self.update_timeout = time.time() + 60 * minutes
|
||||
|
||||
def on_start(self):
|
||||
self.set_update_timeout(0)
|
||||
|
||||
def refresh(self, force=False):
|
||||
if self.update_timeout is None:
|
||||
self.set_update_timeout()
|
||||
|
||||
if force or time.time() > self.update_timeout:
|
||||
self.radionet.login(self.username, self.password)
|
||||
self.radionet.get_bookmarks()
|
||||
self.radionet.get_my_stations_streams()
|
||||
self.radionet.get_top_stations()
|
||||
self.radionet.get_local_stations()
|
||||
self.set_update_timeout()
|
||||
6
mopidy_radionet/ext.conf
Normal file
6
mopidy_radionet/ext.conf
Normal file
@@ -0,0 +1,6 @@
|
||||
[radionet]
|
||||
enabled = true
|
||||
username = alice666.9
|
||||
password = secret
|
||||
language = pl
|
||||
min_bitrate = 96
|
||||
116
mopidy_radionet/library.py
Normal file
116
mopidy_radionet/library.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import pykka
|
||||
import logging
|
||||
import re
|
||||
from mopidy import backend
|
||||
from mopidy.models import Album, Artist, Ref, Track, SearchResult
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RadioNetLibraryProvider(backend.LibraryProvider):
|
||||
root_directory = Ref.directory(uri='radionet:root', name='Radio.net')
|
||||
|
||||
def lookup(self, uri):
|
||||
|
||||
if not uri.startswith('radionet:'):
|
||||
return None
|
||||
|
||||
variant, identifier = self.parse_uri(uri)
|
||||
|
||||
if variant == 'station':
|
||||
identifier = int(identifier)
|
||||
radio_data = self.backend.radionet.get_station_by_id(identifier)
|
||||
|
||||
artist = Artist(name=radio_data.name)
|
||||
|
||||
album = Album(
|
||||
artists=[artist],
|
||||
images=[radio_data.image],
|
||||
name=radio_data.description + " / " + radio_data.continent +
|
||||
" / " +
|
||||
radio_data.country + " - " + radio_data.city,
|
||||
uri='radionet:station:%s' % (identifier))
|
||||
|
||||
track = Track(
|
||||
artists=[artist],
|
||||
album=album,
|
||||
name=radio_data.name,
|
||||
genre=radio_data.genres,
|
||||
comment=radio_data.description,
|
||||
uri=radio_data.stream_url)
|
||||
|
||||
return [track]
|
||||
|
||||
return []
|
||||
|
||||
def browse(self, uri):
|
||||
self.backend.refresh()
|
||||
|
||||
directories = []
|
||||
tracks = []
|
||||
variant, identifier = self.parse_uri(uri)
|
||||
if variant == 'root':
|
||||
if self.backend.radionet.fav_stations:
|
||||
directories.append(
|
||||
self.ref_directory(
|
||||
"radionet:category:favstations", "My stations")
|
||||
)
|
||||
if self.backend.radionet.local_stations:
|
||||
directories.append(
|
||||
self.ref_directory(
|
||||
"radionet:category:localstations", "Local stations")
|
||||
)
|
||||
if self.backend.radionet.top_stations:
|
||||
directories.append(
|
||||
self.ref_directory(
|
||||
"radionet:category:top100", "Top 100")
|
||||
)
|
||||
elif variant == 'category' and identifier:
|
||||
if identifier == "favstations":
|
||||
for station in self.backend.radionet.fav_stations:
|
||||
tracks.append(self.station_to_ref(station))
|
||||
if identifier == "localstations":
|
||||
for station in self.backend.radionet.local_stations:
|
||||
tracks.append(self.station_to_ref(station))
|
||||
if identifier == "top100":
|
||||
for station in self.backend.radionet.top_stations:
|
||||
tracks.append(self.station_to_ref(station))
|
||||
else:
|
||||
logger.debug('Unknown URI: %s', uri)
|
||||
return []
|
||||
|
||||
tracks.sort(key=lambda ref: ref.name)
|
||||
|
||||
return directories + tracks
|
||||
|
||||
def search(self, query=None, uris=None, exact=False):
|
||||
|
||||
result = []
|
||||
|
||||
self.backend.radionet.do_search(' '.join(query['any']))
|
||||
|
||||
for station in self.backend.radionet.search_results:
|
||||
result.append(self.station_to_track(station))
|
||||
|
||||
return SearchResult(
|
||||
tracks=result
|
||||
)
|
||||
|
||||
def station_to_ref(self, station):
|
||||
return Ref.track(
|
||||
uri='radionet:station:%s' % (station.id),
|
||||
name=station.name,
|
||||
)
|
||||
|
||||
def station_to_track(self, station):
|
||||
ref = self.station_to_ref(station)
|
||||
return Track(uri=ref.uri, name=ref.name)
|
||||
|
||||
def ref_directory(self, uri, name):
|
||||
return Ref.directory(uri=uri, name=name)
|
||||
|
||||
def parse_uri(self, uri):
|
||||
result = re.findall(r'^radionet:([a-z]+):?([a-z0-9]+|\d+)?$', uri)
|
||||
if result:
|
||||
return result[0]
|
||||
return None, None
|
||||
320
mopidy_radionet/radionet.py
Normal file
320
mopidy_radionet/radionet.py
Normal file
@@ -0,0 +1,320 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import requests
|
||||
import re
|
||||
import time
|
||||
|
||||
from mopidy import httpclient
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Station(object):
|
||||
id = None
|
||||
continent = None
|
||||
country = None
|
||||
city = None
|
||||
genres = None
|
||||
name = None
|
||||
stream_url = None
|
||||
image = None
|
||||
description = None
|
||||
playable = False
|
||||
|
||||
|
||||
class RadioNetClient(object):
|
||||
|
||||
base_url = 'https://radio.net/'
|
||||
api_base_url = 'https://api.radio.net/info/v2/'
|
||||
|
||||
session = requests.Session()
|
||||
api_key = None
|
||||
user_login = None
|
||||
min_bitrate = 96
|
||||
max_top_stations = 100
|
||||
station_bookmarks = None
|
||||
|
||||
fav_stations = []
|
||||
top_stations = []
|
||||
local_stations = []
|
||||
search_results = []
|
||||
|
||||
username = None
|
||||
password = None
|
||||
|
||||
def __init__(self, proxy_config=None, user_agent=None):
|
||||
super(RadioNetClient, self).__init__()
|
||||
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})
|
||||
self.session.headers.update({'cache-control': 'no-cache'})
|
||||
|
||||
self.get_api_key()
|
||||
|
||||
def set_lang(self, lang):
|
||||
langs = ['net', 'de', 'at', 'fr', 'pt', 'es', 'dk', 'se', 'it', 'pl']
|
||||
if lang in langs:
|
||||
self.base_url = self.base_url.replace(".net", "." + lang)
|
||||
self.api_base_url = self.api_base_url.replace(".net", "." + lang)
|
||||
else:
|
||||
logging.error("Radio.net not supported language: " - str(lang))
|
||||
|
||||
def flush(self):
|
||||
self.fav_stations = []
|
||||
self.top_stations = []
|
||||
self.local_stations = []
|
||||
self.search_results = []
|
||||
|
||||
def current_milli_time(self):
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
def get_api_key(self):
|
||||
tmp_str = self.session.get(self.base_url)
|
||||
m = re.search('apiKey ?= ?[\'|"](.*)[\'|"];', tmp_str.content)
|
||||
self.api_key = m.group(1).encode()
|
||||
|
||||
def check_auth(self):
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
}
|
||||
logger.debug('Radio.net: Check auth.')
|
||||
api_sufix = 'user/account'
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Auth error.')
|
||||
else:
|
||||
json = response.json()
|
||||
self.user_login = json['login']
|
||||
if len(self.user_login) == 0:
|
||||
self.auth = False
|
||||
else:
|
||||
self.auth = True
|
||||
|
||||
def login(self, username, password):
|
||||
self.check_auth()
|
||||
|
||||
if self.auth:
|
||||
return
|
||||
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
}
|
||||
|
||||
logger.debug('Radio.net: Login.')
|
||||
api_sufix = 'user/login'
|
||||
payload = {
|
||||
'login': username,
|
||||
'password': password,
|
||||
}
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params, data=payload)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Login error. ' + response.text)
|
||||
else:
|
||||
json = response.json()
|
||||
self.user_login = json['login']
|
||||
|
||||
if self.user_login == username:
|
||||
logger.debug('Radio.net: Login successful.')
|
||||
|
||||
def logout(self):
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
}
|
||||
api_sufix = 'user/logout'
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Error logout.')
|
||||
else:
|
||||
json = response.json()
|
||||
if len(json['login']) > 0:
|
||||
logger.error('Radio.net: Error logout.')
|
||||
else:
|
||||
logger.info('Radio.net: Logout successful.')
|
||||
|
||||
self.session.cookies.clear_session_cookies()
|
||||
|
||||
def get_bookmarks(self):
|
||||
self.station_bookmarks = None
|
||||
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
'list': 'STATION',
|
||||
}
|
||||
api_sufix = 'user/bookmarks'
|
||||
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: ' + response.text)
|
||||
else:
|
||||
logger.debug('Radio.net: Done get bookmarks')
|
||||
json = response.json()
|
||||
self.station_bookmarks = json['stationBookmarks']
|
||||
|
||||
def __get_stream_url(self, stream_json, bitrate):
|
||||
stream_url = None
|
||||
|
||||
for stream in stream_json:
|
||||
if int(stream['bitRate']) >= bitrate and \
|
||||
stream['streamStatus'] == 'VALID':
|
||||
stream_url = stream['streamUrl']
|
||||
break
|
||||
|
||||
if stream_url is None and len(stream_json) > 0:
|
||||
stream_url = stream_json[0]['streamUrl']
|
||||
|
||||
return stream_url
|
||||
|
||||
def get_my_stations_streams(self):
|
||||
self.fav_stations = []
|
||||
for station_item in self.station_bookmarks['pageItems']:
|
||||
station = self.get_station_by_id(station_item['id'])
|
||||
if station.playable:
|
||||
self.fav_stations.append(station)
|
||||
|
||||
logger.info('Radio.net: Loaded ' + str(len(self.fav_stations)) +
|
||||
' my stations.')
|
||||
|
||||
def get_station_by_id(self, station_id):
|
||||
|
||||
api_sufix = 'search/station'
|
||||
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
'station': station_id,
|
||||
}
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Error on get station by id ' +
|
||||
str(station_id) + ". Error: " + response.text)
|
||||
return False
|
||||
else:
|
||||
logger.debug('Radio.net: Done get top stations list')
|
||||
json = response.json()
|
||||
|
||||
tmpStation = Station()
|
||||
tmpStation.id = json['id']
|
||||
tmpStation.continent = json['continent']
|
||||
tmpStation.country = json['country']
|
||||
tmpStation.city = json['city']
|
||||
tmpStation.genres = ', '.join(json["genres"])
|
||||
tmpStation.name = json['name']
|
||||
tmpStation.stream_url = self.__get_stream_url(
|
||||
json['streamUrls'], self.min_bitrate)
|
||||
tmpStation.image = json['logo300x300']
|
||||
tmpStation.description = json['shortDescription']
|
||||
if json['playable'] == 'PLAYABLE':
|
||||
tmpStation.playable = True
|
||||
|
||||
return tmpStation
|
||||
|
||||
def get_local_stations(self):
|
||||
api_sufix = 'search/localstations'
|
||||
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
'pageindex': 1,
|
||||
'sizeperpage': 100,
|
||||
}
|
||||
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Get local stations error. ' +
|
||||
response.text)
|
||||
else:
|
||||
logger.debug('Radio.net: Done get local stations list')
|
||||
json = response.json()
|
||||
for match in json['categories'][0]['matches']:
|
||||
station = self.get_station_by_id(match['id'])
|
||||
if station:
|
||||
if station.playable:
|
||||
self.local_stations.append(station)
|
||||
|
||||
logger.info('Radio.net: Loaded ' + str(len(self.local_stations)) +
|
||||
' local stations.')
|
||||
|
||||
def get_top_stations(self):
|
||||
api_sufix = 'search/topstations'
|
||||
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
'pageindex': 1,
|
||||
'sizeperpage': 100,
|
||||
}
|
||||
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Get top stations error. ' + response.text)
|
||||
else:
|
||||
logger.debug('Radio.net: Done get top stations list')
|
||||
json = response.json()
|
||||
for match in json['categories'][0]['matches']:
|
||||
station = self.get_station_by_id(match['id'])
|
||||
if station:
|
||||
if station.playable:
|
||||
self.top_stations.append(station)
|
||||
|
||||
logger.info('Radio.net: Loaded ' + str(len(self.top_stations)) +
|
||||
' top stations.')
|
||||
|
||||
def do_search(self, query_string, page_index=1):
|
||||
if page_index == 1:
|
||||
self.search_results = []
|
||||
|
||||
api_sufix = 'search/stationsonly'
|
||||
url_params = {
|
||||
'apikey': self.api_key,
|
||||
'_': self.current_milli_time(),
|
||||
'query': query_string,
|
||||
'pageindex': page_index,
|
||||
}
|
||||
response = self.session.post(self.api_base_url + api_sufix,
|
||||
params=url_params)
|
||||
|
||||
if response.status_code is not 200:
|
||||
logger.error('Radio.net: Search error ' + response.text)
|
||||
else:
|
||||
logger.debug('Radio.net: Done search')
|
||||
json = response.json()
|
||||
for match in json['categories'][0]['matches']:
|
||||
station = self.get_station_by_id(match['id'])
|
||||
if station and station.playable:
|
||||
self.search_results.append(station)
|
||||
|
||||
number_pages = int(json['numberPages'])
|
||||
if number_pages >= page_index:
|
||||
self.do_search(query_string, page_index + 1)
|
||||
else:
|
||||
logger.info('Radio.net: Found ' +
|
||||
str(len(self.search_results)) + ' stations.')
|
||||
6
setup.cfg
Normal file
6
setup.cfg
Normal file
@@ -0,0 +1,6 @@
|
||||
[flake8]
|
||||
application-import-names = mopidy_radionet,tests
|
||||
exclude = .git,.tox
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
44
setup.py
Normal file
44
setup.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
|
||||
def get_version(filename):
|
||||
with open(filename) as fh:
|
||||
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", fh.read()))
|
||||
return metadata['version']
|
||||
|
||||
|
||||
setup(
|
||||
name='Mopidy-RadioNet',
|
||||
version=get_version('mopidy_radionet/__init__.py'),
|
||||
url='https://github.com/blakberrymamba/mopidy-radionet',
|
||||
license='Apache License, Version 2.0',
|
||||
author='blakberrymamba',
|
||||
author_email='mariusz@typedef.pl',
|
||||
description='Mopidy extension for radio.net',
|
||||
long_description=open('README.rst').read(),
|
||||
packages=find_packages(exclude=['tests', 'tests.*']),
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
'setuptools',
|
||||
'Mopidy >= 1.0',
|
||||
'Pykka >= 1.1',
|
||||
],
|
||||
entry_points={
|
||||
'mopidy.ext': [
|
||||
'radionet = mopidy_radionet:Extension',
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
'Environment :: No Input/Output (Daemon)',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Topic :: Multimedia :: Sound/Audio :: Players',
|
||||
],
|
||||
)
|
||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
24
tests/test_extension.py
Normal file
24
tests/test_extension.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import unicode_literals
|
||||
from mopidy_radionet import Extension
|
||||
|
||||
|
||||
def test_get_default_config():
|
||||
ext = Extension()
|
||||
|
||||
config = ext.get_default_config()
|
||||
|
||||
assert '[radionet]' in config
|
||||
assert 'enabled = true' in config
|
||||
|
||||
|
||||
def test_get_config_schema():
|
||||
ext = Extension()
|
||||
|
||||
schema = ext.get_config_schema()
|
||||
|
||||
assert 'username' in schema
|
||||
assert 'password' in schema
|
||||
assert 'language' in schema
|
||||
assert 'min_bitrate' in schema
|
||||
|
||||
|
||||
57
tests/test_radionet.py
Normal file
57
tests/test_radionet.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import unittest
|
||||
|
||||
from mopidy_radionet.radionet import RadioNetClient
|
||||
|
||||
|
||||
class RadioNetClientTest(unittest.TestCase):
|
||||
|
||||
username = 'alice666.9'
|
||||
password = 'secret'
|
||||
|
||||
def test_get_api_key(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.get_api_key()
|
||||
|
||||
self.assertIsNotNone(radionet.api_key)
|
||||
|
||||
def test_login(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username,self.password)
|
||||
self.assertEqual(radionet.user_login,self.username)
|
||||
|
||||
def test_get_bookmarks(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username, self.password)
|
||||
radionet.get_bookmarks()
|
||||
self.assertIsNotNone(radionet.station_bookmarks)
|
||||
|
||||
def test_get_bookmarks_station_streams(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username, self.password)
|
||||
radionet.get_bookmarks()
|
||||
radionet.get_my_stations_streams()
|
||||
self.assertGreater(len(radionet.fav_stations), 0)
|
||||
|
||||
def test_get_top_stations(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username, self.password)
|
||||
radionet.get_top_stations()
|
||||
self.assertGreater(len(radionet.top_stations), 0)
|
||||
|
||||
def test_get_local_stations(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username, self.password)
|
||||
radionet.get_local_stations()
|
||||
self.assertGreater(len(radionet.local_stations), 0)
|
||||
|
||||
def test_do_search(self):
|
||||
radionet = RadioNetClient()
|
||||
radionet.login(self.username, self.password)
|
||||
radionet.do_search("radio ram")
|
||||
self.assertGreater(len(radionet.search_results), 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
unittest.main()
|
||||
|
||||
|
||||
22
tox.ini
Normal file
22
tox.ini
Normal file
@@ -0,0 +1,22 @@
|
||||
[tox]
|
||||
envlist = py27, flake8
|
||||
|
||||
[testenv]
|
||||
sitepackages = true
|
||||
deps =
|
||||
mock
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-xdist
|
||||
commands =
|
||||
py.test \
|
||||
--basetemp={envtmpdir} \
|
||||
--cov=mopidy_radionet --cov-report=term-missing \
|
||||
{posargs}
|
||||
|
||||
[testenv:flake8]
|
||||
deps =
|
||||
flake8
|
||||
flake8-import-order
|
||||
skip_install = true
|
||||
commands = flake8
|
||||
Reference in New Issue
Block a user