254 lines
5.4 KiB
Python
Executable File
254 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
from pathlib import Path
|
|
|
|
from services.iview import iViewService
|
|
|
|
|
|
# -------------------------
|
|
# Metadata paths
|
|
# -------------------------
|
|
DOWNLOAD_META = Path("./.download")
|
|
|
|
HISTORY_FILE = DOWNLOAD_META / ".history"
|
|
SERIES_FILE = DOWNLOAD_META / ".series"
|
|
|
|
|
|
# -------------------------
|
|
# Service registry
|
|
# -------------------------
|
|
SERVICES = {
|
|
"IVIEW": iViewService(),
|
|
}
|
|
|
|
|
|
# -------------------------
|
|
# Core Autograbber
|
|
# -------------------------
|
|
class AutoGrabber:
|
|
|
|
def __init__(self, download_dir, dry_run=False):
|
|
|
|
self.download_dir = Path(download_dir)
|
|
self.dry_run = dry_run
|
|
|
|
self.history = self.load_history()
|
|
self.series_list = self.load_series()
|
|
|
|
# -------------------------
|
|
# History handling
|
|
# -------------------------
|
|
def load_history(self):
|
|
|
|
history = {}
|
|
|
|
if not HISTORY_FILE.exists():
|
|
HISTORY_FILE.touch()
|
|
|
|
with open(HISTORY_FILE, "r") as f:
|
|
|
|
for line in f:
|
|
|
|
line = line.strip()
|
|
|
|
if not line:
|
|
continue
|
|
|
|
if "|" in line:
|
|
|
|
ep_id, filename = line.split("|", 1)
|
|
|
|
history[ep_id.strip()] = filename.strip()
|
|
|
|
else:
|
|
history[line.strip()] = None
|
|
|
|
return history
|
|
|
|
def save_history(self):
|
|
|
|
with open(HISTORY_FILE, "w") as f:
|
|
|
|
for ep_id in sorted(self.history.keys()):
|
|
|
|
filename = self.history[ep_id]
|
|
|
|
if filename:
|
|
f.write(f"{ep_id} | {filename}\n")
|
|
else:
|
|
f.write(f"{ep_id}\n")
|
|
|
|
# -------------------------
|
|
# Series loading
|
|
# -------------------------
|
|
def load_series(self):
|
|
|
|
if not SERIES_FILE.exists():
|
|
|
|
print(
|
|
"❌ Missing required file: "
|
|
f"{SERIES_FILE}"
|
|
)
|
|
|
|
sys.exit(1)
|
|
|
|
series = []
|
|
|
|
with open(SERIES_FILE, "r") as f:
|
|
|
|
for line in f:
|
|
|
|
line = line.strip()
|
|
|
|
if not line:
|
|
continue
|
|
|
|
if "/" not in line:
|
|
continue
|
|
|
|
service_name, show_title = line.split("/", 1)
|
|
|
|
series.append((
|
|
service_name.strip(),
|
|
show_title.strip()
|
|
))
|
|
|
|
return series
|
|
|
|
# -------------------------
|
|
# Process a single show
|
|
# -------------------------
|
|
def process_show(self, service_name, show_title):
|
|
|
|
service = SERVICES.get(service_name.upper())
|
|
|
|
if not service:
|
|
|
|
print(f"❌ Unknown service: {service_name}")
|
|
return
|
|
|
|
print("\n==============================")
|
|
print(f"📺 Show: {show_title}")
|
|
print(f"📡 Service: {service_name}")
|
|
print("==============================")
|
|
|
|
seasons = service.discover_seasons(show_title)
|
|
|
|
if not seasons:
|
|
|
|
print("⚠️ No seasons found")
|
|
return
|
|
|
|
for season_data in seasons:
|
|
|
|
season_num = season_data["season"]
|
|
data = season_data["data"]
|
|
|
|
print(f"\n📦 Processing Season {season_num}")
|
|
|
|
for entry in data["entries"]:
|
|
|
|
episode = service.normalize_episode(
|
|
show_title,
|
|
entry
|
|
)
|
|
|
|
ep_id = episode["episode_id"]
|
|
|
|
if not ep_id:
|
|
continue
|
|
|
|
filename = episode["filename"]
|
|
|
|
# already downloaded
|
|
if ep_id in self.history:
|
|
|
|
print(
|
|
f"⏩ "
|
|
f"{self.history[ep_id]} "
|
|
f"(already downloaded)"
|
|
)
|
|
|
|
continue
|
|
|
|
# dry-run mode
|
|
if self.dry_run:
|
|
|
|
print(
|
|
f"🧪 "
|
|
f"{filename} "
|
|
f"(would download)"
|
|
)
|
|
|
|
continue
|
|
|
|
print(f"✅ {filename} → downloading")
|
|
|
|
success = service.download_episode(
|
|
episode,
|
|
entry,
|
|
self.download_dir
|
|
)
|
|
|
|
if success:
|
|
|
|
self.history[ep_id] = filename
|
|
self.save_history()
|
|
|
|
# -------------------------
|
|
# Main execution
|
|
# -------------------------
|
|
def run(self):
|
|
|
|
if not self.series_list:
|
|
|
|
print("⚠️ No shows found in .series")
|
|
return
|
|
|
|
for service_name, show_title in self.series_list:
|
|
|
|
self.process_show(
|
|
service_name,
|
|
show_title
|
|
)
|
|
|
|
print("\n✅ Autograbber run complete")
|
|
|
|
|
|
# -------------------------
|
|
# CLI
|
|
# -------------------------
|
|
def parse_args():
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Do not download anything"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--downloads",
|
|
default="./downloads",
|
|
help="Download directory"
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
# -------------------------
|
|
# Entry point
|
|
# -------------------------
|
|
if __name__ == "__main__":
|
|
|
|
args = parse_args()
|
|
|
|
AutoGrabber(
|
|
download_dir=args.downloads,
|
|
dry_run=args.dry_run
|
|
).run()
|