Skip to content

Instantly share code, notes, and snippets.

@jbylund
Last active June 1, 2022 22:22
Show Gist options
  • Save jbylund/5f307bef7f36438c05e74015e9f090ea to your computer and use it in GitHub Desktop.
Save jbylund/5f307bef7f36438c05e74015e9f090ea to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""
let's try to do this without subprocess?
"""
# stdlib
import argparse
import datetime
import os
import shelve
# third party
import cachetools
# pylint: disable=import-outside-toplevel
def download_file(url, local_filename):
"""Download the given url to the local path"""
import requests
with requests.get(url, stream=True) as response:
response.raise_for_status()
with open(local_filename, "wb") as fh:
for chunk in response.iter_content(chunk_size=8192):
fh.write(chunk)
def unpack_image(filename, destdir):
"""Unpack all the images of the filename into destdir"""
from PIL import Image
import pillow_heif
heif_file = pillow_heif.read_heif(filename)
for idx, heif_frame in enumerate(
heif_file
): # you still can use it without iteration, like before.
pil_image = Image.frombytes(
heif_frame.mode,
heif_frame.size,
heif_frame.data,
"raw", # ???
heif_frame.mode,
heif_frame.stride,
)
pil_image.save(f"{destdir}/{idx}.jpg", quality=95, format="jpeg")
def get_images(imagename):
"""Return the list of images for the given background"""
frames_dir = f"{imagename}/extracted"
os.makedirs(frames_dir, exist_ok=True)
# if the raw file doesn't exist we need to fetch it
rawpath = f"{imagename}/raw.heic"
if not os.path.isfile(rawpath):
url = get_sources()[imagename]
download_file(url, rawpath)
# now if the pieces haven't been extracted need to extract them
if not os.path.exists(f"{frames_dir}/0.jpg"):
unpack_image(rawpath, frames_dir)
images = []
frames_dir = os.path.abspath(frames_dir)
for root, dirs, files in os.walk(frames_dir):
dirs[:] = [] # don't recurse
for ifile in files:
if ifile.endswith("jpg"):
images.append(os.path.join(root, ifile))
return sorted(images)
class ShelveCache:
"""Simple cache backed by a shelve db"""
def __init__(self, filepath):
"""Construct the cache"""
self.filepath = filepath
self.backing = shelve.open(self.filepath)
def __getitem__(self, key):
"""Get an item from the cache"""
return self.backing[key]
def __setitem__(self, key, value):
"""Save an item in the cache"""
self.backing[key] = value
def identity(key):
"""Return the thing"""
return key
@cachetools.cached(cache=ShelveCache("/tmp/.brightness"), key=identity)
def get_image_brightness(filename):
"""Get the "brightness" of the given image"""
import subprocess
cmd = f"convert {filename} -resize 1x1! -format %[pixel:B] info:-".split()
res = subprocess.check_output(cmd).strip().decode()
return float(res.partition("(")[2].partition("%")[0])
def get_sources():
"""Get the possible images & urls"""
return {
"catalina": "https://cdn.dynamicwallpaper.club/wallpapers/v5y04cx6k9k/Catalina.heic",
"dome": "https://cdn.dynamicwallpaper.club/wallpapers/3mj0fahqhsv/Dome.heic",
"monterey": "https://cdn.dynamicwallpaper.club/wallpapers/la4wfuwtkg/macOS%20Monterey.heic",
}
def get_time_image_pairs(images):
"""Return a list of (timestamp, image) pairs spread evenly over the day"""
image_to_brightness = {image: get_image_brightness(image) for image in images}
by_brightness = sorted(image_to_brightness.items(), key=lambda x: x[-1])
window = datetime.timedelta(hours=12)
step = window / (len(images) - 1)
time_to_image = []
start_of_day = datetime.datetime.today().replace(
hour=0, minute=0, second=0, microsecond=0
)
for imageidx, (image, _) in enumerate(by_brightness + by_brightness[-2::-1]):
time_to_image.append((start_of_day + imageidx * step, image))
return time_to_image
def get_args():
"""Argument parsing"""
sources = get_sources()
parser = argparse.ArgumentParser()
parser.add_argument("--binary", action="store_true")
parser.add_argument("--image", choices=sorted(sources), default=min(sources))
return vars(parser.parse_args())
def main():
"""Update the live wallpaper"""
args = get_args()
# get the images
images = get_images(args["image"])
# get the images spaced out by time of day
time_to_image = get_time_image_pairs(images)
current_time = datetime.datetime.now()
idx = 0
for idx, (imagetime, _image) in enumerate(time_to_image):
if current_time < imagetime:
break
prev_ts, prev_path = time_to_image[idx - 1]
next_ts, next_path = time_to_image[idx]
pct_next = 100 * (current_time - prev_ts) / (next_ts - prev_ts)
pct_prev = 100 - pct_next
out_path = os.path.expanduser("~/Pictures/live_wallpaper.jpg")
if args["binary"]:
import shutil
if pct_prev < pct_next:
# use next
shutil.copy(next_path, out_path)
else:
# use prev
shutil.copy(prev_path, out_path)
else:
import subprocess
print(f"{pct_prev}% {prev_path} and {pct_next}% {next_path}")
swap_path = os.path.expanduser("~/Pictures/live_wallpaper.swp.jpg")
cmd = f"composite -blend {pct_prev} {prev_path} {next_path} {swap_path}".split()
subprocess.check_call(cmd)
os.replace(swap_path, out_path)
if "__main__" == __name__:
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment