split display centre into actions, display and numpad input. lots of refactoring along the way

This commit is contained in:
ben-caldwell
2017-12-27 23:27:43 +13:00
parent 6570ad3823
commit 4b2c086e7d
25 changed files with 1190 additions and 959 deletions

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/r_e_c_u_r.iml" filepath="$PROJECT_DIR$/.idea/r_e_c_u_r.iml" />
</modules>
</component>
</project>

13
.idea/r_e_c_u_r.iml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

633
.idea/workspace.xml generated Normal file
View File

@@ -0,0 +1,633 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="908505e2-8b2f-4abb-8017-7a9728876708" name="Default" comment="">
<change beforePath="" afterPath="$PROJECT_DIR$/data_objects/key_map.json" />
<change beforePath="" afterPath="$PROJECT_DIR$/display_centre/display.py" />
<change beforePath="" afterPath="$PROJECT_DIR$/user_input/actions.py" />
<change beforePath="" afterPath="$PROJECT_DIR$/user_input/numpad_input.py" />
<change beforePath="$PROJECT_DIR$/data_centre.py" afterPath="$PROJECT_DIR$/data_centre.py" />
<change beforePath="$PROJECT_DIR$/display_centre.py" afterPath="$PROJECT_DIR$/r_e_c_u_r.py" />
<change beforePath="$PROJECT_DIR$/display_data.json" afterPath="$PROJECT_DIR$/data_objects/display_data.json" />
<change beforePath="$PROJECT_DIR$/launcher.sh" afterPath="$PROJECT_DIR$/scripts/launcher.sh" />
<change beforePath="$PROJECT_DIR$/next_bank_number.json" afterPath="$PROJECT_DIR$/data_objects/next_bank_number.json" />
<change beforePath="$PROJECT_DIR$/old-omxdriver.py" afterPath="" />
<change beforePath="$PROJECT_DIR$/omxdriver.py" afterPath="" />
<change beforePath="$PROJECT_DIR$/pi_dev_mode.json" afterPath="" />
<change beforePath="$PROJECT_DIR$/settings.json" afterPath="$PROJECT_DIR$/data_objects/settings.json" />
<change beforePath="$PROJECT_DIR$/switch_to_display.sh" afterPath="$PROJECT_DIR$/scripts/switch_to_display.sh" />
<change beforePath="$PROJECT_DIR$/switch_to_hdmi.sh" afterPath="$PROJECT_DIR$/scripts/switch_to_hdmi.sh" />
<change beforePath="$PROJECT_DIR$/video_driver.py" afterPath="$PROJECT_DIR$/video_centre/videodriver.py" />
<change beforePath="$PROJECT_DIR$/video_player.py" afterPath="$PROJECT_DIR$/video_centre/video_player.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="375">
<file leaf-file-name="r_e_c_u_r.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/r_e_c_u_r.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-41">
<caret line="16" column="0" lean-forward="true" selection-start-line="16" selection-start-column="0" selection-end-line="16" selection-end-column="0" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="numpad_input.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/user_input/numpad_input.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="247">
<caret line="40" column="41" lean-forward="true" selection-start-line="40" selection-start-column="41" selection-end-line="40" selection-end-column="41" />
<folding>
<element signature="e#806#1113#0" expanded="false" />
<element signature="e#1843#1877#0" expanded="false" />
<element signature="e#1916#1949#0" expanded="false" />
<element signature="e#1989#1993#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="display.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/display_centre/display.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="275">
<caret line="23" column="47" lean-forward="true" selection-start-line="23" selection-start-column="47" selection-end-line="23" selection-end-column="47" />
<folding>
<element signature="e#0#29#0" expanded="true" />
<element signature="e#955#1016#0" expanded="false" />
<element signature="e#1050#1504#0" expanded="false" />
<element signature="e#1542#1961#0" expanded="false" />
<element signature="e#1997#2131#0" expanded="false" />
<element signature="e#2168#2562#0" expanded="false" />
<element signature="e#3187#3733#0" expanded="false" />
<element signature="e#3771#3966#0" expanded="false" />
<element signature="e#4004#4538#0" expanded="false" />
<element signature="e#4587#4724#0" expanded="false" />
<element signature="e#4775#4918#0" expanded="false" />
<element signature="e#4970#5520#0" expanded="false" />
<element signature="e#5609#6199#0" expanded="false" />
<element signature="e#6240#6609#0" expanded="false" />
<element signature="e#6648#6756#0" expanded="false" />
<element signature="e#6817#7009#0" expanded="false" />
<element signature="e#7052#7480#0" expanded="false" />
<element signature="e#7521#7842#0" expanded="false" />
<element signature="e#7881#8325#0" expanded="false" />
<element signature="e#8849#9178#0" expanded="false" />
<element signature="e#9218#9294#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="actions.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/user_input/actions.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="413">
<caret line="30" column="0" lean-forward="true" selection-start-line="30" selection-start-column="0" selection-end-line="30" selection-end-column="0" />
<folding>
<element signature="e#240#272#0" expanded="false" />
<element signature="e#405#433#0" expanded="false" />
<element signature="e#748#777#0" expanded="false" />
<element signature="e#819#923#0" expanded="false" />
<element signature="e#986#1074#0" expanded="false" />
<element signature="e#1119#1155#0" expanded="false" />
<element signature="e#1199#1497#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="videodriver.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/video_centre/videodriver.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="300">
<caret line="12" column="22" lean-forward="true" selection-start-line="12" selection-start-column="22" selection-end-line="12" selection-end-column="22" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="video_player.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/video_centre/video_player.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="125">
<caret line="5" column="0" lean-forward="false" selection-start-line="4" selection-start-column="2" selection-end-line="5" selection-end-column="0" />
<folding>
<element signature="e#229#2801#0" expanded="false" />
<element signature="e#666#999#0" expanded="false" />
<element signature="e#1039#1249#0" expanded="false" />
<element signature="e#1279#1400#0" expanded="false" />
<element signature="e#1438#1705#0" expanded="false" />
<element signature="e#1737#1801#0" expanded="false" />
<element signature="e#1836#1866#0" expanded="false" />
<element signature="e#1903#1935#0" expanded="false" />
<element signature="e#1973#2119#0" expanded="false" />
<element signature="e#2167#2443#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="data_centre.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/data_centre.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="183">
<caret line="222" column="4" lean-forward="false" selection-start-line="222" selection-start-column="4" selection-end-line="222" selection-end-column="4" />
<folding>
<element signature="e#0#11#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>refr</find>
<find>data_ob</find>
<find>self.display</find>
<find>self.display</find>
<find>settings</find>
<find>video_driver</find>
<find>browser_start_index</find>
<find>MAX_LINES</find>
<find>data_object</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$/startup.py" />
<option value="$PROJECT_DIR$/display_centre.py" />
<option value="$PROJECT_DIR$/data_objects/display_data.json" />
<option value="$PROJECT_DIR$/data_objects/key_map.json" />
<option value="$PROJECT_DIR$/display_centre/navigation.py" />
<option value="$PROJECT_DIR$/display_centre/actions.py" />
<option value="$PROJECT_DIR$/r_e_c_u_r.py" />
<option value="$PROJECT_DIR$/data_centre.py" />
<option value="$PROJECT_DIR$/video_centre/video_player.py" />
<option value="$PROJECT_DIR$/video_centre/videodriver.py" />
<option value="$PROJECT_DIR$/display_centre/display.py" />
<option value="$PROJECT_DIR$/user_input/numpad_input.py" />
<option value="$PROJECT_DIR$/user_input/actions.py" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="343" />
<option name="y" value="424" />
<option name="width" value="1400" />
<option name="height" value="990" />
</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="r_e_c_u_r" type="b2602c69:ProjectViewProjectNode" />
<item name="r_e_c_u_r" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="r_e_c_u_r" type="b2602c69:ProjectViewProjectNode" />
<item name="r_e_c_u_r" type="462c0819:PsiDirectoryNode" />
<item name="data_objects" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="r_e_c_u_r" type="b2602c69:ProjectViewProjectNode" />
<item name="r_e_c_u_r" type="462c0819:PsiDirectoryNode" />
<item name="display_centre" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="r_e_c_u_r" type="b2602c69:ProjectViewProjectNode" />
<item name="r_e_c_u_r" type="462c0819:PsiDirectoryNode" />
<item name="user_input" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="r_e_c_u_r" type="b2602c69:ProjectViewProjectNode" />
<item name="r_e_c_u_r" type="462c0819:PsiDirectoryNode" />
<item name="video_centre" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$/display_centre/display.py" />
<property name="settings.editor.selected.configurable" value="configurable.group.tools" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\r_e_c_u_r\data_objects" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\r_e_c_u_r\user_input\" />
<recent name="C:\r_e_c_u_r\scripts" />
<recent name="C:\r_e_c_u_r\data_objects\" />
<recent name="C:\r_e_c_u_r\video_centre" />
</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.r_e_c_u_r">
<configuration name="Unnamed" 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="C:\r_e_c_u_r\venv\Scripts\python.exe" />
<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="r_e_c_u_r" />
<option name="SCRIPT_NAME" value="" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
</configuration>
<configuration name="display_centre" 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="r_e_c_u_r" />
<option name="SCRIPT_NAME" value="C:\r_e_c_u_r\r_e_c_u_r.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
</configuration>
<configuration name="r_e_c_u_r" 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="r_e_c_u_r" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/r_e_c_u_r.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
</configuration>
<list size="3">
<item index="0" class="java.lang.String" itemvalue="Python.Unnamed" />
<item index="1" class="java.lang.String" itemvalue="Python.display_centre" />
<item index="2" class="java.lang.String" itemvalue="Python.r_e_c_u_r" />
</list>
<recent_temporary>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="Python.r_e_c_u_r" />
<item index="1" class="java.lang.String" itemvalue="Python.display_centre" />
</list>
</recent_temporary>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="908505e2-8b2f-4abb-8017-7a9728876708" name="Default" comment="" />
<created>1514007090883</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1514007090883</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="-9" y="-9" width="1938" height="1048" extended-state="6" />
<editor active="true" />
<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.1796875" 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="7" 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.32928178" sideWeight="0.5" order="1" 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="7" 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.32928178" sideWeight="0.5" order="2" 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="7" 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="Debug" 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="3" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout>
<layout-to-restore>
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="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="8" side_tool="false" content_ui="tabs" />
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32928178" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.1796875" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<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="Debug" 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="3" side_tool="false" content_ui="tabs" />
</layout-to-restore>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<option name="time" value="3" />
</breakpoint-manager>
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/r_e_c_u_r.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/omxdriver.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$/video_centre.py" />
<entry file="file://$PROJECT_DIR$/omxdriver.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$/r_e_c_u_r.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2163">
<caret line="224" column="15" lean-forward="false" selection-start-line="224" selection-start-column="15" selection-end-line="224" selection-end-column="15" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/omxdriver.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$/video_centre.py" />
<entry file="file://$PROJECT_DIR$/r_e_c_u_r.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="575">
<caret line="23" column="34" lean-forward="false" selection-start-line="23" selection-start-column="34" selection-end-line="23" selection-end-column="34" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/data_objects/key_map_old.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="75">
<caret line="3" column="0" lean-forward="false" selection-start-line="3" selection-start-column="0" selection-end-line="4" selection-end-column="15" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/data_objects/display_data.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="175">
<caret line="7" column="3" lean-forward="false" selection-start-line="7" selection-start-column="3" selection-end-line="7" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/data_objects/key_map.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="25">
<caret line="1" column="9" lean-forward="false" selection-start-line="1" selection-start-column="9" selection-end-line="1" selection-end-column="9" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/user_input/actions.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="234">
<caret line="17" column="67" lean-forward="false" selection-start-line="17" selection-start-column="67" selection-end-line="17" selection-end-column="67" />
<folding>
<element signature="e#240#272#0" expanded="false" />
<element signature="e#405#433#0" expanded="false" />
<element signature="e#748#777#0" expanded="false" />
<element signature="e#819#923#0" expanded="false" />
<element signature="e#986#1074#0" expanded="false" />
<element signature="e#1119#1155#0" expanded="false" />
<element signature="e#1199#1497#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://C:/Program Files (x86)/Python36-32/Lib/tkinter/constants.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="291">
<caret line="62" column="0" lean-forward="false" selection-start-line="62" selection-start-column="0" selection-end-line="62" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/data_objects/path_to_browser.json">
<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$/video_centre/videodriver.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="300">
<caret line="12" column="22" lean-forward="true" selection-start-line="12" selection-start-column="22" selection-end-line="12" selection-end-column="22" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/video_centre/video_player.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="125">
<caret line="5" column="0" lean-forward="false" selection-start-line="4" selection-start-column="2" selection-end-line="5" selection-end-column="0" />
<folding>
<element signature="e#229#2801#0" expanded="false" />
<element signature="e#666#999#0" expanded="false" />
<element signature="e#1039#1249#0" expanded="false" />
<element signature="e#1279#1400#0" expanded="false" />
<element signature="e#1438#1705#0" expanded="false" />
<element signature="e#1737#1801#0" expanded="false" />
<element signature="e#1836#1866#0" expanded="false" />
<element signature="e#1903#1935#0" expanded="false" />
<element signature="e#1973#2119#0" expanded="false" />
<element signature="e#2167#2443#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/user_input/numpad_input.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="247">
<caret line="40" column="41" lean-forward="true" selection-start-line="40" selection-start-column="41" selection-end-line="40" selection-end-column="41" />
<folding>
<element signature="e#806#1113#0" expanded="false" />
<element signature="e#1843#1877#0" expanded="false" />
<element signature="e#1916#1949#0" expanded="false" />
<element signature="e#1989#1993#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/user_input/actions.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="413">
<caret line="30" column="0" lean-forward="true" selection-start-line="30" selection-start-column="0" selection-end-line="30" selection-end-column="0" />
<folding>
<element signature="e#240#272#0" expanded="false" />
<element signature="e#405#433#0" expanded="false" />
<element signature="e#748#777#0" expanded="false" />
<element signature="e#819#923#0" expanded="false" />
<element signature="e#986#1074#0" expanded="false" />
<element signature="e#1119#1155#0" expanded="false" />
<element signature="e#1199#1497#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/display_centre/display.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="275">
<caret line="23" column="47" lean-forward="true" selection-start-line="23" selection-start-column="47" selection-end-line="23" selection-end-column="47" />
<folding>
<element signature="e#0#29#0" expanded="true" />
<element signature="e#955#1016#0" expanded="false" />
<element signature="e#1050#1504#0" expanded="false" />
<element signature="e#1542#1961#0" expanded="false" />
<element signature="e#1997#2131#0" expanded="false" />
<element signature="e#2168#2562#0" expanded="false" />
<element signature="e#3187#3733#0" expanded="false" />
<element signature="e#3771#3966#0" expanded="false" />
<element signature="e#4004#4538#0" expanded="false" />
<element signature="e#4587#4724#0" expanded="false" />
<element signature="e#4775#4918#0" expanded="false" />
<element signature="e#4970#5520#0" expanded="false" />
<element signature="e#5609#6199#0" expanded="false" />
<element signature="e#6240#6609#0" expanded="false" />
<element signature="e#6648#6756#0" expanded="false" />
<element signature="e#6817#7009#0" expanded="false" />
<element signature="e#7052#7480#0" expanded="false" />
<element signature="e#7521#7842#0" expanded="false" />
<element signature="e#7881#8325#0" expanded="false" />
<element signature="e#8849#9178#0" expanded="false" />
<element signature="e#9218#9294#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/data_centre.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="183">
<caret line="222" column="4" lean-forward="false" selection-start-line="222" selection-start-column="4" selection-end-line="222" selection-end-column="4" />
<folding>
<element signature="e#0#11#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/r_e_c_u_r.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-41">
<caret line="16" column="0" lean-forward="true" selection-start-line="16" selection-start-column="0" selection-end-line="16" selection-end-column="0" />
<folding>
<element signature="e#0#16#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project>

View File

@@ -66,7 +66,7 @@ def get_path_to_browser():
logger = setup_logging() logger = setup_logging()
######## sets paths and constants ######## ######## sets paths and constants ########
PATH_TO_DATA_OBJECTS = get_the_current_dir_path() PATH_TO_DATA_OBJECTS = '{}\\data_objects\\'.format(get_the_current_dir_path())
PATH_TO_BROWSER = get_path_to_browser() PATH_TO_BROWSER = get_path_to_browser()
EMPTY_BANK = dict(name='',location='',length=-1,start=-1,end=-1) EMPTY_BANK = dict(name='',location='',length=-1,start=-1,end=-1)
DEV_MODE = read_json(SETTINGS_JSON)[6]["value"] DEV_MODE = read_json(SETTINGS_JSON)[6]["value"]

View File

@@ -0,0 +1,107 @@
[
{
"start": -1,
"length": 4,
"end": -1,
"name": "samplerloop3s.mp4",
"location": "/media/pi/TIM1/samplerloop3s.mp4"
},
{
"start": -1,
"length": 3,
"end": -1,
"name": "teaser1.mp4",
"location": "/media/pi/TIM1/teaser1.mp4"
},
{
"start": -1,
"length": 3,
"end": -1,
"name": "teaser2.mp4",
"location": "/media/pi/TIM1/teaser2.mp4"
},
{
"start": -1,
"length": 3,
"end": -1,
"name": "teaser3.mp4",
"location": "/media/pi/TIM1/teaser3.mp4"
},
{
"start": -1,
"length": 2,
"end": -1,
"name": "teaser4.mp4",
"location": "/media/pi/TIM1/teaser4.mp4"
},
{
"start": -1,
"length": 600,
"end": -1,
"name": "Test.mp4",
"location": "/media/pi/TIM1/Test.mp4"
},
{
"start": -1,
"length": 26,
"end": -1,
"name": "01_trashpalaceintro.mp4",
"location": "/media/pi/TIM1/TRASHPALACEVIDEOS/01_trashpalaceintro.mp4"
},
{
"start": -1,
"length": 49,
"end": -1,
"name": "colour_pixel_01.mp4",
"location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4"
},
{
"start": -1,
"end": -1,
"length": 0,
"name": "teaser1.mp4",
"location": "/media/pi/TIM1/teaser1.mp4"
},
{
"start": -1,
"end": -1,
"length": 0,
"name": "samplerloop3s2.mp4",
"location": "/media/pi/TIM1/samplerloop3s2.mp4"
},
{
"start": -1,
"length": -1,
"end": -1,
"name": "",
"location": ""
},
{
"start": -1,
"length": -1,
"end": -1,
"name": "",
"location": ""
},
{
"start": -1,
"length": -1,
"end": -1,
"name": "",
"location": ""
},
{
"start": -1,
"length": -1,
"end": -1,
"name": "",
"location": ""
},
{
"start": -1,
"length": -1,
"end": -1,
"name": "",
"location": ""
}
]

21
data_objects/key_map.json Normal file
View File

@@ -0,0 +1,21 @@
[
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
{"DEFAULT":["",""]},
]

View File

@@ -0,0 +1 @@
[{"name": "PLAYBACK_MODE", "value": "PLAYLIST"}, {"name": "PLAYLIST", "value": "[1,1,1,4,1,2,1,4]"}, {"name": "SYNC_LENGTHS", "value": "ON"}, {"name": "SYNC_LENGTHS_TO", "value": "00:08"}, {"name": "RAND_START", "value": "OFF"}, {"name": "VIDEO_OUTPUT", "value": "COMPOSITE"}, {"name": "DEV_MODE", "value": "ON"}]

View File

@@ -1,333 +0,0 @@
import logging
import math
import os
import sys
import time
import traceback
from data_centre import *
from tkinter import *
import tkinter.font
from video_driver import video_driver
import data_centre
VIDEO_DISPLAY_TEXT = 'NOW [{}] {} NEXT [{}] {}'
VIDEO_DISPLAY_BANNER_TEXT = '{} {} {}'
SELECTOR_WIDTH = 0.28
ROW_OFFSET = 6.0
MAX_LINES = 5
browser_start_index = 0
browser_index = 0
print('the start')
try:
tk = Tk()
except Exception as e:
print('failed to load tk - trying again after 2 minute')
time.sleep(120)
tk =Tk()
frame = Frame(tk, width=500, height=400)
video_driver = video_driver(frame)
# our data store
data_object = data_centre.data()
#video_player = omxdriver.omx_driver(frame, 'nope')
browser_list = data_object.get_browser_data_for_display()
bank_info = data_centre.get_all_looper_data_for_display()
# terminal_font = Font(family="Terminal", size=12)
# terminal_font_bold = Font(family="Terminal", size=12, weight='bold')
# titles.configure(font=terminal_font_bold)
display_mode = 'BROWSER'
def load_display(display):
load_title(display)
#load_divider(display)
load_player(display)
#load_divider(display)
if display_mode == 'BROWSER':
load_browser(display)
elif display_mode == 'SETTINGS':
load_settings(display)
else:
load_looper(display)
#load_divider(display)
if data_centre.current_message:
print('trying to display')
load_message(display)
display.pack()
def load_title(display):
display.insert(END, '================ r_e_c_u_r ================ \n')
display.tag_add("TITLE", 1.17, 1.26)
def load_divider(display):
display.insert(END, '------------------------------------------- \n')
def load_player(display):
text, banner = get_text_for_video_display()
end_of_text = float("3." + str(len(text)))
end_of_banner = float("3." + str(len(banner)))
display.insert(END, text + '\n')
display.tag_add("PLAYER_INFO", 2.0, end_of_text)
display.insert(END, banner + '\n')
display.tag_add("PLAYER_INFO", 3.0, end_of_banner)
def load_settings(display):
global data_object
global browser_start_index
line_count = 0
settings_list = data_centre.get_all_settings_data_for_display()
display.insert(END, '--------------- <SETTINGS> --------------- \n')
display.insert(END, '{:>20} {:>20} \n'.format('SETTING', 'VALUE'))
for index in range(len(settings_list)):
if line_count >= MAX_LINES:
break
if index >= browser_start_index:
setting = settings_list[index]
display.insert(END, '{:>20} {:>20} \n'.format(setting[0], setting[1]))
line_count = line_count + 1
def load_looper(display):
bank_info = data_centre.get_all_looper_data_for_display()
display.insert(END, '--------------- <LOOPER> --------------- \n')
display.insert(END, '{:>4} {:>15} {:>4} {:>4} {:>4} \n'.format(
'bank', 'name', 'length', 'start', 'end'))
for bank in bank_info:
display.insert(END, '{:>4} {:>15} {:>4} {:>4} {:>4} \n'.format(
bank[0], bank[1][0:15], bank[2], bank[3], bank[4]))
select_current_playing(video_driver.current_player.bank_number)
def select_current_playing(bank_number):
if(bank_number != '-'):
display.tag_add("SELECT", ROW_OFFSET + bank_number,
ROW_OFFSET + SELECTOR_WIDTH + bank_number)
def load_message(display):
display.insert(END, 'INFO: {}'.format(data_centre.current_message))
display.tag_add("ERROR_MESSAGE", 14.0, 15.0)
tk.after(4000,data_centre.clear_message)
def get_text_for_video_display():
now_bank, now_status, next_bank, next_status, duration, video_length = video_driver.get_info_for_video_display()
banner = create_video_display_banner(duration, video_length)
time_been = data_centre.convert_int_to_string_for_display(duration)
time_left = data_centre.convert_int_to_string_for_display(
video_length - duration)
return VIDEO_DISPLAY_BANNER_TEXT.format(time_been, banner, time_left),\
VIDEO_DISPLAY_TEXT.format(now_bank, now_status, next_bank, next_status)
def create_video_display_banner(duration, video_length):
banner_list = ['[', '-', '-', '-', '-', '-', '-', '-', '-',
'-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', ']']
max = len(banner_list) - 1
if duration <= 0:
banner_list[0] = '<'
elif duration >= video_length:
banner_list[max] = '>'
else:
marker = int(math.floor(float(duration) /
float(video_length) * (max - 1)) + 1)
banner_list[marker] = '*'
return ''.join(banner_list)
def load_browser(self):
global data_object
global browser_start_index
global browser_list
line_count = 0
display.insert(END, '--------------- <BROWSER> --------------- \n')
display.insert(END, '{:35} {:5} \n'.format('path', 'bank'))
for index in range(len(browser_list)):
if line_count >= MAX_LINES:
break
if index >= browser_start_index:
path = browser_list[index]
display.insert(END, '{:35} {:5} \n'.format(path[0][0:35], path[1]))
line_count = line_count + 1
def move_browser_selection_up():
global browser_index
global browser_start_index
if browser_index == 0:
if(browser_start_index > 0):
browser_start_index = browser_start_index - 1
refresh_display()
return
deselect_current_browser_index()
browser_index = browser_index - 1
select_current_browser_index()
def move_browser_selection_down():
global browser_index
global data_object
global browser_start_index
global browser_list
last_index = len(browser_list) - 1
if browser_index + browser_start_index >= last_index:
return
if browser_index >= MAX_LINES - 1:
browser_start_index = browser_start_index + 1
refresh_display()
return
deselect_current_browser_index()
browser_index = browser_index + 1
select_current_browser_index()
def select_current_browser_index():
display.tag_add("SELECT", ROW_OFFSET + browser_index,
ROW_OFFSET + SELECTOR_WIDTH + browser_index)
def deselect_current_browser_index():
display.tag_remove("SELECT", ROW_OFFSET + browser_index,
ROW_OFFSET + SELECTOR_WIDTH + browser_index)
def refresh_display():
display.configure(state='normal')
display.delete(1.0, END)
load_display(display)
display.configure(state='disable')
if display_mode in ["BROWSER", "SETTINGS"]:
select_current_browser_index()
display = Text(tk, bg="black", fg="white", font=('courier', 14))
display.tag_configure("SELECT", background="white", foreground="black")
display.tag_configure("TITLE", background="black", foreground="red")
display.tag_configure("ERROR_MESSAGE", background="red", foreground="black")
display.tag_configure("INFO_MESSAGE", background="blue", foreground="black")
display.tag_configure("PLAYER_INFO", background="black", foreground="yellow")
load_display(display)
select_current_browser_index()
def key(event):
print(event.char)
## '/' clear all banks
if event.char == '/':
print('it\'s cleared!')
data_centre.clear_all_banks()
refresh_display()
## '.' quits r_e_c_u_r
elif event.char == '.':
if video_driver.has_omx:
video_driver.exit_all_players()
tk.destroy()
## 'num' sets current selection to bank number num
elif event.char in ['0', '1', '2', '3', '4', '5', '6', '7','8','9']:
data_centre.update_next_bank_number(int(event.char))
video_driver.next_player.reload()
## 'enter' sets manual next flag
elif event.char in ['\r']:
print('manual skip')
video_driver.manual_next = True
## '*' switches display mode
elif(event.char in ['*']):
global display_mode
if display_mode == "BROWSER":
display_mode = "LOOPER"
elif display_mode == "LOOPER":
display_mode = "SETTINGS"
elif display_mode == "SETTINGS":
display_mode = "BROWSER"
refresh_display()
elif(event.char in ['+']):
down_key(event)
elif(event.char in ['-']):
up_key(event)
## 'enter' sets manual next flag
elif event.char in ['z']:
print('playing video')
video_player.play_video()
elif event.char in ['x']:
print('playing video')
video_player.pause_video()
def up_key(event):
if display_mode in ["BROWSER", "SETTINGS"]:
move_browser_selection_up()
global browser_index
global browser_start_index
elif display_mode == "LOOPER":
pass
#video_driver.current_player.jump_video_back()
def down_key(event):
if display_mode in ["BROWSER", "SETTINGS"]:
move_browser_selection_down()
global browser_index
global browser_start_index
elif display_mode == "LOOPER":
pass
#video_driver.current_player.jump_video_forward()
def backspace_key(event):
try:
global browser_index
global data_object
global browser_start_index
global browser_list
if display_mode == "BROWSER":
is_file, name = data_centre.extract_file_type_and_name_from_browser_format(
browser_list[browser_index + browser_start_index][0])
if is_file:
data_centre.create_new_bank_mapping_in_first_open(name)
else:
data_object.update_open_folders(name)
data_object.rewrite_browser_list()
browser_list = data_object.get_browser_data_for_display()
refresh_display()
elif display_mode == "LOOPER":
video_driver.current_player.toggle_pause()
elif display_mode == "SETTINGS":
data_centre.switch_settings(browser_index + browser_start_index)
refresh_display()
except Exception as e:
print('the current message is: {}'.format(e.message))
data_centre.set_message(e.message)
def update_screen():
refresh_display()
display.focus_set()
tk.after(1000, update_screen)
display.bind("<Key>", key)
display.bind("<Up>", up_key)
display.bind("<Down>", down_key)
display.bind("<BackSpace>", backspace_key)
#display.bind("<Num_Lock>", num_lock_key)
frame.pack()
tk.attributes("-fullscreen", True)
tk.after(1000, update_screen)
try:
tk.mainloop()
except:
data_centre.set_message(traceback.print_tb(exc_traceback, limit=1, file=sys.stdout))

215
display_centre/display.py Normal file
View File

@@ -0,0 +1,215 @@
from tkinter import Text, END
import math
import data_centre
class Display(object):
MAX_LINES = 5
SELECTOR_WIDTH = 0.28
ROW_OFFSET = 6.0
VIDEO_DISPLAY_TEXT = 'NOW [{}] {} NEXT [{}] {}'
VIDEO_DISPLAY_BANNER_TEXT = '{} {} {}'
def __init__(self, tk, video_driver):
self.video_driver = video_driver
self.display_mode = "LOOPER"
self.tk = tk
self.browser_data = data_centre.data()
self.browser_start_index = 0
self.browser_index = self.browser_start_index
self.browser_list = self.browser_data.get_browser_data_for_display()
self.settings_start_index = 0
self.settings_index = self.settings_start_index
self.settings_list = data_centre.get_all_settings_data_for_display()
self.display_text = self.create_display_text(self.tk)
self.add_tags()
self.update_screen()
@staticmethod
def create_display_text(tk):
return Text(tk, bg="black", fg="white", font=('courier', 14))
def add_tags(self):
self.display_text.tag_configure("SELECT", background="white", foreground="black")
self.display_text.tag_configure("TITLE", background="black", foreground="red")
self.display_text.tag_configure("ERROR_MESSAGE", background="red", foreground="black")
self.display_text.tag_configure("INFO_MESSAGE", background="blue", foreground="black")
self.display_text.tag_configure("PLAYER_INFO", background="black", foreground="yellow")
def load_display(self):
self.load_title()
self.load_player()
if self.display_mode == 'BROWSER':
self.load_browser()
elif self.display_mode == 'SETTINGS':
self.load_settings()
else:
self.load_looper()
# load_divider(display)
if data_centre.current_message:
print('trying to display')
self.load_message()
self.display_text.pack()
def load_title(self):
self.display_text.insert(END, '================ r_e_c_u_r ================ \n')
self.display_text.tag_add("TITLE", 1.17, 1.26)
def load_player(self):
text, banner = self.get_text_for_video_display()
end_of_text = float("3." + str(len(text)))
end_of_banner = float("3." + str(len(banner)))
self.display_text.insert(END, text + '\n')
self.display_text.tag_add("PLAYER_INFO", 2.0, end_of_text)
self.display_text.insert(END, banner + '\n')
self.display_text.tag_add("PLAYER_INFO", 3.0, end_of_banner)
def load_settings(self):
line_count = 0
self.display_text.insert(END, '--------------- <SETTINGS> --------------- \n')
self.display_text.insert(END, '{:>20} {:>20} \n'.format('SETTING', 'VALUE'))
for index in range(len(self.settings_list)):
if line_count >= self.MAX_LINES:
break
if index >= self.browser_start_index:
setting = self.settings_list[index]
self.display_text.insert(END, '{:>20} {:>20} \n'.format(setting[0], setting[1]))
line_count = line_count + 1
def load_looper(self):
bank_info = data_centre.get_all_looper_data_for_display()
self.display_text.insert(END, '--------------- <LOOPER> --------------- \n')
self.display_text.insert(END, '{:>4} {:>15} {:>4} {:>4} {:>4} \n'.format(
'bank', 'name', 'length', 'start', 'end'))
for bank in bank_info:
self.display_text.insert(END, '{:>4} {:>15} {:>4} {:>4} {:>4} \n'.format(
bank[0], bank[1][0:15], bank[2], bank[3], bank[4]))
self.select_current_playing(self.video_driver.current_player.bank_number)
def load_message(self):
self.display_text.insert(END, 'INFO: {}'.format(data_centre.current_message))
self.display_text.tag_add("ERROR_MESSAGE", 14.0, 15.0)
self.tk.after(4000, data_centre.clear_message)
def load_browser(self):
line_count = 0
self.display_text.insert(END, '--------------- <BROWSER> --------------- \n')
self.display_text.insert(END, '{:35} {:5} \n'.format('path', 'bank'))
for index in range(len(self.browser_list)):
if line_count >= self.MAX_LINES:
break
if index >= self.browser_start_index:
path = self.browser_list[index]
self.display_text.insert(END, '{:35} {:5} \n'.format(path[0][0:35], path[1]))
line_count = line_count + 1
def highlight_this_row(self, row):
self.display_text.tag_add("SELECT", self.ROW_OFFSET + row,
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
def unhighlight_this_row(self, row):
self.display_text.tag_remove("SELECT", self.ROW_OFFSET + row,
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
def get_text_for_video_display(self):
now_bank, now_status, next_bank, next_status, duration, video_length = self.video_driver.get_info_for_video_display()
banner = self.create_video_display_banner(duration, video_length)
time_been = data_centre.convert_int_to_string_for_display(duration)
time_left = data_centre.convert_int_to_string_for_display(
video_length - duration)
return self.VIDEO_DISPLAY_BANNER_TEXT.format(time_been, banner, time_left), \
self.VIDEO_DISPLAY_TEXT.format(now_bank, now_status, next_bank, next_status)
@staticmethod
def create_video_display_banner(duration, video_length):
banner_list = ['[', '-', '-', '-', '-', '-', '-', '-', '-',
'-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
']']
max = len(banner_list) - 1
if duration <= 0:
banner_list[0] = '<'
elif duration >= video_length:
banner_list[max] = '>'
else:
marker = int(math.floor(float(duration) /
float(video_length) * (max - 1)) + 1)
banner_list[marker] = '*'
return ''.join(banner_list)
def refresh_display(self):
self.display_text.configure(state='normal')
self.display_text.delete(1.0, END)
self.load_display()
self.display_text.configure(state='disable')
if self.display_mode is 'BROWSER':
self.highlight_this_row(self.browser_index)
elif self.display_mode is 'SETTINGS':
self.highlight_this_row(self.settings_index)
def update_screen(self):
self.refresh_display()
self.display_text.focus_set()
self.tk.after(1000, self.update_screen)
def select_current_playing(self, bank_number):
if bank_number != '-':
self.display_text.tag_add("SELECT", self.ROW_OFFSET + bank_number,
self.ROW_OFFSET + self.SELECTOR_WIDTH + bank_number)
def move_browser_down(self):
last_index = len(self.browser_list) - 1
if self.browser_index + self.browser_start_index >= last_index:
return
if self.browser_index >= self.MAX_LINES - 1:
self.browser_start_index = self.browser_start_index + 1
return
self.unhighlight_this_row(self.browser_index)
self.browser_index = self.browser_index + 1
self.highlight_this_row(self.browser_index)
def move_browser_up(self):
if self.browser_index == 0:
if self.browser_start_index > 0:
self.browser_start_index = self.browser_start_index - 1
return
self.unhighlight_this_row(self.browser_index)
self.browser_index = self.browser_index - 1
self.highlight_this_row(self.browser_index)
def browser_enter(self):
is_file, name = data_centre.extract_file_type_and_name_from_browser_format(
self.browser_list[self.browser_index + self.browser_start_index][0])
if is_file:
data_centre.create_new_bank_mapping_in_first_open(name)
else:
self.browser_data.update_open_folders(name)
self.browser_data.rewrite_browser_list()
self.browser_list = self.browser_data.get_browser_data_for_display()
def move_settings_down(self):
last_index = len(self.settings_list) - 1
if self.settings_index + self.settings_start_index >= last_index:
return
if self.settings_index >= self.MAX_LINES - 1:
self.settings_start_index = self.settings_start_index + 1
return
self.unhighlight_this_row(self.settings_index)
self.settings_index = self.settings_index + 1
self.highlight_this_row(self.settings_index)
def move_settings_up(self):
if self.settings_index == 0:
if self.settings_start_index > 0:
self.settings_start_index = self.settings_start_index - 1
return
self.unhighlight_this_row(self.settings_index)
self.settings_index = self.settings_index - 1
self.highlight_this_row(self.settings_index)
def settings_enter(self):
data_centre.switch_settings(self.settings_index + self.settings_start_index)

View File

@@ -1 +0,0 @@
[{"start": -1, "length": 4, "end": -1, "name": "samplerloop3s.mp4", "location": "/media/pi/TIM1/samplerloop3s.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser1.mp4", "location": "/media/pi/TIM1/teaser1.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser2.mp4", "location": "/media/pi/TIM1/teaser2.mp4"}, {"start": -1, "length": 3, "end": -1, "name": "teaser3.mp4", "location": "/media/pi/TIM1/teaser3.mp4"}, {"start": -1, "length": 2, "end": -1, "name": "teaser4.mp4", "location": "/media/pi/TIM1/teaser4.mp4"}, {"start": -1, "length": 600, "end": -1, "name": "Test.mp4", "location": "/media/pi/TIM1/Test.mp4"}, {"start": -1, "length": 26, "end": -1, "name": "01_trashpalaceintro.mp4", "location": "/media/pi/TIM1/TRASHPALACEVIDEOS/01_trashpalaceintro.mp4"}, {"start": -1, "length": 49, "end": -1, "name": "colour_pixel_01.mp4", "location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4"}, {"start": -1, "end": -1, "length": 0, "name": "teaser1.mp4", "location": "/media/pi/TIM1/teaser1.mp4"}, {"start": -1, "end": -1, "length": 0, "name": "samplerloop3s2.mp4", "location": "/media/pi/TIM1/samplerloop3s2.mp4"}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}, {"start": -1, "length": -1, "end": -1, "name": "", "location": ""}]

View File

@@ -1,547 +0,0 @@
import signal
import os
import sys
import dbus
import subprocess
from time import time,strftime
import data_centre
logger = data_centre.setup_logging()
"""
12/6/2016 - rewrite to use dbus
2/11/2016 - connection needs to wait for dbus filemane to be populated
2/11/2016 - remove busy wait for conection
24/11/2016 - move pause after load to after first get_position to ensure omxplayer has loaded track before pause
24/11/2016 - report dbus exception messages in log
30/11/2016 - pause at start waits until position is not 0 as video has not started until it becomes -ve
2/12/2016 - make pause glitch tolerant, try again if fails
3/12/2016 - remove threading to stop pause and unpause for showing happening in wrong order
5/12/2016 - deal with situation where pause at end happened so late that video finished first
5/12/2016 - need to send nice-day when stop is received and paused for end as now do not intercept one from omxplayer
omxdriver hides the detail of using the omxplayer command from videoplayer
This is meant to be used with videoplayer.py
Its easy to end up with many copies of omxplayer.bin running if this class is not used with care. use pp_videoplayer.py for a safer interface.
External commands
----------------------------
__init__ just creates the instance and initialises variables (e.g. omx=OMXDriver())
load - processes the track up to where it is ready to display, at this time it pauses.
show - plays the video from where 'prepare' left off by resuming from the pause.
play - plays a track (not used by gapless)
pause/unpause - pause on/off
toggle_pause - toggles pause
control - sends controls to omxplayer.bin while track is playing (use stop and pause instead of q and p)
stop - stops a video that is playing.
terminate - Stops a video playing. Used when aborting an application.
kill - kill of omxplayer when it hasn't terminated at the end of a track.
Signals
----------
The following signals are produced while a track is playing
self.start_play_signal = True when a track is ready to be shown
self.end_play_signal= True when a track has finished due to stop or because it has come to an end
self.end_play_reason reports the reason for the end
Also is_running() tests whether the sub-process running omxplayer is present.
"""
class OMXDriver(object):
# adjust this to determine freeze after the first frame
after_first_frame_position =-50000 # microseconds
_LAUNCH_CMD = '/usr/bin/omxplayer --no-keys ' # needs changing if user has installed his own version of omxplayer elsewhere
KEY_MAP = { '-': 17, '+': 18, '=': 18} # add more keys here, see popcornmix/omxplayer github file KeyConfig.h
def __init__(self,widget,pp_dir):
self.widget=widget
self.pp_dir=pp_dir
self.start_play_signal=False
self.end_play_signal=False
self.end_play_reason='nothing'
self.duration=0
self.video_position = 0
self.pause_at_end_required=False
self.paused_at_end=False
self.pause_at_end_time=0
# self.pause_before_play_required='before-first-frame' #no,before-first-frame, after-first-frame
# self.pause_before_play_required='no'
self.paused_at_start='False'
self.paused=False
self.terminate_reason=''
# dbus and subprocess
self._process=None
self.__iface_root=None
self.__iface_props = None
self.__iface_player = None
def load(self, track, freeze_at_start,options,caller):
self.pause_before_play_required=freeze_at_start
self.caller=caller
track= "'"+ track.replace("'","'\\''") + "'"
# self.mon.log(self,'TIME OF DAY: '+ strftime("%Y-%m-%d %H:%M"))
self.dbus_user = os.environ["USER"]
self.id=str(int(time()*10))
self.dbus_name = "org.mpris.MediaPlayer2.omxplayer"+self.id
self.omxplayer_cmd = OMXDriver._LAUNCH_CMD + options + " --dbus_name '"+ self.dbus_name + "' " + track
# self.mon.log(self, 'dbus user ' + self.dbus_user)
# self.mon.log(self, 'dbus name ' + self.dbus_name)
# logger.info self.omxplayer_cmd
logger.info("Send command to omxplayer: "+ self.omxplayer_cmd)
# self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/home/pi/pipresents/pp_logs/stdout.txt','a'),stderr=file('/home/pi/pipresents/pp_logs/stderr.txt','a'))
self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/dev/null','a'),stderr=file('/dev/null','a'))
self.pid=self._process.pid
# wait for omxplayer to start then start monitoring thread
self.dbus_tries = 0
self.omx_loaded = False
self._wait_for_dbus()
return
def _wait_for_dbus(self):
connect_success=self.__dbus_connect()
if connect_success is True:
# print 'SUCCESS'
logger.info('connected to omxplayer dbus after ' + str(self.dbus_tries) + ' centisecs')
# get duration of the track in microsecs if fails return a very large duration
# posibly faile because omxplayer is running but not omxplayer.bin
duration_success,duration=self.get_duration()
if duration_success is False:
logger.info('get duration failed for n attempts using '+ str(duration/60000000)+ ' minutes')
# calculate time to pause before last frame
self.duration = duration
self.pause_at_end_time = duration - 350000
# start the thread that is going to monitor output from omxplayer.
self._monitor_status()
else:
self.dbus_tries+=1
self.widget.after(100,self._wait_for_dbus)
def _monitor_status(self):
# print '\n',self.id, '** STARTING ',self.duration
self.start_play_signal=False
self.end_play_signal=False
self.end_play_reason='nothing'
self.paused_at_end=False
self.paused_at_start='False'
self.delay = 50
self.widget.after(0,self._status_loop)
"""
freeze at start
'no' - unpause in show - test !=0
'before_first_frame' - don't unpause in show, test !=0
'after_first_frame' - don't unpause in show, test > -100000
"""
def _status_loop(self):
if self.is_running() is False:
# process is not running because quit or natural end - seems not to happen
self.end_play_signal=True
self.end_play_reason='nice_day'
# print ' send nice day - process not running'
return
else:
success, video_position = self.get_position()
# if video_position <= 0: print 'read position',video_position
if success is False:
# print 'send nice day - exception when reading video position'
self.end_play_signal=True
self.end_play_reason='nice_day'
return
else:
self.video_position=video_position
# if timestamp is near the end then pause
if self.pause_at_end_required is True and self.video_position>self.pause_at_end_time: #microseconds
# print 'pausing at end, leeway ',self.duration - self.video_position
pause_end_success = self.pause(' at end of track')
if pause_end_success is True:
# print self.id,' pause for end success', self.video_position
self.paused_at_end=True
self.end_play_signal=True
self.end_play_reason='pause_at_end'
return
else:
logger.info( 'pause at end failed, probably because of delay after detection, just run on')
self.widget.after(self.delay,self._status_loop)
else:
# need to do the pausing for preload after first timestamp is received 0 is default value before start
# print self.pause_before_play_required,self.paused_at_start,self.video_position,OMXDriver.after_first_frame_position
if (self.pause_before_play_required == 'after-first-frame' and self.paused_at_start == 'False' and self.video_position >OMXDriver.after_first_frame_position)\
or(self.pause_before_play_required != 'after-first-frame' and self.paused_at_start == 'False' and self.video_position !=0):
pause_after_load_success=self.pause('after load')
if pause_after_load_success is True:
# print self.id,' pause after load success',self.video_position
self.start_play_signal = True
self.paused_at_start='True'
else:
# should never fail, just warn at the moment
# print 'pause after load failed '+ + str(self.video_position)
logger.info( str(self.id)+ ' pause after load fail ' + str(self.video_position))
self.widget.after(self.delay,self._status_loop)
else:
self.widget.after(self.delay,self._status_loop)
def show(self,freeze_at_end_required,initial_volume):
self.initial_volume=initial_volume
self.pause_at_end_required=freeze_at_end_required
# unpause to start playing
if self.pause_before_play_required =='no':
unpause_show_success=self.unpause(' to start showing')
# print 'unpause for show',self.paused
if unpause_show_success is True:
pass
# print self.id,' unpause for show success', self.video_position
else:
# should never fail, just warn at the moment
logger.info(str(self.id)+ ' unpause for show fail ' + str(self.video_position))
def control(self,char):
val = OMXDriver.KEY_MAP[char]
#logger.info('>control received and sent to omxplayer ' + str(self.pid))
if self.is_running():
try:
self.__iface_player.Action(dbus.Int32(val))
except dbus.exceptions.DBusException as ex:
#logger.info('Failed to send control - dbus exception: {}'.format(ex.get_dbus_message()))
return
else:
logger.info('Failed to send control - process not running')
return
# USE ONLY at end and after load
# return succces of the operation, several tries if pause did not work and no error reported.
def pause(self,reason):
#logger.info(self,'pause received {}'.format(reason))
if self.paused is False:
logger.info('not paused so send pause {}'.format(reason))
tries=1
while True:
if self.send_pause() is False:
# failed for good reason
return False
status=self.omxplayer_is_paused() # test omxplayer after sending the command
if status == 'Paused':
self.paused = True
return True
if status == 'Failed':
# failed for good reason because of exception or process not running caused by end of track
return False
else:
# failed for no good reason
logger.info(self, '!!!!! repeat pause {}'.format(str(tries)))
# print self.id,' !!!!! repeat pause ',self.video_position, tries
tries +=1
if tries >5:
# print self.id, ' pause failed for n attempts'
logger.info('pause failed for n attempts')
return False
# repeat
# USE ONLY for show
def unpause(self,reason):
logger.info('MON' + 'Unpause received {}'.format(reason))
if self.paused is True:
logger.info('MON' +'Is paused so Track will be unpaused {}'.format(reason))
tries=1
while True:
if self.send_unpause() is False:
return False
status = self.omxplayer_is_paused() # test omxplayer
if status == 'Playing':
self.paused = False
self.paused_at_start='done'
self.set_volume(self.initial_volume)
return True
if status == 'Failed':
# failed for good reason because of exception or process not running caused by end of track
return False
else:
logger.info('warn' + '!!!!! repeat unpause {}'.format(tries))
# print self.id,' !!!! repeat unpause ',self.video_position, tries
tries +=1
if tries >5:
# print self.id, ' unpause failed for n attempts'
logger.info('warn' + 'unpause failed for n attempts')
return False
def omxplayer_is_paused(self):
if self.is_running():
try:
result=self.__iface_props.PlaybackStatus()
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to test paused - dbus exception: {}'.format(ex.get_dbus_message()))
return 'Failed'
return result
else:
logger.info('warn'+'Failed to test paused - process not running')
# print self.id,' test paused not successful - process'
return 'Failed'
def send_pause(self):
if self.is_running():
try:
self.__iface_player.Pause()
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to send pause - dbus exception: {}'.format(ex.get_dbus_message()))
return False
return True
else:
logger.info('warn'+'Failed to send pause - process not running')
# print self.id,' send pause not successful - process'
return False
def send_unpause(self):
if self.is_running():
try:
self.__iface_player.Action(16)
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to send unpause - dbus exception: {}'.format(ex.get_dbus_message()))
return False
return True
else:
logger.info('warn'+'Failed to send unpause - process not running')
# print self.id,' send unpause not successful - process'
return False
def pause_on(self):
logger.info('mon'+'pause on received ')
# print 'pause on',self.paused
if self.paused is True:
return
if self.is_running():
try:
# self.__iface_player.Action(16)
self.__iface_player.Pause() # - this should work but does not!!!
self.paused=True
# print 'paused OK'
return
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to do pause on - dbus exception: {}'.format(ex.get_dbus_message()))
return
else:
logger.info('warn'+'Failed to do pause on - process not running')
return
def pause_off(self):
logger.info('mon'+'pause off received ')
# print 'pause off',self.paused
if self.paused is False:
return
if self.is_running():
try:
self.__iface_player.Action(16)
self.paused=False
# print 'not paused OK'
return
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to do pause off - dbus exception: {}'.format(ex.get_dbus_message()))
return
else:
logger.info('warn'+'Failed to do pause off - process not running')
return
def go(self):
logger.info('log'+'go received ')
self.unpause('for go')
def mute(self):
self.__iface_player.Mute()
def unmute(self):
self.__iface_player.Unmute()
def set_volume(self,millibels):
volume = pow(10, millibels / 2000.0);
self.__iface_props.Volume(volume)
def toggle_pause(self,reason):
logger.info('log'+'toggle pause received {}'.format(reason))
if not self.paused:
self.paused = True
else:
self.paused=False
if self.is_running():
try:
self.__iface_player.Action(16)
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to toggle pause - dbus exception: {}'.format(ex.get_dbus_message()))
return
else:
logger.info('warn'+'Failed to toggle pause - process not running')
return
def run_action(self, num):
self.__iface_player.Action(num)
def stop(self):
logger.info('log'+'>stop received and quit sent to omxplayer {} '.format(self.pid))
# need to send 'nice day'
if self.paused_at_end is True:
self.end_play_signal=True
self.end_play_reason='nice_day'
# print 'send nice day for close track'
if self.is_running():
try:
self.__iface_root.Quit()
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed to quit - dbus exception: {}'.format(ex.get_dbus_message()))
return
else:
logger.info('warn'+'Failed to quit - process not running')
return
# kill the subprocess (omxplayer and omxplayer.bin). Used for tidy up on exit.
def terminate(self,reason):
self.terminate_reason=reason
self.stop()
def get_terminate_reason(self):
return self.terminate_reason
# test of whether _process is running
def is_running(self):
retcode=self._process.poll()
# print 'is alive', retcode
if retcode is None:
return True
else:
return False
# kill off omxplayer when it hasn't terminated at the end of a track.
# send SIGINT (CTRL C) so it has a chance to tidy up daemons and omxplayer.bin
def kill(self):
if self.is_running()is True:
self._process.send_signal(signal.SIGINT)
def get_position(self):
# don't test process as is done just before
try:
micros = self.__iface_props.Position()
return True,micros
except dbus.exceptions.DBusException as ex:
# print 'Failed get_position - dbus exception: {}'.format(ex.get_dbus_message())
return False,-1
def get_duration(self):
tries=1
while True:
success,duration=self._try_duration()
if success is True:
return True,duration
else:
logger.info('warn'+ 'repeat get duration {}'.format(tries))
tries +=1
if tries >5:
return False,sys.maxsize*100
def _try_duration(self):
"""Return the total length of the playing media"""
if self.is_running() is True:
try:
micros = self.__iface_props.Duration()
return True,micros
except dbus.exceptions.DBusException as ex:
logger.info('warn'+'Failed get duration - dbus exception: {}'.format(ex.get_dbus_message()))
return False,-1
else:
return False,-1
# *********************
# connect to dbus
# *********************
def __dbus_connect(self):
if self.omx_loaded is False:
# read the omxplayer dbus data from files generated by omxplayer
bus_address_filename = "/tmp/omxplayerdbus.{}".format(self.dbus_user)
bus_pid_filename = "/tmp/omxplayerdbus.{}.pid".format(self.dbus_user)
if not os.path.exists(bus_address_filename):
logger.info('log'+'waiting for bus address file {}'.format(bus_address_filename))
self.omx_loaded=False
return False
else:
f = open(bus_address_filename, "r")
bus_address = f.read().rstrip()
if bus_address == '':
logger.info('log'+ 'waiting for bus address in file {}'.format(bus_address_filename))
self.omx_loaded=False
return False
else:
# self.mon.log(self, 'bus address found ' + bus_address)
if not os.path.exists(bus_pid_filename):
logger.info('warn'+ 'bus pid file does not exist {}'.format(bus_pid_filename))
self.omx_loaded=False
return False
else:
f= open(bus_pid_filename, "r")
bus_pid = f.read().rstrip()
if bus_pid == '':
self.omx_loaded=False
return False
else:
# self.mon.log(self, 'bus pid found ' + bus_pid)
os.environ["DBUS_SESSION_BUS_ADDRESS"] = bus_address
os.environ["DBUS_SESSION_BUS_PID"] = bus_pid
self.omx_loaded = True
if self.omx_loaded is True:
session_bus = dbus.SessionBus()
try:
omx_object = session_bus.get_object(self.dbus_name, "/org/mpris/MediaPlayer2", introspect=False)
self.__iface_root = dbus.Interface(omx_object, "org.mpris.MediaPlayer2")
self.__iface_props = dbus.Interface(omx_object, "org.freedesktop.DBus.Properties")
self.__iface_player = dbus.Interface(omx_object, "org.mpris.MediaPlayer2.Player")
except dbus.exceptions.DBusException as ex:
# self.mon.log(self,"Waiting for dbus connection to omxplayer: {}".format(ex.get_dbus_message()))
return False
return True

View File

@@ -1,65 +0,0 @@
from omxplayer.player import OMXPlayer
from time import sleep
class omx_driver:
def __init__(self, root, dbus_name):
self.root = root
self.path = ''
self.player = None
self.status = 'UNASSIGNED'
self.duration = 0
self.dbus_name = dbus_name
self.omx_running = True
def load(self, location, arguments):
self.status = 'LOADING'
self.player = OMXPlayer(location, args=arguments, dbus_name=self.dbus_name)
self.duration = self.player.duration()
print('{}: the duration is {}'.format(self.player._dbus_name, self.duration))
self.pause_at_start()
def pause_at_start(self):
position = self.get_position()
print('{}: the pause_at_start position is {}'.format(self.player._dbus_name, position))
if(position > -0.05):
self.status = 'LOADED'
self.player.pause()
print('{}: its paused'.format(self.player._dbus_name))
else:
self.root.after(5,self.pause_at_start)
def play(self):
self.status = 'PLAYING'
self.player.play()
self.pause_at_end()
def pause_at_end(self):
position = self.get_position()
print('{}: the pause_at_end position is {}'.format(self.player._dbus_name, position))
if(position > (self.duration - 0.15 )):
self.status = 'FINISHED'
print('time to end is {}'.format(self.duration - position))
self.player.pause()
print('its finished')
elif(self.omx_running):
self.root.after(5,self.pause_at_end)
def get_position(self):
try:
return self.player.position()
except:
return -1
def toggle_pause(self):
self.player.play_pause()
self.status = self.player.playback_status().upper()
def seek(self, amount):
self.player.seek(amount)
def quit(self):
self.player.quit()
self.omx_running = False

View File

@@ -1 +0,0 @@
"hdmi"

32
r_e_c_u_r.py Normal file
View File

@@ -0,0 +1,32 @@
import traceback
from tkinter import Tk, Frame
import sys
from user_input.actions import Actions
from display_centre.display import Display
from user_input.numpad_input import NumpadInput
from video_centre.videodriver import VideoDriver
import data_centre
## create tk object
tk = Tk()
frame = Frame(tk, width=500, height=400)
## setup the video driver
video_driver = VideoDriver(frame)
## setup the display
display = Display(tk, video_driver)
## setup the actions
actions = Actions(tk, video_driver, display)
numpad_input = NumpadInput(display, actions)
frame.pack()
tk.attributes("-fullscreen", True)
try:
tk.mainloop()
except:
data_centre.set_message(traceback.print_tb(sys.exc_traceback, limit=1, file=sys.stdout))

0
launcher.sh → scripts/launcher.sh Executable file → Normal file
View File

0
switch_to_display.sh → scripts/switch_to_display.sh Executable file → Normal file
View File

0
switch_to_hdmi.sh → scripts/switch_to_hdmi.sh Executable file → Normal file
View File

View File

@@ -1 +0,0 @@
[{"name": "PLAYBACK_MODE", "value": "LOOPER"}, {"name": "PLAYLIST", "value": "[1,1,1,4,1,2,1,4]"}, {"name": "SYNC_LENGTHS", "value": "OFF"}, {"name": "SYNC_LENGTHS_TO", "value": "00:08"}, {"name": "RAND_START", "value": "OFF"}, {"name": "VIDEO_OUTPUT", "value": "COMPOSITE"}, {"name": "DEV_MODE", "value": "ON"}]

59
user_input/actions.py Normal file
View File

@@ -0,0 +1,59 @@
import data_centre
class Actions(object):
def __init__(self, tk, video_driver, display):
self.tk = tk
self.video_driver = video_driver
self.display = display
def move_browser_selection_down(self):
self.display.move_browser_down()
def move_browser_selection_up(self):
self.display.move_browser_up()
def enter_on_browser_selection(self):
self.display.browser_enter()
def move_settings_selection_down(self):
self.display.move_settings_down()
def move_settings_selection_up(self):
self.display.move_settings_up()
def enter_on_settings_selection(self):
self.display.settings_enter()
@staticmethod
def clear_all_sampler_banks():
data_centre.clear_all_banks()
def quit_the_program(self):
if self.video_driver.has_omx:
self.video_driver.exit_all_players()
self.tk.destroy()
def load_this_bank_into_next_player(self, bank):
data_centre.update_next_bank_number(bank)
self.video_driver.next_player.reload()
def trigger_next_player(self):
self.video_driver.manual_next = True
def cycle_display_mode(self):
if self.display.display_mode == "BROWSER":
self.display.display_mode = "LOOPER"
elif self.display.display_mode == "LOOPER":
self.display.display_mode = "SETTINGS"
elif self.display.display_mode == "SETTINGS":
self.display.display_mode = "BROWSER"
def toggle_pause_on_player(self):
self.video_driver.current_player.toggle_pause()
def seek_forward_on_player(self):
self.video_driver.current_player.seek(30)
def seek_back_on_player(self):
self.video_driver.current_player.seek(-30)

View File

@@ -0,0 +1,61 @@
class NumpadInput(object):
def __init__(self, display, actions):
self.display = display
self.actions = actions
self.bind_actions()
def bind_actions(self):
self.display.display_text.bind("<Key>", self.on_key_press)
self.display.display_text.bind("<BackSpace>", self.on_backspace_press)
def on_key_press(self, event):
if event.char == '-':
self.on_minus_press()
elif event.char == '+':
self.on_plus_press()
elif event.char == '\r':
self.on_enter_press()
elif event.char == '*':
self.on_star_press()
elif event.char == '/':
self.on_slash_press()
elif event.char == '.':
self.on_dot_press()
def on_backspace_press(self):
if self.display.display_mode == 'BROWSER':
self.actions.enter_on_browser_selection()
elif self.display.display_mode == 'LOOPER':
self.actions.toggle_pause_on_player()
elif self.display.display_mode == 'SETTINGS':
self.actions.enter_on_settings_selection()
def on_minus_press(self):
if self.display.display_mode == 'BROWSER':
self.actions.move_browser_selection_up()
elif self.display.display_mode == 'LOOPER':
self.actions.seek_back_on_player()
elif self.display.display_mode == 'SETTINGS':
self.actions.move_settings_selection_up()
def on_plus_press(self):
if self.display.display_mode == 'BROWSER':
self.actions.move_browser_selection_down()
elif self.display.display_mode == 'LOOPER':
self.actions.seek_forward_on_player()
elif self.display.display_mode == 'SETTINGS':
self.actions.move_settings_selection_down()
def on_enter_press(self):
self.actions.trigger_next_player()
def on_star_press(self):
self.actions.cycle_display_mode()
def on_slash_press(self):
pass
def on_dot_press(self):
self.actions.quit_the_program()

View File

@@ -1,4 +1,7 @@
from omxplayer.player import OMXPlayer try:
from omxplayer.player import OMXPlayer
except:
pass
import data_centre import data_centre
if data_centre.DEV_MODE == 'ON': if data_centre.DEV_MODE == 'ON':
screen_size = '250,350,800,800' screen_size = '250,350,800,800'
@@ -94,4 +97,16 @@ class video_player:
except: except:
pass pass
class fake_video_player:
def __init__(self):
self.player = None
self.name = name
self.omx_running = False
self.status = 'UNASSIGNED'
self.duration = 0
self.bank_number = '-'
self.start = -1
self.end = -1
self.length = 0
self.location = ''

View File

@@ -1,13 +1,12 @@
import time
try: try:
from video_player import video_player # <== for deving only from video_centre.video_player import video_player # <== for deving only
has_omx = True has_omx = True
except ImportError: except ImportError:
has_omx = False has_omx = False
from tkinter import Tk, Canvas from video_centre.video_player import fake_video_player
class video_driver(object):
class VideoDriver(object):
def __init__(self, root=None): def __init__(self, root=None):
print('has omx :{}'.format(has_omx)) print('has omx :{}'.format(has_omx))
self.root = root self.root = root
@@ -20,6 +19,11 @@ class video_driver(object):
self.manual_next = False self.manual_next = False
self.print_status() self.print_status()
self.root.after(self.delay, self.begin_playing) self.root.after(self.delay, self.begin_playing)
else:
self.last_player = fake_video_player()
self.current_player = fake_video_player()
self.next_player = fake_video_player()
def print_status(self): def print_status(self):
print('l({}):{}, c({}):{}, n({}):{}'.format(self.last_player.name, self.last_player.status, self.current_player.name, self.current_player.status, self.next_player.name, self.next_player.status,)) print('l({}):{}, c({}):{}, n({}):{}'.format(self.last_player.name, self.last_player.status, self.current_player.name, self.current_player.status, self.next_player.name, self.next_player.status,))
@@ -37,10 +41,10 @@ class video_driver(object):
self.root.after(self.delay, self.wait_for_first_load) self.root.after(self.delay, self.wait_for_first_load)
def switch_players(self): def switch_players(self):
self.temp_player = self.last_player temp_player = self.last_player
self.last_player = self.current_player self.last_player = self.current_player
self.current_player = self.next_player self.current_player = self.next_player
self.next_player = self.temp_player self.next_player = temp_player
self.last_player.exit() self.last_player.exit()
def play_video(self): def play_video(self):
@@ -49,14 +53,14 @@ class video_driver(object):
self.wait_for_next_cycle() self.wait_for_next_cycle()
def wait_for_next_cycle(self): def wait_for_next_cycle(self):
if (self.current_player.is_finished() or self.manual_next): if self.current_player.is_finished() or self.manual_next:
self.manual_next = False self.manual_next = False
self.wait_for_next_load() self.wait_for_next_load()
else: else:
self.root.after(self.delay, self.wait_for_next_cycle) self.root.after(self.delay, self.wait_for_next_cycle)
def wait_for_next_load(self): def wait_for_next_load(self):
if (self.next_player.is_loaded()): if self.next_player.is_loaded():
self.switch_players() self.switch_players()
self.play_video() self.play_video()
else: else: