mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-01 20:28:16 +02:00
Add Transcode entry to Nautilus context menu (#5635)
* Add Transcode entry to Nautilus context menu Right-click on image or video files in Nautilus to send them to omarchy-transcode in a presentation terminal, mirroring the existing LocalSend integration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Use shlex.quote for shell-safe command construction in transcode.py Quote both the resolved binary path and file paths via shlex.quote instead of a custom escaper. Addresses Copilot review on #5635. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Style changes --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: David Heinemeier Hansson <david@hey.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
David Heinemeier Hansson
parent
5cf83d2073
commit
ec4a3d0249
@@ -0,0 +1,94 @@
|
||||
import shlex
|
||||
import shutil
|
||||
|
||||
from gi import require_version
|
||||
|
||||
require_version("Nautilus", "4.1")
|
||||
|
||||
from gi.repository import GObject, Gio, Nautilus
|
||||
|
||||
|
||||
SUPPORTED_MIME_PREFIXES = ("image/", "video/")
|
||||
SUPPORTED_EXTENSIONS = {
|
||||
".jpg", ".jpeg", ".png", ".webp", ".gif", ".heic", ".avif",
|
||||
".mp4", ".mov", ".m4v", ".mkv", ".webm", ".avi",
|
||||
}
|
||||
|
||||
|
||||
class TranscodeAction(GObject.GObject, Nautilus.MenuProvider):
|
||||
def _launch_transcode(self, paths):
|
||||
wrapper = shutil.which("omarchy-launch-floating-terminal-with-presentation")
|
||||
binary = shutil.which("omarchy-transcode")
|
||||
if not wrapper or not binary:
|
||||
return
|
||||
|
||||
if len(paths) == 1:
|
||||
cmd = shlex.join([binary, paths[0]])
|
||||
else:
|
||||
cmd = "; ".join(
|
||||
f"echo {shlex.quote(f'Transcoding {path}')} && "
|
||||
f"{shlex.join([binary, path])} || true"
|
||||
for path in paths
|
||||
)
|
||||
|
||||
Gio.Subprocess.new([wrapper, cmd], Gio.SubprocessFlags.NONE)
|
||||
|
||||
def _is_supported(self, file):
|
||||
mime = file.get_mime_type() or ""
|
||||
if mime.startswith(SUPPORTED_MIME_PREFIXES):
|
||||
return True
|
||||
|
||||
location = file.get_location()
|
||||
if not location:
|
||||
return False
|
||||
path = location.get_path() or ""
|
||||
lower = path.lower()
|
||||
return any(lower.endswith(ext) for ext in SUPPORTED_EXTENSIONS)
|
||||
|
||||
def _selected_paths(self, files):
|
||||
paths = []
|
||||
seen = set()
|
||||
|
||||
for file in files:
|
||||
if file.is_directory():
|
||||
continue
|
||||
if not self._is_supported(file):
|
||||
continue
|
||||
location = file.get_location()
|
||||
if not location:
|
||||
continue
|
||||
path = location.get_path()
|
||||
if path and path not in seen:
|
||||
seen.add(path)
|
||||
paths.append(path)
|
||||
return paths
|
||||
|
||||
def _make_item(self, paths):
|
||||
label = "Transcode" if len(paths) == 1 else f"Transcode {len(paths)} items"
|
||||
item = Nautilus.MenuItem(
|
||||
name="OmarchyTranscodeNautilus::transcode",
|
||||
label=label,
|
||||
icon="media-playback-start",
|
||||
)
|
||||
item.connect("activate", self._on_activate, paths)
|
||||
return item
|
||||
|
||||
def _on_activate(self, _menu, paths):
|
||||
self._launch_transcode(paths)
|
||||
|
||||
def _tools_available(self):
|
||||
return bool(
|
||||
shutil.which("omarchy-launch-floating-terminal-with-presentation")
|
||||
and shutil.which("omarchy-transcode")
|
||||
)
|
||||
|
||||
def get_file_items(self, *args):
|
||||
files = args[0] if len(args) == 1 else args[1]
|
||||
if not self._tools_available():
|
||||
return []
|
||||
|
||||
paths = self._selected_paths(files)
|
||||
if not paths:
|
||||
return []
|
||||
|
||||
return [self._make_item(paths)]
|
||||
Reference in New Issue
Block a user