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
1213
logging.basicConfig()
1415
powerpoint = None
16cache = r'''C:\Windows\Temp'''
1718
class Handler(server.CGIHTTPRequestHandler):
19def __init__(self, *args, **kwargs):
20super().__init__(*args, directory=os.path.dirname(os.path.realpath(__file__)))
2122
def run_http():
23http_server = server.HTTPServer(("", 80), Handler)
24http_server.serve_forever()
2526
async def first(websocket, path):
27slideshow_view_first()
28await websocket.send(True)
2930
STATE = {"value": "?", "visible": "1"}
3132
USERS = set()
3334
35
def state_event():
36return json.dumps({"type": "state", **STATE})
3738
39
def users_event():
40return json.dumps({"type": "users", "count": len(USERS)})
4142
43
async def notify_state():
44STATE["value"] = str(current_slide()) + "/" + str(total_slides())
45if USERS: # asyncio.wait doesn't accept an empty list
46message = state_event()
47await asyncio.wait([user.send(message) for user in USERS])
4849
50
async def notify_users():
51if USERS: # asyncio.wait doesn't accept an empty list
52message = users_event()
53await asyncio.wait([user.send(message) for user in USERS])
5455
56
async def register(websocket):
57USERS.add(websocket)
58await notify_users()
5960
61
async def unregister(websocket):
62USERS.remove(websocket)
63await notify_users()
6465
66
async def ws_handle(websocket, path):
67# register(websocket) sends user_event() to websocket
68await register(websocket)
69try:
70await websocket.send(state_event())
71async for message in websocket:
72data = json.loads(message)
73if data["action"] == "prev":
74slideshow_view_previous()
75await notify_state()
76elif data["action"] == "next":
77slideshow_view_next()
78await notify_state()
79elif data["action"] == "first":
80slideshow_view_first()
81await notify_state()
82elif data["action"] == "last":
83slideshow_view_last()
84await notify_state()
85else:
86logging.error("unsupported event: {}", data)
87finally:
88await unregister(websocket)
8990
def run_ws():
91start_server = websockets.serve(ws_handle, "0.0.0.0", 5678)
92asyncio.get_event_loop().run_until_complete(start_server)
93asyncio.get_event_loop().run_forever()
9495
def start_server():
96STATE["value"] = current_slide()
97http_daemon = threading.Thread(name="http_daemon", target=run_http)
98http_daemon.setDaemon(True)
99http_daemon.start()
100101
run_ws()
102#ws_daemon = threading.Thread(name="ws_daemon", target=run_ws)
103#ws_daemon.setDaemon(True)
104#ws_daemon.start()
105106
#try:
107# ws_daemon.start()
108# http_daemon.start()
109#except (KeyboardInterrupt, SystemExit):
110# cleanup_stop_thread()
111# sys.exit()
112113
114
def get_slideshow_view():
115global powerpoint
116117
if powerpoint is None:
118powerpoint = win32com.client.Dispatch('Powerpoint.Application')
119120
if powerpoint is None:
121return
122123
ssw = powerpoint.SlideShowWindows
124if ssw.Count == 0:
125return
126127
# https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowwindow.view
128ssv = ssw[0].View
129130
return ssv
131132
def get_activepresentation():
133global powerpoint
134135
if powerpoint is None:
136powerpoint = win32com.client.Dispatch('Powerpoint.Application')
137138
if powerpoint is None:
139return
140141
activepres = powerpoint.ActivePresentation
142return activepres
143144
def total_slides():
145ssp = get_activepresentation()
146if ssp:
147return len(ssp.Slides)
148149
def current_slide():
150ssv = get_slideshow_view()
151if ssv:
152return ssv.CurrentShowPosition
153154
def export(slide):
155global cache
156ssp = get_activepresentation()
157if ssp:
158for (slide, name) in [(slide, "current"), (slide+1, "next")]:
159if slide < len(ssp.Slides):
160ssp.Slides(slide).Export(os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + r'''0.jpg''', "JPG")
161attempts = 0
162while attempts < 3:
163try:
164os.replace(os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + r'''0.jpg''', os.path.dirname(os.path.realpath(__file__)) + r'''\\''' + name + '''.jpg''')
165except:
166pass
167attempts += 1
168else:
169shutil.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'))
170171
def slideshow_view_first():
172ssv = get_slideshow_view()
173if ssv:
174ssv.First()
175export(ssv.CurrentShowPosition)
176177
def slideshow_view_previous():
178ssv = get_slideshow_view()
179if ssv:
180ssv.Previous()
181export(ssv.CurrentShowPosition)
182183
def slideshow_view_next():
184ssv = get_slideshow_view()
185if ssv:
186ssv.Next()
187export(ssv.CurrentShowPosition)
188189
190
def slideshow_view_last():
191ssv = get_slideshow_view()
192if ssv:
193ssv.Last()
194export(ssv.CurrentShowPosition)
195196
def slideshow_view_black():
197ssv = get_slideshow_view()
198if ssv:
199ssv.State = 3
200201
def slideshow_view_white():
202ssv = get_slideshow_view()
203if ssv:
204ssv.State = 4
205206
def slideshow_view_normal():
207ssv = get_slideshow_view()
208if ssv:
209ssv.State = 1
210211
if __name__ == "__main__":
212start_server()