98 lines
3.0 KiB
Python
Executable File
98 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env -S uv run
|
|
# /// script
|
|
# dependencies = [
|
|
# "httpx",
|
|
# ]
|
|
# ///
|
|
import argparse
|
|
import base64
|
|
import logging
|
|
from os import getenv
|
|
import os
|
|
import subprocess
|
|
import httpx
|
|
from pathlib import Path
|
|
|
|
|
|
def move_to_trash(file_path: Path):
|
|
if not file_path.is_file():
|
|
raise FileNotFoundError
|
|
if os.name != "darwin":
|
|
args = [
|
|
"osascript",
|
|
"-e",
|
|
f'tell app "Finder" to move POSIX file "{file_path}" to trash',
|
|
]
|
|
subprocess.run(
|
|
args,
|
|
check=True,
|
|
)
|
|
if os.name == "win32":
|
|
# move to recycle bin
|
|
# Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile("C:\path\to\your\file.txt", 'OnlyErrorDialogs', 'SendToRecycleBin')
|
|
args = [
|
|
"powershell",
|
|
"-NoProfile",
|
|
"-Command",
|
|
f'Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile("{file_path}", "OnlyErrorDialogs", "SendToRecycleBin")',
|
|
]
|
|
subprocess.run(
|
|
args,
|
|
check=True,
|
|
)
|
|
|
|
|
|
def add_torrent(client: httpx.Client, torrent_path: Path):
|
|
encoded_torrent = base64.b64encode(torrent_path.read_bytes()).decode()
|
|
|
|
payload = {
|
|
"method": "torrent-add",
|
|
"arguments": {
|
|
"download-dir": "/downloads/",
|
|
"metainfo": encoded_torrent,
|
|
"paused": False,
|
|
},
|
|
}
|
|
|
|
res = client.post("/transmission/rpc", json=payload)
|
|
if res.is_error:
|
|
raise Exception(f"HTTP {res.status_code}: {res.text}")
|
|
result = res.json()
|
|
|
|
return result["result"] in ["duplicate-torrent", "success"]
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description="Add torrent to Transmission via RPC")
|
|
parser.add_argument("torrent_paths", type=Path, nargs="+", help="Path to the torrent file")
|
|
parser.add_argument("--host", required=True, default=getenv("TRANSMISSION_HOST", "http://localhost:9091"), help="Transmission RPC host URL")
|
|
parser.add_argument("--auth", default=getenv("TRANSMISSION_AUTH"), help="Transmission RPC username:password")
|
|
parser.add_argument("--clean", action="store_true", help="Delete torrent file after successful upload")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
client = httpx.Client(
|
|
base_url=args.host,
|
|
auth=httpx.BasicAuth(*args.auth.split(":")) if args.auth else None,
|
|
timeout=10,
|
|
)
|
|
csrf_token = client.post("/transmission/rpc", json={"method": "session-get"}).headers["x-transmission-session-id"]
|
|
client.headers["X-Transmission-Session-Id"] = csrf_token
|
|
|
|
for torrent_path in args.torrent_paths:
|
|
if not torrent_path.is_file():
|
|
logging.error(f"Torrent file not found: {args.torrent_path}")
|
|
raise SystemError(1)
|
|
add_torrent(client=client, torrent_path=torrent_path)
|
|
if args.clean:
|
|
move_to_trash(torrent_path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|