Skip to content

Instantly share code, notes, and snippets.

@gurrgur
Last active June 10, 2023 01:24
Show Gist options
  • Save gurrgur/0993e0cdb0033ca492c05aafb00873c0 to your computer and use it in GitHub Desktop.
Save gurrgur/0993e0cdb0033ca492c05aafb00873c0 to your computer and use it in GitHub Desktop.
import xml.etree.ElementTree as ET
from pathlib import Path
from datetime import datetime, timedelta
import json
import subprocess
d = Path("Dynamic_Wallpapers")
for xmlfile in d.glob("*.xml"):
f = xmlfile.name
name = f.rsplit(".")[0]
tree = ET.parse(d / f)
root = tree.getroot()
t = datetime(
year=int(root.find("starttime").find("year").text),
month=int(root.find("starttime").find("month").text),
day=int(root.find("starttime").find("day").text),
hour=int(root.find("starttime").find("hour").text),
minute=int(root.find("starttime").find("minute").text),
second=int(root.find("starttime").find("second").text),
)
sequence = []
for c in root:
if c.tag == "starttime":
continue
crossfade = c.tag == "transition"
filename = c.find("from").text if crossfade else c.find("file").text
sequence.append(
{
#"SolarAzimuth": "*",
#"SolarElevation": "*",
"CrossFade": crossfade,
"Time": str(t.hour).zfill(2) + ":" + str(t.minute).zfill(2),
"FileName": str(Path(name) / Path(filename).name)
}
)
dt = timedelta(seconds=float(c.find("duration").text))
t = t + dt
manifest_data = {"Type": "solar", "Meta": sequence}
manifest_file = d / (name + ".json")
with open(manifest_file, "w") as m:
json.dump(manifest_data, m, indent=4)
out_dir = Path("avif")
if not out_dir.is_dir():
out_dir.mkdir()
out_file = out_dir / (name + '.avif')
cmd = [
'kdynamicwallpaperbuilder',
'--output',
f'./{out_file}',
f'./{str(manifest_file)}',
]
if not out_file.is_file():
print("starting subprocess:", cmd)
subprocess.run(cmd)
else:
print("skip:", cmd)
@the-phinet
Copy link

Hey, thanks for this! I modified it a bit for some large speed improvements. Hope it's helpful to you

-Marcus

#!/usr/bin/env python3

# usage:        ./make_avif_all.py [target_resolution]
#
# for unscaled: ./make_avif_all.py
# for 1080p:    ./make_avif_all.py 1920x1080

import xml.etree.ElementTree as ET
from pathlib import Path
from datetime import datetime, timedelta
import json
import subprocess
import sys
import os

# requires `gm` command from package `GraphicsMagick`
# requires `kdynamicwallpaperbuilder` `plasma-wallpapers-dynamic-builder`

try:
    size=sys.argv[1]
except:
    size = False

in_dir = Path("Dynamic_Wallpapers")
out_dir = Path("avif")

work_dir = Path("temp")

if not out_dir.is_dir():
    out_dir.mkdir()
if not work_dir.is_dir():
    work_dir.mkdir()

for xmlfile in in_dir.glob("*.xml"):

    f = xmlfile.name
    name = f.rsplit(".")[0]
    tree = ET.parse(in_dir / f)
    root = tree.getroot()

    suffix = size and ("-" + size) or ""

    out_file = out_dir / (name + suffix + '.avif')
    tmp_file = work_dir / (name + suffix + '.avif')

    if out_file.is_file():
        print(f'Skip {out_file}')
        continue

    t = datetime(
        year=int(root.find("starttime").find("year").text),
        month=int(root.find("starttime").find("month").text),
        day=int(root.find("starttime").find("day").text),
        hour=int(root.find("starttime").find("hour").text),
        minute=int(root.find("starttime").find("minute").text),
        second=int(root.find("starttime").find("second").text),
    )

    files = set()
    sequence = []
    for c in root:
        if c.tag == "starttime":
            continue

        crossfade = c.tag == "transition"
        filename = c.find("from").text if crossfade else c.find("file").text
        in_file = str(Path(name) / Path(filename).name)

        files.add(in_file)

        sequence.append(
            {
                #"SolarAzimuth": "*",
                #"SolarElevation": "*",
                "CrossFade": crossfade,
                "Time": str(t.hour).zfill(2) + ":" + str(t.minute).zfill(2),
                "FileName": in_file
            }
        )
        dt = timedelta(seconds=float(c.find("duration").text))
        t = t + dt

    manifest_data = {"Type": "solar", "Meta": sequence}
    manifest_file = work_dir / (name + ".json")
    with open(manifest_file, "w") as m:
        json.dump(manifest_data, m, indent=4)

    if not (work_dir / Path(name)).is_dir():
        (work_dir / Path(name)).mkdir()

    def link():
        try:
            os.remove(work_dir / in_file)
        except:
            pass
        try:
            os.link(in_dir / in_file, work_dir / in_file)
        except:
            pass

    if (size):
        print(f'Scaling {name} to {size} ({len(files)} files)')

        for in_file in files:
            scaled = subprocess.run([
                'gm', 'convert',
                in_dir / in_file,
                '-filter', 'Sinc',
                '-resize', size + '^>',
                work_dir / in_file
            ], stderr=subprocess.DEVNULL)

            if (scaled.returncode > 0):
                link()
    else:
        for in_file in files:
            link()

    # Speed comparisons with Adwaita.avif
    # 10: 1.48MiB   4s    9: 1.48MiB   3s
    #  8: 1.48MiB   4s    7: 1.48MiB   5s
    #  6: 1.24MiB  43s    5: 1.23MiB  75s
    #  4: 1.23MiB  80s    3: 1.23MiB  80s
    #  2: 1.23MiB 112s    1: 1.22MiB 140s

    cmd = [
        'kdynamicwallpaperbuilder',
        '--max-threads', '1',
        '--speed', '7',
        '--output',
        f'./{tmp_file}',
        f'./{str(manifest_file)}',
    ]

    print("starting subprocess:", " ".join(cmd))
    subprocess.run(cmd)

    try:
        os.rename(tmp_file, out_file)
    except:
        pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment