add/change a few python scripts

This commit is contained in:
Seaswimmer 2024-11-22 09:50:05 -05:00
parent de0e43ef6a
commit 7e1ed655ce
Signed by: cswimr
GPG key ID: 0EC431A8DA8F8087
6 changed files with 207 additions and 79 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
hosts/configuration.nix hosts/configuration.nix
__pycache__

0
scripts/__init__.py Normal file
View file

View file

71
scripts/common/common.py Normal file
View file

@ -0,0 +1,71 @@
import os
import subprocess
from pathlib import Path
from shutil import which
def notify(
application_name: str,
title: str,
message: str,
urgency: str = "low",
category: str | None = None,
icon: Path | None = None,
desktop_entry: str | None = None,
) -> None:
args = ["notify-send", "-a", application_name, "-u", urgency]
if category:
args.append("-c")
args.append(category)
if icon:
args.append("-i")
args.append(str(icon))
if desktop_entry:
args.append("-h")
args.append(f"string:desktop-entry:{desktop_entry}")
args.append(title)
args.append(message)
print(args)
subprocess.run(args)
def read_secret_file(secret: str) -> str:
with open(f"/run/secrets/{secret}", "r") as f:
return f.read().strip()
def does_desktop_entry_exist(desktop_entry: str) -> bool:
if not desktop_entry:
raise ValueError("Please provide the full filename of the desktop entry.")
if not desktop_entry.endswith(".desktop"):
desktop_entry += ".desktop"
entry_paths = []
if which("qtpaths"):
result = subprocess.run(
["qtpaths", "--paths", "ApplicationsLocation"],
stdout=subprocess.PIPE,
text=True,
)
entry_paths = result.stdout.strip().split(":")
else:
print("qtpaths is not installed, falling back to XDG_DATA_DIRS.")
xdg_data_dirs = os.getenv("XDG_DATA_DIRS", "/usr/share:/usr/local/share").split(
":"
)
entry_paths = [os.path.join(path, "applications") for path in xdg_data_dirs]
entry_paths.append(os.path.expanduser("~/.local/share/applications"))
print(f"Checking the following paths for {desktop_entry}:\n{entry_paths}\n{'-'*20}")
for entry_path in entry_paths:
entry_file = Path(entry_path) / f"{desktop_entry}"
print(f"Checking for {entry_file}")
if entry_file.is_file():
print(f"{desktop_entry} found in {entry_path}")
return True
print(f"Desktop entry {desktop_entry} does not exist.")
return False

118
scripts/spectacle-screenshot Executable file
View file

@ -0,0 +1,118 @@
#! /usr/bin/env nix-shell
#! nix-shell -i python -p python312
import argparse
import os
import subprocess
import tempfile
from pathlib import Path
from shutil import which
from common.common import notify
def spectacle_screenshot(
url: str | None = None, record: bool = False, file_path: Path | None = None
) -> None:
try:
if not which("spectacle"):
raise FileNotFoundError("spectacle is not installed.")
if file_path and Path(file_path).exists():
raise FileExistsError(
'File already exists. Please provide a different file path, or use the zipline function to upload the file.\nExample: zipline "{file_path}"'
)
if not file_path:
# Spectacle actually defaults to .webm for video recordings,
# but Zipline doesn't behave well with .webm files so we use .mp4 instead.
use_temp_file = True
suffix = ".mp4" if record else ".png"
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
file_path = temp_file.name
temp_file.close()
else:
use_temp_file = False
command = [
"spectacle",
"--nonotify",
"--background",
"--pointer",
"--copy-image",
"--output",
file_path,
]
if record:
command.append("--record=region")
else:
command.append("--region")
try:
subprocess.run(command, check=True)
except subprocess.CalledProcessError as e:
if Path(file_path).exists() and use_temp_file:
os.remove(file_path)
raise e
if not Path(file_path).stat().st_size:
os.remove(file_path)
raise FileNotFoundError("The file was not created properly.")
try:
opts = [
"/etc/nixos/scripts/zipline",
file_path,
"--application-name",
"Spectacle",
"--desktop-entry",
"org.kde.spectacle",
]
if url:
opts.extend(["--url", url])
subprocess.run(opts)
finally:
if Path(file_path).exists() and use_temp_file:
os.remove(file_path)
except Exception as e:
notify(
application_name="Spectacle",
title="An error occurred",
message=str(e),
urgency="critical",
category="transfer.error",
desktop_entry="org.kde.spectacle",
)
raise e
if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="spectacle-screenshot",
description="Take a screenshot or recording with Spectacle and automatically upload it to a Zipline instance.",
epilog="Example usage: spectacle-screenshot",
)
parser.add_argument(
"--url",
help="The URL of the Zipline instance to upload the screenshot or recording to. Defaults to 'https://csw.im'.",
default="https://csw.im",
)
parser.add_argument(
"--record",
help="If this is set, Spectacle will record the region instead of taking a screenshot.",
action="store_true",
)
parser.add_argument(
"--file-path",
help="The path to save the screenshot or recording to. If not provided, the screenshot or recording will be saved to a temporary file.",
default=None,
)
args = parser.parse_args()
spectacle_screenshot(
url=args.url,
record=args.record,
file_path=args.file_path,
)

View file

@ -1,5 +1,5 @@
#! /usr/bin/env nix-shell #! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python312 python312Packages.tkinter python312Packages.requests libnotify #! nix-shell -i python -p python312 python312Packages.tkinter python312Packages.requests libnotify
import argparse import argparse
import mimetypes import mimetypes
@ -11,53 +11,18 @@ from tkinter import Tk
from typing import Any from typing import Any
import requests # type: ignore import requests # type: ignore
from common.common import does_desktop_entry_exist, notify, read_secret_file
def read_secret_file(secret: str) -> str:
with open(f"/run/secrets/{secret}", "r") as f:
return f.read().strip()
def does_desktop_entry_exist(desktop_entry: str) -> bool:
if not desktop_entry:
raise ValueError("Please provide the full filename of the desktop entry.")
if not desktop_entry.endswith(".desktop"):
desktop_entry += ".desktop"
entry_paths = []
# Check if qtpaths is available
if which("qtpaths"):
result = subprocess.run(
["qtpaths", "--paths", "ApplicationsLocation"],
stdout=subprocess.PIPE,
text=True,
)
entry_paths = result.stdout.strip().split(":")
else:
print("qtpaths is not installed, falling back to XDG_DATA_DIRS.")
xdg_data_dirs = os.getenv("XDG_DATA_DIRS", "/usr/share:/usr/local/share").split(
":"
)
entry_paths = [os.path.join(path, "applications") for path in xdg_data_dirs]
entry_paths.append(os.path.expanduser("~/.local/share/applications"))
print(f"Checking the following paths for {desktop_entry}:\n{entry_paths}\n{'-'*20}")
# Search for the desktop entry file
for entry_path in entry_paths:
entry_file = Path(entry_path) / f"{desktop_entry}"
print(f"Checking for {entry_file}")
if entry_file.is_file():
print(f"{desktop_entry} found in {entry_path}")
return True
print(f"Desktop entry {desktop_entry} does not exist.")
return False
def copy_to_clipboard(text: str) -> None: def copy_to_clipboard(text: str) -> None:
if which("xclip"):
subprocess.run(
["xclip", "-selection", "clipboard", "-t", "text/plain", "-i"],
input=text.encode(),
)
elif which("wl-copy"):
subprocess.run(["wl-copy", "--type", "text/plain"], input=text.encode())
else:
root = Tk() root = Tk()
root.withdraw() root.withdraw()
root.clipboard_clear() root.clipboard_clear()
@ -66,30 +31,6 @@ def copy_to_clipboard(text: str) -> None:
root.destroy() root.destroy()
def notify(
application_name: str,
title: str,
message: str,
urgency: str = "low",
category: str | None = None,
icon: Path | None = None,
desktop_entry: str | None = None,
) -> None:
args = ["notify-send" "-a", application_name, "-u", urgency]
if category:
args.append("-c")
args.append(category)
if icon:
args.append("-i")
args.append(str(icon))
if desktop_entry:
args.append("-h")
args.append(f"string:desktop-entry:{desktop_entry}")
args.append(title)
args.append(message)
subprocess.run(args)
def zipline( def zipline(
file_path: Path, file_path: Path,
instance_url: str, instance_url: str,
@ -98,23 +39,19 @@ def zipline(
) -> Any: ) -> Any:
token = read_secret_file("zipline") token = read_secret_file("zipline")
if not token: if not token:
print("Secret file at /run/secrets/zipline either does not exist or is empty.")
raise FileNotFoundError( raise FileNotFoundError(
"Secret file at /run/secrets/zipline either does not exist or is empty." "Secret file at /run/secrets/zipline either does not exist or is empty."
) )
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
print(f"File at {file_path} does not exist.")
raise FileNotFoundError(f"File at {file_path} does not exist.") raise FileNotFoundError(f"File at {file_path} does not exist.")
use_send_notify = False use_send_notify = False
if application_name and desktop_entry: if application_name and desktop_entry:
if not does_desktop_entry_exist(desktop_entry=desktop_entry): if not does_desktop_entry_exist(desktop_entry=desktop_entry):
print("Desktop entry does not exist.")
raise FileNotFoundError("Desktop entry does not exist.") raise FileNotFoundError("Desktop entry does not exist.")
if not which("notify-send"): if not which("notify-send"):
print("notify-send is not installed.")
raise FileNotFoundError("notify-send is not installed.") raise FileNotFoundError("notify-send is not installed.")
use_send_notify = True use_send_notify = True
@ -136,6 +73,7 @@ def zipline(
if link: if link:
copy_to_clipboard(text=link) copy_to_clipboard(text=link)
print(f"Link copied to clipboard: {link}")
if use_send_notify: if use_send_notify:
notify( notify(