nixos: add affinity thumbnailer for kde
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
{
|
||||
description = "Thumbnailer for Affinity files (.afpub, .afdesign, .afphoto, .af, .afpackage) on KDE Plasma / freedesktop";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (pkgs: {
|
||||
default = self.packages.${pkgs.stdenv.hostPlatform.system}.affinity-thumbnailer;
|
||||
|
||||
affinity-thumbnailer = pkgs.stdenv.mkDerivation {
|
||||
pname = "affinity-thumbnailer";
|
||||
version = "0.1.0";
|
||||
|
||||
# Don't pull source from GitHub — we build everything from inline content
|
||||
src = pkgs.runCommand "affinity-thumbnailer-src" { } ''
|
||||
mkdir -p $out
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||
|
||||
# Runtime dependencies
|
||||
buildInputs = [ pkgs.python3 ];
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# --- 1. Install the Python thumbnailer script ---
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/affinity-thumbnailer << 'PYEOF'
|
||||
#!/usr/bin/env python3
|
||||
"""Extract embedded PNG thumbnails from Affinity files (.afpub, .afdesign, .afphoto, .af, .afpackage)."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
PNG_SIGNATURE = b"\x89PNG"
|
||||
PNG_IEND = b"IEND"
|
||||
SUPPORTED_EXTENSIONS = {".afpub", ".afdesign", ".afphoto", ".af", ".afpackage"}
|
||||
|
||||
|
||||
def find_png(data: bytes) -> bytes | None:
|
||||
"""Find and extract the first complete PNG from binary data."""
|
||||
sig_offset = data.find(PNG_SIGNATURE)
|
||||
if sig_offset == -1:
|
||||
return None
|
||||
|
||||
iend_offset = data.find(PNG_IEND, sig_offset)
|
||||
if iend_offset == -1:
|
||||
return None
|
||||
|
||||
png_end = iend_offset + len(PNG_IEND) + 4
|
||||
return data[sig_offset:png_end]
|
||||
|
||||
|
||||
def extract_thumbnail(filepath: str) -> bytes | None:
|
||||
"""Read a file and extract its embedded PNG thumbnail."""
|
||||
ext = os.path.splitext(filepath)[1].lower()
|
||||
if ext not in SUPPORTED_EXTENSIONS:
|
||||
print(
|
||||
f"Error: unsupported extension '{ext}'. "
|
||||
f"Supported: {', '.join(sorted(SUPPORTED_EXTENSIONS))}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return None
|
||||
|
||||
if not os.path.isfile(filepath):
|
||||
print(f"Error: file not found: {filepath}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
with open(filepath, "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
return find_png(data)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extract embedded PNG thumbnail from Affinity files."
|
||||
)
|
||||
parser.add_argument("input", help="Input Affinity file (.afpub, .afdesign, .afphoto, .af, .afpackage)")
|
||||
parser.add_argument(
|
||||
"output",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="Output PNG file (default: stdout)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
png_data = extract_thumbnail(args.input)
|
||||
if png_data is None:
|
||||
print("Error: no embedded PNG thumbnail found.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, "wb") as f:
|
||||
f.write(png_data)
|
||||
print(f"Thumbnail saved: {args.output} ({len(png_data)} bytes)")
|
||||
else:
|
||||
sys.stdout.buffer.write(png_data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
PYEOF
|
||||
chmod +x $out/bin/affinity-thumbnailer
|
||||
|
||||
# Wrap so it finds python3 in NixOS
|
||||
wrapProgram $out/bin/affinity-thumbnailer \
|
||||
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.python3 ]}
|
||||
|
||||
# --- 2. Install the .thumbnailer freedesktop entry ---
|
||||
mkdir -p $out/share/thumbnailers
|
||||
cat > $out/share/thumbnailers/affinity.thumbnailer << EOF
|
||||
[Thumbnailer Entry]
|
||||
TryExec=$out/bin/affinity-thumbnailer
|
||||
Exec=$out/bin/affinity-thumbnailer %i %o
|
||||
MimeType=application/affinity-publisher;application/affinity-designer;application/affinity-photo;application/affinity-v3;application/affinity-package;
|
||||
EOF
|
||||
|
||||
# --- 3. Install MIME type definitions ---
|
||||
mkdir -p $out/share/mime/packages
|
||||
cat > $out/share/mime/packages/application-affinity.xml << 'MIMEXML'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/affinity-publisher">
|
||||
<comment>Affinity File</comment>
|
||||
<glob pattern="*.afpub"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/affinity-designer">
|
||||
<comment>Affinity File</comment>
|
||||
<glob pattern="*.afdesign"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/affinity-photo">
|
||||
<comment>Affinity File</comment>
|
||||
<glob pattern="*.afphoto"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/affinity-v3">
|
||||
<comment>Affinity File</comment>
|
||||
<glob pattern="*.af"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/affinity-package">
|
||||
<comment>Affinity File</comment>
|
||||
<glob pattern="*.afpackage"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
MIMEXML
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Thumbnailer for Affinity files on KDE Plasma / freedesktop";
|
||||
homepage = "https://github.com/Nczer/Affinity-thumbnailer-KDE-plasma";
|
||||
license = licenses.mit; # No license specified in the repo
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
# --- NixOS module for easy integration ---
|
||||
nixosModules.default =
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options.services.affinity-thumbnailer = {
|
||||
enable = lib.mkEnableOption "Affinity file thumbnailer for KDE Plasma / freedesktop";
|
||||
};
|
||||
|
||||
config = lib.mkIf config.services.affinity-thumbnailer.enable {
|
||||
environment.systemPackages = [
|
||||
self.packages.${pkgs.stdenv.hostPlatform.system}.default
|
||||
];
|
||||
|
||||
# Make sure thumbnailer and MIME directories are linked
|
||||
environment.pathsToLink = [
|
||||
"/share/thumbnailers"
|
||||
"/share/mime"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user