f09d94e34b
Bridge between qBittorrent and Stash that polls for completed torrents, deduplicates via SHA256 hashing and SQLite, and imports new media files. Supports daemon mode (continuous polling) and scan mode (bulk operations). Configuration via environment variables for Docker Swarm compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
import sqlite3
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
def init_db(db_path):
|
|
"""Initialize the database and return a connection."""
|
|
conn = sqlite3.connect(db_path)
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS seen_files (
|
|
hash TEXT PRIMARY KEY,
|
|
filename TEXT NOT NULL,
|
|
source TEXT,
|
|
info_hash TEXT,
|
|
first_seen TEXT NOT NULL,
|
|
times_seen INTEGER DEFAULT 1
|
|
)
|
|
""")
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS processed_torrents (
|
|
info_hash TEXT PRIMARY KEY,
|
|
torrent_name TEXT,
|
|
processed_at TEXT NOT NULL
|
|
)
|
|
""")
|
|
conn.commit()
|
|
return conn
|
|
|
|
|
|
def is_known(conn, file_hash):
|
|
"""Check if a file hash is already in the database."""
|
|
row = conn.execute("SELECT 1 FROM seen_files WHERE hash = ?", (file_hash,)).fetchone()
|
|
return row is not None
|
|
|
|
|
|
def record_file(conn, file_hash, filename, source, info_hash=None):
|
|
"""Record a file hash in the database."""
|
|
now = datetime.now(timezone.utc).isoformat()
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO seen_files (hash, filename, source, info_hash, first_seen) VALUES (?, ?, ?, ?, ?)",
|
|
(file_hash, filename, source, info_hash, now),
|
|
)
|
|
conn.commit()
|
|
|
|
|
|
def increment_seen(conn, file_hash):
|
|
"""Increment the times_seen counter for a known hash."""
|
|
conn.execute("UPDATE seen_files SET times_seen = times_seen + 1 WHERE hash = ?", (file_hash,))
|
|
conn.commit()
|
|
|
|
|
|
def is_torrent_processed(conn, info_hash):
|
|
"""Check if a torrent has already been processed."""
|
|
row = conn.execute("SELECT 1 FROM processed_torrents WHERE info_hash = ?", (info_hash,)).fetchone()
|
|
return row is not None
|
|
|
|
|
|
def record_torrent(conn, info_hash, torrent_name):
|
|
"""Record a torrent as processed."""
|
|
now = datetime.now(timezone.utc).isoformat()
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO processed_torrents (info_hash, torrent_name, processed_at) VALUES (?, ?, ?)",
|
|
(info_hash, torrent_name, now),
|
|
)
|
|
conn.commit()
|