implement remaining config options
authorAndrew Lorimer <andrew@lorimer.id.au>
Sat, 8 May 2021 04:12:30 +0000 (14:12 +1000)
committerAndrew Lorimer <andrew@lorimer.id.au>
Sat, 8 May 2021 04:12:30 +0000 (14:12 +1000)
README.md
ppt_control/ppt_control.py
setup.py
index 0fa4b2724df4c6e155170982d6fc455d02ea17ce..2c3eb4f08bcbf9e9532300b93ae4e97b72a14ac7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@ An interface for controlling PowerPoint slideshows over the network using WebSoc
 This was originally designed for controlling a PowerPoint slideshow from an instance of OBS (Open Broadcaster Software) running on the same computer (removing the need for an extra monitor to show presenter view).
 
 This package includes three main components:
 This was originally designed for controlling a PowerPoint slideshow from an instance of OBS (Open Broadcaster Software) running on the same computer (removing the need for an extra monitor to show presenter view).
 
 This package includes three main components:
+
 1. The daemon, which runs in the background, independently of PowerPoint, and listens for WebSocket commands and hosts an HTTP server for the frontend
 2. The HTTP frontend, written in JavaScript, which displays status information and sends commands to the daemon through WebSocket (this can be docked in one of OBS's "custom browser docks")
 3. The OBS script, which allows a mapping of keyboard shortcuts to commands within OBS in order to control the slideshow from anywhere in OBS (keyboard shortcuts are implemented in the HTTP interface but only work when this is focused in OBS)
 1. The daemon, which runs in the background, independently of PowerPoint, and listens for WebSocket commands and hosts an HTTP server for the frontend
 2. The HTTP frontend, written in JavaScript, which displays status information and sends commands to the daemon through WebSocket (this can be docked in one of OBS's "custom browser docks")
 3. The OBS script, which allows a mapping of keyboard shortcuts to commands within OBS in order to control the slideshow from anywhere in OBS (keyboard shortcuts are implemented in the HTTP interface but only work when this is focused in OBS)
@@ -14,14 +15,19 @@ Due to the implementation's use of `pywin32` for COM communication, this daemon
 ## Installation
 
 `pip install ppt-control`
 ## Installation
 
 `pip install ppt-control`
+
 will install all three components. You can then start the daemon by running 
 will install all three components. You can then start the daemon by running 
+
 `py -m ppt_control`
 `py -m ppt_control`
+
 from a command prompt (note the underscore). There are a few steps to set the package up fully:
 
 ### Starting the daemon at bootup
 
 To start the daemon automatically at login, run 
 from a command prompt (note the underscore). There are a few steps to set the package up fully:
 
 ### Starting the daemon at bootup
 
 To start the daemon automatically at login, run 
+
 `pip show ppt-control`
 `pip show ppt-control`
+
 and get the location of the package. Create a shortcut to `ppt_control.py` in Explorer and put it in `%AppData%\Microsoft\Windows\Start Menu\Programs\Startup`.
 
 ### Using the HTTP interface in OBS
 and get the location of the package. Create a shortcut to `ppt_control.py` in Explorer and put it in `%AppData%\Microsoft\Windows\Start Menu\Programs\Startup`.
 
 ### Using the HTTP interface in OBS
@@ -31,9 +37,11 @@ To view the HTTP interface from within OBS, you can add a "custom browser dock"
 ### Global keyboard shortcuts in OBS
 
 Keyboard shortcuts in OBS browser docks only work when the browser dock is focused by clicking in it (there is actually no indication of focus in the interface, but if you click away from the browser dock the shortcuts will not work). To resolve this, there is another Python script called `ppt_control_obs.py` which can be added as a custom script in OBS. This script will listen for specific keys (configured in OBS's Hotkeys settings) and send commands to the daemon directly over WebSocket (no HTTP involved). To add the custom script, go to Tools -> Scripts, then click the + and choose the script. This will be located in the package directory which can be found with
 ### Global keyboard shortcuts in OBS
 
 Keyboard shortcuts in OBS browser docks only work when the browser dock is focused by clicking in it (there is actually no indication of focus in the interface, but if you click away from the browser dock the shortcuts will not work). To resolve this, there is another Python script called `ppt_control_obs.py` which can be added as a custom script in OBS. This script will listen for specific keys (configured in OBS's Hotkeys settings) and send commands to the daemon directly over WebSocket (no HTTP involved). To add the custom script, go to Tools -> Scripts, then click the + and choose the script. This will be located in the package directory which can be found with
+
 `pip show ppt-control`
 `pip show ppt-control`
+
 as above. It is a good idea to turn off the keyboard shortcuts in the HTTP interface after loading the OBS hotkey script, otherwise commands will be sent to the daemon twice when the browser dock is focused.
 
 ## Configuration
 
 as above. It is a good idea to turn off the keyboard shortcuts in the HTTP interface after loading the OBS hotkey script, otherwise commands will be sent to the daemon twice when the browser dock is focused.
 
 ## Configuration
 
-Various settings can be changed in `%AppData%\ppt-control\ppt-control.ini`. This file is populated with the defaults for all possible settings at installation.
+Various settings can be changed in `%AppData%\ppt-control\ppt-control.ini`. This file is populated with the defaults for all possible settings at installation. A settings GUI accessible from the system tray icon is also available (work in progress).
index f942b328f2c2a637ef94015b184a54fc1eaa9941..5ff80efbee1277b7dfad8630091a5933565cac62 100755 (executable)
@@ -40,7 +40,6 @@ global ws_label
 global http_server\r
 scheduler = None\r
 current_slideshow = None\r
 global http_server\r
 scheduler = None\r
 current_slideshow = None\r
-CACHEDIR = r'''C:\Windows\Temp\ppt-cache'''\r
 interface_root = None\r
 CONFIG_FILE = r'''..\ppt-control.ini'''\r
 LOGFILE = r'''..\ppt-control.log'''\r
 interface_root = None\r
 CONFIG_FILE = r'''..\ppt-control.ini'''\r
 LOGFILE = r'''..\ppt-control.log'''\r
@@ -81,7 +80,7 @@ class Handler(server.SimpleHTTPRequestHandler):
             black = 0\r
             if current_slideshow:\r
                 try:\r
             black = 0\r
             if current_slideshow:\r
                 try:\r
-                    path = CACHEDIR + "\\" + current_slideshow.name()\r
+                    path = config.prefs["Main"]["cache"] + "\\" + current_slideshow.name()\r
                 except Exception as e:\r
                     path = os.path.join(os.path.dirname(os.path.realpath(__file__)), r'''\static\black.jpg''') + '/'\r
                     logger.warning("Failed to get current slideshow name: ", e)\r
                 except Exception as e:\r
                     path = os.path.join(os.path.dirname(os.path.realpath(__file__)), r'''\static\black.jpg''') + '/'\r
                     logger.warning("Failed to get current slideshow name: ", e)\r
@@ -103,7 +102,7 @@ class Handler(server.SimpleHTTPRequestHandler):
 \r
 def run_http():\r
     global http_server\r
 \r
 def run_http():\r
     global http_server\r
-    http_server = server.HTTPServer(("", 80), Handler)\r
+    http_server = server.HTTPServer((config.prefs["HTTP"]["interface"], config.prefs.getint("HTTP", "port")), Handler)\r
     http_server.serve_forever()\r
 \r
 STATE_DEFAULT = {"connected": 0, "current": 0, "total": 0, "visible": 0, "name": ""}\r
     http_server.serve_forever()\r
 \r
 STATE_DEFAULT = {"connected": 0, "current": 0, "total": 0, "visible": 0, "name": ""}\r
@@ -190,7 +189,6 @@ async def ws_receive(websocket, path):
                 notify_state()\r
             else:\r
                 logger.error("Received unnsupported event: {}", data)\r
                 notify_state()\r
             else:\r
                 logger.error("Received unnsupported event: {}", data)\r
-            message = ""\r
     finally:\r
         USERS.remove(websocket)\r
 \r
     finally:\r
         USERS.remove(websocket)\r
 \r
@@ -209,7 +207,7 @@ def run_ws():
     ws_queue = asyncio.Queue()\r
     global loop\r
     loop = asyncio.get_event_loop()\r
     ws_queue = asyncio.Queue()\r
     global loop\r
     loop = asyncio.get_event_loop()\r
-    start_server = websockets.serve(ws_handler, "0.0.0.0", 5678, ping_interval=None)\r
+    start_server = websockets.serve(ws_handler, config.prefs["WebSocket"]["interface"], config.prefs.getint("WebSocket", "port"), ping_interval=None)\r
     asyncio.get_event_loop().run_until_complete(start_server)\r
     asyncio.get_event_loop().run_forever()\r
 \r
     asyncio.get_event_loop().run_until_complete(start_server)\r
     asyncio.get_event_loop().run_forever()\r
 \r
@@ -236,7 +234,7 @@ def start_ws():
     logger.info("Started websocket server")\r
 \r
 class Slideshow:\r
     logger.info("Started websocket server")\r
 \r
 class Slideshow:\r
-    def __init__(self, instance):\r
+    def __init__(self, instance, blackwhite):\r
         self.instance = instance\r
         if self.instance is None:\r
             raise ValueError("PPT instance cannot be None")\r
         self.instance = instance\r
         if self.instance is None:\r
             raise ValueError("PPT instance cannot be None")\r
@@ -249,6 +247,8 @@ class Slideshow:
             raise ValueError("PPT instance has no  active presentation")\r
         self.presentation = self.instance.ActivePresentation\r
 \r
             raise ValueError("PPT instance has no  active presentation")\r
         self.presentation = self.instance.ActivePresentation\r
 \r
+        self.blackwhite = blackwhite\r
+\r
         self.export_current_next()\r
 \r
     def unload(self):\r
         self.export_current_next()\r
 \r
     def unload(self):\r
@@ -336,7 +336,10 @@ class Slideshow:
     def black(self):\r
         try:\r
             self.refresh()\r
     def black(self):\r
         try:\r
             self.refresh()\r
-            self.view.State = 3\r
+            if self.blackwhite == "both" and self.view.State == 4:\r
+                self.view.state = 1\r
+            else:\r
+                self.view.State = 3\r
             self.export_current_next()\r
         except (ValueError, pywintypes.com_error):\r
             self.unload()\r
             self.export_current_next()\r
         except (ValueError, pywintypes.com_error):\r
             self.unload()\r
@@ -344,7 +347,10 @@ class Slideshow:
     def white(self):\r
         try:\r
             self.refresh()\r
     def white(self):\r
         try:\r
             self.refresh()\r
-            self.view.State = 4\r
+            if self.blackwhite == "both" and self.view.State == 3:\r
+                self.view.state = 1\r
+            else:\r
+                self.view.State = 4\r
             self.export_current_next()\r
         except (ValueError, pywintypes.com_error):\r
             self.unload()\r
             self.export_current_next()\r
         except (ValueError, pywintypes.com_error):\r
             self.unload()\r
@@ -371,14 +377,14 @@ class Slideshow:
         self.export(self.current_slide() + 2)\r
 \r
     def export(self, slide):\r
         self.export(self.current_slide() + 2)\r
 \r
     def export(self, slide):\r
-        destination = CACHEDIR + "\\" + self.name() + "\\" + str(slide) + ".jpg"\r
+        destination = config.prefs["Main"]["cache"] + "\\" + self.name() + "\\" + str(slide) + ".jpg"\r
         os.makedirs(os.path.dirname(destination), exist_ok=True)\r
         if not os.path.exists(destination) or time.time() - os.path.getmtime(destination) > config.prefs.getint("Main", "cache_timeout"):\r
             if slide <= self.total_slides():\r
                 attempts = 0\r
                 while attempts < 3:\r
                     try:\r
         os.makedirs(os.path.dirname(destination), exist_ok=True)\r
         if not os.path.exists(destination) or time.time() - os.path.getmtime(destination) > config.prefs.getint("Main", "cache_timeout"):\r
             if slide <= self.total_slides():\r
                 attempts = 0\r
                 while attempts < 3:\r
                     try:\r
-                        self.presentation.Slides(slide).Export(destination, "JPG")\r
+                        self.presentation.Slides(slide).Export(destination, config.prefs["Main"]["cache_format"])\r
                         break\r
                     except:\r
                         pass\r
                         break\r
                     except:\r
                         pass\r
@@ -430,7 +436,7 @@ def connect_ppt():
         try:\r
             instance = get_ppt_instance()\r
             global current_slideshow\r
         try:\r
             instance = get_ppt_instance()\r
             global current_slideshow\r
-            current_slideshow = Slideshow(instance)\r
+            current_slideshow = Slideshow(instance, config.prefs["Main"]["blackwhite"])\r
             STATE["connected"] = 1\r
             STATE["current"] = current_slideshow.current_slide()\r
             STATE["total"] = current_slideshow.total_slides()\r
             STATE["connected"] = 1\r
             STATE["current"] = current_slideshow.current_slide()\r
             STATE["total"] = current_slideshow.total_slides()\r
@@ -565,7 +571,7 @@ def start_interface():
 \r
     #logging.getLogger("asyncio").setLevel(logging.ERROR)\r
     #logging.getLogger("asyncio.coroutines").setLevel(logging.ERROR)\r
 \r
     #logging.getLogger("asyncio").setLevel(logging.ERROR)\r
     #logging.getLogger("asyncio.coroutines").setLevel(logging.ERROR)\r
-    #logging.getLogger("websockets.server").setLevel(logging.ERROR)\r
+    logging.getLogger("websockets.server").setLevel(logging.ERROR)\r
     #logging.getLogger("websockets.protocol").setLevel(logging.ERROR)\r
 \r
 \r
     #logging.getLogger("websockets.protocol").setLevel(logging.ERROR)\r
 \r
 \r
index dd4b9bd66ddc7d58fe946aac5c58428900aaa4da..8a032b7fc48f92005622217ac4da6ab15f061d50 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -11,6 +11,7 @@ setuptools.setup(
     name='ppt-control',
     version=ppt_control.__version__,
     description='Interface for controlling PowerPoint slideshows over WebSocket/HTTP',
     name='ppt-control',
     version=ppt_control.__version__,
     description='Interface for controlling PowerPoint slideshows over WebSocket/HTTP',
+    long_description=long_description,
     long_description_content_type='text/markdown',
     url='https://git.lorimer.id.au/ppt-control.git',
     author='Andrew Lorimer',
     long_description_content_type='text/markdown',
     url='https://git.lorimer.id.au/ppt-control.git',
     author='Andrew Lorimer',