-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.py
158 lines (141 loc) · 5.82 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import threading, time, sqlite3, os, sys, datetime, platform
if not sys.platform.startswith('darwin'):
sys.exit('OpenEmu is a macOS exclusive application.')
import rumps, pypresence, Quartz, AppKit
# Set default appname
appName = 'OpenEmu'
path = os.path.expanduser('~/Library/Application Support/OpenEmuRPC')
emupath = os.path.expanduser('~/Library/Application Support/OpenEmu/Game Library')
# Define menu bar object and run it
class Client(rumps.App):
def __init__(self):
try:
if not self.check_permissions():
self.request_permissions()
self.handle_error('Failed to receive permissions.', True)
except AttributeError as error:
ver = platform.mac_ver()[0].split('.')
if ver[0] == '10' and int(ver[1]) < 15:
print('running pre-screen-recording permissions macos')
else:
raise error
self.rpc = None
self.games = None
self.connect()
super().__init__('OpenEmuRPC', title = '🎮')
threading.Thread(target = self.background, daemon = True).start()
def create_instance(self, clientID:str = '901628121214779412', pipe:int = 0):
self.rpc = pypresence.Presence(clientID, pipe = pipe)
def connect(self):
if not self.rpc:
self.create_instance()
try:
self.rpc.connect()
except Exception as e:
self.handle_error(e, True)
def handle_error(self, error:Exception, quit:bool):
if not os.path.isdir(path):
os.mkdir(path)
with open(f'{path}/error.txt', 'a') as file:
file.write('[%s] %s\n' % (datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), error))
print(error)
if quit:
rumps.alert('Error in OpenEmuRPC', '"%s"' % error)
sys.exit()
rumps.notification('Error in OpenEmuRPC', 'Make an issue if error persists', '"%s"' % error)
def check_permissions(self):
return Quartz.CGPreflightScreenCaptureAccess()
def request_permissions(self):
Quartz.CGRequestScreenCaptureAccess()
def is_running(self):
apps = AppKit.NSWorkspace.sharedWorkspace().launchedApplications()
for app in apps:
if app['NSApplicationName'] == appName:
return True
return False
def update(self):
if not self.is_running():
self.rpc.clear()
return
windows = self.get_windows()
menus = False
dict = {
'large_image': 'main',
'large_text': appName,
'buttons': [{'label': 'See %s' % appName, 'url': 'https://openemu.org/'},],
'details': 'Idly in menus...',
}
for i in ('Library', 'Gameplay', 'Controls', 'Cores', 'System Files', 'Shader Parameters'):
if i in windows:
menus = i
windows.remove(i)
for i in ('', 'Apple', 'About', 'Updating OpenEmu', 'File', 'Edit', 'View', 'Window', 'Help'):
if i in windows:
windows.remove(i)
if windows and windows != [appName]:
if self.games != windows:
self.start = round(time.time())
self.games = windows.copy()
dict['start'] = self.start
if appName in windows:
windows.remove(appName)
game = windows[0]
art = self.get_artwork(windows[0])
if art:
dict['large_image'] = art
if len(windows) > 1:
game = ', '.join(windows)
art = self.get_artwork(windows[1])
if art:
dict['small_image'] = art
dict['small_text'] = windows[1]
dict['details'] = 'Playing %s' % game
dict['large_text'] = windows[0]
if menus:
dict['details'] = ('In %s of ' + game) % menus
for key in list(dict):
if isinstance(dict[key], str):
if len(dict[key]) < 2:
del dict[key]
elif len(dict[key]) > 128:
dict[key] = dict[key][:128]
self.rpc.update(**dict)
def get_artwork(self, title:str):
try:
# Connect to OpenEmu's library database
con = sqlite3.connect(os.path.join(emupath, 'Library.storedata'))
cursor = con.cursor()
# Get sources from image db
cursor.execute('SELECT ZBOX, ZSOURCE FROM ZIMAGE')
art = [(i[0], i[1]) for i in cursor.fetchall()]
cursor.execute('SELECT ZGAMETITLE FROM ZGAME')
games = [ i[0] for i in cursor.fetchall() ]
cursor.execute('SELECT Z_PK FROM ZROM')
zpk = [ i[0] for i in cursor.fetchall() ]
games = [ [zpk[i], games[i]] for i in range(len(games)) ]
con.close()
# Find game in sources
for i in games:
if not i[1]: # Prevent irregular games from prematurely ending the recursion
continue
if title in i[1]:
url = next(n[1] for n in art if n[0] == i[0])
return url
return None
except: # On possible failure, just return None
return None
def get_windows(self):
response = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements|Quartz.kCGWindowListOptionOnScreenOnly,Quartz.kCGNullWindowID)
windows = []
for window in response:
if window[Quartz.kCGWindowOwnerName] == appName:
windows.append(window.get(Quartz.kCGWindowName, '<no name>'))
while '' in windows:
windows.remove('')
return windows
def background(self):
while True:
self.update()
time.sleep(1)
if __name__ == '__main__':
Client().run()