Skip to content

Commit cf09b2e

Browse files
committed
lots of optimization changes + folder structure + better logs
1 parent f45227b commit cf09b2e

File tree

8 files changed

+137
-199
lines changed

8 files changed

+137
-199
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,6 @@ cython_debug/
153153

154154
output/
155155
.vscode/
156-
mmt/
157156
config.ini
157+
MultiMonitorToolConfig.ini
158+
MultiMonitorToolScommaOutput.tmp

smct/config.py

Lines changed: 49 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,80 @@
11
import configparser
22
import os
3-
43
import requests
5-
64
from smct import paths, ui
7-
from smct.logger import log
5+
from smct.logger import log, INFO, ERROR
86

9-
# config.ini structure
107
ENCODING = "utf-8"
11-
12-
_SETTINGS_SECTION = "Settings"
13-
14-
_MONITOR_NAME_KEY = "monitor_name"
15-
_MONITOR_SERIAL_KEY = "monitor_serial"
16-
_MMT_PATH_KEY = "multimonitortool_executable"
17-
_START_WITH_WINDOWS_KEY = "start_with_windows"
18-
_FIRST_START_KEY = "first_start"
19-
8+
_SECTION_SETTINGS = "Settings"
9+
KEY_MONITOR_NAME = "monitor_name"
10+
KEY_MONITOR_SERIAL = "monitor_serial"
11+
KEY_MMT_PATH = "multimonitortool_executable"
12+
KEY_START_WITH_WINDOWS = "start_with_windows"
13+
KEY_FIRST_START = "first_start"
14+
15+
_DEFAULT_CONFIG = {
16+
KEY_MONITOR_NAME: "Example Monitor",
17+
KEY_MONITOR_SERIAL: "12345",
18+
KEY_MMT_PATH: "C:/MultiMonitorTool.exe",
19+
KEY_START_WITH_WINDOWS: "no",
20+
KEY_FIRST_START: "yes",
21+
}
2022
_configparser = configparser.ConfigParser()
2123

2224

2325
def _check_for_missing_files():
24-
if not os.path.exists(paths.CONFIG_PATH):
25-
_create_default_config_file()
26-
log(f"Creating {paths.CONFIG_FILE_NAME}")
27-
28-
if not os.path.exists(paths.ASSETS_DIR_PATH):
29-
os.mkdir(paths.ASSETS_DIR_PATH)
30-
log(f"Creating {paths.ASSETS_DIR_NAME} folder")
31-
32-
# Check for Icons
33-
if not os.path.exists(paths.ASSETS_ICO_PATH):
34-
log(f"Downloading {paths.ASSETS_BASE_URL}{paths.ASSETS_ICO_NAME}")
35-
download_assets_file(paths.ASSETS_ICO_NAME)
36-
# sys.exit(1)
37-
if not os.path.exists(paths.ASSETS_ICON_ENABLED_PATH):
38-
log(f"Downloading {paths.ASSETS_BASE_URL}{paths.ASSETS_ICON_ENABLED_NAME}")
39-
download_assets_file(paths.ASSETS_ICON_ENABLED_NAME)
40-
# sys.exit(1)
41-
if not os.path.exists(paths.ASSETS_ICON_DISABLED_PATH):
42-
log(f"Downloading {paths.ASSETS_BASE_URL}{paths.ASSETS_ICON_DISABLED_NAME}")
43-
download_assets_file(paths.ASSETS_ICON_DISABLED_NAME)
44-
# sys.exit(1)
45-
46-
# Check for temp folder
47-
if not os.path.exists(paths.MMT_DIR_PATH):
48-
os.makedirs(paths.MMT_DIR_PATH)
49-
log(f"Creating {paths.MMT_DIR_NAME} folder")
26+
paths_actions = {
27+
paths.CONFIG_PATH: _create_default_config_file,
28+
paths.ASSETS_DIR_PATH: lambda: os.mkdir(paths.ASSETS_DIR_PATH),
29+
paths.ASSETS_ICO_PATH: lambda: download_assets_file(paths.ASSETS_ICO_NAME),
30+
paths.ASSETS_ICON_ENABLED_PATH: lambda: download_assets_file(
31+
paths.ASSETS_ICON_ENABLED_NAME
32+
),
33+
paths.ASSETS_ICON_DISABLED_PATH: lambda: download_assets_file(
34+
paths.ASSETS_ICON_DISABLED_NAME
35+
),
36+
}
37+
for path, action in paths_actions.items():
38+
if not os.path.exists(path):
39+
action()
40+
log(INFO, f"Creating or downloading {os.path.basename(path)}")
5041

5142

5243
def download_assets_file(image_name):
53-
image_url = paths.ASSETS_BASE_URL + image_name
44+
image_url = os.path.join(paths.ASSETS_BASE_URL, image_name)
5445
response = requests.get(image_url, stream=True, timeout=5)
55-
5646
if response.status_code == 200:
57-
filename = response.url.split("/")[-1]
58-
59-
with open(os.path.join(paths.ASSETS_DIR_PATH, filename), "wb") as f:
47+
with open(os.path.join(paths.ASSETS_DIR_PATH, image_name), "wb") as f:
6048
for chunk in response.iter_content(1024):
6149
f.write(chunk)
6250
else:
63-
log(f"Error occurred while downloading {image_name}: {response.status_code}")
51+
log(
52+
ERROR,
53+
f"Error occurred while downloading {image_name}: {response.status_code}",
54+
)
6455

6556

6657
def init_config():
6758
_check_for_missing_files()
68-
69-
if get_first_start_value():
59+
if get_value(KEY_FIRST_START):
7060
ui.init_root_window()
71-
set_first_start_value(False)
72-
73-
74-
def get_mmt_path_value():
75-
_read_from_config()
76-
return _configparser.get(_SETTINGS_SECTION, _MMT_PATH_KEY)
77-
78-
79-
def set_mmt_path_value(_value):
80-
log(f"Config.ini - Setting mmt_path to {_value}")
81-
_configparser[_SETTINGS_SECTION][_MMT_PATH_KEY] = _value
82-
_write_to_config()
83-
84-
85-
def get_monitor_name_value():
86-
_read_from_config()
87-
return _configparser.get(_SETTINGS_SECTION, _MONITOR_NAME_KEY)
88-
61+
set_value(KEY_FIRST_START, False)
8962

90-
def set_monitor_name_value(_value):
91-
log(f"Config.ini - Setting monitor_name to {_value}")
92-
_configparser[_SETTINGS_SECTION][_MONITOR_NAME_KEY] = _value
93-
_write_to_config()
9463

95-
96-
def get_monitor_serial_value():
64+
def get_value(key):
9765
_read_from_config()
98-
return _configparser.get(_SETTINGS_SECTION, _MONITOR_SERIAL_KEY)
99-
66+
value = _configparser.get(_SECTION_SETTINGS, key)
67+
return value.lower() == "yes" if value.lower() in ["yes", "no"] else value
10068

101-
def set_monitor_serial_value(_value):
102-
log(f"Config.ini - Setting monitor_serial to {_value}")
103-
_configparser[_SETTINGS_SECTION][_MONITOR_SERIAL_KEY] = _value
104-
_write_to_config()
105-
106-
107-
def get_start_with_windows_value():
108-
_read_from_config()
109-
return _configparser.getboolean(_SETTINGS_SECTION, _START_WITH_WINDOWS_KEY)
110-
111-
112-
def set_start_with_windows_value(_value):
113-
value_str = "yes" if _value else "no"
114-
log(f"Config.ini - Setting start_with_windows to {value_str}")
115-
_configparser[_SETTINGS_SECTION][_START_WITH_WINDOWS_KEY] = value_str
116-
_write_to_config()
117-
118-
119-
def get_first_start_value():
120-
_read_from_config()
121-
return _configparser.getboolean(_SETTINGS_SECTION, _FIRST_START_KEY)
12269

70+
def set_value(key, value):
71+
if isinstance(value, bool):
72+
value_str = "yes" if value else "no"
73+
else:
74+
value_str = str(value)
12375

124-
def set_first_start_value(_value):
125-
value_str = "yes" if _value else "no"
126-
log(f"Config.ini - Setting first_start to {value_str}")
127-
_configparser[_SETTINGS_SECTION][_FIRST_START_KEY] = value_str
76+
log(INFO, f"{paths.CONFIG_FILE_NAME} - Setting {key} to {value_str}")
77+
_configparser[_SECTION_SETTINGS][key] = value_str
12878
_write_to_config()
12979

13080

@@ -138,11 +88,5 @@ def _write_to_config():
13888

13989

14090
def _create_default_config_file():
141-
_configparser[_SETTINGS_SECTION] = {
142-
_MONITOR_NAME_KEY: "Example Monitor",
143-
_MONITOR_SERIAL_KEY: "12345",
144-
_MMT_PATH_KEY: "C:/MultiMonitorTool.exe",
145-
_START_WITH_WINDOWS_KEY: "no",
146-
_FIRST_START_KEY: "yes",
147-
}
91+
_configparser[_SECTION_SETTINGS] = _DEFAULT_CONFIG
14892
_write_to_config()

smct/logger.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@
33
from smct.paths import LOG_PATH
44

55
ENCODING = "utf-8"
6+
INFO = "info"
7+
ERROR = "error"
68

79
LOG = None
810
STARTUP = True
911

1012
LOG_LINE_LIMIT = 300
1113

1214

13-
def log(text):
14-
LOG.info(text)
15+
def log(log_type, text):
16+
if log_type == ERROR:
17+
LOG.error(text)
18+
elif log_type == INFO:
19+
LOG.info(text)
1520

1621

1722
def clear_log_if_needed():

smct/multimonitortool.py

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import subprocess
2+
import os
23
import pandas as pd
34
from smct import config, paths
4-
from smct.logger import log
5+
from smct.logger import log, INFO, ERROR
56

67
MMT_CSV_MONITOR_NAME = "Monitor Name"
78
MMT_CSV_SERIAL_NUMBER = "Monitor Serial Number"
@@ -17,22 +18,24 @@ def get_monitor_selection_list():
1718
lambda row: f"{row[MMT_CSV_NAME][-1]} | {row[MMT_CSV_MONITOR_NAME]} | {row[MMT_CSV_SERIAL_NUMBER]}",
1819
axis=1,
1920
)
20-
monitor_df["display_string"].apply(lambda x: log(f"Monitor detected: {x}"))
21+
monitor_df["display_string"].apply(lambda x: log(INFO, f"Monitor detected: {x}"))
2122
return sorted(monitor_df["display_string"].tolist())
2223

2324

2425
def _get_monitor_df():
2526
_run_mmt_command("/scomma", paths.MMT_CSV_PATH)
26-
return pd.read_csv(paths.MMT_CSV_PATH)
27+
_return_df = pd.read_csv(paths.MMT_CSV_PATH)
28+
os.remove(paths.MMT_CSV_PATH)
29+
return _return_df
2730

2831

2932
def _run_mmt_command(command, destination):
30-
command_line = [config.get_mmt_path_value(), command, destination]
33+
command_line = [config.get_value(config.KEY_MMT_PATH), command, destination]
3134
try:
3235
subprocess.run(command_line, check=True)
33-
log(f"{' '.join(command_line)}")
36+
log(INFO, f"{paths.MMT_EXE_NAME} {command} {os.path.basename(destination)}")
3437
except subprocess.CalledProcessError as error:
35-
log(f"{' '.join(command_line)} failed: {error}")
38+
log(ERROR, f"{paths.MMT_EXE_NAME} {command} failed: {error}")
3639

3740

3841
def save_mmt_config():
@@ -43,44 +46,21 @@ def enable_monitor():
4346
_run_mmt_command("/LoadConfig", paths.MMT_CONFIG_PATH)
4447

4548

46-
def disable_monitor():
47-
if selected_monitor_id := get_selected_monitor_id():
48-
_run_mmt_command("/disable", selected_monitor_id)
49+
def disable_monitor(monitor_id):
50+
_run_mmt_command("/disable", str(monitor_id))
4951

5052

51-
def enable_all_disabled_monitors():
52-
disabled_monitor_ids = _get_all_disabled_monitor_ids()
53-
log("enable_all_disabled_monitors()")
54-
for _monitor_id in disabled_monitor_ids:
55-
_run_mmt_command("/enable", _monitor_id)
56-
57-
58-
def get_selected_monitor_id():
59-
condition = (
60-
_get_monitor_df()[MMT_CSV_MONITOR_NAME] == config.get_monitor_name_value()
53+
# returns if selected monitor is enabled AND its id
54+
def get_state_and_id_of_monitor():
55+
df = _get_monitor_df()
56+
id_condition = (
57+
df[MMT_CSV_MONITOR_NAME] == config.get_value(config.KEY_MONITOR_NAME)
6158
) & (
62-
_get_monitor_df()[MMT_CSV_SERIAL_NUMBER].astype(str)
63-
== config.get_monitor_serial_value()
59+
df[MMT_CSV_SERIAL_NUMBER].astype(str)
60+
== config.get_value(config.KEY_MONITOR_SERIAL)
6461
)
65-
filtered_df = _get_monitor_df().loc[condition]
66-
if not filtered_df.empty:
67-
return filtered_df.iloc[0][MMT_CSV_NAME][-1]
68-
69-
70-
def _get_all_disabled_monitor_ids():
71-
monitor_df = _get_monitor_df()
62+
state_condition = id_condition & (df[MMT_CSV_ACTIVE].str.lower() == MMT_CSV_YES)
7263
return (
73-
monitor_df[monitor_df[MMT_CSV_ACTIVE].str.lower() == MMT_CSV_NO][MMT_CSV_NAME]
74-
.apply(lambda x: x[-1])
75-
.tolist()
76-
)
77-
78-
79-
def is_selected_monitor_enabled():
80-
df = _get_monitor_df()
81-
condition = (
82-
(df[MMT_CSV_MONITOR_NAME] == config.get_monitor_name_value())
83-
& (df[MMT_CSV_SERIAL_NUMBER].astype(str) == config.get_monitor_serial_value())
84-
& (df[MMT_CSV_ACTIVE].str.lower() == MMT_CSV_YES)
64+
len(df.loc[state_condition]) == 1,
65+
df.loc[id_condition].iloc[0][MMT_CSV_NAME][-1],
8566
)
86-
return condition.any()

smct/paths.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ def strip_package_name_from_path(path):
2222
CONFIG_FILE_NAME = "config.ini"
2323
LOG_FILE_NAME = "smct.log"
2424
ASSETS_DIR_NAME = "assets"
25-
MMT_DIR_NAME = "mmt"
2625

27-
MMT_CSV_NAME = "MultiMonitorToolOutput.csv"
28-
MMT_CONFIG_NAME = "MultiMonitorToolConfig"
26+
MMT_EXE_NAME = "MultiMonitorTool.exe"
27+
MMT_CSV_NAME = "MultiMonitorToolScommaOutput.tmp"
28+
MMT_CONFIG_NAME = "MultiMonitorToolConfig.ini"
2929

3030
ASSETS_ICON_ENABLED_NAME = "tray_monitor_enabled.png"
3131
ASSETS_ICON_DISABLED_NAME = "tray_monitor_disabled.png"
@@ -40,10 +40,9 @@ def strip_package_name_from_path(path):
4040
CONFIG_PATH = os.path.join(BASE_PATH, CONFIG_FILE_NAME)
4141
LOG_PATH = os.path.join(BASE_PATH, LOG_FILE_NAME)
4242
ASSETS_DIR_PATH = os.path.join(BASE_PATH, ASSETS_DIR_NAME)
43-
MMT_DIR_PATH = os.path.join(BASE_PATH, MMT_DIR_NAME)
4443

45-
MMT_CSV_PATH = os.path.join(MMT_DIR_PATH, MMT_CSV_NAME)
46-
MMT_CONFIG_PATH = os.path.join(MMT_DIR_PATH, MMT_CONFIG_NAME)
44+
MMT_CSV_PATH = os.path.join(BASE_PATH, MMT_CSV_NAME)
45+
MMT_CONFIG_PATH = os.path.join(BASE_PATH, MMT_CONFIG_NAME)
4746

4847
ASSETS_ICON_ENABLED_PATH = os.path.join(ASSETS_DIR_PATH, ASSETS_ICON_ENABLED_NAME)
4948
ASSETS_ICON_DISABLED_PATH = os.path.join(ASSETS_DIR_PATH, ASSETS_ICON_DISABLED_NAME)

0 commit comments

Comments
 (0)