Skip to content

Commit

Permalink
Changed the distribution of functions by classes
Browse files Browse the repository at this point in the history
  • Loading branch information
HappyCthulhu committed Oct 8, 2021
1 parent a906d42 commit 31d094d
Show file tree
Hide file tree
Showing 3 changed files with 322 additions and 0 deletions.
109 changes: 109 additions & 0 deletions card0_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import json
import os
from pathlib import Path

from logging_settings import set_logger


class CARD0:

@staticmethod
def check_cable_status(fp):
if Path(fp).is_file():
with open(fp, 'r') as file:
status = file.read().replace('\n', '')
return status

else:
return 'disconnected'

@staticmethod
def get_cables_path_condition_from_card0():
dirs = os.listdir(os.environ['CABLES_DIR'])
cables_dirs = list(filter(lambda path: 'HDMI' in path or 'DP' in path, dirs))
cables_path = [f'{os.environ["CABLES_DIR"]}{dir}' for dir in cables_dirs]
cables_path_condition = {}

for cable_path in cables_path:
with open(f'{cable_path}/status', 'r', encoding='utf-8') as file:
cables_path_condition[cable_path] = file.read().replace('\n', '')

return cables_path_condition

@staticmethod
def check_if_cable_was_disconnected(past_cables_conditions, cables_conditions_file_path):
removed_cables = []

# проходимся по списку из старых кабелей, отдельно получаем текущую информацию для кабеля, сравниваем
for port_path, port_past_condition in past_cables_conditions.copy().items():
current_cable_status = CARD0.check_cable_status(f'{port_path}/status').replace('\n', '')

if current_cable_status != port_past_condition:
removed_cables.append(port_path.split("/")[-1])
past_cables_conditions[port_path] = current_cable_status

with open(cables_conditions_file_path, 'w') as file:
json.dump(past_cables_conditions, file, indent=4)

# TODO: does this continue still needed?
continue

return removed_cables

@staticmethod
def check_if_cable_was_connected(past_cables_conditions, current_cables_conditions_from_card0):
new_cables = []

# проходимся по каждой кабелю из текущего состояния, смотрим, есть ли он в предыдущем состоянии
for port_path, current_condition in current_cables_conditions_from_card0.items():

# Проверяем, не появился ли новый кабель в card0
if not past_cables_conditions.get(port_path):
new_cables.append(port_path.split("/")[-1])

continue

return new_cables

@staticmethod
def check_cable_conditions_until_it_change(cabels_conditions_file_path):
p = Path('.')
PATH_TO_CURRENT_DIRECTORY = p.absolute()

while True:
path_for_check = Path(f'{PATH_TO_CURRENT_DIRECTORY}/{cabels_conditions_file_path}')
if not path_for_check.is_file() or path_for_check.stat().st_size == 0:
logger.debug(f'Файл конфигов был пуст или не существовал')

with open(cabels_conditions_file_path, 'w') as file:
json.dump(CARD0.get_cables_path_condition_from_card0(), file, indent=4)
return True

else:
with open(cabels_conditions_file_path, 'r') as file:
past_cables_conditions = json.load(file)

current_cables_conditions_from_card0 = CARD0.get_cables_path_condition_from_card0()

cables_changes = {
'new_cables': CARD0.check_if_cable_was_connected(past_cables_conditions,
current_cables_conditions_from_card0),
'removed_cables': CARD0.check_if_cable_was_disconnected(past_cables_conditions,
cabels_conditions_file_path)
}

with open(cabels_conditions_file_path, 'w') as file:
json.dump(current_cables_conditions_from_card0, file, indent=4)

if cables_changes['new_cables']:
logger.debug(f'Обнаружены новыe подключения: {cables_changes["new_cables"]}')
return True

if cables_changes['removed_cables']:
logger.debug(f'Следующие подключения были удалены: {cables_changes["removed_cables"]}')
return True

logger.debug('Подключения портов не изменились')


logger = set_logger()
126 changes: 126 additions & 0 deletions monitors_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import os
import time
from collections import OrderedDict

from logging_settings import set_logger
from xrandr_manager import XRANDR


class MONITORS:

@staticmethod
def set_monitors_position_manually():
monitors_data_from_xrandr = XRANDR.get_monitors_data_from_xrandr()

cables_ids_names = XRANDR.create_cable_id_cable_name_dict([*monitors_data_from_xrandr])

logger.info(
f"\n\nВот список подключенных мониторов в формате 'monitor_id --- monitor_name':\n"
f"{[f'{cable_id} --- {cable_name}' for cable_id, cable_name in cables_ids_names.items()]}\n"
f'\n'
f'Ниже через запятую введите список id мониторов в последовательности, которую вы хотели вы наблюдать:\n')
# TODO: проверить инпут на верность (мб там лишние значения есть например)
order_of_monitor_ids_from_input = [int(count) for count in input().strip().split(',')]

ordered_monitors = []

for monitor_id in order_of_monitor_ids_from_input:
cable_name = cables_ids_names[monitor_id]
ordered_monitors.append(cable_name)

return ordered_monitors

@staticmethod
def match_monitor_with_cable():
monitors_data_from_xrandr = XRANDR.get_monitors_data_from_xrandr()

# TODO: вот это у меня во многих местах встречается, нужно в отдельную функцию вынести

cables_ids_names = XRANDR.create_cable_id_cable_name_dict(monitors_data_from_xrandr.keys())

# TODO: вот это в отдельную функцию вынести, ибо используется в разных местах
logger.info(
f"\n\nВот список портов, к которым подключены мониторы в формате 'port_id --- port_name':\n"
f"{[f'{cable_id} --- {cable_name}' for cable_id, cable_name in cables_ids_names.items()]}\n"
f'\n'
f'Ниже введите id порта, чтобы узнать, какой монитор к нему подключен\n')
# TODO: проверить инпут на верность (мб там лишние значения есть например)
cable_id_from_input = int(input().strip())

logger.info(
'Сейчас на 3 секунды монитор, подключенный к выбранному вами кабелю поменяет яркость. Не прервайте работу скрипта!')

string_for_execute = f'xrandr --output {cables_ids_names[cable_id_from_input]} --brightness 0.5'
os.system(string_for_execute)

time.sleep(3)

string_for_execute = f'xrandr --output {cables_ids_names[cable_id_from_input]} --brightness 1'
os.system(string_for_execute)

logger.debug('Работа скрипта закончена')

@staticmethod
def delete_saved_config(saved_cables_positions):

saved_cable_position_with_id = XRANDR.create_layout_id_layout_name_dict(saved_cables_positions)

logger.info('Next strings will show monitors_positions in format: {config: [cable_1, cable_2, etc]}\n')
for id, monitors_names in saved_cable_position_with_id.items():
print(f'\n{id}: {monitors_names}')

logger.info('Write separate by commas ids of configs and script will delete them from saved configs')

# filter is needed in case of string: "1, 2, "
input_ids = [int(id) for id in list(filter(None, input().strip().split(',')))]
configs_for_delete = [saved_cable_position_with_id[id] for id in input_ids]

new_configs = []

for saved_config in saved_cables_positions:
if saved_config not in configs_for_delete:
new_configs.append(saved_config)

return new_configs

@staticmethod
def connect_monitors_automatically(data_from_xrandr):

if len(data_from_xrandr) > 1:
monitors_sorted_by_size = list(OrderedDict(sorted(list(data_from_xrandr.items()),
key=lambda value: XRANDR.get_monitor_dimensions(
value[1]['monitor_size']))).keys())
# TODO: нужно описать кейсы, когда в этой функции вообще есть смысл
# например, если скрипт начал работу на заднем плане. Чтоб хоть как-то моники подрубились... Удобнее работать?

return monitors_sorted_by_size

else:
os.system('xrandr --auto')
return data_from_xrandr

@staticmethod
def print_connected_cables(cables_conditions):
connected_cables = []

for cable_path, condition in cables_conditions.items():
if condition == 'connected':
connected_cables.append(cable_path.split('/')[-1])

logger.debug(f'Подключены следующие кабели: {connected_cables}')

@staticmethod
def create_new_collections_of_mon_positions(new_mon_pos, previous_monitor_positions):
for id, monitors_names_from_settings in enumerate(previous_monitor_positions):

if monitors_names_from_settings == new_mon_pos:
previous_monitor_positions.insert(0, previous_monitor_positions.pop(id))
new_monitors_positions = previous_monitor_positions
return new_monitors_positions

previous_monitor_positions.insert(0, new_mon_pos)
new_monitors_positions = previous_monitor_positions
return new_monitors_positions


logger = set_logger()
87 changes: 87 additions & 0 deletions xrandr_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import re
import subprocess


class XRANDR:
@staticmethod
def get_monitors_data_from_xrandr():
monitors = subprocess.check_output('xrandr').decode()

iterator = re.finditer(r"^\S[\W\w]*?(?=^(\S|$))", monitors, re.MULTILINE)
monitors = [match.group() for match in iterator]
connected_monitors = list(filter(lambda monitor_data: ' connected' in monitor_data, monitors))

monitors_data = list(zip([monitor.split()[0] for monitor in connected_monitors], connected_monitors))
physically_connected_monitors_data = {elem[0]: elem[1] for elem in monitors_data}

data_from_xrandr_about_physically_connected_monitors = {}

for port, data in physically_connected_monitors_data.items():
resolutions = list(filter(lambda word: 'x' in word, ''.join(data.splitlines()[1:-1]).split()))

monitor_size = data.splitlines()[0].split('y axis) ')[1]
monitor_size = [int(option.replace('mm', '')) for option in monitor_size.split('x')]

data_from_xrandr_about_physically_connected_monitors[port] = {'resolutions': resolutions,
'monitor_size': monitor_size}

return data_from_xrandr_about_physically_connected_monitors

@staticmethod
def create_cable_id_cable_name_dict(cables_names: list[str]):
# TODO: XRANDR_MANAGER. Почему? Это разве не действия с мониторами?
cables_ids_names = {id: cable for id, cable in enumerate(list(cables_names))}
return cables_ids_names

@staticmethod
def create_layout_id_layout_name_dict(cables_layout: list[list[str]]):
cables_ids_names = {id: [*monitors_position] for id, monitors_position in
enumerate(cables_layout)}

return cables_ids_names

@staticmethod
def get_monitor_dimensions(monitor_dimensions):
return monitor_dimensions[0] * monitor_dimensions[1]

@staticmethod
def create_string_for_execute(monitors_data: list[str]):
# TODO: XRANDR_MANAGER (приватная функция)
execute_command = []

# TODO: сюда еще дописать логгирование: в xrandr нет указанного вами монитора: monitor_name
xrandr_data = XRANDR.get_monitors_data_from_xrandr()

for id, cable_name in enumerate(monitors_data):
if len(monitors_data) == id + 1:
break

"""
sometimes, on some devices, xrandr works better, if u will enter commands sequentially.
so, its better to write command, each parts of which divided be |
also, we creating command with top quality of each monitor
"""

# TODO: первый аргумент в пользу данных из xrandr в формате словаря: можно будет спокойно получать информацию о мониторе по названию подключенного к нему кабеля. При использовании списка приходится юзать filter

execute_command.append(
f'xrandr --output {cable_name} --pos {xrandr_data[cable_name]["resolutions"][0]} --left-of {monitors_data[id + 1]} --pos {xrandr_data[monitors_data[id + 1]]["resolutions"][0]} | ')

execute_command = ' '.join(execute_command)

# cleaning spaces
execute_command = execute_command[0: -3]

return execute_command

@staticmethod
def get_needed_monitors_layout_config_automatically(data_from_xrandr, saved_configs):
# TODO: вот здесь нужно посмотреть, что происходт
# TODO: не очень понятно, к какому классу это стоит отнести
current_connection = set([elem for elem in [*data_from_xrandr]])

for saved_config in saved_configs:
if current_connection == set(saved_config):
return saved_config

return None

0 comments on commit 31d094d

Please sign in to comment.