From 9f867d002c0ebcc716c6b6bffcf5ea8636c5297d Mon Sep 17 00:00:00 2001 From: Emma Nora Theuer Date: Mon, 3 Jun 2024 21:38:03 +0200 Subject: [PATCH] Move file to src/ --- src/wallman_lib.py | 182 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/wallman_lib.py diff --git a/src/wallman_lib.py b/src/wallman_lib.py new file mode 100644 index 0000000..1594a30 --- /dev/null +++ b/src/wallman_lib.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +from sys import exit +from os import chdir, getenv, system +import logging +import tomllib +from datetime import datetime, time +from apscheduler.schedulers.blocking import BlockingScheduler +from apscheduler.triggers.cron import CronTrigger + +# setup logging +chdir(str(getenv("HOME")) + "/.local/share/wallman/") +logger = logging.getLogger(__name__) +logging.basicConfig(filename="wallman.log", encoding="utf-8", level=logging.WARNING) + +# read config + # a = list(data["changing_times"].values()) + # print(a[0]) + +class ConfigError(Exception): + pass + +class _ConfigLib: + def _initialize_config(self) -> dict: + chdir(str(getenv("HOME")) + "/.config/wallman/") + with open("wallman.toml", "rb") as config_file: + data = tomllib.load(config_file) + return data + # a = list(data["changing_times"].values()) + # print(a[0]) + + def __init__(self): + self.config_file: dict = self._initialize_config() # Full config + # Dictionaries + self.config_general: dict = self.config_file["general"] + self.config_changing_times: dict = self.config_file["changing_times"] + # Values in Dicts + self.config_wallpaper_sets_enabled: bool = self.config_general["enable_wallpaper_sets"] + self.config_used_sets: list = self.config_general["used_sets"] + self.config_wallpapers_per_set: int = self.config_general["wallpapers_per_set"] + self.config_total_changing_times: int = len(self.config_changing_times) + try: + self.config_notify = self.config_general["notify"] + except KeyError: + self.config_notify = False + logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.") + + def _set_fallback_wallpaper(self): + if self.config_general["fallback_wallpaper"]: + system(f"feh --bg-fill --no-fehbg {self.config_general['fallback_wallpaper']}") + logger.info("The fallback Wallpaper has been set.") + else: + logger.critical("An Error occured and no fallback wallpaper was provided, exiting...") + raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...") + +class ConfigValidity(_ConfigLib): + def __init__(self): + super().__init__() + + def _check_fallback_wallpaper(self): + if self.config_general["fallback_wallpaper"]: + logger.debug("A fallback wallpaper has been defined.") + else: + logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.") + + def _check_wallpapers_per_set_and_changing_times(self) -> None: + # Check if the amount of wallpapers_per_set and given changing times match + if self.config_total_changing_times == self.config_wallpapers_per_set: + logger.debug("The amount of changing times and wallpapers per set is set correctly") + else: + try: + self._set_fallback_wallpaper() + logger.error("The amount of changing_times and the amount of wallpapers_per_set does not much, the fallback wallpaper has been set.") + print("ERROR: The amount of changing_times and the amount of wallpapers_per_set does not much, the fallback wallpaper has been set.") + exit(1) + except ConfigError: + logger.critical("The amount of changing times and the amount of wallpapers per set does not match, exiting...") + raise ConfigError("Please provide an amount of changing_times equal to wallpapers_per_set, exiting...") + + def _check_general_validity(self) -> None: + if len(self.config_general) < 3: + try: + self._set_fallback_wallpaper() + logger.error("An insufficient amount of elements has been provided for general, the fallback wallpaper has been set.") + print("ERROR: An insufficient amount of wallpapers has been provided for general, the fallback wallpaper has been set.") + exit(1) + except ConfigError: + logger.critical("An insufficient amount of elements for general has been provided, exiting...") + raise ConfigError("general should have at least 3 elements, exiting...") + + def _check_wallpaper_dicts(self)-> None: + # This block checks if a dictionary for each wallpaper set exists + for wallpaper_set in self.config_used_sets: + if wallpaper_set in self.config_file: + logger.debug(f"The dictionary {wallpaper_set} has been found in config.") + else: + try: + self._set_fallback_wallpaper() + logger.error(f"The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.") + print(f"ERROR: The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.") + exit(1) + except ConfigError: + logger.critical(f"No dictionary {wallpaper_set} has been found in the config exiting...") + raise ConfigError(f"The dictionary {wallpaper_set} has not been found in the config, exiting...") + + def _check_wallpaper_amount(self) -> None: + # This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set + for wallpaper_set in self.config_used_sets: + if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set: + logger.debug(f"Dictionary {wallpaper_set} has sufficient values.") + else: + try: + self._set_fallback_wallpaper() + logger.error(f"The Dictionary {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.") + print(f"ERROR: The Dictionaty {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.") + exit(1) + except ConfigError: + logger.critical(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...") + raise ConfigError(f"Dictionary {wallpaper_set} does not have the correct amount of entries, exciting...") + + def validate_config(self) -> None: + self._check_fallback_wallpaper() + self._check_wallpapers_per_set_and_changing_times() + self._check_general_validity() + self._check_wallpaper_dicts() + self._check_wallpaper_amount() + logger.debug("The config file has been validated successfully (No Errors)") + +class WallpaperLogic(_ConfigLib): + def __init__(self): + super().__init__() + self.chosen_wallpaper_set = False + + # Returns a list of a split string that contains a changing time from the config file + def _clean_times(self, desired_time) -> list: + unclean_times = list(self.config_changing_times.values())[desired_time] + return unclean_times.split(":") + + def _choose_wallpaper_set(self) -> None: + from random import choice as choose_from + self.chosen_wallpaper_set = choose_from(self.config_used_sets) + self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values()) + logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}") + + # Verify if a given time is in a given range + def _time_in_range(self, start, end, x) -> bool: + if start <= end: + return start <= x <= end + else: + return start <= x or x < end + + def _notify_user(self): + system("notify-send 'Wallman' 'A new Wallpaper has been set.'") + logger.debug("Sent desktop notification.") + + def set_wallpaper_by_time(self) -> None: + # Ensure use of a consistent wallpaper set + if self.chosen_wallpaper_set is False: + self._choose_wallpaper_set() + for time_range in range(self.config_total_changing_times - 1): + clean_time = self._clean_times(time_range) + clean_time_two = self._clean_times(time_range + 1) + # Check if the current time is between a given and the following changing time and if so, set that wallpaper. If not, keep trying. + if self._time_in_range(time(int(clean_time[0]), int(clean_time[1]), int(clean_time[2])), time(int(clean_time_two[0]), int(clean_time_two[1]), int(clean_time_two[2])), datetime.now().time()): + system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[time_range]}") + if self.config_notify: + self._notify_user() + return + else: + continue + + system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}") + if self.config_notify: + self._notify_user() + + def schedule_wallpapers(self): + scheduler = BlockingScheduler() + # Create a scheduled job for every changing time + for changing_time in range(len(self.config_changing_times)): + clean_time = self._clean_times(changing_time) + scheduler.add_job(self.set_wallpaper_by_time, trigger=CronTrigger(hour=clean_time[0], minute=clean_time[1], second=clean_time[2])) + scheduler.start() + logger.info("The scheduler has been started.")