Merge branch 'CalfMoon-mpvpaper'

This commit is contained in:
Roman 2024-10-18 16:08:45 +09:00
commit 8bf2ced1a9
8 changed files with 95 additions and 15 deletions

View File

@ -8,19 +8,20 @@ GUI wallpaper setter for Wayland and Xorg window managers. It works as a fronten
- Vim keys
- Support for GIF animations (with `swww`)
- Support for videos (with `mpvpaper`)
- Support for multiple monitors (with `swww`)
- Works on Wayland (with `swww` or `swaybg` or `hyprpaper` or `wallutils`)
- Works on Wayland (with `swww` or `swaybg` or `hyprpaper` or `wallutils` or `mpvpaper`)
- Works on Xorg (with `feh` or `wallutils`)
- Restores wallpaper at launch of your WM
- Caching for fast loading
## Installation
You need to install at least one of the backends and Waypaper, which works as a frontend.
### 1. Install a backend
Install a preferred backend from your package manager: [swww](https://github.com/Horus645/swww) or [swaybg](https://github.com/swaywm/swaybg) or [swaybg](https://github.com/hyprwm/hyprpaper) on Wayland or [feh](https://github.com/derf/feh) on Xorg or [wallutils](https://github.com/xyproto/wallutils) on both.
Install a preferred backend from your package manager: [swww](https://github.com/Horus645/swww) or [swaybg](https://github.com/swaywm/swaybg) or [hyprpaper](https://github.com/hyprwm/hyprpaper) on Wayland or [feh](https://github.com/derf/feh) on Xorg or [mpvpaper](https://github.com/GhostNaN/mpvpaper) or [wallutils](https://github.com/xyproto/wallutils) on both.
### 2. Install Waypaper
@ -48,11 +49,11 @@ Users of OpenSUSE [reported issue with installation](https://github.com/anufriev
#### On Fedora
Waypaper is available in an external repository owned by Solopasha. You can add this repository as `sudo dnf copr enable solopasha/hyprland` and install as `sudo dnf install wayapaper`.
Waypaper is available in an external repository owned by Solopasha. You can add this repository as `sudo dnf copr enable solopasha/hyprland` and install as `sudo dnf install waypaper`.
### Dependencies
- `swww` or `swaybg` or `feh` or `wallutils` or `hyprpaper`
- `swww` or `swaybg` or `feh` or `wallutils` or `hyprpaper` or `mpvpaper`
- gobject python library (it might be called `python-gobject` or `python3-gi` or `python3-gobject` in your package manager.)
- `python-importlib_metadata`
- `python-platformdirs`

View File

@ -17,7 +17,7 @@ setuptools.setup(
"waypaper = waypaper.__main__:run"
]
},
install_requires=["PyGObject", "importlib_metadata", "platformdirs", "Pillow"],
install_requires=["PyGObject", "importlib_metadata", "platformdirs", "Pillow", "opencv-python-headless"],
version='2.3',
python_requires='>3.9',
classifiers=[

View File

@ -69,7 +69,7 @@ def run():
for wallpaper, monitor in zip(cf.wallpapers, cf.monitors):
if args.random:
wallpaper_str = get_random_file(cf.backend, str(cf.image_folder), cf.include_subfolders, cf.show_hidden)
wallpaper_str = get_random_file(cf.backend, str(cf.image_folder), cf.include_subfolders, cf.cache_dir, cf.show_hidden)
if wallpaper_str:
cf.select_wallpaper(wallpaper_str)
cf.save()
@ -112,4 +112,3 @@ def run():
if __name__ == "__main__":
run()

View File

@ -11,7 +11,7 @@ from waypaper.aboutdata import AboutData
from waypaper.changer import change_wallpaper
from waypaper.config import Config
from waypaper.common import get_image_paths, get_random_file, get_monitor_names_hyprctl, get_monitor_names_swww
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS, SORT_DISPLAYS
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS, SORT_DISPLAYS, VIDEO_EXTENSIONS
from waypaper.translations import Chinese, English, French, German, Polish, Russian, Belarusian, Spanish
gi.require_version("Gtk", "3.0")
@ -26,6 +26,16 @@ def read_webp_image(image_path: str) -> GdkPixbuf:
pixbuf = GdkPixbuf.Pixbuf.new_from_data(data, GdkPixbuf.Colorspace.RGB, False, 8, width, height, width * 3)
return pixbuf
def read_video_frame(image_path: str, cache_dir: Path) -> GdkPixbuf:
"""Read first frame of video and convert it inot pixbuf format"""
import cv2
temp_frame = cache_dir / "temp_frame.jpeg"
vidcap = cv2.VideoCapture(image_path)
_, image = vidcap.read()
cv2.imwrite(temp_frame, image)
pixbuf = GdkPixbuf.Pixbuf.new_from_file(temp_frame)
os.remove(temp_frame)
return pixbuf
def cache_image(image_path: str, cache_dir: Path) -> None:
"""Resize and cache images using gtk library"""
@ -33,6 +43,8 @@ def cache_image(image_path: str, cache_dir: Path) -> None:
try:
if ext == ".webp":
pixbuf = read_webp_image(str(image_path))
elif ext in VIDEO_EXTENSIONS:
pixbuf = read_video_frame(str(image_path), cache_dir)
else:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(str(image_path))
@ -496,7 +508,7 @@ class App(Gtk.Window):
def set_random_wallpaper(self) -> None:
"""Choose a random image and set it as the wallpaper"""
self.cf.backend = self.backend_option_combo.get_active_text()
new_wallpaper = get_random_file(self.cf.backend, str(self.cf.image_folder), self.cf.include_subfolders)
new_wallpaper = get_random_file(self.cf.backend, str(self.cf.image_folder), self.cf.include_subfolders, self.cf.cache_dir)
if new_wallpaper:
self.cf.select_wallpaper(new_wallpaper)
else:

View File

@ -9,7 +9,6 @@ from pathlib import Path
import re
def change_wallpaper(image_path: Path, cf: Config, monitor: str, txt: Chinese|English|French|German|Polish|Russian|Belarusian):
"""Run system commands to change the wallpaper depending on the backend"""
try:
@ -33,6 +32,37 @@ def change_wallpaper(image_path: Path, cf: Config, monitor: str, txt: Chinese|En
subprocess.Popen(command)
print(f"{txt.msg_setwith} {cf.backend}")
# mpvpaper backend:
elif cf.backend == "mpvpaper":
# Kill previous mpvpaper instances:
try:
subprocess.check_output(["pgrep", "mpvpaper"], encoding='utf-8')
subprocess.Popen(["killall", ".mpvpaper-wrapp"])
time.sleep(0.5)
except subprocess.CalledProcessError:
pass
fill_types = {
"fill": "panscan=1.0",
"fit": "panscan=0.0",
"center": "",
"stretch": "--keepaspect=no",
"tile": "",
}
fill = fill_types[cf.fill_option.lower()]
command = ["mpvpaper"]
command.extend(["-o", f"no-audio loop {fill} --background-color='{cf.color}'"])
# if monitor != "All":
# command.extend([monitor])
# else:
# command.extend('*')
command.extend('*')
command.extend([image_path])
subprocess.Popen(command)
print(f"{txt.msg_setwith} {cf.backend}")
# swww backend:
elif cf.backend == "swww":
@ -119,7 +149,7 @@ def change_wallpaper(image_path: Path, cf: Config, monitor: str, txt: Chinese|En
subprocess.Popen(["hyprpaper"])
time.sleep(1)
preload_command = ["hyprctl", "hyprpaper", "preload", image_path]
# Decide which monitors are affected:
if monitor == "All":
monitors = get_monitor_names_hyprctl()

View File

@ -5,6 +5,8 @@ import re
import random
import shutil
import subprocess
from pathlib import Path
import json
from waypaper.options import IMAGE_EXTENSIONS, BACKEND_OPTIONS
from typing import List
@ -58,16 +60,46 @@ def get_image_paths(backend: str,
def get_random_file(backend: str,
folder: str,
include_subfolders: bool,
cache_dir: Path,
include_hidden: bool = False) -> str | None:
"""Pick a random file from the folder"""
try:
cache_file = cache_dir / "cache.json"
# Create cache file if it doesn't exist:
if not cache_file.exists():
with open(cache_file, 'x') as f:
f.write('''{}''')
image_paths = get_image_paths(backend,
folder,
include_subfolders,
include_hidden,
only_gifs=False,
depth=1)
return random.choice(image_paths)
with open(cache_file, "r+") as cachefile:
cache = json.load(cachefile)
# Read used_image list from cache file:
try:
used_images = cache['used_images']
except KeyError:
used_images = []
# Pick a random image from possible images:
remaining_images = list(filter(lambda x: x not in set(used_images), image_paths))
if len(remaining_images) == 0:
used_images.clear()
random_choice = random.choice(image_paths)
else:
random_choice = random.choice(remaining_images)
# Write used_image list back into cache file after adding new selected image:
used_images.append(random_choice)
cache['used_images'] = used_images
cachefile.seek(0)
json.dump(cache, cachefile, indent=4)
return random_choice
except:
return None

View File

@ -49,7 +49,7 @@ class Config:
# Create config and cache folders:
self.config_dir.mkdir(parents=True, exist_ok=True)
self.cache_dir.mkdir(parents=True,exist_ok=True)
self.cache_dir.mkdir(parents=True, exist_ok=True)
self.state_dir.mkdir(parents=True, exist_ok=True)

View File

@ -1,5 +1,5 @@
from typing import List, Dict
BACKEND_OPTIONS: List[str] = ["none", "swaybg", "swww", "feh", "wallutils", "hyprpaper"]
BACKEND_OPTIONS: List[str] = ["none", "swaybg", "swww", "feh", "wallutils", "hyprpaper", "mpvpaper"]
FILL_OPTIONS: List[str] = ["fill", "stretch", "fit", "center", "tile"]
SORT_OPTIONS: List[str] = ["name", "namerev", "date", "daterev"]
SORT_DISPLAYS: Dict[str, str] = {
@ -8,6 +8,11 @@ SORT_DISPLAYS: Dict[str, str] = {
"date": "Date ↓",
"daterev": "Date ↑"}
VIDEO_EXTENSIONS: List[str] = ['.webm', '.mkv', '.flv', '.vob', '.ogv', '.ogg', '.rrc', '.gifv', '.mng', '.mov',
'.avi', '.qt', '.wmv', '.yuv', '.rm', '.asf', '.amv', '.mp4', '.m4p', '.m4v',
'.mpg', '.mp2', '.mpeg', '.mpe', '.mpv', '.m4v', '.svi', '.3gp', '.3g2', '.mxf',
'.roq', '.nsv', '.flv', '.f4v', '.f4p', '.f4a', '.f4b', '.mod' ]
IMAGE_EXTENSIONS: Dict[BACKEND_OPTIONS, List[str]] = {
BACKEND_OPTIONS[0]: ['.gif', '.jpg', '.jpeg', '.png', '.webp', '.bmp', '.pnm', '.tiff'],
BACKEND_OPTIONS[1]: ['.gif', '.jpg', '.jpeg', '.png'],
@ -15,6 +20,7 @@ IMAGE_EXTENSIONS: Dict[BACKEND_OPTIONS, List[str]] = {
BACKEND_OPTIONS[3]: ['.gif', '.jpg', '.jpeg', '.png', '.bmp', '.pnm', '.tiff'],
BACKEND_OPTIONS[4]: ['.gif', '.jpg', '.jpeg', '.png'],
BACKEND_OPTIONS[5]: ['.jpg', '.jpeg', '.png', '.webp'],
BACKEND_OPTIONS[6]: ['.gif', '.jpg', '.jpeg', '.png', '.webp', '.bmp', '.pnm', '.tiff'] + VIDEO_EXTENSIONS,
}
SWWW_TRANSITION_TYPES: List[str] = ["any", "none", "simple", "fade", "wipe", "left", "right", "top",