mirror of
https://github.com/anufrievroman/waypaper.git
synced 2024-11-22 07:22:19 +03:00
Merge branch 'CalfMoon-mpvpaper'
This commit is contained in:
commit
8bf2ced1a9
11
README.md
11
README.md
@ -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`
|
||||
|
2
setup.py
2
setup.py
@ -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=[
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user