Compare commits
81 commits
wallman-re
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
018a651d28 | ||
|
49c7cc9a05 | ||
|
e845bccdae | ||
|
c169438896 | ||
|
b3659914cd | ||
|
d21fd29dff | ||
|
b6f42fbf97 | ||
|
6f1d11a494 | ||
|
34590a6afe | ||
|
70f93f4405 | ||
|
c0c83246e3 | ||
|
72c736e6cd | ||
|
594ee118b6 | ||
|
2515d2d411 | ||
|
28b13ab589 | ||
|
3477c51b3d | ||
|
01983bfea6 | ||
|
8523929abc | ||
|
d3d2f8a829 | ||
|
10dabc805c | ||
|
5a913e25d8 | ||
|
5e0fd1f12b | ||
|
61a2962cb7 | ||
|
02354022fd | ||
|
291b45ec58 | ||
|
d69f539dd1 | ||
|
3c77a5f161 | ||
|
7fc02ac4a8 | ||
|
138053d8d1 | ||
|
fa13c7f135 | ||
|
e0aaed8e36 | ||
|
72b0d4b60f | ||
|
9d761e355b | ||
|
12dd9d66eb | ||
|
42c59597bf | ||
|
d69e03bcc0 | ||
|
55a753ac20 | ||
|
c9b76190f0 | ||
|
c6c4ba5a48 | ||
|
4aa7aa8577 | ||
|
22ae8e095f | ||
|
8592c226e7 | ||
|
391d60822a | ||
|
5fa2446830 | ||
|
c4aa64fdd9 | ||
|
155aad6fb7 | ||
|
93c5d7c938 | ||
|
38a83d5e09 | ||
|
1f1d181641 | ||
|
67ba450c36 | ||
|
e7a8243d6d | ||
|
c4bd6c2007 | ||
|
2b3c1518dc | ||
|
6f33d42600 | ||
|
76d2f164dd | ||
|
5fb88d7ccb | ||
|
74a275b423 | ||
|
83e6157cad | ||
|
b5c027a01a | ||
|
246152537e | ||
|
8918f934aa | ||
|
d8a46f2913 | ||
|
4c114c0e07 | ||
|
1bda243430 | ||
|
647837be27 | ||
|
aa927cd1db | ||
|
1b4bb676f7 | ||
|
61bcd19eb7 | ||
|
6c6e47a1c0 | ||
|
f329f3b455 | ||
|
fe657bdb02 | ||
|
03596e0423 | ||
|
e3a3cd2077 | ||
|
ce24b34eb1 | ||
|
c98d206ca3 | ||
|
a834483698 | ||
|
95fc359073 | ||
|
5a7b2fd43c | ||
|
f509f0b696 | ||
|
3329eef36f | ||
|
0587d5a983 |
17 changed files with 451 additions and 119 deletions
|
@ -1,2 +1,6 @@
|
||||||
graft src
|
graft src
|
||||||
|
include src/*.py
|
||||||
|
graft icons
|
||||||
|
graft distfiles
|
||||||
include sample_config.toml
|
include sample_config.toml
|
||||||
|
exclude README.org
|
||||||
|
|
55
README.org
55
README.org
|
@ -12,6 +12,7 @@ Wallman currently has three main features:
|
||||||
+ Reading configuration details from a TOML file
|
+ Reading configuration details from a TOML file
|
||||||
+ Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
|
+ Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
|
||||||
+ Settings Wallpapers at a specific time of the day
|
+ Settings Wallpapers at a specific time of the day
|
||||||
|
+ Be controlled via a systray
|
||||||
|
|
||||||
* Installation
|
* Installation
|
||||||
** Depedencies
|
** Depedencies
|
||||||
|
@ -21,30 +22,54 @@ Wallman currently has three main features:
|
||||||
+ feh (Used for setting the wallpapers, hard dependency)
|
+ feh (Used for setting the wallpapers, hard dependency)
|
||||||
*** Optional
|
*** Optional
|
||||||
+ libnotify (for desktop notification support)
|
+ libnotify (for desktop notification support)
|
||||||
|
+ pillow (For systray support)
|
||||||
|
+ pystray (For systray support)
|
||||||
*** Build dependencies
|
*** Build dependencies
|
||||||
+ setuptools
|
+ setuptools
|
||||||
+ build
|
+ build
|
||||||
|
|
||||||
|
|
||||||
|
** Installing with package Manager
|
||||||
|
*** Gentoo
|
||||||
|
This program, as of now, can be installed very easily on gentoo. Just follow these instructions:
|
||||||
|
#+BEGIN_SRC shell
|
||||||
|
git clone https://git.entheuer.de/emma/Wallman.git
|
||||||
|
doas eselect repository create wallman
|
||||||
|
doas cp -rf Wallman/distfiles/Gentoo/wallman /var/db/repos/
|
||||||
|
doas emerge -av wallman
|
||||||
|
#+END_SRC
|
||||||
|
A proper portage overlay will be created soon, so that updates can be handled automatically.
|
||||||
|
|
||||||
|
*** Arch Linux
|
||||||
|
Support for Arch Linux will be added soon.
|
||||||
|
|
||||||
|
*** Others
|
||||||
|
I will potentially write a version for nixpkgs and will also bundle wallman as a flatpak.
|
||||||
|
|
||||||
** Installing with pip
|
** Installing with pip
|
||||||
Wallman is available on PYPI. Simply run:
|
Wallman is available on PyPI. Simply run:
|
||||||
#+BEGIN_SRC shell
|
#+BEGIN_SRC shell
|
||||||
pip install wallman
|
pip install wallman
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Installing with package Manager
|
|
||||||
Versions in the AUR and an ebuild for Gentoo will be added soon. A flatpak and Nixpkgs version are on the horizon, too.
|
|
||||||
|
|
||||||
** Installing manually
|
** Installing manually
|
||||||
+ Clone this git repo
|
+ Install libnotify and feh from your package manager
|
||||||
+ Create a log file and a configuration file:
|
|
||||||
#+BEGIN_SRC shell
|
#+BEGIN_SRC shell
|
||||||
mkdir -p ~/.local/share/wallman
|
pip install APScheduler pystray pillow
|
||||||
|
git clone https://git.entheuer.de/emma/Wallman.git
|
||||||
|
cd Wallman/
|
||||||
|
sudo mkdir -p /var/log/wallman
|
||||||
|
sudo chmod 733 /var/log/wallman
|
||||||
mkdir -p ~/.config/wallman
|
mkdir -p ~/.config/wallman
|
||||||
touch ~/.local/share/wallman/wallman.log
|
|
||||||
cp sample_config.toml ~/.config/wallman/wallman.toml
|
cp sample_config.toml ~/.config/wallman/wallman.toml
|
||||||
|
doas mkdir -p /etc/wallman/
|
||||||
|
cp -R icons/ /etc/wallman/
|
||||||
|
doas cp src/wallman.py /usr/bin/wallman
|
||||||
|
doas cp src/wallman_lib.py /usr/bin/wallman_lib.py
|
||||||
|
doas cp src/wallman_systray.py /usr/bin/wallman_systray.py
|
||||||
|
doas chmod +x /usr/bin/wallman
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
+ Edit the sample config
|
+ Edit the sample config
|
||||||
+ (Optional): Adjust the loglevel to your liking. This will be part of the config or a command line argument soon.
|
|
||||||
+ Profit
|
+ Profit
|
||||||
|
|
||||||
* Configuration
|
* Configuration
|
||||||
|
@ -52,7 +77,7 @@ This is a short guide on how to correctly configure wallman. Look in the sample
|
||||||
** TOML Dictionaries
|
** TOML Dictionaries
|
||||||
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing_times that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used_sets list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
|
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing_times that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used_sets list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
|
||||||
*** general
|
*** general
|
||||||
In general, you need to always define 3 variables and you can optionally add two more:
|
In general, you need to always define 3 variables and you can optionally add three more:
|
||||||
+ enable_wallpaper_sets: bool
|
+ enable_wallpaper_sets: bool
|
||||||
A simple switch that states if you want to use different sets of wallpapers or not.
|
A simple switch that states if you want to use different sets of wallpapers or not.
|
||||||
+ used_sets: list
|
+ used_sets: list
|
||||||
|
@ -62,7 +87,11 @@ In general, you need to always define 3 variables and you can optionally add two
|
||||||
+ Optional: notify: bool
|
+ Optional: notify: bool
|
||||||
This defaults to "false". Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
|
This defaults to "false". Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
|
||||||
+ Optional: fallback_wallpaper: bool
|
+ Optional: fallback_wallpaper: bool
|
||||||
Wallpaper to be set if an error is found in the config. Defaults to None. If none is set and the config is written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1.
|
Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to None. If none is set and the config has been written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1. If The config is written correctly but the wallpaper intended to be set can't be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers.
|
||||||
|
+ Optional: loglevel: string
|
||||||
|
Loglevel to be used by wallman. Defaults to INFO. Choices MUST be DEBUG, INFO, WARNING, ERROR or CRITICAL. Using any capitalization is valid, all caps is reccomended. Wallman will crash if a value is specified that is not one of the specified ones.
|
||||||
|
+ Optional: systray: bool
|
||||||
|
This defaults to "true". This enables support for a systray that has the features to re-set your wallpaper (Mostly useful if feh shits itself or if you want to set the correct wallpaper for a specific time of day after your device was suspended) without rerolling the wallpaper set used, a button to reroll and then re-set the wallpaper, as well as a Quit button. Disable this to save a very tiny amount of memory.
|
||||||
|
|
||||||
*** changing_times
|
*** changing_times
|
||||||
The changing_times dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the "XX:YY:ZZ" 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
|
The changing_times dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the "XX:YY:ZZ" 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
|
||||||
|
@ -78,13 +107,11 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
|
||||||
+ Add documentation for developers
|
+ Add documentation for developers
|
||||||
|
|
||||||
** Technical Details
|
** Technical Details
|
||||||
+ Improve Modularity
|
+ Improve Modularity (Partially done)
|
||||||
+ Make the enabled flag in wallpaper_sets actually useful by making the used_sets field optional
|
+ Make the enabled flag in wallpaper_sets actually useful by making the used_sets field optional
|
||||||
+ Add support for different loglevels in the config file or as a command line argument
|
|
||||||
+ Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
|
+ Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
|
||||||
|
|
||||||
** Features
|
** Features
|
||||||
+ Add support for setting a fallback wallpaper if a wallpaper the user set is not found
|
|
||||||
+ Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
|
+ Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
|
||||||
+ Add support for wallpapers that change by the weather
|
+ Add support for wallpapers that change by the weather
|
||||||
+ Add support for live wallpapers
|
+ Add support for live wallpapers
|
||||||
|
|
1
distfiles/Gentoo/wallman/app-misc/wallman/Manifest
Normal file
1
distfiles/Gentoo/wallman/app-misc/wallman/Manifest
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DIST wallman-1.4.2.4.tar.gz 871198 BLAKE2B 02ccfa69e14b73eff667ecf4707fcebd08ba63362a6e25ae77bef96ff77d8723e417e14e8586f2b8a9e0b23f29a1be8b7e1c0cab10a7f242dc8a7b2fe418cfe4 SHA512 87f2cad40f6db418dc4a94a259b4c491e69fc0f7bdf121196679270492227449f79751f40467d6f50e4bf7598e38d78853818ac9df8cfa96a7dc34698128ac71
|
21
distfiles/Gentoo/wallman/app-misc/wallman/metadata.xml
Normal file
21
distfiles/Gentoo/wallman/app-misc/wallman/metadata.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE pkgmetadata SYSTEM "https://www.gentoo.org/dtd/metadata.dtd">
|
||||||
|
<pkgmetadata>
|
||||||
|
<maintainer type="person">
|
||||||
|
<name>Emma Nora Theuer</name>
|
||||||
|
<email>gentoo@entheuer.de</email>
|
||||||
|
</maintainer>
|
||||||
|
<upstream>
|
||||||
|
<remote-id type="pypi">Wallman</remote-id>
|
||||||
|
</upstream>
|
||||||
|
<longdescription>
|
||||||
|
Wallman is a small python program meant to bring dynamic wallpapers
|
||||||
|
to standalone X11 Window managers and Wayland compositors.
|
||||||
|
It uses APScheduler in the background. For setting wallpaperss
|
||||||
|
It currently relies on feh in the background. libnotify is used for
|
||||||
|
Desktop notifications.
|
||||||
|
|
||||||
|
Wallman reads it's configuration data from a TOML file and logs to
|
||||||
|
~/.local/share/wallman/wallman.log
|
||||||
|
</longdescription>
|
||||||
|
</pkgmetadata>
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Copyright 1999-2024 Gentoo Authors
|
||||||
|
# Distributed under the terms of the MIT License
|
||||||
|
|
||||||
|
EAPI=8
|
||||||
|
|
||||||
|
DISTUTILS_USE_PEP517=setuptools
|
||||||
|
PYTHON_COMPAT=( python3_{11,12} )
|
||||||
|
inherit distutils-r1 pypi
|
||||||
|
|
||||||
|
DESCRIPTION="A python program that sets dynamic wallpapers on minimalistic Window Managers."
|
||||||
|
HOMEPAGE="https://git.entheuer.de/emma/wallman/"
|
||||||
|
SRC_URI="$(pypi_sdist_url "${PN^}" "${PV}")"
|
||||||
|
|
||||||
|
LICENSE="MIT"
|
||||||
|
SLOT="0"
|
||||||
|
KEYWORDS="~amd64 ~x86"
|
||||||
|
|
||||||
|
RDEPEND="
|
||||||
|
dev-python/APScheduler[${PYTHON_USEDEP}]
|
||||||
|
dev-python/pillow[${PYTHON_USEDEP}]
|
||||||
|
dev-python/pystray[${PYTHON_USEDEP}]
|
||||||
|
media-gfx/feh
|
||||||
|
x11-libs/libnotify
|
||||||
|
"
|
||||||
|
|
||||||
|
BDEPEND="
|
||||||
|
dev-python/setuptools[${PYTHON_USEDEP}]
|
||||||
|
dev-python/wheel[${PYTHON_USEDEP}]
|
||||||
|
dev-python/certifi[${PYTHON_USEDEP}]
|
||||||
|
"
|
||||||
|
|
||||||
|
src_prepare() {
|
||||||
|
distutils-r1_python_prepare_all
|
||||||
|
}
|
||||||
|
|
||||||
|
#src_prepare() {
|
||||||
|
# mv src/* . || die "Failed to move source files"
|
||||||
|
#}
|
||||||
|
python_compile() {
|
||||||
|
distutils-r1_python_compile -j1
|
||||||
|
}
|
||||||
|
python_install() {
|
||||||
|
distutils-r1_python_install
|
||||||
|
# Add a symlink to make the script callable from the commandline
|
||||||
|
local scriptname="wallman.py"
|
||||||
|
local target="/usr/bin/wallman"
|
||||||
|
local scriptpath="$(python_get_sitedir)/${scriptname}"
|
||||||
|
fperms +x "${scriptpath}"
|
||||||
|
dosym "${scriptpath}" "${target}"
|
||||||
|
# Copy files into /etc/wallman
|
||||||
|
dodir /etc/wallman
|
||||||
|
insinto /etc/wallman
|
||||||
|
newins "${S}/sample_config.toml" "wallman.toml"
|
||||||
|
doins -r "${S}/icons/" "icons/"
|
||||||
|
# Create logfile directory
|
||||||
|
dodir /var/log/wallman
|
||||||
|
keepdir /var/log/wallman
|
||||||
|
fperms 0733 /var/log/wallman
|
||||||
|
# Copy .desktop file into the appropriate location
|
||||||
|
insinto /usr/share/applications
|
||||||
|
newins "${S}/distfiles/wallman.desktop" "wallman.desktop"
|
||||||
|
}
|
||||||
|
|
||||||
|
#src_install() {
|
||||||
|
#}
|
||||||
|
|
||||||
|
pkg_postinst() {
|
||||||
|
elog "Wallman has been installed. A sample configuration file called wallman.toml is located in /etc/wallman. Copy that file into ~/.config/wallman/wallman.toml to configure wallman."
|
||||||
|
elog "A log file for Wallman can be found in /etc/log/wallman"
|
||||||
|
}
|
3
distfiles/Gentoo/wallman/metadata/layout.conf
Normal file
3
distfiles/Gentoo/wallman/metadata/layout.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
masters = gentoo
|
||||||
|
thin-manifests = true
|
||||||
|
sign-manifests = false
|
1
distfiles/Gentoo/wallman/profiles/eapi
Normal file
1
distfiles/Gentoo/wallman/profiles/eapi
Normal file
|
@ -0,0 +1 @@
|
||||||
|
8
|
1
distfiles/Gentoo/wallman/profiles/repo_name
Normal file
1
distfiles/Gentoo/wallman/profiles/repo_name
Normal file
|
@ -0,0 +1 @@
|
||||||
|
wallman
|
8
distfiles/wallman.desktop
Executable file
8
distfiles/wallman.desktop
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=wallman
|
||||||
|
Comment=run wallman
|
||||||
|
Exec=wallman
|
||||||
|
Icon=/etc/wallman/icons/WallmanLogo.jpg
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility;
|
BIN
icons/WallmanLogo.jpg
Normal file
BIN
icons/WallmanLogo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 833 KiB |
BIN
icons/systrayIcon.jpg
Normal file
BIN
icons/systrayIcon.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
156
pypireadme.md
156
pypireadme.md
|
@ -1,34 +1,38 @@
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
1. [Overwiev](#org19ef638)
|
1. [Overwiev](#orga779aae)
|
||||||
1. [What is this?](#org148aad0)
|
1. [What is this?](#orgf7b412d)
|
||||||
2. [What can it do?](#org0041bf1)
|
2. [What can it do?](#org935ec0e)
|
||||||
2. [Installation](#orgc40ee8b)
|
2. [Installation](#org022a1fd)
|
||||||
1. [Depedencies](#org2cb62ef)
|
1. [Depedencies](#org90be55c)
|
||||||
1. [Always Required](#org0d0b0f7)
|
1. [Always Required](#orgadb7aa8)
|
||||||
2. [Optional](#orgf04ec77)
|
2. [Optional](#org407e4c9)
|
||||||
3. [Build dependencies](#org3951087)
|
3. [Build dependencies](#orgab711aa)
|
||||||
2. [Installing with pip](#org24bde1c)
|
2. [Installing with package Manager](#org2a19ad0)
|
||||||
3. [Installing with package Manager](#org9575c55)
|
1. [Gentoo](#org6686b86)
|
||||||
4. [Installing manually](#org2c63e0f)
|
2. [Arch Linux](#org4eb492d)
|
||||||
3. [Configuration](#org812c501)
|
3. [Others](#orga6b4e6a)
|
||||||
1. [TOML Dictionaries](#org51e3333)
|
3. [Installing with pip](#org1b5b1b3)
|
||||||
1. [general](#org79747a5)
|
4. [Installing manually](#org050e242)
|
||||||
2. [changing<sub>times</sub>](#orgc425813)
|
3. [Configuration](#orgf368a5c)
|
||||||
3. [The other dictionaries](#org9f47b06)
|
1. [TOML Dictionaries](#org05ab08e)
|
||||||
4. [TODOs](#orgc26c243)
|
1. [general](#orgfa7800e)
|
||||||
1. [Structuring](#org8dd22d4)
|
2. [changing<sub>times</sub>](#org2778aa9)
|
||||||
2. [Technical Details](#org6103451)
|
3. [The other dictionaries](#orgf21f2d8)
|
||||||
3. [Features](#org38d78ba)
|
4. [TODOs](#org8cbebae)
|
||||||
|
1. [Structuring](#orgb43553d)
|
||||||
|
2. [Technical Details](#org0a633fb)
|
||||||
|
3. [Features](#org1c5725d)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a id="org19ef638"></a>
|
<a id="orga779aae"></a>
|
||||||
|
|
||||||
# Overwiev
|
# Overwiev
|
||||||
|
|
||||||
|
|
||||||
<a id="org148aad0"></a>
|
<a id="orgf7b412d"></a>
|
||||||
|
|
||||||
## What is this?
|
## What is this?
|
||||||
|
|
||||||
|
@ -37,7 +41,7 @@ This version is an early Alpha. As of now, it supports the most important featur
|
||||||
As such, please make absolutely sure you follow the instructions on how to write the config file very closely. I will implement better config handling with more meaningful error output in the future. For now, follow everything really closely and read the logs if needed. If you do that, it *should* work.
|
As such, please make absolutely sure you follow the instructions on how to write the config file very closely. I will implement better config handling with more meaningful error output in the future. For now, follow everything really closely and read the logs if needed. If you do that, it *should* work.
|
||||||
|
|
||||||
|
|
||||||
<a id="org0041bf1"></a>
|
<a id="org935ec0e"></a>
|
||||||
|
|
||||||
## What can it do?
|
## What can it do?
|
||||||
|
|
||||||
|
@ -46,19 +50,20 @@ Wallman currently has three main features:
|
||||||
- Reading configuration details from a TOML file
|
- Reading configuration details from a TOML file
|
||||||
- Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
|
- Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
|
||||||
- Settings Wallpapers at a specific time of the day
|
- Settings Wallpapers at a specific time of the day
|
||||||
|
- Be controlled via a systray
|
||||||
|
|
||||||
|
|
||||||
<a id="orgc40ee8b"></a>
|
<a id="org022a1fd"></a>
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
|
|
||||||
<a id="org2cb62ef"></a>
|
<a id="org90be55c"></a>
|
||||||
|
|
||||||
## Depedencies
|
## Depedencies
|
||||||
|
|
||||||
|
|
||||||
<a id="org0d0b0f7"></a>
|
<a id="orgadb7aa8"></a>
|
||||||
|
|
||||||
### Always Required
|
### Always Required
|
||||||
|
|
||||||
|
@ -67,14 +72,16 @@ Wallman currently has three main features:
|
||||||
- feh (Used for setting the wallpapers, hard dependency)
|
- feh (Used for setting the wallpapers, hard dependency)
|
||||||
|
|
||||||
|
|
||||||
<a id="orgf04ec77"></a>
|
<a id="org407e4c9"></a>
|
||||||
|
|
||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- libnotify (for desktop notification support)
|
- libnotify (for desktop notification support)
|
||||||
|
- pillow (For systray support)
|
||||||
|
- pystray (For systray support)
|
||||||
|
|
||||||
|
|
||||||
<a id="org3951087"></a>
|
<a id="orgab711aa"></a>
|
||||||
|
|
||||||
### Build dependencies
|
### Build dependencies
|
||||||
|
|
||||||
|
@ -82,58 +89,91 @@ Wallman currently has three main features:
|
||||||
- build
|
- build
|
||||||
|
|
||||||
|
|
||||||
<a id="org24bde1c"></a>
|
<a id="org2a19ad0"></a>
|
||||||
|
|
||||||
|
## Installing with package Manager
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org6686b86"></a>
|
||||||
|
|
||||||
|
### Gentoo
|
||||||
|
|
||||||
|
This program, as of now, can be installed very easily on gentoo. Just follow these instructions:
|
||||||
|
|
||||||
|
git clone https://git.entheuer.de/emma/Wallman.git
|
||||||
|
doas eselect repository create wallman
|
||||||
|
doas cp -rf Wallman/distfiles/Gentoo/wallman /var/db/repos/
|
||||||
|
doas emerge -av wallman
|
||||||
|
|
||||||
|
A proper portage overlay will be created soon, so that updates can be handled automatically.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org4eb492d"></a>
|
||||||
|
|
||||||
|
### Arch Linux
|
||||||
|
|
||||||
|
Support for Arch Linux will be added soon.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orga6b4e6a"></a>
|
||||||
|
|
||||||
|
### Others
|
||||||
|
|
||||||
|
I will potentially write a version for nixpkgs and will also bundle wallman as a flatpak.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org1b5b1b3"></a>
|
||||||
|
|
||||||
## Installing with pip
|
## Installing with pip
|
||||||
|
|
||||||
Wallman is available on PYPI. Simply run:
|
Wallman is available on PyPI. Simply run:
|
||||||
|
|
||||||
pip install wallman
|
pip install wallman
|
||||||
|
|
||||||
|
|
||||||
<a id="org9575c55"></a>
|
<a id="org050e242"></a>
|
||||||
|
|
||||||
## Installing with package Manager
|
|
||||||
|
|
||||||
Versions in the AUR and an ebuild for Gentoo will be added soon. A flatpak and Nixpkgs version are on the horizon, too.
|
|
||||||
|
|
||||||
|
|
||||||
<a id="org2c63e0f"></a>
|
|
||||||
|
|
||||||
## Installing manually
|
## Installing manually
|
||||||
|
|
||||||
- Clone this git repo
|
- Install libnotify and feh from your package manager
|
||||||
- Create a log file and a configuration file:
|
|
||||||
|
|
||||||
mkdir -p ~/.local/share/wallman
|
pip install APScheduler pystray pillow
|
||||||
|
git clone https://git.entheuer.de/emma/Wallman.git
|
||||||
|
cd Wallman/
|
||||||
|
sudo mkdir -p /var/log/wallman
|
||||||
|
sudo chmod 733 /var/log/wallman
|
||||||
mkdir -p ~/.config/wallman
|
mkdir -p ~/.config/wallman
|
||||||
touch ~/.local/share/wallman/wallman.log
|
|
||||||
cp sample_config.toml ~/.config/wallman/wallman.toml
|
cp sample_config.toml ~/.config/wallman/wallman.toml
|
||||||
|
doas mkdir -p /etc/wallman/
|
||||||
|
cp -R icons/ /etc/wallman/
|
||||||
|
doas cp src/wallman.py /usr/bin/wallman
|
||||||
|
doas cp src/wallman_lib.py /usr/bin/wallman_lib.py
|
||||||
|
doas cp src/wallman_systray.py /usr/bin/wallman_systray.py
|
||||||
|
doas chmod +x /usr/bin/wallman
|
||||||
|
|
||||||
- Edit the sample config
|
- Edit the sample config
|
||||||
- (Optional): Adjust the loglevel to your liking. This will be part of the config or a command line argument soon.
|
|
||||||
- Profit
|
- Profit
|
||||||
|
|
||||||
|
|
||||||
<a id="org812c501"></a>
|
<a id="orgf368a5c"></a>
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
This is a short guide on how to correctly configure wallman. Look in the sample config for additional context.
|
This is a short guide on how to correctly configure wallman. Look in the sample config for additional context.
|
||||||
|
|
||||||
|
|
||||||
<a id="org51e3333"></a>
|
<a id="org05ab08e"></a>
|
||||||
|
|
||||||
## TOML Dictionaries
|
## TOML Dictionaries
|
||||||
|
|
||||||
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing<sub>times</sub> that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used<sub>sets</sub> list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
|
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing<sub>times</sub> that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used<sub>sets</sub> list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
|
||||||
|
|
||||||
|
|
||||||
<a id="org79747a5"></a>
|
<a id="orgfa7800e"></a>
|
||||||
|
|
||||||
### general
|
### general
|
||||||
|
|
||||||
In general, you need to always define 3 variables and you can optionally add two more:
|
In general, you need to always define 3 variables and you can optionally add three more:
|
||||||
|
|
||||||
- enable<sub>wallpaper</sub><sub>sets</sub>: bool
|
- enable<sub>wallpaper</sub><sub>sets</sub>: bool
|
||||||
A simple switch that states if you want to use different sets of wallpapers or not.
|
A simple switch that states if you want to use different sets of wallpapers or not.
|
||||||
|
@ -144,17 +184,21 @@ In general, you need to always define 3 variables and you can optionally add two
|
||||||
- Optional: notify: bool
|
- Optional: notify: bool
|
||||||
This defaults to “false”. Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
|
This defaults to “false”. Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
|
||||||
- Optional: fallback<sub>wallpaper</sub>: bool
|
- Optional: fallback<sub>wallpaper</sub>: bool
|
||||||
Wallpaper to be set if an error is found in the config. Defaults to None. If none is set and the config is written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1.
|
Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to None. If none is set and the config has been written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1. If The config is written correctly but the wallpaper intended to be set can’t be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers.
|
||||||
|
- Optional: loglevel: string
|
||||||
|
Loglevel to be used by wallman. Defaults to INFO. Choices MUST be DEBUG, INFO, WARNING, ERROR or CRITICAL. Using any capitalization is valid, all caps is reccomended. Wallman will crash if a value is specified that is not one of the specified ones.
|
||||||
|
- Optional: systray: bool
|
||||||
|
This defaults to “true”. This enables support for a systray that has the features to re-set your wallpaper (Mostly useful if feh shits itself or if you want to set the correct wallpaper for a specific time of day after your device was suspended) without rerolling the wallpaper set used, a button to reroll and then re-set the wallpaper, as well as a Quit button. Disable this to save a very tiny amount of memory.
|
||||||
|
|
||||||
|
|
||||||
<a id="orgc425813"></a>
|
<a id="org2778aa9"></a>
|
||||||
|
|
||||||
### changing<sub>times</sub>
|
### changing<sub>times</sub>
|
||||||
|
|
||||||
The changing<sub>times</sub> dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the “XX:YY:ZZ” 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
|
The changing<sub>times</sub> dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the “XX:YY:ZZ” 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
|
||||||
|
|
||||||
|
|
||||||
<a id="org9f47b06"></a>
|
<a id="orgf21f2d8"></a>
|
||||||
|
|
||||||
### The other dictionaries
|
### The other dictionaries
|
||||||
|
|
||||||
|
@ -162,12 +206,12 @@ The other dictionaries must always have the names of the wallpaper sets from use
|
||||||
The keys in the dictionary once again do not matter, the names of the keys in each dictionary must be strings and be absolute paths. They should not include spaces unless prefaced by a backslash.
|
The keys in the dictionary once again do not matter, the names of the keys in each dictionary must be strings and be absolute paths. They should not include spaces unless prefaced by a backslash.
|
||||||
|
|
||||||
|
|
||||||
<a id="orgc26c243"></a>
|
<a id="org8cbebae"></a>
|
||||||
|
|
||||||
# TODOs
|
# TODOs
|
||||||
|
|
||||||
|
|
||||||
<a id="org8dd22d4"></a>
|
<a id="orgb43553d"></a>
|
||||||
|
|
||||||
## Structuring
|
## Structuring
|
||||||
|
|
||||||
|
@ -175,21 +219,19 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
|
||||||
- Add documentation for developers
|
- Add documentation for developers
|
||||||
|
|
||||||
|
|
||||||
<a id="org6103451"></a>
|
<a id="org0a633fb"></a>
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
- Improve Modularity
|
- Improve Modularity (Partially done)
|
||||||
- Make the enabled flag in wallpaper<sub>sets</sub> actually useful by making the used<sub>sets</sub> field optional
|
- Make the enabled flag in wallpaper<sub>sets</sub> actually useful by making the used<sub>sets</sub> field optional
|
||||||
- Add support for different loglevels in the config file or as a command line argument
|
|
||||||
- Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
|
- Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
|
||||||
|
|
||||||
|
|
||||||
<a id="org38d78ba"></a>
|
<a id="org1c5725d"></a>
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Add support for setting a fallback wallpaper if a wallpaper the user set is not found
|
|
||||||
- Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
|
- Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
|
||||||
- Add support for wallpapers that change by the weather
|
- Add support for wallpapers that change by the weather
|
||||||
- Add support for live wallpapers
|
- Add support for live wallpapers
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "wallman"
|
name = "wallman"
|
||||||
version = "1.3.0b1"
|
version = "1.4.2.4"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Emma Nora Theuer", email = "wallman@entheuer.de"},
|
{name = "Emma Nora Theuer", email = "wallman@entheuer.de"},
|
||||||
]
|
]
|
||||||
|
@ -24,6 +24,8 @@ classifiers = [
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"APScheduler",
|
"APScheduler",
|
||||||
|
"pillow",
|
||||||
|
"pystray",
|
||||||
'importlib-metadata; python_version<"3.10"',
|
'importlib-metadata; python_version<"3.10"',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ used_sets = ["anime", "nature"]
|
||||||
wallpapers_per_set = 5
|
wallpapers_per_set = 5
|
||||||
notify = False
|
notify = False
|
||||||
fallback_wallpaper = "/path/to/paper"
|
fallback_wallpaper = "/path/to/paper"
|
||||||
|
loglevel = "INFO"
|
||||||
|
systray = true
|
||||||
|
|
||||||
# Enter the hours at which you want the wallpaper to change.
|
# Enter the hours at which you want the wallpaper to change.
|
||||||
# If the script is called between one of this times, it will go back to the previous time.
|
# If the script is called between one of this times, it will go back to the previous time.
|
||||||
|
|
|
@ -6,7 +6,7 @@ def main():
|
||||||
logic = wallman_lib.WallpaperLogic()
|
logic = wallman_lib.WallpaperLogic()
|
||||||
validator.validate_config()
|
validator.validate_config()
|
||||||
logic.set_wallpaper_by_time()
|
logic.set_wallpaper_by_time()
|
||||||
logic.schedule_wallpapers()
|
logic.run_wallpapers()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
|
@ -1,33 +1,18 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from sys import exit
|
from sys import exit
|
||||||
from os import chdir, getenv, system
|
from os import chdir, getenv, system
|
||||||
import logging
|
import logging
|
||||||
import tomllib
|
import tomllib
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
|
|
||||||
# setup logging
|
# Setup Logging. NOTE: Declaration as a global variable is necessary to ensure correct functionality across multiple modules.
|
||||||
chdir(str(getenv("HOME")) + "/.local/share/wallman/")
|
logger = logging.getLogger("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):
|
class ConfigError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class _ConfigLib:
|
class _ConfigLib:
|
||||||
def _initialize_config(self) -> dict:
|
# Initializes the most important config values. TODO: Add handling for the empty config case
|
||||||
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):
|
def __init__(self):
|
||||||
self.config_file: dict = self._initialize_config() # Full config
|
self.config_file: dict = self._initialize_config() # Full config
|
||||||
# Dictionaries
|
# Dictionaries
|
||||||
|
@ -38,11 +23,46 @@ class _ConfigLib:
|
||||||
self.config_used_sets: list = self.config_general["used_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_wallpapers_per_set: int = self.config_general["wallpapers_per_set"]
|
||||||
self.config_total_changing_times: int = len(self.config_changing_times)
|
self.config_total_changing_times: int = len(self.config_changing_times)
|
||||||
|
self.config_log_level: str = self.config_general.get("loglevel", "INFO").upper()
|
||||||
|
# HACK: Add a function to handle these try/except blocks cleanlier.
|
||||||
try:
|
try:
|
||||||
self.config_notify = self.config_general["notify"]
|
self.config_notify: bool = self.config_general["notify"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.config_notify = False
|
self.config_notify: bool = False
|
||||||
logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.")
|
logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.")
|
||||||
|
try:
|
||||||
|
self.config_systray = self.config_general["systray"]
|
||||||
|
except KeyError:
|
||||||
|
self.config_systray = True
|
||||||
|
logger.warning("'systray' is not set in the dictionary general in the config file, defaulting to 'true'.")
|
||||||
|
|
||||||
|
# Setup logging
|
||||||
|
self._set_log_level()
|
||||||
|
# Setup systray.
|
||||||
|
if self.config_systray:
|
||||||
|
self._initialize_systray()
|
||||||
|
|
||||||
|
# Read config. TODO: Add error handling for the config not found case.
|
||||||
|
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
|
||||||
|
|
||||||
|
# HACK on this to avoid double importing of wallman_systray due to variable scope. Idea: Global variable or Variable that is inherited?
|
||||||
|
def _initialize_systray(self):
|
||||||
|
try:
|
||||||
|
import wallman_systray
|
||||||
|
except (ImportError, FileNotFoundError):
|
||||||
|
self.config_systray = False
|
||||||
|
|
||||||
|
def _set_log_level(self):
|
||||||
|
global logging
|
||||||
|
global logger
|
||||||
|
chdir("/var/log/wallman/")
|
||||||
|
numeric_level = getattr(logging, self.config_log_level, logging.INFO)
|
||||||
|
logger.setLevel(numeric_level)
|
||||||
|
logging.basicConfig(filename="wallman.log", encoding="utf-8", level=numeric_level)
|
||||||
|
|
||||||
def _set_fallback_wallpaper(self):
|
def _set_fallback_wallpaper(self):
|
||||||
if self.config_general["fallback_wallpaper"]:
|
if self.config_general["fallback_wallpaper"]:
|
||||||
|
@ -53,94 +73,121 @@ class _ConfigLib:
|
||||||
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
|
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
|
||||||
|
|
||||||
class ConfigValidity(_ConfigLib):
|
class ConfigValidity(_ConfigLib):
|
||||||
|
# TODO: Add handling for the empty config case.
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def _check_fallback_wallpaper(self):
|
def _check_fallback_wallpaper(self):
|
||||||
if self.config_general["fallback_wallpaper"]:
|
if self.config_general["fallback_wallpaper"]:
|
||||||
logger.debug("A fallback wallpaper has been defined.")
|
logger.debug("A fallback wallpaper has been defined.")
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.")
|
logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.")
|
||||||
|
return False
|
||||||
|
|
||||||
def _check_wallpapers_per_set_and_changing_times(self) -> None:
|
def _check_wallpapers_per_set_and_changing_times(self) -> bool:
|
||||||
# Check if the amount of wallpapers_per_set and given changing times match
|
# Check if the amount of wallpapers_per_set and given changing times match
|
||||||
if self.config_total_changing_times == self.config_wallpapers_per_set:
|
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")
|
logger.debug("The amount of changing times and wallpapers per set is set correctly")
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._set_fallback_wallpaper()
|
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.")
|
logger.error("The amount of changing_times and the amount of wallpapers_per_set does not match, 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.")
|
print("ERROR: The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
|
||||||
exit(1)
|
return False
|
||||||
except ConfigError:
|
except ConfigError:
|
||||||
logger.critical("The amount of changing times and the amount of wallpapers per set does not match, exiting...")
|
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...")
|
raise ConfigError("Please provide an amount of changing_times equal to wallpapers_per_set, exiting...")
|
||||||
|
|
||||||
def _check_general_validity(self) -> None:
|
def _check_general_validity(self) -> bool:
|
||||||
|
# FIXME!
|
||||||
|
# HACK: Adjust it to check for the actually required variables existing rather than check if a number of options is set, which is highly error prone.
|
||||||
if len(self.config_general) < 3:
|
if len(self.config_general) < 3:
|
||||||
try:
|
try:
|
||||||
self._set_fallback_wallpaper()
|
self._set_fallback_wallpaper()
|
||||||
logger.error("An insufficient amount of elements has been provided for general, the fallback wallpaper has been set.")
|
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.")
|
print("ERROR: An insufficient amount of wallpapers has been provided for general, the fallback wallpaper has been set.")
|
||||||
exit(1)
|
return False
|
||||||
except ConfigError:
|
except ConfigError:
|
||||||
logger.critical("An insufficient amount of elements for general has been provided, exiting...")
|
logger.critical("An insufficient amount of elements for general has been provided, exiting...")
|
||||||
raise ConfigError("general should have at least 3 elements, exiting...")
|
raise ConfigError("general should have at least 3 elements, exiting...")
|
||||||
|
|
||||||
def _check_wallpaper_dicts(self)-> None:
|
else:
|
||||||
|
logger.debug("A valid amount of options has been provided in general")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _check_wallpaper_dicts(self):
|
||||||
# This block checks if a dictionary for each wallpaper set exists
|
# This block checks if a dictionary for each wallpaper set exists
|
||||||
for wallpaper_set in self.config_used_sets:
|
for wallpaper_set in self.config_used_sets:
|
||||||
if wallpaper_set in self.config_file:
|
if wallpaper_set in self.config_file:
|
||||||
logger.debug(f"The dictionary {wallpaper_set} has been found in config.")
|
logger.debug(f"The dictionary {wallpaper_set} has been found in config.")
|
||||||
|
return True
|
||||||
|
# TODO split this into smaller pieces. This goes too deep.
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._set_fallback_wallpaper()
|
self._set_fallback_wallpaper()
|
||||||
logger.error(f"The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
|
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.")
|
print(f"ERROR: The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
|
||||||
exit(1)
|
return False
|
||||||
except ConfigError:
|
except ConfigError:
|
||||||
logger.critical(f"No dictionary {wallpaper_set} has been found in the config exiting...")
|
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...")
|
raise ConfigError(f"The dictionary {wallpaper_set} has not been found in the config, exiting...")
|
||||||
|
|
||||||
def _check_wallpaper_amount(self) -> None:
|
def _check_wallpaper_amount(self):
|
||||||
# This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set
|
# 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:
|
for wallpaper_set in self.config_used_sets:
|
||||||
if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set:
|
if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set:
|
||||||
logger.debug(f"Dictionary {wallpaper_set} has sufficient values.")
|
logger.debug(f"Dictionary {wallpaper_set} has sufficient values.")
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._set_fallback_wallpaper()
|
self._set_fallback_wallpaper()
|
||||||
logger.error(f"The Dictionary {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.")
|
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.")
|
print(f"ERROR: The Dictionaty {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.")
|
||||||
exit(1)
|
return False
|
||||||
except ConfigError:
|
except ConfigError:
|
||||||
logger.critical(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...")
|
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...")
|
raise ConfigError(f"Dictionary {wallpaper_set} does not have the correct amount of entries, exciting...")
|
||||||
|
|
||||||
def validate_config(self) -> None:
|
def validate_config(self) -> bool:
|
||||||
self._check_fallback_wallpaper()
|
# NOTE: Consider changing this to exit(-1)
|
||||||
self._check_wallpapers_per_set_and_changing_times()
|
# HACK: Consider using different exit codes for different errors to help users debug.
|
||||||
self._check_general_validity()
|
if not self._check_fallback_wallpaper():
|
||||||
self._check_wallpaper_dicts()
|
pass
|
||||||
self._check_wallpaper_amount()
|
if not self._check_wallpapers_per_set_and_changing_times():
|
||||||
|
exit(1)
|
||||||
|
if not self._check_general_validity():
|
||||||
|
exit(1)
|
||||||
|
if not self._check_wallpaper_dicts():
|
||||||
|
exit(1)
|
||||||
|
if not self._check_wallpaper_amount():
|
||||||
|
exit(1)
|
||||||
logger.debug("The config file has been validated successfully (No Errors)")
|
logger.debug("The config file has been validated successfully (No Errors)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# TODO: Improve modularity. See notes inside the class for more details.
|
||||||
|
# TODO: Ensure functionality and if needed add handling for the 1 wallpaper per set case.
|
||||||
class WallpaperLogic(_ConfigLib):
|
class WallpaperLogic(_ConfigLib):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
# NOTE: This looks a bit ugly. Consider pros and cons of adding this into _ConfigLib
|
||||||
self.chosen_wallpaper_set = False
|
self.chosen_wallpaper_set = False
|
||||||
|
|
||||||
|
# NOTE: This function could be in a different file because it's not needed in the case only 1 wallpaper per set is needed.
|
||||||
# Returns a list of a split string that contains a changing time from the config file
|
# Returns a list of a split string that contains a changing time from the config file
|
||||||
def _clean_times(self, desired_time) -> list:
|
def _clean_times(self, desired_time) -> list:
|
||||||
unclean_times = list(self.config_changing_times.values())[desired_time]
|
unclean_times = list(self.config_changing_times.values())[desired_time]
|
||||||
return unclean_times.split(":")
|
return unclean_times.split(":")
|
||||||
|
|
||||||
|
# NOTE: This could be in a different file because it's not needed in the "Only one wallpaper set" case.
|
||||||
def _choose_wallpaper_set(self) -> None:
|
def _choose_wallpaper_set(self) -> None:
|
||||||
from random import choice as choose_from
|
from random import choice as choose_from
|
||||||
self.chosen_wallpaper_set = choose_from(self.config_used_sets)
|
self.chosen_wallpaper_set = choose_from(self.config_used_sets)
|
||||||
self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values())
|
self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values())
|
||||||
logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}")
|
logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}")
|
||||||
|
|
||||||
|
# NOTE: Same as _clean_times()
|
||||||
# Verify if a given time is in a given range
|
# Verify if a given time is in a given range
|
||||||
def _time_in_range(self, start, end, x) -> bool:
|
def _time_in_range(self, start, end, x) -> bool:
|
||||||
if start <= end:
|
if start <= end:
|
||||||
|
@ -148,35 +195,96 @@ class WallpaperLogic(_ConfigLib):
|
||||||
else:
|
else:
|
||||||
return start <= x or x < end
|
return start <= x or x < end
|
||||||
|
|
||||||
|
# NOTE: Potentially add handling for this to be also usable for notify_user and add logging if notify_user fails. Consider adding an argument that is where it's called from and handle accordingly.
|
||||||
|
def _check_system_exitcode(self, code) -> bool:
|
||||||
|
if code != 0:
|
||||||
|
try:
|
||||||
|
self._set_fallback_wallpaper()
|
||||||
|
logger.error(f"The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found, the fallback wallpaper has been set. Future wallpapers will still attempted to be set.")
|
||||||
|
print(f"ERROR: The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found, the fallback wallpaper has been set. Future wallpapers will still attempted to be set.")
|
||||||
|
return False
|
||||||
|
except ConfigError:
|
||||||
|
logger.error(f"The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found and no fallback wallpaper has been set. Future wallpapers will still attempted to be set.")
|
||||||
|
print(f"ERROR: The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found and no fallback wallpaper has been set. Future wallpapers will still attempted to be set.")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logger.info(f"The wallpaper {self.wallpaper_list[self.current_time_range]} has been set.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# NOTE: Add error handling in case libnotify is not installed or notify-send fails for any other reason.
|
||||||
|
# TODO: Add a check whether config[notify] is true or not.
|
||||||
def _notify_user(self):
|
def _notify_user(self):
|
||||||
system("notify-send 'Wallman' 'A new Wallpaper has been set.'")
|
system("notify-send 'Wallman' 'A new Wallpaper has been set.'")
|
||||||
logger.debug("Sent desktop notification.")
|
logger.debug("Sent desktop notification.")
|
||||||
|
|
||||||
def set_wallpaper_by_time(self) -> None:
|
# TODO: Clean this up. It's way too large and way too intimidating.
|
||||||
|
# NOTE: This could be in a different for the case that the user only wants 1 wallpaper per set.
|
||||||
|
# TODO: Add an way for the user to choose if the wallpaper should scale, fill or otherwise. This needs to be editable in the config file.
|
||||||
|
def set_wallpaper_by_time(self) -> bool:
|
||||||
# Ensure use of a consistent wallpaper set
|
# Ensure use of a consistent wallpaper set
|
||||||
if self.chosen_wallpaper_set is False:
|
if self.chosen_wallpaper_set is False:
|
||||||
self._choose_wallpaper_set()
|
self._choose_wallpaper_set()
|
||||||
for time_range in range(self.config_total_changing_times - 1):
|
for time_range in range(self.config_total_changing_times - 1):
|
||||||
|
self.current_time_range = time_range # Store current time for better debugging output
|
||||||
clean_time = self._clean_times(time_range)
|
clean_time = self._clean_times(time_range)
|
||||||
clean_time_two = self._clean_times(time_range + 1)
|
clean_time_two = self._clean_times(time_range + 1)
|
||||||
|
# HACK on this to make it more readable. This function call is way too long. Consider storing these in a bunch of temporary variables, though keep function length in mind.
|
||||||
|
# HACK on this to see if this logic can be simplified. It's very ugly to check it that way.
|
||||||
# Check if the current time is between a given and the following changing time and if so, set that wallpaper. If not, keep trying.
|
# 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()):
|
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]}")
|
system(f"feh --bg-scale --no-fehbg --quiet {self.wallpaper_list[time_range]}")
|
||||||
|
exitcode = system(f"feh --bg-scale --no-fehbg --quiet {self.wallpaper_list[time_range]}")
|
||||||
|
has_wallpaper_been_set = self._check_system_exitcode(exitcode)
|
||||||
|
# TODO: Add this check to _notify_user.
|
||||||
if self.config_notify:
|
if self.config_notify:
|
||||||
self._notify_user()
|
self._notify_user()
|
||||||
return
|
return has_wallpaper_been_set
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
|
system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
|
||||||
|
exitcode = system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
|
||||||
|
has_wallpaper_been_set = self._check_system_exitcode(exitcode)
|
||||||
if self.config_notify:
|
if self.config_notify:
|
||||||
self._notify_user()
|
self._notify_user()
|
||||||
|
return has_wallpaper_been_set
|
||||||
|
|
||||||
|
# NOTE: Consider avoiding nested functions.
|
||||||
def schedule_wallpapers(self):
|
def schedule_wallpapers(self):
|
||||||
scheduler = BlockingScheduler()
|
def _schedule_background_wallpapers():
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
scheduler = BackgroundScheduler()
|
||||||
# Create a scheduled job for every changing time
|
# Create a scheduled job for every changing time
|
||||||
|
# NOTE: This should be a function.
|
||||||
for changing_time in range(len(self.config_changing_times)):
|
for changing_time in range(len(self.config_changing_times)):
|
||||||
clean_time = self._clean_times(changing_time)
|
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.add_job(self.set_wallpaper_by_time, trigger=CronTrigger(hour=clean_time[0], minute=clean_time[1], second=clean_time[2]))
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
logger.info("The scheduler has been started.")
|
logger.info("The background scheduler has been started.")
|
||||||
|
return scheduler
|
||||||
|
|
||||||
|
def _schedule_blocking_wallpapers():
|
||||||
|
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||||
|
scheduler = BlockingScheduler()
|
||||||
|
# Create a scheduled job for every changing time
|
||||||
|
# NOTE: Thisshould be a function.
|
||||||
|
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]))
|
||||||
|
logger.info("The blocking scheduler has been started.")
|
||||||
|
scheduler.start()
|
||||||
|
|
||||||
|
if self.config_systray:
|
||||||
|
# NOTE: The wallman_systray impomrt should be handled differently. See the note in Config_Validity.
|
||||||
|
import wallman_systray as systray
|
||||||
|
from functools import partial
|
||||||
|
scheduler = _schedule_background_wallpapers()
|
||||||
|
menu = systray.Menu (
|
||||||
|
systray.item("Re-Set Wallpaper", partial(systray.set_wallpaper_again, wallpaper_setter=self.set_wallpaper_by_time)),
|
||||||
|
systray.item("Reroll Wallpapers", partial(systray.reroll_wallpapers, wallpaper_chooser=self._choose_wallpaper_set, wallpaper_setter=self.set_wallpaper_by_time)),
|
||||||
|
systray.item("Quit", partial(systray.on_quit, shutdown_scheduler=scheduler.shutdown))
|
||||||
|
)
|
||||||
|
icon = systray.Icon("wallman_icon", systray.icon_image, "My Tray Icon", menu)
|
||||||
|
icon.run()
|
||||||
|
else:
|
||||||
|
_schedule_blocking_wallpapers()
|
||||||
|
|
42
src/wallman_systray.py
Normal file
42
src/wallman_systray.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
from os import getenv, chdir
|
||||||
|
import logging
|
||||||
|
# Use logger that is also in wallman_lib
|
||||||
|
logger = logging.getLogger("wallman")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
except ImportError:
|
||||||
|
logging.error("Couldn't import PIL, wallman will launch without a systray.")
|
||||||
|
print("Couldn't import PIL, wallman will launch without a systray.")
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pystray import Icon, MenuItem as item, Menu
|
||||||
|
except ImportError:
|
||||||
|
logging.error("Couldn't import pystray, wallman will launch without a systray.")
|
||||||
|
print("Couldn't import pystray, wallman will launch without a systray.")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# This should always be ran with "set_wallpaper_by_time" as input!
|
||||||
|
def set_wallpaper_again(icon, item, wallpaper_setter):
|
||||||
|
logging.info("Re-Setting wallpaper due to systray input.")
|
||||||
|
wallpaper_setter()
|
||||||
|
|
||||||
|
def reroll_wallpapers(icon, item, wallpaper_chooser, wallpaper_setter):
|
||||||
|
logging.info("Rerolling Wallpaper sets and resetting wallpaper due to systray input")
|
||||||
|
wallpaper_chooser()
|
||||||
|
wallpaper_setter()
|
||||||
|
|
||||||
|
# This should always be ran with "scheduler.shutdown" as input!
|
||||||
|
def on_quit(icon, item, shutdown_scheduler):
|
||||||
|
logging.info("Shutting down wallman due to systray input.")
|
||||||
|
shutdown_scheduler()
|
||||||
|
icon.stop()
|
||||||
|
|
||||||
|
|
||||||
|
chdir("/etc/wallman/icons/")
|
||||||
|
try:
|
||||||
|
icon_image = Image.open("systrayIcon.jpg")
|
||||||
|
except FileNotFoundError:
|
||||||
|
logger.error("~/.config/wallman/systrayIcon.jpg has not been found, wallman will launch without a systray.")
|
||||||
|
print("~/.config/wallman/systrayIcon.jpg has not been found, wallman will launch without a systray.")
|
Loading…
Reference in a new issue