obs_ppt_server.pyon commit initial commit (06b398e)
   1import win32com.client
   2import pywintypes
   3import os
   4import shutil
   5import http_server_39 as server
   6#import http.server as server
   7import socketserver
   8import threading
   9import asyncio
  10import websockets
  11import logging, json
  12
  13logging.basicConfig()
  14
  15powerpoint = None
  16cache = r'''C:\Windows\Temp'''
  17
  18class Handler(server.CGIHTTPRequestHandler):
  19    def __init__(self, *args, **kwargs):
  20        super().__init__(*args, directory=os.path.dirname(os.path.realpath(__file__)))
  21
  22def run_http():
  23    http_server = server.HTTPServer(("", 80), Handler)
  24    http_server.serve_forever()
  25
  26async def first(websocket, path):
  27    slideshow_view_first()
  28    await websocket.send(True)
  29
  30STATE = {"value": "?", "visible": "1"}
  31
  32USERS = set()
  33
  34
  35def state_event():
  36    return json.dumps({"type": "state", **STATE})
  37
  38
  39def users_event():
  40    return json.dumps({"type": "users", "count": len(USERS)})
  41
  42
  43async def notify_state():
  44    STATE["value"] = str(current_slide()) + "/" + str(total_slides())
  45    if USERS:  # asyncio.wait doesn't accept an empty list
  46        message = state_event()
  47        await asyncio.wait([user.send(message) for user in USERS])
  48
  49
  50async def notify_users():
  51    if USERS:  # asyncio.wait doesn't accept an empty list
  52        message = users_event()
  53        await asyncio.wait([user.send(message) for user in USERS])
  54
  55
  56async def register(websocket):
  57    USERS.add(websocket)
  58    await notify_users()
  59
  60
  61async def unregister(websocket):
  62    USERS.remove(websocket)
  63    await notify_users()
  64
  65
  66async def ws_handle(websocket, path):
  67    # register(websocket) sends user_event() to websocket
  68    await register(websocket)
  69    try:
  70        await websocket.send(state_event())
  71        async for message in websocket:
  72            data = json.loads(message)
  73            if data["action"] == "prev":
  74                slideshow_view_previous()
  75                await notify_state()
  76            elif data["action"] == "next":
  77                slideshow_view_next()
  78                await notify_state()
  79            elif data["action"] == "first":
  80                slideshow_view_first()
  81                await notify_state()
  82            elif data["action"] == "last":
  83                slideshow_view_last()
  84                await notify_state()
  85            else:
  86                logging.error("unsupported event: {}", data)
  87    finally:
  88        await unregister(websocket)
  89
  90def run_ws():
  91    start_server = websockets.serve(ws_handle, "0.0.0.0", 5678)
  92    asyncio.get_event_loop().run_until_complete(start_server)
  93    asyncio.get_event_loop().run_forever()
  94
  95def start_server():
  96    STATE["value"] = current_slide()
  97    http_daemon = threading.Thread(name="http_daemon", target=run_http)
  98    http_daemon.setDaemon(True)
  99    http_daemon.start()
 100
 101    run_ws()
 102    #ws_daemon = threading.Thread(name="ws_daemon", target=run_ws)
 103    #ws_daemon.setDaemon(True)
 104    #ws_daemon.start()
 105
 106    #try:
 107    #    ws_daemon.start()
 108    #    http_daemon.start()
 109    #except (KeyboardInterrupt, SystemExit):
 110    #    cleanup_stop_thread()
 111    #    sys.exit()
 112
 113
 114def get_slideshow_view():
 115    global powerpoint
 116
 117    if powerpoint is None:
 118        powerpoint = win32com.client.Dispatch('Powerpoint.Application')
 119
 120    if powerpoint is None:
 121        return
 122
 123    ssw = powerpoint.SlideShowWindows
 124    if ssw.Count == 0:
 125        return
 126
 127    # https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowwindow.view
 128    ssv = ssw[0].View
 129
 130    return ssv
 131
 132def get_activepresentation():
 133    global powerpoint
 134
 135    if powerpoint is None:
 136        powerpoint = win32com.client.Dispatch('Powerpoint.Application')
 137
 138    if powerpoint is None:
 139        return
 140
 141    activepres = powerpoint.ActivePresentation
 142    return activepres
 143
 144def total_slides():
 145    ssp = get_activepresentation()
 146    if ssp:
 147        return len(ssp.Slides)
 148
 149def current_slide():
 150    ssv = get_slideshow_view()
 151    if ssv:
 152        return ssv.CurrentShowPosition
 153
 154def export(slide):
 155    global cache
 156    ssp = get_activepresentation()
 157    if ssp:
 158        for (slide, name) in [(slide, "current"), (slide+1, "next")]:
 159            if slide < len(ssp.Slides):
 160                ssp.Slides(slide).Export(os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + r'''0.jpg''', "JPG")
 161                attempts = 0
 162                while attempts < 3:
 163                    try:
 164                        os.replace(os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + r'''0.jpg''', os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + '''.jpg''')
 165                    except:
 166                        pass
 167                    attempts += 1
 168            else:
 169                    shutil.copyfileobj(open(os.path.dirname(os.path.realpath(__file__)) + r'''\blank.jpg''', 'rb'), open(os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + r'''next.jpg''', 'wb'))
 170
 171def slideshow_view_first():
 172    ssv = get_slideshow_view()
 173    if ssv:
 174        ssv.First()
 175        export(ssv.CurrentShowPosition)
 176
 177def slideshow_view_previous():
 178    ssv = get_slideshow_view()
 179    if ssv:
 180        ssv.Previous()
 181        export(ssv.CurrentShowPosition)
 182
 183def slideshow_view_next():
 184    ssv = get_slideshow_view()
 185    if ssv:
 186        ssv.Next()
 187        export(ssv.CurrentShowPosition)
 188            
 189
 190def slideshow_view_last():
 191    ssv = get_slideshow_view()
 192    if ssv:
 193        ssv.Last()
 194        export(ssv.CurrentShowPosition)
 195
 196def slideshow_view_black():
 197    ssv = get_slideshow_view()
 198    if ssv:
 199        ssv.State = 3
 200
 201def slideshow_view_white():
 202    ssv = get_slideshow_view()
 203    if ssv:
 204        ssv.State = 4
 205
 206def slideshow_view_normal():
 207    ssv = get_slideshow_view()
 208    if ssv:
 209        ssv.State = 1
 210
 211if __name__ == "__main__":
 212    start_server()