Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • dev-old
  • dev-old-david
  • develop
  • lars-tests
  • master
  • master-old
  • topic/filesystem-fallbacks
  • topic/tank_connection
  • topic/tank_connection_david
  • user/equinox/docker
10 results

Target

Select target project
  • aura/engine
  • hermannschwaerzler/engine
  • sumpfralle/aura-engine
3 results
Select Git revision
  • 122-synchronized-ci
  • feat-use-docker-main-tag
  • fix-aura-sysuser
  • fix-broken-pipe-153
  • fix-docker-release
  • fix-push-latest-with-tag
  • fix-streamchannel-retries
  • gitlab-templates
  • improve-test-coverage-137
  • improve-test-coverage-143
  • main
  • orm-less-scheduling
  • remove-mailer
  • update-changelog-alpha3
  • virtual-timeslots-131
  • 1.0.0-alpha1
  • 1.0.0-alpha2
  • 1.0.0-alpha3
  • 1.0.0-alpha4
  • 1.0.0-alpha5
20 results
Show changes
Commits on Source (3)
Showing
with 2880 additions and 0 deletions
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5.3 (/usr/bin/python3.5)" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/aura.iml" filepath="$PROJECT_DIR$/.idea/aura.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PreferredVcsStorage">
<preferredVcsName>ApexVCS</preferredVcsName>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="c58ca86a-4167-4474-accb-41439a535514" name="Default" comment="">
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/aura.py" afterPath="$PROJECT_DIR$/aura.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/guru.py" afterPath="$PROJECT_DIR$/guru.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/libraries/base/calendar.py" afterPath="$PROJECT_DIR$/libraries/base/calendar.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/libraries/database/broadcasts.py" afterPath="$PROJECT_DIR$/libraries/database/broadcasts.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/communication/zmq/zmqadapter.py" afterPath="$PROJECT_DIR$/modules/communication/zmq/zmqadapter.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/controller/controller.py" afterPath="$PROJECT_DIR$/modules/controller/controller.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/controller/liquidcontroller.py" afterPath="$PROJECT_DIR$/modules/controller/liquidcontroller.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/liquidsoap/simplestmixer.liq" afterPath="$PROJECT_DIR$/modules/liquidsoap/simplestmixer.liq" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/scheduling/models.py" afterPath="$PROJECT_DIR$/modules/scheduling/models.py" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/modules/scheduling/scheduler.py" afterPath="$PROJECT_DIR$/modules/scheduling/scheduler.py" />
</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="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="guru.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/guru.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="252">
<caret line="78" column="46" lean-forward="true" selection-start-line="78" selection-start-column="46" selection-end-line="78" selection-end-column="46" />
<folding>
<element signature="e#20#31#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="__init__.py" pinned="false" current-in-tab="false">
<entry file="file:///usr/local/lib/python3.5/dist-packages/simplejson/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-711">
<caret line="403" column="4" lean-forward="false" selection-start-line="403" selection-start-column="4" selection-end-line="403" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="calendar.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/libraries/base/calendar.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="267">
<caret line="302" column="59" lean-forward="true" selection-start-line="302" selection-start-column="59" selection-end-line="302" selection-end-column="59" />
<folding>
<element signature="e#805#818#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="scheduler.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/modules/scheduling/scheduler.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="184">
<caret line="151" column="31" lean-forward="true" selection-start-line="151" selection-start-column="31" selection-end-line="151" selection-end-column="31" />
<folding>
<element signature="e#1046#1059#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="aura.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/aura.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="227">
<caret line="26" column="53" lean-forward="false" selection-start-line="26" selection-start-column="53" selection-end-line="26" selection-end-column="53" />
<folding>
<element signature="e#0#13#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="broadcasts.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/libraries/database/broadcasts.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="153">
<caret line="54" column="36" lean-forward="true" selection-start-line="54" selection-start-column="36" selection-end-line="54" selection-end-column="36" />
<folding>
<element signature="e#47#79#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="models.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/modules/scheduling/models.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="207">
<caret line="15" column="40" lean-forward="false" selection-start-line="15" selection-start-column="40" selection-end-line="15" selection-end-column="40" />
<folding>
<element signature="e#47#77#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="zmqadapter.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/modules/communication/zmq/zmqadapter.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="252">
<caret line="77" column="53" lean-forward="true" selection-start-line="77" selection-start-column="53" selection-end-line="77" selection-end-column="53" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="statestore.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/libraries/reporting/statestore.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="372">
<caret line="113" column="0" lean-forward="true" selection-start-line="113" selection-start-column="0" selection-end-line="113" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="controller.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/modules/controller/controller.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="354">
<caret line="114" column="38" lean-forward="false" selection-start-line="114" selection-start-column="38" selection-end-line="114" selection-end-column="38" />
<folding>
<element signature="e#43#60#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>class Timeslot</find>
<find>params</find>
<find>war</find>
<find>zmq</find>
<find>sender</find>
<find>fetching</find>
<find>i belie</find>
<find>return message:</find>
<find>Timeslot</find>
<find>client</find>
<find>no time</find>
<find>redis</find>
<find>publish</find>
<find>RedisStateStore</find>
<find>listen</find>
<find>hardcode</find>
<find>fetching</find>
<find>delta</find>
<find>datetime.</find>
<find>timedelta</find>
<find>hardcoded</find>
<find>has_in</find>
<find>hard</find>
<find>got reply</find>
<find>schedule_job</find>
<find>acs</find>
<find>serverz</find>
<find>simplejs</find>
<find>json</find>
<find>.load</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$/README.md" />
<option value="$PROJECT_DIR$/modules/communication/LiquidSoapCommunicator.py" />
<option value="$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapRecorderClient.py" />
<option value="$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapPlayerClient.py" />
<option value="$PROJECT_DIR$/modules/communication/calendar/Calendar.py" />
<option value="$PROJECT_DIR$/modules/communication/calendar/FetchCalendarData.py" />
<option value="$PROJECT_DIR$/libraries/aurabase.py" />
<option value="$PROJECT_DIR$/modules/communication/scheduler/FetchSchedulerData.py" />
<option value="$PROJECT_DIR$/libraries/base/aurabase.py" />
<option value="$PROJECT_DIR$/libraries/reporting/mail.py" />
<option value="$PROJECT_DIR$/libraries/reporting/messenger.py" />
<option value="$PROJECT_DIR$/libraries/reporting/statestore.py" />
<option value="$PROJECT_DIR$/modules/communication/scheduler/scheduler.py" />
<option value="$PROJECT_DIR$/modules/communication/scheduling/scheduler.py" />
<option value="$PROJECT_DIR$/libraries/base/schedulerconfig.py" />
<option value="$PROJECT_DIR$/modules/communication/scheduling/Scheduler.py" />
<option value="$PROJECT_DIR$/modules/scheduling/Scheduler.py" />
<option value="$PROJECT_DIR$/libraries/security/user.py" />
<option value="$PROJECT_DIR$/libraries/security/whitelist.py" />
<option value="$PROJECT_DIR$/modules/liquidsoap/simplestmixer.log" />
<option value="$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapClient.py" />
<option value="$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapCommunicator.py" />
<option value="$PROJECT_DIR$/modules/communication/zmqadapter.py" />
<option value="$PROJECT_DIR$/modules/communication/zmq/zmqclient.py" />
<option value="$PROJECT_DIR$/libraries/base/config.py" />
<option value="$PROJECT_DIR$/libraries/database/database.py" />
<option value="$PROJECT_DIR$/libraries/client/auraclient.py" />
<option value="$PROJECT_DIR$/libraries/database/combadb.py" />
<option value="$PROJECT_DIR$/modules/controller/liquidcontroller.py" />
<option value="$PROJECT_DIR$/modules/communication/zmq/zmqworker.py" />
<option value="$PROJECT_DIR$/modules/scheduling/programme.py" />
<option value="$PROJECT_DIR$/modules/liquidsoap/simplestmixer.liq" />
<option value="$PROJECT_DIR$/modules/scheduling/models.py" />
<option value="$PROJECT_DIR$/modules/controller/controller.py" />
<option value="$PROJECT_DIR$/modules/scheduling/scheduler.py" />
<option value="$PROJECT_DIR$/aura.py" />
<option value="$PROJECT_DIR$/libraries/database/broadcasts.py" />
<option value="$PROJECT_DIR$/libraries/base/calendar.py" />
<option value="$PROJECT_DIR$/guru.py" />
<option value="$PROJECT_DIR$/modules/communication/zmq/zmqadapter.py" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="645" />
<option name="y" value="31" />
<option name="width" value="971" />
<option name="height" value="1000" />
</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="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="libraries" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="libraries" type="462c0819:PsiDirectoryNode" />
<item name="reporting" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="libraries" type="462c0819:PsiDirectoryNode" />
<item name="security" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
<item name="communication" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
<item name="communication" type="462c0819:PsiDirectoryNode" />
<item name="zmq" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
<item name="controller" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
<item name="liquidsoap" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="aura" type="b2602c69:ProjectViewProjectNode" />
<item name="aura" type="462c0819:PsiDirectoryNode" />
<item name="modules" type="462c0819:PsiDirectoryNode" />
<item name="scheduling" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="settings.editor.selected.configurable" value="preferences.lookFeel" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/modules/communication/zmq" />
<recent name="$PROJECT_DIR$/errormessages" />
<recent name="$PROJECT_DIR$/modules" />
<recent name="$PROJECT_DIR$/libraries/base" />
<recent name="$PROJECT_DIR$/modules/communication/liquidsoap" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/libraries/client" />
<recent name="$PROJECT_DIR$/errormessages" />
<recent name="$PROJECT_DIR$/libraries/base" />
<recent name="$PROJECT_DIR$/modules/scheduling/error" />
<recent name="$PROJECT_DIR$/modules/communication/scheduling" />
</key>
</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.aura">
<configuration default="true" type="PythonConfigurationType" factoryName="Python">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="/usr/bin/python3.5" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="aura" />
<option name="SCRIPT_NAME" value="" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
</configuration>
<configuration name="aura" 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="/usr/bin/python3.5" />
<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="aura" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/aura.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
</configuration>
<configuration name="guru" 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="aura" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/guru.py" />
<option name="PARAMETERS" value="-fnp" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
</configuration>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="Python.guru" />
<item index="1" class="java.lang.String" itemvalue="Python.aura" />
</list>
<recent_temporary>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="Python.aura" />
<item index="1" class="java.lang.String" itemvalue="Python.guru" />
</list>
</recent_temporary>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="c58ca86a-4167-4474-accb-41439a535514" name="Default" comment="" />
<created>1509437402378</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1509437402378</updated>
</task>
<task id="LOCAL-00001" summary="verbindung zwischen guru und auraserver bei fetchNewProgrammes">
<created>1510515005716</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1510515005716</updated>
</task>
<option name="localTasksCounter" value="2" />
<servers />
</component>
<component name="ToolWindowManager">
<frame x="-3" y="31" width="1926" height="1052" 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.19635417" sideWeight="0.5" 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.33" 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.33" sideWeight="0.5" order="13" side_tool="true" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32910052" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32910052" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<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="8" 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.25" sideWeight="0.5" 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="11" 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.46349207" 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.33" sideWeight="0.5" 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="Debug Logs" 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="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="Execute Anonymous" 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="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="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="Salesforce" 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="12" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="verbindung zwischen guru und auraserver bei fetchNewProgrammes" />
<option name="LAST_COMMIT_MESSAGE" value="verbindung zwischen guru und auraserver bei fetchNewProgrammes" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/guru.py</url>
<line>74</line>
<option name="timeStamp" value="10" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/modules/controller/controller.py</url>
<line>113</line>
<option name="timeStamp" value="12" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/libraries/reporting/statestore.py</url>
<line>156</line>
<option name="timeStamp" value="13" />
</line-breakpoint>
</breakpoints>
<option name="time" value="14" />
</breakpoint-manager>
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor 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" />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/scheduling/FetchSchedulerData.py" />
<entry file="file://$PROJECT_DIR$/guru.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#20#31#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/__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://$PROJECT_DIR$/modules/liquidsoap/helpers/message.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="85">
<caret line="7" column="54" lean-forward="false" selection-start-line="7" selection-start-column="54" selection-end-line="7" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor 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" />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/guru.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#20#31#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/__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://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor 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" />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/helpers/message.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="85">
<caret line="7" column="54" lean-forward="false" selection-start-line="7" selection-start-column="54" selection-end-line="7" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/guru.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#20#31#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/__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://$PROJECT_DIR$/modules/liquidsoap/helpers/message.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="85">
<caret line="7" column="54" lean-forward="false" selection-start-line="7" selection-start-column="54" selection-end-line="7" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<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$/modules/liquidsoap/helpers/message.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="85">
<caret line="7" column="54" lean-forward="false" selection-start-line="7" selection-start-column="54" selection-end-line="7" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/__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://$PROJECT_DIR$/README.md">
<provider 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>
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor 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" />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapRecorderClient.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="2" selection-end-column="49" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/reporting/mail.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="425">
<caret line="25" column="21" lean-forward="true" selection-start-line="25" selection-start-column="21" selection-end-line="25" selection-end-column="21" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/scheduling/FetchSchedulerData.py" />
<entry file="file://$PROJECT_DIR$/libraries/base/parsexml.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 />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/security/whitelist.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204">
<caret line="14" column="29" lean-forward="true" selection-start-line="14" selection-start-column="29" selection-end-line="14" selection-end-column="29" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/security/user.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="221">
<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#111#120#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/errormessages/controller_error.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="340">
<caret line="20" column="49" lean-forward="false" selection-start-line="20" selection-start-column="49" selection-end-line="20" selection-end-column="49" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/errormessages/scheduler_error.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="306">
<caret line="18" column="20" lean-forward="false" selection-start-line="18" selection-start-column="20" selection-end-line="18" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/simplestmixer.log" />
<entry file="file://$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapPlayerClient.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="68">
<caret line="4" column="0" lean-forward="false" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/zmq/zmqclient.py" />
<entry file="file://$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapClient.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="465">
<caret line="70" column="11" lean-forward="true" selection-start-line="70" selection-start-column="11" selection-end-line="70" selection-end-column="11" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/base/config.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="785">
<caret line="82" column="63" lean-forward="true" selection-start-line="82" selection-start-column="63" selection-end-line="82" selection-end-column="63" />
<folding>
<element signature="e#1105#1114#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/client/auraclient.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-748">
<caret line="15" column="30" lean-forward="false" selection-start-line="15" selection-start-column="29" selection-end-line="15" selection-end-column="30" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/base/schedulerconfig.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="119">
<caret line="11" column="32" lean-forward="true" selection-start-line="11" selection-start-column="32" selection-end-line="11" selection-end-column="32" />
<folding />
</state>
</provider>
</entry>
<entry file="file:///usr/local/lib/python3.5/dist-packages/flask_sqlalchemy/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="422">
<caret line="1021" column="11" lean-forward="true" selection-start-line="1021" selection-start-column="11" selection-end-line="1021" selection-end-column="11" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/liquidsoap/LiquidSoapCommunicator.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1734">
<caret line="102" column="20" lean-forward="true" selection-start-line="102" selection-start-column="20" selection-end-line="102" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/database/combadb.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="27" lean-forward="false" selection-start-line="0" selection-start-column="27" selection-end-line="0" selection-end-column="27" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/controller/liquidcontroller.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-37">
<caret line="20" column="19" lean-forward="false" selection-start-line="20" selection-start-column="19" selection-end-line="20" selection-end-column="19" />
<folding>
<element signature="e#44#53#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/zmq/zmqworker.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="51">
<caret line="3" column="19" lean-forward="false" selection-start-line="3" selection-start-column="19" selection-end-line="3" selection-end-column="19" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/scheduling/programme.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 />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/database/database.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="85">
<caret line="5" column="23" lean-forward="false" selection-start-line="5" selection-start-column="23" selection-end-line="5" selection-end-column="23" />
<folding>
<element signature="e#0#55#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/reporting/messenger.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="91">
<caret line="150" column="0" lean-forward="false" selection-start-line="150" selection-start-column="0" selection-end-line="150" selection-end-column="0" />
<folding>
<element signature="e#24#39#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/liquidsoap/simplestmixer.liq">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="289">
<caret line="17" column="0" lean-forward="true" selection-start-line="17" selection-start-column="0" selection-end-line="17" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/aura.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="227">
<caret line="26" column="53" lean-forward="false" selection-start-line="26" selection-start-column="53" selection-end-line="26" selection-end-column="53" />
<folding>
<element signature="e#0#13#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/database/broadcasts.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="153">
<caret line="54" column="36" lean-forward="true" selection-start-line="54" selection-start-column="36" selection-end-line="54" selection-end-column="36" />
<folding>
<element signature="e#47#79#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/reporting/statestore.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="372">
<caret line="113" column="0" lean-forward="true" selection-start-line="113" selection-start-column="0" selection-end-line="113" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/scheduling/models.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="207">
<caret line="15" column="40" lean-forward="false" selection-start-line="15" selection-start-column="40" selection-end-line="15" selection-end-column="40" />
<folding>
<element signature="e#47#77#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file:///usr/local/lib/python3.5/dist-packages/simplejson/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-711">
<caret line="403" column="4" lean-forward="false" selection-start-line="403" selection-start-column="4" selection-end-line="403" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/libraries/base/calendar.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="267">
<caret line="302" column="59" lean-forward="true" selection-start-line="302" selection-start-column="59" selection-end-line="302" selection-end-column="59" />
<folding>
<element signature="e#805#818#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/guru.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="252">
<caret line="78" column="46" lean-forward="true" selection-start-line="78" selection-start-column="46" selection-end-line="78" selection-end-column="46" />
<folding>
<element signature="e#20#31#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/communication/zmq/zmqadapter.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="252">
<caret line="77" column="53" lean-forward="true" selection-start-line="77" selection-start-column="53" selection-end-line="77" selection-end-column="53" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/controller/controller.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="354">
<caret line="114" column="38" lean-forward="false" selection-start-line="114" selection-start-column="38" selection-end-line="114" selection-end-column="38" />
<folding>
<element signature="e#43#60#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/modules/scheduling/scheduler.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="184">
<caret line="151" column="31" lean-forward="true" selection-start-line="151" selection-start-column="31" selection-end-line="151" selection-end-column="31" />
<folding>
<element signature="e#1046#1059#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project>
\ No newline at end of file
import signal
import sys
import threading
from datetime import datetime
from libraries.base.config import ConfigReader
from libraries.reporting.messenger import AuraMessenger
from modules.controller.controller import AuraController
from modules.communication.zmq.zmqadapter import ServerZMQAdapter
class Aura(threading.Thread):
config = None
messenger = None
controller = None
def __init__(self):
self.config = ConfigReader()
self.config.loadConfig()
messenger = AuraMessenger()
messenger.setChannel("aura")
server = object
self.controller = AuraController(self.config)
def receive_signal(signum, stack):
print("received signal")
server.reload()
signal.signal(signal.SIGUSR1, receive_signal)
def startListening(self):
# start listener thread
server = ServerZMQAdapter(self.controller, self.config)
try:
while server.is_alive():
print(str(datetime.now())+" joining")
server.join()
print("join out")
# if cnt % 30 == 0:
# print(datetime.datetime.now().isoformat())
# server.printLastMessages()
# cnt = 0
# cnt = cnt + 1
except (KeyboardInterrupt, SystemExit):
# Dem Server den Shutdown event setzen
# server.shutdown_event.set()
# Der Server wartet auf Eingabe
# Daher einen Client initiieren, der eine Nachricht schickt
server.halt()
sys.exit('Terminated')
# # ## ## ## ## ## # #
# # ENTRY FUNCTION # #
# # ## ## ## ## ## # #
def main():
aura = Aura()
aura.startListening()
# # ## ## ## ## ## ## # #
# # End ENTRY FUNCTION # #
# # ## ## ## ## ## ## # #
if __name__ == "__main__":
main()
\ No newline at end of file
{
"allData": {
"id": "01",
"00": "Global Metadata delivered",
"01": "Could not get Data from Sound Engine"
},
"channel_insert": {
"id": "02",
"00": "On Channel ::channel:: insert ::uri:: at position ::pos::",
"02": "On Channel ::channel:: could not insert ::uri:: at position ::pos::"
},
"channel_move": {
"id": "03",
"00": "On Channel ::channel:: moved Item from ::fromPos:: to position ::toPos::",
"01": "Warning: Position ::fromPos:: out of range",
"02": "Warning: Cannot move to same position",
"03": "On Channel ::channel:: could not move from position ::fromPos:: to position ::toPos::"
},
"channel_off": {
"id": "04",
"00": "Channel ::channel:: off",
"01": "Could not activate Channel ::channel::"
},
"channel_on": {
"id": "05",
"00": "Channel ::channel:: on",
"01": "Could not deactivate Channel ::channel::"
},
"channel_queue": {
"id": "06",
"00": "Channel Queue for ::channel:: delivered",
"01": "Could not get channel queue from channel ::channel::",
"02": "Could not get channel queue from channel ::channel::",
"03": "Could not get channel queue from channel ::channel::"
},
"channel_remove": {
"id": "07",
"00": "Removed item on position ::pos:: from channel ::channel::",
"01": "Could not remove item on position ::pos:: from channel ::channel::",
"02": "Warning: position ::pos:: out of range'"
},
"channel_seek": {
"id": "08",
"00": "Seeked channel ::channel:: ::duration:: seconds",
"01": "Could not seek channel ::channel:: ::duration:: seconds"
},
"channel_skip": {
"id": "09",
"00": "Skipped channel ::channel::",
"01": "0 Channels listed",
"02": "Could not get channels from sound engine",
"03": "Could not skip ::channel::"
},
"channel_volume": {
"id": "10",
"00": "Volume ::volume::% set on channel ::channel::",
"01": "Could not set volume to ::volume::% on channel ::channel::",
"02": "0 Channels listed",
"03": "Could not get channels from sound engine"
},
"currentData": {
"id": "11",
"00": "Current track metadata delivered",
"01": "Nothing seems to be on air",
"02": "Could not detect metadata"
},
"help": {
"id": "12",
"00": "none",
"01": "Could not open help file"
},
"listChannels": {
"id": "13",
"00": "Listed Channels",
"01": "0 Channels listed",
"02": "Could not get channels from sound engine"
},
"message": {
"id": "14",
"00": "none"
},
"playlist_data": {
"id": "15",
"00": "Playlist data delivered"
},
"playlist_flush": {
"id": "16",
"00": "Flushed playlist",
"01": "Could not flush playlist"
},
"playlist_insert":{
"id": "17",
"00": "Insert track ::uri:: on position ::pos::"
},
"playlist_load": {
"id": "18",
"00": "Load Playlist ::uri::",
"01": "Could not load Playlist ::uri::",
"02": "Playlist is not well formed XML"
},
"playlist_move": {
"id": "19",
"00": "Moved playlist track from position ::fromPos:: to ::toPos::"
},
"playlist_pause": {
"id": "20",
"00": "Playlist paused",
"01": "Playlist already paused"
},
"playlist_stop": {
"id": "21",
"00": "Playlist stopped",
"01": "Playlist already stopped"
},
"playlist_play": {
"id": "22",
"00": "Playlist started",
"01": "Playlist already playing",
"02": "0 Channels listed",
"03": "Could not get channels from sound engine"
},
"playlist_push": {
"id": "23",
"00": "Playlist: pushed ::uri::",
"01": "Could not push ::uri::"
},
"playlist_remove":{
"id": "24",
"00": "Removed track on position ::pos:: from playlist",
"01": "Could not remove track on position ::pos:: from playlist"
},
"playlist_seek": {
"id": "25",
"00": "Seeked playlist ::duration:: seconds",
"01": "Could not seek playlist ::duration:: seconds"
},
"playlist_skip": {
"id": "26",
"00": "Skipped playlist",
"00": "Could not skip playlist"
},
"recorder_data": {
"id": "27",
"00": "Delivered recorder data",
"01": "Could not deliver recorder data"
},
"recorder_start": {
"id": "28",
"00": "Recorder started",
"01": "Could not start recorder"
},
"recorder_stop": {
"id": "29",
"00": "Recorder stopped",
"01": "Could not stop recorder"
},
"scheduler_reload": {
"id": "30",
"00": "Reload signal was sent to scheduler",
"01": "Could not find the scheduler process"
},
"sendLqcCommand": {
"id": "31",
"01": "Soundengine not running",
"02": "Recorder not running"
},
"get_channel_state" : {
"id": "32",
"00": "Channels ::channel:: state",
"01": "Could not get channel state from channel ::channel::"
},
"setPassword": {
"id": "33",
"00": "Successfull set password",
"01": "Not enough access rights for this operation"
},
"addUser": {
"id": "34",
"00": "Successfull add user ::username::",
"01": "Not enough access rights for this operation"
},
"delUser": {
"id": "35",
"00": "Successfull removed user ::username::",
"01": "Not enough access rights for this operation"
},
"scheduler_data": {
"id": "36",
"00": "Successfull delivered scheduler config",
"01": "Scheduler config seems to be broken"
},
"scheduler_store": {
"id": "37",
"00": "Successfull stored scheduler config",
"01": "Not enough access rights for this operation",
"02": "Could not store a valid scheduler XML"
},
"getUserlist": {
"id": "38",
"00": "Userlist was successfully delivered",
"01": "Not enough access rights for this operation"
}
}
{
"exec_job": {
"id": "01",
"00": "Execute job ::job::",
"01": "Fatal: Could not execute job ::job::. Command ::exec:: results in Exception ::Exception::. Stopped watcher"
},
"schedule_job": {
"id": "02",
"00": "Scheduled job ::job:: for ::scheduled_for:: at ::scheduled_at::",
"01": "Could not execute job"
},
"load_playlist": {
"id": "03",
"00": "Load playlist ::uri::",
"01": "Could not load playlist ::uri::. File does not exist!",
"02": "Controller failed to load playlist ::uri::. Message was '::message::'"
},
"play_playlist": {
"id": "04",
"00": "Started playlist",
"01": "Controller failed to start playlist. Message was '::message::'"
},
"stop_playlist": {
"id": "05",
"00": "Started playlist",
"01": "Controller failed to start playlist. Message was '::message::'"
},
"start_recording": {
"id": "06",
"00": "Started recording",
"01": "Controller failed to start recording. Message was '::message::'"
},
"stop_recording": {
"id": "07",
"00": "Stopped recording",
"01": "Controller failed to stop recording. Message was '::message::'" },
"precache": {
"id": "08",
"00": "Precached playlists",
"01": "Could not precache playlist."
},
"clean_cached": {
"id": "09",
"00": "Cleaned cache",
"01": "Could not clean cache"
},
"on_start": {
"id": "10",
"00": "Do initial jobs",
"01": "Could not do initial jobs"
},
"lookup_prearranged": {
"id": "11",
"00": "Lookup for prearranged tracks",
"01": "No system channel available"
},
"start_prearranged": {
"id": "12",
"00": "Started preaarranged tracks"
},
"end_prearranged": {
"id": "13",
"00": "Stopped preaarranged tracks"
}
}
#!/usr/bin/python3
import time
import simplejson
from argparse import ArgumentParser
from modules.communication.liquidsoap.LiquidSoapCommunicator import LiquidSoapCommunicator
from libraries.base.config import ConfigReader
from modules.communication.zmq.zmqadapter import ClientZMQAdapter
class Guru:
config = ConfigReader()
config.loadConfig()
lsc = LiquidSoapCommunicator(False)
# # AuraScheduler(lsc.getClient(), "/etc/comba/scheduler.xml")
#fcd = FetchCalendarData()
zmqclient = ClientZMQAdapter(config.get('zmqhostip'), config.get('zmqport'))
def __init__(self):
nothing_done = True
try:
parser = ArgumentParser()
# commands
parser.add_argument("-fnp", "--fetch-new-programmes", action="store_true", dest="fetch_new_programme",
default=False, help="Fetch new programmes from calendarurl in comba.ini")
# getter
parser.add_argument("-gam", "--get-active-mixer", action="store_true", dest="getactivemixer", default=False,
help="Which mixer is activated?")
parser.add_argument("-pms", "--print-mixer-status", action="store_true", dest="printmixerstatus", default=False,
help="Prints all mixer sources and their states")
parser.add_argument("-pap", "--print-act-programme", action="store_true", dest="printactprog", default=False,
help="Prints the actual Programme, the controller holds")
# manipulation
parser.add_argument("-am", "--select-mixer", action="store", dest="selectmixer", default=-1,
help="Which mixer should be activated?", type=int)
parser.add_argument("-dm", "--de-select-mixer", action="store", dest="deselectmixer", default=-1,
help="Which mixer should be activated?", type=int)
parser.add_argument("-as", "--add-source", action="store", dest="addsource", default="",
help="Add new source to LiquidSoap mixer [Experimental]")
args = parser.parse_args()
except ValueError:
parser.print_help()
exit(1)
if args.fetch_new_programme:
print("Guru is learning how to fetch new programmes")
self.fetch_new_programme()
nothing_done = False
if args.getactivemixer:
self.getactivemixer()
nothing_done = False
if args.printmixerstatus:
self.printmixerstatus()
nothing_done = False
if args.printactprog:
self.printactprog()
nothing_done = False
if args.addsource != "":
print("Guru still has to learn to add a source")
nothing_done = False
if args.selectmixer != -1:
self.selectmixer(args.selectmixer)
nothing_done = False
if args.deselectmixer != -1:
self.selectmixer(args.deselectmixer, False)
nothing_done = False
if nothing_done:
parser.print_help()
def fetch_new_programme(self):
reply = self.zmqclient.send("fetch_new_programme")
print(type(reply))
print(reply)
print(simplejson.loads(reply))
def selectmixer(self, mixernumber, activate=True):
return self.lsc.switchmixernumber(mixernumber, activate)
def getactivemixer(self):
print("Guru thinking...")
am = self.lsc.getactivemixer()
if len(am) == 0:
print("Guru recognized a problem: No active source!!!")
elif len(am) > 1:
print("Guru recognized a problem: Multiple active sources!!! " + str(am))
else:
print("Guru thinking result: ActiveMixer: " + str(am[0]))
def printmixerstatus(self):
status = self.lsc.getmixerstatus()
for k,v in status.items():
print("source: "+k+"\t status: "+v)
def printactprog(self):
reply = self.zmqclient.send("get_act_programme")
print(reply)
# # ## ## ## ## ## # #
# # ENTRY FUNCTION # #
# # ## ## ## ## ## # #
def main():
guru = Guru()
# # ## ## ## ## ## ## # #
# # End ENTRY FUNCTION # #
# # ## ## ## ## ## ## # #
if __name__ == "__main__":
main()
File added
File added
File added
File added
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# combac.py
#
# Copyright 2014 BFR <info@freie-radios.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; Version 3 of the License
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, the license can be downloaded here:
#
# http://www.gnu.org/licenses/gpl.html
import codecs
import sys
import threading
import simplejson
import queue
from datetime import datetime, timedelta
from libraries.database.broadcasts import TimeSlot, TimeSlotEntry
from libraries.reporting.messenger import AuraMessenger
class AuraCalendarService(threading.Thread):
messenger = AuraMessenger()
calendarurl = ""
audiobase = ""
playlistdir = ""
until = ''
secondspertrack = 0
xmlplaylist = range(0)
queue = None
config = None
"""
Fetching playlist data, write it into the database and notify service
"""
def __init__(self, config, datefrom="", dateto=""):
threading.Thread.__init__(self)
self.config = config
self.messenger.setChannel('aura')
self.messenger.setSection('calendar')
self.messenger.setMailAddresses(self.config.get('frommail'), self.config.get('adminmail'))
self.dateto = dateto
self.datefrom = str(datefrom)
self.queue = queue.Queue()
self._stop_event = threading.Event()
# ------------------------------------------------------------------------------------------ #
def setDateFrom(self, date):
self.datefrom = str(date).replace(" ", "T")
# ------------------------------------------------------------------------------------------ #
def setDateTo(self, date):
self.dateto = str(date).replace(" ", "T")
# ------------------------------------------------------------------------------------------ #
def setUntilTime(self, timestring):
self.until = timestring
# ------------------------------------------------------------------------------------------ #
def setSecondsPerTrack(self, seconds):
self.secondspertrack = int(seconds)
# ------------------------------------------------------------------------------------------ #
def setCalendarUrl(self, url):
self.calendarurl = url
# ------------------------------------------------------------------------------------------ #
def setAudioPath(self, path):
self.audiobase = path
# ------------------------------------------------------------------------------------------ #
def setAudioPath(self, path):
self.audiobase = path
# ------------------------------------------------------------------------------------------ #
def setPlaylistStore(self, path):
self.playlistdir = path
# ------------------------------------------------------------------------------------------ #
def getDuration(self, start, end):
return self._calcDuration(start, end)
# ------------------------------------------------------------------------------------------ #
def getQueue(self):
return self.queue
# ------------------------------------------------------------------------------------------ #
def getUri(self):
if not self.playlistdir:
return False
if not self.datefrom:
return False
if not self._calcDateTo():
return
hostname = self.get('servername');
port = self.get('serviceport');
date_from = self.datefrom[0:16] + ':00';
date_to = self.dateto[0:16] + ':00';
uri = 'http://' + hostname + ':' + port + '/playlist/' + date_from + '/' + date_to
return uri
# ------------------------------------------------------------------------------------------ #
def run(self):
"""
Fetch calendar data, store it in the database and send a message to the aura service
"""
filestotal = 0
#if not self._calcDateTo():
# return
self._setUrl()
self._fetchData()
# secondspertrack may be a string from config
self.secondspertrack = int(self.secondspertrack)
#print(self.data['timeslots'])
entrynum = 0
lasttimeslot_id = 0
for timeslot in self.data:
#fix nonexisting origdatetime
if 'end' not in timeslot:
continue
if 'start' not in timeslot:
continue
timeslot_db = TimeSlot.query.filter(TimeSlot.timeslot_id == timeslot['timeslot_id']).first()
if not timeslot_db:
print("no timeslot with given timeslot id in database => create new")
timeslot_db = TimeSlot()
timeslot_entry = TimeSlotEntry.query.filter(TimeSlotEntry.entry_start == timeslot["start"], TimeSlotEntry.entry_end == timeslot["end"]).first()
if not timeslot_entry:
print("no timeslotentry from "+timeslot["start"]+" to "+timeslot["end"]+" in database => create new")
timeslot_entry = TimeSlotEntry()
# calc duration
duration = self._calcDuration(timeslot['start'], timeslot['end'])
timeslot['duration'] = timedelta(seconds=duration).__str__()
timeslot_db.show_id = timeslot["show_id"]
timeslot_db.timeslot_id = timeslot["timeslot_id"]
timeslot_db.timeslot_start = timeslot["timeslot_start"]
timeslot_db.timeslot_end = timeslot["timeslot_end"]
timeslot_db.show_name = timeslot["show_name"]
timeslot_db.show_hosts = timeslot["show_hosts"]
timeslot_db.is_repetition = timeslot["is_repetition"]
timeslot_db.fallback_playlist = timeslot["fallback_playlist"]
timeslot_db.show_fallback_pool = timeslot["show_fallback_pool"]
timeslot_db.station_fallback_pool = timeslot["station_fallback_pool"]
timeslot_entry.timeslot_id = timeslot["timeslot_id"]
timeslot_entry.entry_start = timeslot["start"]
timeslot_entry.entry_end = timeslot["end"]
timeslot_entry.source = timeslot["source"]
timeslot_db.store(True)
timeslot_entry.store(True)
event = {'job': 'dump', 'location': timeslot['timeslot_id'], 'length': duration}
self.messenger.queueAddEvent('dumpstart', timeslot["start"], event)
event = {'job': 'dump', 'location': timeslot['timeslot_id'], 'length': duration}
self.messenger.queueAddEvent('dumpend', timeslot["end"], event)
self.queue.put("fetching_finished")
# terminate the thread
return
# ------------------------------------------------------------------------------------------ #
def _calcDateTo(self):
if self.dateto:
return True
if not self.until:
return False
if not self.datefrom:
return False
date_start = datetime.strptime(self.datefrom.replace('T',' '), "%Y-%m-%d %H:%M")
time_start = date_start.strftime('%H:%M')
day_offset = 1 if (time_start > self.until) else 0
end_date = date_start + timedelta(day_offset)
self.dateto = end_date.strftime('%F') + 'T' + self.until
return True
# ------------------------------------------------------------------------------------------ #
def _calcDuration(self, start, end):
"""
Berechnet Zeit in Sekunden aus Differenz zwischen Start und Enddatum
@type start: datetime
@param start: Startzeit
@type end: datetime
@param end: Endzeit
@rtype: int
@return: Zeit in Sekunden
"""
sec1 = int(datetime.strptime(start[0:16].replace(" ","T"),"%Y-%m-%dT%H:%M").strftime("%s"));
sec2 = int(datetime.strptime(end[0:16].replace(" ","T"),"%Y-%m-%dT%H:%M").strftime("%s"));
return (sec2 - sec1);
# ------------------------------------------------------------------------------------------ #
def _fetchData(self):
# Now open Calendar Url
try:
url = self.getUrl()
data = self.getData()
#request = urllib.request.Request(url, data)
#with urllib.request.urlopen(request) as response:
# html_response = response.read()
html_response = '[{"source": "file://path/to/interview_mit_luger.flac", "start": "2017-10-09 18:03:00", "end": "2017-10-09 18:05:40", "timeslot_id": 1, "timeslot_start": "2017-10-09 18:00:00", "timeslot_end": "2017-10-09 19:00:00", "show_id": 1, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": false, "fallback_playlist": "file:///var/audio/music.flac", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"},{"source": "file://path/to/interview_mit_luger.flac", "start": "2017-10-09 18:05:40", "end": "2017-10-09 19:00:00", "timeslot_id": 1, "timeslot_start": "2017-10-09 18:00:00", "timeslot_end": "2017-10-09 19:00:00", "show_id": 1, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": false, "fallback_playlist": "file:///var/audio/music.ogg", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"}, {"source": "file://path/to/interview_mit_luger.flac", "start": "2017-10-09 19:00:00", "end": "2017-10-09 20:00:00", "timeslot_id": 2, "timeslot_start": "2017-10-09 19:00:00", "timeslot_end": "2017-10-09 20:00:00", "show_id": 2, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": true, "fallback_playlist": "file://path/to/playlist.m3u", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"}]'
except IOError as e:
self.messenger.send("Could not connect to service " + self.dataURL, '1101', 'error', 'fetchCalenderData',
self._getErrorData(), 'getcalendar')
#TODO: so gehts nicht
sys.exit()
else:
# Read in data
#print(html_response[0:100])
#jsondata = html_response # .read()
# print("Hardcoded Response for this request: http://bermudafunk-kalender.critmass.de/index.php?option=com_jimtawl&view=calendar&format=json&from=2017-09-26T08:00&to=2017-09-27T07:00")
self.jsondata = \
'[' \
'{' \
'"source": "file:///var/audio/music.flac", ' \
'"start": "'+(datetime.now()+timedelta(hours=1)).strftime('%Y-%m-%d %H:03:00')+'", ' \
'"end": "'+(datetime.now()+timedelta(hours=1)).strftime('%Y-%m-%d %H:05:40')+'", ' \
'"timeslot_id": 1, ' \
'"timeslot_start": "2017-10-09 18:00:00", ' \
'"timeslot_end": "2017-10-09 19:00:00", ' \
'"show_id": 1, ' \
'"show_name": "FROzine", ' \
'"show_hosts": "Sandra Hochholzer, Martina Schweiger", ' \
'"is_repetition": false, ' \
'"fallback_playlist": "file:///var/audio/music.flac", ' \
'"show_fallback_pool": "file:///var/audio/fallback/", ' \
'"station_fallback_pool": "file:///var/audio/station_fallback_pool/"' \
'}' \
',' \
'{' \
'"source": "linein://0", ' \
'"start": "'+(datetime.now()+timedelta(hours=1)).strftime('%Y-%m-%d %H:05:40')+'", ' \
'"end": "'+(datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00')+'", ' \
'"timeslot_id": 1, "timeslot_start": "2017-10-09 18:00:00", ' \
'"timeslot_end": "2017-10-09 19:00:00", ' \
'"show_id": 1, "show_name": "FROzine", ' \
'"show_hosts": "Sandra Hochholzer, Martina Schweiger", ' \
'"is_repetition": false, ' \
'"fallback_playlist": "file:///var/audio/music.ogg", ' \
'"show_fallback_pool": "file:///var/audio/fallback/", ' \
'"station_fallback_pool": "file:///var/audio/station_fallback_pool/"' \
'}' \
',' \
'{' \
'"source": "http://stream.fro.at/fro128.mp3", ' \
'"start": "'+(datetime.now()+timedelta(hours=2)).strftime('%Y-%m-%d %H:00:00')+'", ' \
'"end": "'+(datetime.now()+timedelta(hours=3)).strftime('%Y-%m-%d %H:00:00')+'", ' \
'"timeslot_id": 2, ' \
'"timeslot_start": "2017-10-09 19:00:00", ' \
'"timeslot_end": "2017-10-09 20:00:00", ' \
'"show_id": 2, ' \
'"show_name": "FROzine", ' \
'"show_hosts": "Sandra Hochholzer, Martina Schweiger", ' \
'"is_repetition": true, ' \
'"fallback_playlist": "file://path/to/playlist.m3u", ' \
'"show_fallback_pool": "file:///var/audio/fallback/", ' \
'"station_fallback_pool": "file:///var/audio/station_fallback_pool/"' \
'}' \
']'
# jsondata = '[{"source": "file:///var/audio/music.flac", "start": "2017-10-09 18:03:00", "end": "2017-10-09 18:05:40", "timeslot_id": 1, "timeslot_start": "2017-10-09 18:00:00", "timeslot_end": "2017-10-09 19:00:00", "show_id": 1, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": false, "fallback_playlist": "file:///var/audio/music.flac", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"},{"source": "file://path/to/interview_mit_luger.flac", "start": "2017-10-09 18:05:40", "end": "2017-10-09 19:00:00", "timeslot_id": 1, "timeslot_start": "2017-10-09 18:00:00", "timeslot_end": "2017-10-09 19:00:00", "show_id": 1, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": false, "fallback_playlist": "file:///var/audio/music.ogg", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"}, {"source": "file://path/to/interview_mit_luger.flac", "start": "2017-10-09 19:00:00", "end": "2017-10-09 20:00:00", "timeslot_id": 2, "timeslot_start": "2017-10-09 19:00:00", "timeslot_end": "2017-10-09 20:00:00", "show_id": 2, "show_name": "FROzine", "show_hosts": "Sandra Hochholzer, Martina Schweiger", "is_repetition": true, "fallback_playlist": "file://path/to/playlist.m3u", "show_fallback_pool": "file:///var/audio/fallback/", "station_fallback_pool": "file:///var/audio/station_fallback_pool/"}]'
#jsondata = '{"num":17,"shows":[{"identifier":"748-2017-09-26-08-00-00","reccurrence_id":"748","start":"2017-09-26 08:00:00","end":"2017-09-26 09:00:00","datetime":"2017-09-26 08:00:00","duration":"01:00:00","rerun":false,"title":"Darktales Radio-Show","subject":"","description":"","text":"","programme_id":"25","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"749-2017-09-26-09-00-00","reccurrence_id":"749","start":"2017-09-26 09:00:00","end":"2017-09-26 11:00:00","datetime":"2017-09-26 09:00:00","duration":"02:00:00","rerun":false,"title":"Bizarre","subject":"","description":"","text":"","programme_id":"14","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"750-2017-09-26-11-00-00","reccurrence_id":"750","start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","datetime":"2017-09-26 11:00:00","duration":"01:00:00","rerun":false,"title":"Netzwerk XX","subject":"","description":"","text":"","programme_id":"74","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"1034-2017-09-26-12-00-00","reccurrence_id":"1034","start":"2017-09-26 12:00:00","end":"2017-09-26 14:00:00","datetime":"2017-09-26 12:00:00","duration":"02:00:00","rerun":false,"title":"POPPATCHWORK","subject":"","description":"","text":"","programme_id":"114","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"","email":"email@bermudafunk.org"}},{"identifier":"1035-2017-09-26-14-00-00","reccurrence_id":"1035","start":"2017-09-26 14:00:00","end":"2017-09-26 15:00:00","datetime":"2017-09-26 14:00:00","duration":"01:00:00","rerun":false,"title":"Lieder und Worte","subject":"","description":"","text":"","programme_id":"115","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"","email":"email@bermudafunk.org"}},{"identifier":"601-2017-09-26-15-00-00","reccurrence_id":"601","start":"2017-09-26 15:00:00","end":"2017-09-26 16:00:00","datetime":"2017-09-26 15:00:00","duration":"01:00:00","rerun":false,"title":"Ohrenschmaus","subject":"","description":"","text":"","programme_id":"77","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"377-2017-09-26-16-00-00","reccurrence_id":"377","start":"2017-09-26 16:00:00","end":"2017-09-26 18:00:00","datetime":"2017-09-26 16:00:00","duration":"02:00:00","rerun":false,"title":"Sonar","subject":"","description":"","text":"","programme_id":"95","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"754-2017-09-26-18-00-00","reccurrence_id":"754","start":"2017-09-26 18:00:00","end":"2017-09-26 20:00:00","datetime":"2017-09-26 18:00:00","duration":"02:00:00","rerun":false,"title":"No Water","subject":"","description":"","text":"","programme_id":"76","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"611-2017-09-26-20-00-00","reccurrence_id":"611","start":"2017-09-26 20:00:00","end":"2017-09-26 21:00:00","datetime":"2017-09-26 20:00:00","duration":"01:00:00","rerun":false,"title":"Leonardo","subject":"","description":"","text":"","programme_id":"63","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"605-2017-09-26-21-00-00","reccurrence_id":"605","start":"2017-09-26 21:00:00","end":"2017-09-26 22:00:00","datetime":"2017-09-26 21:00:00","duration":"01:00:00","rerun":false,"title":"bermuda.music","subject":"","description":"","text":"","programme_id":"11","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"612-2017-09-26-22-00-00","reccurrence_id":"612","start":"2017-09-26 22:00:00","end":"2017-09-27 00:00:00","datetime":"2017-09-26 22:00:00","duration":"02:00:00","rerun":false,"title":"Clubbers Paradise","subject":"","description":"","text":"","programme_id":"20","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"629-2017-09-27-00-00-00","reccurrence_id":"629","start":"2017-09-27 00:00:00","end":"2017-09-27 01:00:00","datetime":"2017-09-27 00:00:00","duration":"01:00:00","rerun":false,"title":"Worte ueber die Welt","subject":"","description":"","text":"","programme_id":"109","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"755-2017-09-27-01-00-00","reccurrence_id":"755","start":"2017-09-27 01:00:00","end":"2017-09-27 03:00:00","datetime":"2017-09-27 01:00:00","duration":"02:00:00","rerun":false,"title":"Grenzenlos","subject":"","description":"","text":"","programme_id":"43","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"756-2017-09-27-03-00-00","reccurrence_id":"756","start":"2017-09-27 03:00:00","end":"2017-09-27 04:00:00","datetime":"2017-09-27 03:00:00","duration":"01:00:00","rerun":false,"title":"bermuda.music special","subject":"","description":"","text":"","programme_id":"12","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"757-2017-09-27-04-00-00","reccurrence_id":"757","start":"2017-09-27 04:00:00","end":"2017-09-27 05:00:00","datetime":"2017-09-27 04:00:00","duration":"01:00:00","rerun":false,"title":"radio.aufschnitt","subject":"","description":"","text":"","programme_id":"86","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"758-2017-09-27-05-00-00","reccurrence_id":"758","start":"2017-09-27 05:00:00","end":"2017-09-27 06:00:00","datetime":"2017-09-27 05:00:00","duration":"01:00:00","rerun":false,"title":"PRESSING","subject":"","description":"","text":"","programme_id":"83","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}},{"identifier":"684-2017-09-27-06-00-00","reccurrence_id":"684","start":"2017-09-27 06:00:00","end":"2017-09-27 08:00:00","datetime":"2017-09-27 06:00:00","duration":"02:00:00","rerun":false,"title":"Sonar","subject":"","description":"","text":"","programme_id":"95","station_name":"Bermudafunk","station_id":"bfunk-003","data":{"www":"bermudafunk.org","email":"email@bermudafunk.org"}}]}'
#jsondata = '{"num":5,"shows":[{"id":"0","name":"frozine","slug":"","image":"","logo":"","description":"25","type":"Magazin","is_repetition":false,"start":"2017-09-26 08:00:00","end":"2017-09-26 09:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"1","name":"bücherwahl","slug":"","image":"","logo":"","description":"25","type":"Magazin","is_repetition":false,"start":"2017-09-26 09:00:00","end":"2017-09-26 10:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"2","name":"sonar","slug":"","image":"","logo":"","description":"25","type":"Magazin","is_repetition":false,"start":"2017-09-26 10:00:00","end":"2017-09-26 11:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"3","name":"Radio Bulgaria","slug":"","image":"","logo":"","description":"25","type":"Magazin","is_repetition":false,"start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"4","name":"#Stimmlagen","slug":"","image":"","logo":"","description":"25","type":"Magazin","is_repetition":false,"start":"2017-09-26 12:00:00","end":"2017-09-26 13:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"}]}'
#jsondata = '{"num":5,"timeslots":[{"id":"0","name":"frozine","slug":"","image":"","logo":"","description":"25","location":"file:///var/audio/test.flac","type":"file to lineout","is_repetition":false,"start":"2017-09-26 13:00:00","end":"2017-09-26 14:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"1","name":"bücherwahl","slug":"","image":"","logo":"","description":"25","location":"http://develop.servus.at:8000/listen.pls","type":"stream to lineout","is_repetition":false,"start":"2017-09-26 09:00:00","end":"2017-09-26 10:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"2","name":"sonar","slug":"","image":"","logo":"","description":"25","location":"linein:///var/audio/test.flac","type":"linein to lineout","is_repetition":false,"start":"2017-09-26 10:00:00","end":"2017-09-26 11:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"3","name":"Radio Bulgaria","slug":"","image":"","logo":"","description":"25","location":"pool:///var/audio/","type":"file (pool) to lineout","is_repetition":false,"start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"4","name":"#Stimmlagen","slug":"","image":"","logo":"","description":"25","location":"file:///var/audio/test.flac","type":"file to lineout","is_repetition":false,"start":"2017-09-26 12:00:00","end":"2017-09-26 13:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"}]}'
#jsondata = '{"num":5,"timeslots":[{"id":"0","name":"frozine","slug":"","image":"","logo":"","description":"25","location":"file:///var/audio/test.flac","type":"file to lineout","is_repetition":false,"origdate":"","start":"2017-09-26 13:00:00","end":"2017-09-26 14:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"1","name":"bücherwahl","slug":"","image":"","logo":"","description":"25","location":"http://develop.servus.at:8000/listen.pls","type":"stream to lineout","is_repetition":false,"origdate":"","start":"2017-09-26 09:00:00","end":"2017-09-26 10:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"2","name":"sonar","slug":"","image":"","logo":"","description":"25","location":"linein:///var/audio/test.flac","type":"linein to lineout","is_repetition":false,"origdate":"","start":"2017-09-26 10:00:00","end":"2017-09-26 11:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"3","name":"Radio Bulgaria","slug":"","image":"","logo":"","description":"25","location":"pool:///var/audio/","type":"file (pool) to lineout","is_repetition":false,"origdate":"","start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"4","name":"#Stimmlagen","slug":"","image":"","logo":"","description":"25","location":"file:///var/audio/test.flac","type":"file to lineout","is_repetition":false,"origdate":"","start":"2017-09-26 12:00:00","end":"2017-09-26 13:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"}]}'
#jsondata = '{"timeslots":[{"id":"0","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","repetition_id":"","start":"2017-09-26 10:00:00","end":"2017-09-26 11:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"0","name":"frozine","playlist_id":"http://fro.at:8000/listen.pls","shortdesc":"test description","repetition_id":"","start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"0","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","repetition_id":"","start":"2017-09-26 12:00:00","end":"2017-09-26 13:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"0","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","repetition_id":"","start":"2017-09-26 13:00:00","end":"2017-09-26 14:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"0","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","repetition_id":"","start":"2017-09-26 14:00:00","end":"2017-09-26 15:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"}]}'
#jsondata = '{"timeslots":[{"id":"0","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","start":"2017-09-26 10:00:00","end":"2017-09-26 11:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"1","name":"bücherwahl","playlist_id":"http://fro.at:8000/listen.pls","shortdesc":"test description","start":"2017-09-26 11:00:00","end":"2017-09-26 12:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"2","name":"Radio Bulgari","playlist_id":"pool:///var/audio/","shortdesc":"test description","start":"2017-09-26 12:00:00","end":"2017-09-26 13:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"3","name":"FROmat","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","start":"2017-09-26 13:00:00","end":"2017-09-26 14:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"},{"id":"4","name":"frozine","playlist_id":"file:///var/audio/test.flac","shortdesc":"test description","repetition_id":1,"start":"2017-09-26 14:00:00","end":"2017-09-26 15:00:00","fallback_pool":"/var/audio","fallback_playlist":"/var/audio/fallback.pls"}]}'
try:
self.data = simplejson.loads(self.jsondata)
except Exception as e:
self.messenger.send("Could not decode calender data from service " + self.dataURL + "! Exception: "+e, '1102', 'error',
'fetchCalenderData', self._getErrorData(), 'getcalendar')
sys.exit()
else:
# check data
try:
print("Warning: Hardcoded Response && no json data checks. i believe what i get here")
#print(self.data)
#print(len(self.data))
except KeyError as e:
self.messenger.send("Could not decode calender data from service " + self.dataURL + "! Exception: "+e, '1102', 'error',
'fetchCalenderData', self._getErrorData(), 'getcalendar')
sys.exit()
except Exception as e:
self.messenger.send("Could not decode calender data from service " + self.dataURL + "! Exception: "+e, '1102', 'error',
'fetchCalenderData', self._getErrorData(), 'getcalendar')
sys.exit()
else:
return self.data
# ------------------------------------------------------------------------------------------ #
def _dumpPlaylist(self, xml):
"""
Dump the playlist
@type xml: string
@param xml: XML-String
"""
# dump file
try:
f = codecs.open(self.playlistpath + '.xspf', 'w', encoding='utf-8')
f.write(xml)
f.close()
except:
self.messenger.send("Couldn't dump playlist " + self.playlistpath + '.xspf', '1201', 'error', 'get_playlist', self._getErrorData(), 'getcalendar')
else:
self.messenger.send("Dumped playlist" + self.playlistpath + ".xspf", '1200', 'success', 'get_playlist', self._getErrorData(), 'getcalendar')
# ------------------------------------------------------------------------------------------ #
def _getErrorData(self):
"""
Basisdaten als dict liefern
"""
return ({'from': str(self.datefrom), 'dateto': str(self.dateto), 'path': "self.playlistpath", 'url': self.calendarurl})
# ------------------------------------------------------------------------------------------ #
def _setUrl(self):
"""
Die URL auf den Zappa-Kalender ermitteln
"""
self.dataURL = self.calendarurl.replace('#datefrom#', self.datefrom.replace(' ', 'T')).replace('#dateto#', self.dateto.replace(' ', 'T'))
def getUrl(self):
url = self.dataURL[0:self.dataURL.find('&')]
print(url)
return url
def getData(self):
params = self.dataURL[self.dataURL.find('&'):]
#print("params: "+params)
def stop(self):
self._stop_event.set()
def get_calendar_data(self):
return self.jsondata # simplejson.dump(self.data)
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# combabase.py
#
# Copyright 2014 BFR <info@freie-radios.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; Version 3 of the License
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, the license can be downloaded here:
#
# http://www.gnu.org/licenses/gpl.html
# Meta
__version__ = '0.1.1'
__license__ = "GNU General Public License (GPL) Version 3"
__version_info__ = (0, 1, 1)
__author__ = 'Michael Liebler <michael-liebler@radio-z.net>'
# massively enhanced by Gottfried Gaisbauer <gottfried.gaisbauer@servus.at>
"""
Comba Base Class - lade Config
"""
import os
import sys
#import StringIO
#import ConfigParser
import socket
from io import StringIO
from configparser import RawConfigParser
from configparser import ConfigParser
class ConfigReader(object):
def set(self, key, value):
"""
Eine property setzen
@type key: string
@param key: Der Key
@type value: mixed
@param value: Beliebiger Wert
"""
if(key == "securitylevel"):
self.__dict__[key] = int(value)
else:
self.__dict__[key] = value
# ------------------------------------------------------------------------------------------ #
def get(self, key, default=None):
"""
Eine property holen
@type key: string
@param key: Der Key
@type default: mixed
@param default: Beliebiger Wert
"""
if key not in self.__dict__:
if default:
self.set(key, default)
else:
print("WARNING: Key "+key+" not found!")
return None
return self.__dict__[key]
# ------------------------------------------------------------------------------------------ #
def loadConfig(self):
"""
Set config defaults and load settings from file
:return:
"""
ini_path = self.get('configpath', '/etc/aura/aura.ini')
if not os.path.isfile(ini_path):
print(ini_path + " not found :(")
sys.exit(1)
# INI einlesen
f = open(ini_path, 'r')
ini_str = '[root]\n' + f.read()
f.close()
self.configDefaults = {
'secondspertrack' : '1800',
'audiobase' : '/var/audio/rec',
'altaudiobase' : '/var/audio/preprod',
'calendarurl' : 'http://localhost/index.php?option=com_jimtawl&view=calendar&format=json&from=#datefrom#&to=#dateto#',
'communication': 'zmq',
'playlistdir': '/var/audio/playlists',
'archivebase': '/var/audio/archive/',
'controllerport': '9099',
'logdir' : '/var/log/comba',
'loglevel': 'info',
'securitylevel': '0',
'adminmail': '',
'frommail': '',
'calendar_precache_days': '7',
'servername': socket.getfqdn(),
'serviceport': '8080',
'stream' : "",
'stream_type' : "",
'stream_host' : "",
'stream_port' : "",
'stream_mountpoint' : "",
'stream_admin_user' : "",
'stream_admin_password' : "",
}
# readfp is deprecated since 3.2
if sys.version_info <= (3, 2):
ini_str = StringIO(ini_str)
config = RawConfigParser(self.configDefaults)
config.readfp(ini_str)
else:
config = ConfigParser(self.configDefaults)
config.read_string(ini_str)
for key, value in config.items('root'):
self.set(key, config.get('root', key).replace('"', '').strip())
#!/usr/bin/env python
"Makes working with XML feel like you are working with JSON"
from xml.parsers import expat
from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesImpl
try: # pragma no cover
from cStringIO import StringIO
except ImportError: # pragma no cover
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
try: # pragma no cover
from collections import OrderedDict
except ImportError: # pragma no cover
try:
from ordereddict import OrderedDict
except ImportError:
OrderedDict = dict
try: # pragma no cover
_basestring = str #basestring
except NameError: # pragma no cover
_basestring = bytes #str
try: # pragma no cover
_unicode = str #unicode
except NameError: # pragma no cover
_unicode = bytes #str
__author__ = 'Martin Blech'
__version__ = '0.9.0'
__license__ = 'MIT'
class ParsingInterrupted(Exception):
pass
class _DictSAXHandler(object):
def __init__(self,
item_depth=0,
item_callback=lambda *args: True,
xml_attribs=True,
attr_prefix='@',
cdata_key='#text',
force_cdata=False,
cdata_separator='',
postprocessor=None,
dict_constructor=OrderedDict,
strip_whitespace=True,
namespace_separator=':',
namespaces=None):
self.path = []
self.stack = []
self.data = None
self.item = None
self.item_depth = item_depth
self.xml_attribs = xml_attribs
self.item_callback = item_callback
self.attr_prefix = attr_prefix
self.cdata_key = cdata_key
self.force_cdata = force_cdata
self.cdata_separator = cdata_separator
self.postprocessor = postprocessor
self.dict_constructor = dict_constructor
self.strip_whitespace = strip_whitespace
self.namespace_separator = namespace_separator
self.namespaces = namespaces
def _build_name(self, full_name):
if not self.namespaces:
return full_name
i = full_name.rfind(self.namespace_separator)
if i == -1:
return full_name
namespace, name = full_name[:i], full_name[i+1:]
short_namespace = self.namespaces.get(namespace, namespace)
if not short_namespace:
return name
else:
return self.namespace_separator.join((short_namespace, name))
def _attrs_to_dict(self, attrs):
if isinstance(attrs, dict):
return attrs
return self.dict_constructor(zip(attrs[0::2], attrs[1::2]))
def startElement(self, full_name, attrs):
name = self._build_name(full_name)
attrs = self._attrs_to_dict(attrs)
self.path.append((name, attrs or None))
if len(self.path) > self.item_depth:
self.stack.append((self.item, self.data))
if self.xml_attribs:
attrs = self.dict_constructor(
(self.attr_prefix+key, value)
for (key, value) in attrs.items())
else:
attrs = None
self.item = attrs or None
self.data = None
def endElement(self, full_name):
name = self._build_name(full_name)
if len(self.path) == self.item_depth:
item = self.item
if item is None:
item = self.data
should_continue = self.item_callback(self.path, item)
if not should_continue:
raise ParsingInterrupted()
if len(self.stack):
item, data = self.item, self.data
self.item, self.data = self.stack.pop()
if self.strip_whitespace and data is not None:
data = data.strip() or None
if data and self.force_cdata and item is None:
item = self.dict_constructor()
if item is not None:
if data:
self.push_data(item, self.cdata_key, data)
self.item = self.push_data(self.item, name, item)
else:
self.item = self.push_data(self.item, name, data)
else:
self.item = self.data = None
self.path.pop()
def characters(self, data):
if not self.data:
self.data = data
else:
self.data += self.cdata_separator + data
def push_data(self, item, key, data):
if self.postprocessor is not None:
result = self.postprocessor(self.path, key, data)
if result is None:
return item
key, data = result
if item is None:
item = self.dict_constructor()
try:
value = item[key]
if isinstance(value, list):
value.append(data)
else:
item[key] = [value, data]
except KeyError:
item[key] = data
return item
def parsexml(xml_input, encoding=None, expat=expat, process_namespaces=False,
namespace_separator=':', **kwargs):
"""Parse the given XML input and convert it into a dictionary.
`xml_input` can either be a `string` or a file-like object.
If `xml_attribs` is `True`, element attributes are put in the dictionary
among regular child elements, using `@` as a prefix to avoid collisions. If
set to `False`, they are just ignored.
Simple example::
>>> import xmltodict
>>> doc = xmltodict.parse(\"\"\"
... <a prop="x">
... <b>1</b>
... <b>2</b>
... </a>
... \"\"\")
>>> doc['a']['@prop']
u'x'
>>> doc['a']['b']
[u'1', u'2']
If `item_depth` is `0`, the function returns a dictionary for the root
element (default behavior). Otherwise, it calls `item_callback` every time
an item at the specified depth is found and returns `None` in the end
(streaming mode).
The callback function receives two parameters: the `path` from the document
root to the item (name-attribs pairs), and the `item` (dict). If the
callback's return value is false-ish, parsing will be stopped with the
:class:`ParsingInterrupted` exception.
Streaming example::
>>> def handle(path, item):
... print 'path:%s item:%s' % (path, item)
... return True
...
>>> xmltodict.parse(\"\"\"
... <a prop="x">
... <b>1</b>
... <b>2</b>
... </a>\"\"\", item_depth=2, item_callback=handle)
path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:1
path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:2
The optional argument `postprocessor` is a function that takes `path`,
`key` and `value` as positional arguments and returns a new `(key, value)`
pair where both `key` and `value` may have changed. Usage example::
>>> def postprocessor(path, key, value):
... try:
... return key + ':int', int(value)
... except (ValueError, TypeError):
... return key, value
>>> xmltodict.parse('<a><b>1</b><b>2</b><b>x</b></a>',
... postprocessor=postprocessor)
OrderedDict([(u'a', OrderedDict([(u'b:int', [1, 2]), (u'b', u'x')]))])
You can pass an alternate version of `expat` (such as `defusedexpat`) by
using the `expat` parameter. E.g:
>>> import defusedexpat
>>> xmltodict.parse('<a>hello</a>', expat=defusedexpat.pyexpat)
OrderedDict([(u'a', u'hello')])
"""
handler = _DictSAXHandler(namespace_separator=namespace_separator,
**kwargs)
if isinstance(xml_input, _unicode):
if not encoding:
encoding = 'utf-8'
xml_input = xml_input.encode(encoding)
if not process_namespaces:
namespace_separator = None
parser = expat.ParserCreate(
encoding,
namespace_separator
)
try:
parser.ordered_attributes = True
except AttributeError:
# Jython's expat does not support ordered_attributes
pass
parser.StartElementHandler = handler.startElement
parser.EndElementHandler = handler.endElement
parser.CharacterDataHandler = handler.characters
parser.buffer_text = True
try:
parser.ParseFile(xml_input)
except (TypeError, AttributeError):
parser.Parse(xml_input, True)
return handler.item
def _emit(key, value, content_handler,
attr_prefix='@',
cdata_key='#text',
depth=0,
preprocessor=None,
pretty=False,
newl='\n',
indent='\t'):
if preprocessor is not None:
result = preprocessor(key, value)
if result is None:
return
key, value = result
if not isinstance(value, (list, tuple)):
value = [value]
if depth == 0 and len(value) > 1:
raise ValueError('document with multiple roots')
for v in value:
if v is None:
v = OrderedDict()
elif not isinstance(v, dict):
v = _unicode(v)
if isinstance(v, _basestring):
v = OrderedDict(((cdata_key, v),))
cdata = None
attrs = OrderedDict()
children = []
for ik, iv in v.items():
if ik == cdata_key:
cdata = iv
continue
if ik.startswith(attr_prefix):
attrs[ik[len(attr_prefix):]] = iv
continue
children.append((ik, iv))
if pretty:
content_handler.ignorableWhitespace(depth * indent)
content_handler.startElement(key, AttributesImpl(attrs))
if pretty and children:
content_handler.ignorableWhitespace(newl)
for child_key, child_value in children:
_emit(child_key, child_value, content_handler,
attr_prefix, cdata_key, depth+1, preprocessor,
pretty, newl, indent)
if cdata is not None:
content_handler.characters(cdata)
if pretty and children:
content_handler.ignorableWhitespace(depth * indent)
content_handler.endElement(key)
if pretty and depth:
content_handler.ignorableWhitespace(newl)
def unparse(input_dict, output=None, encoding='utf-8', full_document=True, **kwargs):
"""Emit an XML document for the given `input_dict` (reverse of `parse`).
The resulting XML document is returned as a string, but if `output`
(afile-like object) is specified, it is written there instead.
Dictionary keys prefixed with `attr_prefix` (default=`'@'`) are interpreted
as XML node attributes, whereas keys equal to `cdata_key`
(default=`'#text'`) are treated as character data.
The `pretty` parameter (default=`False`) enables pretty-printing. In this
mode, lines are terminated with `'\n'` and indented with `'\t'`, but this
can be customized with the `newl` and `indent` parameters.
"""
((key, value),) = input_dict.items()
must_return = False
if output is None:
output = StringIO()
must_return = True
content_handler = XMLGenerator(output, encoding)
if full_document:
content_handler.startDocument()
_emit(key, value, content_handler, **kwargs)
if full_document:
content_handler.endDocument()
if must_return:
value = output.getvalue()
try: # pragma no cover
value = value.decode(encoding)
except AttributeError: # pragma no cover
pass
return value
if __name__ == '__main__': # pragma: no cover
import sys
import marshal
(item_depth,) = sys.argv[1:]
item_depth = int(item_depth)
def handle_item(path, item):
marshal.dump((path, item), sys.stdout)
return True
try:
root = parsexml(sys.stdin,
item_depth=item_depth,
item_callback=handle_item,
dict_constructor=dict)
if item_depth == 0:
handle_item([], root)
except KeyboardInterrupt:
pass
from xml.dom.minidom import parse
import datetime
from datetime import timedelta
import simplejson
from xml.etree import ElementTree
class NotTextNodeError(BaseException):
pass
class AuraSchedulerConfig():
def __init__(self, xmlpath):
self.jobs = {}
self.filename = xmlpath
self.playperiods = []
self.recordperiods = []
self.hasinstance = False
self.until = None
# -----------------------------------------------------------------------#
def getPlayPeriods(self):
if not self.hasinstance:
self.getJobs()
return self.playperiods
# -----------------------------------------------------------------------#
def getRecordPeriods(self):
if not self.hasinstance:
self.getJobs()
return self.recordperiods
# -----------------------------------------------------------------------#
def getJobs(self):
self.hasinstance = True
self.loadXml()
for job in self.jobs:
if 'job' not in job:
continue;
if 'until' not in job:
job['until'] = ''
if 'day' not in job:
job['day'] = 'all'
# self.jobs.sort(cmp=lambda x,y: cmp(x['time'], y['time']))
# self.jobs.sort(cmp=lambda x,y: cmp(x['day'], y['day']))
self.jobs.sort(key=lambda job: job['time'])
self.jobs.sort(key=lambda job: job['day'])
for index, job in enumerate(self.jobs):
if job['job'] == 'play_playlist':
job['duration'] = self._calcDuration(job['time'], job['until'])
self.playperiods.append({'from': job['time'],'until': job['until'], 'duration': job['duration']})
day = None
if 'day' in job:
day = job['day']
self.addPlaylistLoadJob(job['time'], job['until'], day)
if job['job'] == 'start_recording':
job['duration'] = self._calcDuration(job['time'], job['until'])
self.recordperiods.append({'from': job['time'],'until': job['until'], 'duration': job['duration']})
return self.jobs
# -----------------------------------------------------------------------#
def addPlaylistLoadJob(self, playTime, untilTime, day=None):
job = {}
playStart = datetime.datetime.strptime('1901-01-01T' + playTime,'%Y-%m-%dT%H:%M');
loadTime = playStart - timedelta(minutes=3)
loadTime = loadTime.strftime('%H:%M')
job['time'] = loadTime
job['from'] = playTime
job['until'] = untilTime
job['job'] = 'load_playlist'
if day and not day == 'all' and loadTime > playTime:
day = int(day)
day = 6 if day == 0 else day - 1
job['day'] = str(day)
self.jobs.append(job)
# -----------------------------------------------------------------------#
def storeJsonToXml(self, json):
try:
jobs = simplejson.loads(json)
except:
return False
xml = '<?xml version="1.0" encoding="UTF-8"?>'+"\n"
xml += '<Config>'+"\n";
xml += ' <Jobs multiple="true">'+"\n";
xmlend = ' </Jobs>'+"\n";
xmlend += '</Config>';
for job in jobs:
xml+= ' <job>'+"\n";
for key in job.keys():
xml+= ' <'+key+'>'+str(job[key])+'</'+key+'>'+"\n"
if not job.has_key('params'):
xml+= ' <params></params>'+"\n"
if not job.has_key('day'):
xml+= ' <day>all</day>'+"\n"
xml+= ' </job>'+"\n"
# validate xml
try:
x = ElementTree.fromstring(xml+xmlend)
except:
return False
else:
try:
file = open(self.filename, "w")
file.write(xml+xmlend)
file.close()
except:
return False
else:
return True
# -----------------------------------------------------------------------#
def loadXml(self):
dom = parse(self.filename)
config = self.nodeToDic(dom)
self.jobs = config['Config']['Jobs']
# -----------------------------------------------------------------------#
def getTextFromNode(self, node):
t = ""
for n in node.childNodes:
if n.nodeType == n.TEXT_NODE:
t += n.nodeValue
else:
raise NotTextNodeError
return t
# -----------------------------------------------------------------------#
def nodeToDic(self, node):
dic = {}
for n in node.childNodes:
if n.nodeType != n.ELEMENT_NODE:
continue
if n.getAttribute("multiple") == "true":
# node with multiple children:
# put them in a list
l = []
for c in n.childNodes:
if c.nodeType != n.ELEMENT_NODE:
continue
l.append(self.nodeToDic(c))
dic.update({n.nodeName: l})
continue
try:
text = self.getTextFromNode(n)
except NotTextNodeError:
# 'normal' node
dic.update({str(n.nodeName): self.nodeToDic(n)})
continue
# text node
dic.update({str(n.nodeName): str(text)})
continue
return dic
# -----------------------------------------------------------------------#
def in_timeperiod(self, now, job):
if 'until' not in job or not job['until']:
print("not in timeperiod")
return False
(hour1, minute1) = job['time'].split(':')
(hour2, minute2) = job['until'].split(':')
if job['time'] > job['until']:
print("in time period. time greater than until")
return datetime.time(hour=int(hour1), minute=int(minute1)) \
<= now.time()
else:
print("in time period. until greater than time")
return datetime.time(hour=int(hour1), minute=int(minute1)) \
<= now.time() \
<= datetime.time(hour=int(hour2), minute=int(minute2))
# -----------------------------------------------------------------------#
def _calcDuration(self, timestring1, timestring2):
"""Berechnet Zeit in Sekunden aus zwei Time-Strings
"""
ftr = [3600, 60, 1]
sec1 = sum([a * b for a, b in zip(ftr, map(int, timestring1.split(':')))])
sec2 = sum([a * b for a, b in zip(ftr, map(int, timestring2.split(':')))])
offset = 0 if sec2 > sec1 else 86400
return (sec2 + offset) - sec1
# -----------------------------------------------------------------------#
def find_next(self, items, index, key, value):
for idx, item in enumerate(items):
if idx <= index:
continue
if item[key] == value:
return idx
return self.find_next(items,0,key,value)
# -*- coding: utf-8 -*-
import sys
import simplejson
import urllib
"""
Die AuraClient Klasse stellt die Tasks zur Verfügung,
die dem Playlout Controller übertragen werden können
Dies ist im Wesentlichen ein Wrapper
"""
class AuraClient():
def __init__(self, sender):
"""
Constructor
@type sender: object
@param sender: Der Communicator Adapter - z-B. zmq
"""
self.sender = sender
# ------------------------------------------------------------------------------------------ #
def command(self, command):
"""
Kommando an den Controller absetzen
und Antwort entgegennehmen
@type command: string
@param command: Kommando
@rtype: string
@return: Antwort des Controllers
"""
self.sender.send(command)
message = self.sender.receive()
return message
# ------------------------------------------------------------------------------------------ #
def channel_skip(self, channel):
"""
Skipt einen Kanal oder die Playlist
@type channel: string
@param channel: Kanal
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_skip ' + channel)
# ------------------------------------------------------------------------------------------ #
def channel_is_active(self, channel='playlist'):
"""
Ist der Kanal aktiv?
@type channel: string
@param channel: Kanal
@rtype: boolean
@return: True/False
"""
state = self._get_channel_state(channel)
is_active = True if state['selected'] == 'true' else False
return is_active
# ------------------------------------------------------------------------------------------ #
def channel_on(self, channel):
"""
Kanal einschalten
@type channel: string
@param channel: Kanal
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_on ' + channel)
# ------------------------------------------------------------------------------------------ #
def channel_off(self, channel):
"""
Kanal ausschalten
@type channel: string
@param channel: Kanal
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_off ' + channel)
# ------------------------------------------------------------------------------------------ #
def get_channellist(self):
"""
Channels als Liste ausgeben
@rtype: list
@return: Antwort des Controllers
"""
return simplejson.loads(self.command('listChannels'))
# ------------------------------------------------------------------------------------------ #
def get_channelqueue(self, channel):
"""
Channel Queue ausgeben
@type channel: string
@param channel: Kanal
@rtype: dict
@return: Antwort des Controllers
"""
return simplejson.loads(self.command('channel_queue ' + channel))
# ------------------------------------------------------------------------------------------ #
def get_channel_volume(self, channel='playlist'):
"""
Lautstärke des Kanals ausgeben
@type channel: string
@param channel: Kanal
@rtype: string/boolean
@return: Volumen von 1-100/False
"""
state = self._get_channel_state(channel)
channels = simplejson.loads(self.command('allData'))
try:
volume = state['volume']
except KeyError:
return False
else:
return volume
return False
# ------------------------------------------------------------------------------------------ #
def channel_remove_track(self, channel, track_pos):
"""
Löscht einen Track aus dem secondary_queue
@type channel: string
@param channel: Kanal
@type track_pos: string/int
@param track_pos: Position des zu entfernenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_remove ' + channel + ' ' + str(track_pos))
# ------------------------------------------------------------------------------------------ #
def channel_seek(self, channel, duration):
"""
Spult den laufenen Track des Kanals <duration> Sekunden weiter (falls möglich)
Beispiel: channel_seek('ch1',60) - 60 Sekunden nach vorne
@type channel: string
@param channel: Kanal
@type duration: string/int
@param duration: Dauer in Sekunden
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_seek ' + channel + ' ' + str(duration))
# ------------------------------------------------------------------------------------------ #
def channel_track_up(self, channel, track_pos):
"""
Einen Track um eine Position nach oben schieben
@type channel: string
@param channel: Kanal
@type track_pos: string
@param track_pos: Position des zu verschiebenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_move ' + channel + ' ' + str(track_pos) + ' ' + str(track_pos - 1))
# ------------------------------------------------------------------------------------------ #
def channel_track_down(self, channel, track_pos):
"""
Einen Track um eine Position nach unten schieben
@type channel: string
@param channel: Kanal
@type track_pos: string
@param track_pos: Position des zu verschiebenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_move ' + channel + ' ' + str(track_pos) + ' ' + str(track_pos + 1))
# ------------------------------------------------------------------------------------------ #
def channel_track_insert(self, channel, uri, pos=0):
"""
Uri eines Audios in den (secondary) queue einfügen
@type channel: string
@param channel: Kanal
@type uri: string
@param uri: uri, z.b. file:///my/audio/song.mp3
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_insert ' + channel + ' ' + urllib.quote(uri) + ' ' + str(pos))
# ------------------------------------------------------------------------------------------ #
def channel_set_volume(self, channel, volume):
"""
Lautstärke setzen (Prozentual von 1 - 100
@type channel: string
@param channel: Kanal
@type volume: string/int
@param volume: Zahl von 1 bis 100
@rtype: string
@return: Antwort des Controllers
"""
return self.command('channel_volume ' + channel + ' ' + str(volume))
# ------------------------------------------------------------------------------------------ #
def _get_channel_state(self, channel):
"""
Private: Status eines Kanals abfragen
Ausgabe Beispiel: {'ready':'true', 'selected:'false', 'single':'false','volume':'100%','remaining:'0.00'}
@type channel: string
@param channel: Kanal
@rtype: dict/boolen
@return: Antwort des Controllers/ False
"""
data = simplejson.loads(self.command('allData'))
if not isinstance(data, dict):
# es wurde kein assoz. Array/dict zurückgegeben
return False
if data['success'] != 'success':
# die Abfrage war nicht erfolgreich
return False
if not data.has_key('value'):
# es wurden keine Werte geliefert
return False
channels = data['value']
if not isinstance(channels, dict):
# es wurde kein assoz. Array/dict zurückgegeben
return False
if channels.has_key(channel):
chan = channels[channel]
try:
state = chan['state']
except KeyError:
return False
else:
return state
else:
return False
# ------------------------------------------------------------------------------------------ #
def playlist_load(self, uri):
"""
Playlist im XSPF-Format laden
@type uri: string
@param uri: Uri einer Playlist - z.B. /my/playlists/2014-12-22-12-00.xspf
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_load ' + str(uri))
# ------------------------------------------------------------------------------------------ #
def playlist_data(self):
"""
Gibt die aktuelle Playlist als dict zurück
@rtype: dict
@return: Antwort des Controllers
"""
return simplejson.loads(self.command('playlist_data'))
# ------------------------------------------------------------------------------------------ #
def playlist_flush(self):
"""
Leert die Playlist
@rtype: dict
@return: Antwort des Controllers
"""
return self.command('playlist_flush')
# ------------------------------------------------------------------------------------------ #
def playlist_insert(self, uri, pos):
"""
Audio in Playlist einfügen
@type uri: string
@param uri: Uri einer Audiodatei - z.B. /my/audio/song.mp3
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_insert ' + uri + ' ' + pos)
# ------------------------------------------------------------------------------------------ #
def playlist_track_up(self, track_pos):
"""
Einen Track der Playlist um eine Position nach oben schieben
@type track_pos: string
@param track_pos: Position des zu verschiebenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_move ' + str(track_pos) + ' ' + str(track_pos - 1))
# ------------------------------------------------------------------------------------------ #
def playlist_track_down(self, track_pos):
"""
Einen Track der Playlist um eine Position nach unten schieben
@type track_pos: string
@param track_pos: Position des zu verschiebenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
self.command('playlist_move ' + str(track_pos) + ' ' + str(track_pos + 1))
# ------------------------------------------------------------------------------------------ #
def playlist_pause(self):
"""
Playlist anhalten
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_pause')
# ------------------------------------------------------------------------------------------ #
def playlist_stop(self):
"""
Playlist stoppen
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_stop')
# ------------------------------------------------------------------------------------------ #
def playlist_play(self):
"""
Playlist starten/abspielen
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_play')
# ------------------------------------------------------------------------------------------ #
def playlist_remove_track(self, track_pos):
"""
Löscht einen Track der Playlist
Hinweis: Der laufende Track wird nicht berücksichtigt
@type track_pos: string/int
@param track_pos: Position des zu entfernenden Eintrags
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_remove ' + str(track_pos))
# ------------------------------------------------------------------------------------------ #
def playlist_seek(self, duration):
"""
Spult den laufenden Track der Playlist <duration> Sekunden weiter (falls möglich)
Beispiel: playlist_seek('ch1',60) - 60 Sekunden nach vorne
@type duration: string/int
@param duration: Dauer in Sekunden
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_seek ' + str(duration))
# ------------------------------------------------------------------------------------------ #
def playlist_skip(self):
"""
Skipt den laufenden Track der Playlist
@rtype: string
@return: Antwort des Controllers
"""
return self.command('playlist_skip')
# ------------------------------------------------------------------------------------------ #
def recorder_start(self):
"""
Recorder starten
@rtype: string
@return: Antwort des Controllers
"""
return self.command('recorder_start')
# ------------------------------------------------------------------------------------------ #
def recorder_stop(self):
"""
Recorder stoppen
@rtype: string
@return: Antwort des Controllers
"""
return self.command('recorder_stop')
def recorder_data(self):
"""
Daten der aktuellen Aufnahme abrufen
Beispiel: {'file':'/my/audio/2014-12-22-12-00.wav', 'recorded': '25'} - Die Aufnahme der Datei /my/audio/2014-12-22-12-00.wav ist bei 25%
@rtype: dict
@return: Antwort des Controllers
"""
return simplejson.loads(self.command('recorder_data'))
\ No newline at end of file