5bcb35e737
Files within a downloading torrent are now imported as soon as their individual progress reaches 100%, without waiting for the full torrent to complete. A new processed_files table (info_hash, file_name) tracks which files have been handled to avoid redundant re-hashing each poll. - db.py: add processed_files table, is_file_processed, record_processed_file - qbit_client.py: replace get_completed_torrents with get_torrents(filter, category) - stash_handler.py: extract process_torrent_files helper, daemon now polls both downloading and completed torrents each cycle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
3.0 KiB
Python
93 lines
3.0 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.execute("""
|
|
CREATE TABLE IF NOT EXISTS processed_files (
|
|
info_hash TEXT NOT NULL,
|
|
file_name TEXT NOT NULL,
|
|
processed_at TEXT NOT NULL,
|
|
PRIMARY KEY (info_hash, file_name)
|
|
)
|
|
""")
|
|
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 fully 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 fully 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()
|
|
|
|
|
|
def is_file_processed(conn, info_hash, file_name):
|
|
"""Check if an individual file within a torrent has already been processed."""
|
|
row = conn.execute(
|
|
"SELECT 1 FROM processed_files WHERE info_hash = ? AND file_name = ?",
|
|
(info_hash, file_name),
|
|
).fetchone()
|
|
return row is not None
|
|
|
|
|
|
def record_processed_file(conn, info_hash, file_name):
|
|
"""Record an individual file within a torrent as processed."""
|
|
now = datetime.now(timezone.utc).isoformat()
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO processed_files (info_hash, file_name, processed_at) VALUES (?, ?, ?)",
|
|
(info_hash, file_name, now),
|
|
)
|
|
conn.commit()
|