-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
155 lines (121 loc) · 4.98 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
from dataclasses import dataclass, asdict
import math
import subprocess, argparse, os, yaml, time
import mergedeep
import webview
parser = argparse.ArgumentParser(description="Quickly Run your favourite scripts and applications.\nFor aditional help, check the README.")
parser.add_argument('--scripts', nargs="+", dest='scripts_filenames', metavar='FILENAME', help="Location of scripts config file(s). Defaults to python script directory.")
parser.add_argument('--id', dest='device_id', help="Device ID for device-specific scripts.")
args = parser.parse_args()
valid_keys = "abcdefghijklmnoprstuvwxyz,.<>/?;:'\"[]{}-_=+!@#$%^&*()`~"
invalid_keys = "q"
def error(message):
raise Exception(message)
@dataclass
class Group:
name: str
key: str
scripts: list
@dataclass
class Script:
name: str
key: str
command: str
class Config():
def __init__(self):
self.groups = []
self.config = {}
self.device_id = args.device_id
self.scripts_filenames = args.scripts_filenames
if self.scripts_filenames is None:
self.scripts_filenames = ['./scripts.yaml']
data = {}
for filename in self.scripts_filenames:
if not os.path.exists(os.path.join(os.path.dirname(__file__), filename)):
error(f"File {filename} does not exist!")
with open(os.path.join(os.path.dirname(__file__), filename), 'r') as file:
try:
filedata = yaml.safe_load(file.read())
except Exception as e:
file.close()
error(f"Error in parsing YAML file {file.name}:\n\n" + str(e))
mergedeep.merge(data, filedata)
groups_raw = data.get('groups', [])
self.config = data.get('config', {})
self.parse_groups(groups_raw)
def get_config(self, option, default):
"""Get an option value, if it's available, from the user-defined `config` field in scripts.yaml"""
if option in self.config:
return self.config[option]
else:
if self.device_id in self.config:
if option in self.config[self.device_id]:
return self.config[self.device_id][option]
return default
def parse_groups(self, groups_raw):
"""Parse the groups from the yaml configuration."""
group_key = 1
for group_raw in groups_raw:
title = group_raw['title']
if 'key' in group_raw.keys():
key = str(group_raw['key'])
else:
if group_key > 9:
error("You cannot have more than 9 un-keyed Groups!")
key = str(group_key)
group_key += 1
group = Group(title, key, [])
self.groups.append(group)
for script in group_raw['scripts']:
name = str(script['name'])
key = str(script['key'])
if key.lower() in invalid_keys:
error(f"It is forbidden to use the key '{key}' for any quickscript!")
if key.lower() not in valid_keys:
error(f"ERROR: key '{key}' is an invalid quickscript key!")
if key in [script.key for script in group.scripts]:
error(f"Key {key} has been used more than once in the same script group!")
if isinstance(script['command'], str):
# Same command for all systems
command = script['command']
else:
# See if there's one specific for this machine name
try:
command = script['command'][self.device_id]
except KeyError:
# There isn't - that's fine, just continue.
continue
for replace_keyword, replace_string in self.get_config('replace', {}).items():
command = command.replace(f"${replace_keyword}", replace_string)
group.scripts.append(Script(name, key, command))
class Api:
def __init__(self):
self.config = Config()
def get_rows(self):
return self.config.get_config("rows", 5)
def get_theme(self):
return self.config.get_config('theme', 'auto')
def get_groups(self):
return [asdict(x) for x in self.config.groups]
def fit_window(self, width, height):
webview.windows[0].resize(width, height)
def execute(self, command):
subprocess.Popen(command, shell=True)
self.close()
def close(self):
webview.windows[0].destroy()
if __name__ == '__main__':
api = Api()
window = webview.create_window(
'Quickscripts',
'assets/index.html',
js_api=api,
frameless=True,
on_top=True,
x=0,
y=0,
width=1000,
height=1000,
transparent=True
)
webview.start(debug=False)