Add auto screenshot backup scripts
This commit is contained in:
parent
5c9d56cdb6
commit
6f68fccaf0
@ -36,6 +36,10 @@ Host 10.80.0.218
|
||||
PubkeyAcceptedKeyTypes +ssh-rsa
|
||||
HostKeyAlgorithms=+ssh-rsa
|
||||
|
||||
Host controller.home
|
||||
User root
|
||||
Port 2222
|
||||
|
||||
# Default hostnames I may encounter in the wild
|
||||
Host openrepeater.local
|
||||
HostName openrepeater.local
|
||||
|
170
configs/systemd/scripts/sync-screenshots-google-photos.py
Normal file
170
configs/systemd/scripts/sync-screenshots-google-photos.py
Normal file
@ -0,0 +1,170 @@
|
||||
#! /usr/bin/env python3
|
||||
import argparse
|
||||
import sys
|
||||
import logging
|
||||
import platform
|
||||
import shutil
|
||||
import glob
|
||||
import datetime
|
||||
import subprocess
|
||||
from PIL import Image
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
RCLONE_REMOTE_NAME = "google-photos"
|
||||
HOSTNAME_MAP = {
|
||||
("ewpratten-desktop"): {
|
||||
"name": "Desktop",
|
||||
"mode": "directory",
|
||||
"directory": "~/Pictures/Screenshots/",
|
||||
},
|
||||
("ewpratten-laptop"): {
|
||||
"name": "Laptop",
|
||||
"mode": "directory",
|
||||
"directory": "~/Pictures/Screenshots/",
|
||||
},
|
||||
("ewpratten-steamdeck"): {
|
||||
"name": "Steam Deck",
|
||||
"mode": "steamdeck",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
# Handle program arguments
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument(
|
||||
"-v", "--verbose", help="Enable verbose logging", action="store_true"
|
||||
)
|
||||
args = ap.parse_args()
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if args.verbose else logging.INFO,
|
||||
format="%(levelname)s: %(message)s",
|
||||
)
|
||||
|
||||
# Get the hostname of this machine
|
||||
hostname = platform.node().lower().split(".")[0]
|
||||
|
||||
# Try to figure out what we are runnning on
|
||||
if hostname not in HOSTNAME_MAP:
|
||||
logger.error(f"Unsupported host: {hostname}")
|
||||
return 1
|
||||
|
||||
# If rclone is not installed, we can't continue
|
||||
if shutil.which("rclone") is None:
|
||||
logger.error("rclone is not installed")
|
||||
return 1
|
||||
|
||||
# If the rclone remote is not configured, we can't continue
|
||||
try:
|
||||
subprocess.check_output(["rclone", "lsf", f"{RCLONE_REMOTE_NAME}:"], stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"rclone remote not found: {RCLONE_REMOTE_NAME}")
|
||||
return 1
|
||||
|
||||
# Get the name of the machine
|
||||
host_settings = HOSTNAME_MAP[hostname]
|
||||
friendly_name = host_settings["name"]
|
||||
album_name = f"{friendly_name} Screenshots"
|
||||
logger.info(f"Syncing screenshots from {friendly_name}")
|
||||
|
||||
# If the mode is "directory", we will just use that directory
|
||||
if host_settings["mode"] == "directory":
|
||||
directory = host_settings["directory"]
|
||||
logger.info(f"Using directory: {directory}")
|
||||
|
||||
# If the mode is "steamdeck", we will need to collect all the screenshots from the Steam Deck
|
||||
elif host_settings["mode"] == "steamdeck":
|
||||
|
||||
# Find all screenshots on the Steam Deck
|
||||
glob_pattern = "/home/deck/.local/share/Steam/userdata/**/screenshots/*.jpg"
|
||||
screenshots = glob.glob(glob_pattern, recursive=True)
|
||||
logger.info(f"Found {len(screenshots)} screenshots on the Steam Deck")
|
||||
|
||||
# Make a temporary directory to store the screenshots
|
||||
temp_dir = Path("/tmp/screenshot-bundle")
|
||||
if temp_dir.exists():
|
||||
shutil.rmtree(temp_dir)
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Copy all the screenshots to the temporary directory
|
||||
for screenshot in screenshots:
|
||||
shutil.copy(screenshot, temp_dir / screenshot.name)
|
||||
|
||||
# Ensure that the timestamps match
|
||||
creation_time = datetime.datetime.fromtimestamp(Path(screenshot).stat().st_ctime)
|
||||
modification_time = datetime.datetime.fromtimestamp(Path(screenshot).stat().st_mtime)
|
||||
earliest_time = min(creation_time, modification_time)
|
||||
subprocess.check_output(["touch", "-t", earliest_time.strftime("%Y%m%d%H%M.%S"), temp_dir / screenshot.name])
|
||||
|
||||
# Set the directory to the temporary directory
|
||||
directory = temp_dir
|
||||
logger.info(f"Using directory: {directory}")
|
||||
|
||||
else:
|
||||
logger.error(f"Unsupported mode: {host_settings['mode']}")
|
||||
return 1
|
||||
|
||||
directory = Path(directory).expanduser()
|
||||
|
||||
# Iterate over each screenshot and update its timestamp if needed
|
||||
for screenshot in directory.glob("*"):
|
||||
# Skip files that are not images
|
||||
if not screenshot.is_file():
|
||||
logger.warning(f"Skipping non-file: {screenshot}")
|
||||
continue
|
||||
if screenshot.suffix.lower() not in [".jpg", ".jpeg", ".png"]:
|
||||
logger.warning(f"Skipping non-image: {screenshot}")
|
||||
continue
|
||||
|
||||
try:
|
||||
image = Image.open(screenshot)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to read {screenshot}: {e}")
|
||||
raise e
|
||||
|
||||
# If the image has an EXIF timestamp, skip
|
||||
exif = image.getexif()
|
||||
if not exif:
|
||||
logger.debug(f"Skipping {screenshot}: EXIF timestamp found")
|
||||
continue
|
||||
|
||||
# Get the creation and modification times of the file
|
||||
creation_time = datetime.datetime.fromtimestamp(screenshot.stat().st_ctime)
|
||||
modification_time = datetime.datetime.fromtimestamp(screenshot.stat().st_mtime)
|
||||
|
||||
# Find the earliest time
|
||||
earliest_time = min(creation_time, modification_time)
|
||||
logger.info(f"Updating {screenshot} to {earliest_time}")
|
||||
|
||||
# Set the file's EXIF timestamp to the earliest time
|
||||
exif[36867] = earliest_time.strftime("%Y:%m:%d %H:%M:%S")
|
||||
logger.info(f"Setting EXIF timestamp to {earliest_time} for {screenshot}")
|
||||
|
||||
|
||||
# Use rclone to sync the screenshots to Google Photos
|
||||
try:
|
||||
subprocess.check_output(["rclone", "mkdir", f"{RCLONE_REMOTE_NAME}:album/{album_name}"])
|
||||
subprocess.check_output(
|
||||
[
|
||||
"rclone",
|
||||
"copy",
|
||||
str(directory),
|
||||
f"{RCLONE_REMOTE_NAME}:album/{album_name}",
|
||||
"--progress",
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"rclone failed: {e.output.decode()}")
|
||||
return 1
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description = Sync Fedora's Screenshot Directory
|
||||
|
||||
[Path]
|
||||
PathModified = %h/Pictures/Screenshots
|
||||
Unit = sync-screenshots-google-photos.service
|
||||
|
||||
[Install]
|
||||
WantedBy = default.target
|
@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description = Sync screenshots to Google Photos
|
||||
|
||||
[Service]
|
||||
Type = oneshot
|
||||
ExecStart = python3 %h/.config/systemd/scripts/sync-screenshots-google-photos.py
|
@ -108,6 +108,10 @@ ln -sf $EWCONFIG_ROOT/configs/logid/logid.cfg ~/.config/logid/logid.cfg
|
||||
# GQRX
|
||||
ln -sf $EWCONFIG_ROOT/configs/gqrx/bookmarks.csv ~/.config/gqrx/bookmarks.csv
|
||||
|
||||
# Systemd
|
||||
ln -sf $EWCONFIG_ROOT/configs/systemd/user/* ~/.config/systemd/user/
|
||||
ln -nsf $EWCONFIG_ROOT/configs/systemd/scripts ~/.config/systemd/scripts
|
||||
|
||||
# Minecraft global configs
|
||||
ln -nsf $EWCONFIG_ROOT/configs/minecraft ~/.config/minecraft
|
||||
if [ -d ~/.var/app/org.prismlauncher.PrismLauncher ]; then
|
||||
|
Loading…
x
Reference in New Issue
Block a user