Files

77 lines
3.1 KiB
Python

import os
import json
from typing import List, Optional
from pathlib import Path
from .models import RippedThread, HistorySummary
class ThreadStorage:
def __init__(self, data_dir: str = "data"):
self.data_dir = Path(data_dir)
self.threads_dir = self.data_dir / "threads"
self.threads_dir.mkdir(parents=True, exist_ok=True)
def save(self, thread: RippedThread) -> str:
"""Saves a ripped thread to disk in JSON, MD, and HTML formats."""
file_path = self.threads_dir / f"{thread.id}.json"
with open(file_path, "w", encoding="utf-8") as f:
f.write(thread.model_dump_json(indent=2))
# Also save standalone .md and .html files for direct browsing
md_path = self.threads_dir / f"{thread.id}.md"
with open(md_path, "w", encoding="utf-8") as f:
f.write(thread.stitched_markdown)
html_path = self.threads_dir / f"{thread.id}.html"
with open(html_path, "w", encoding="utf-8") as f:
f.write(thread.stitched_html)
txt_path = self.threads_dir / f"{thread.id}.txt"
with open(txt_path, "w", encoding="utf-8") as f:
f.write(thread.stitched_text)
return thread.id
def get(self, thread_id: str) -> Optional[RippedThread]:
"""Loads a saved ripped thread by ID."""
file_path = self.threads_dir / f"{thread_id}.json"
if not file_path.exists():
return None
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
return RippedThread(**data)
def list_history(self) -> List[HistorySummary]:
"""Lists summaries of all previously ripped threads, newest first."""
history = []
for file in self.threads_dir.glob("*.json"):
try:
with open(file, "r", encoding="utf-8") as f:
data = json.load(f)
history.append(
HistorySummary(
id=data["id"],
title=data.get("title", "Untitled Thread"),
author_handle=data.get("author_handle", "unknown"),
author_name=data.get("author_name", "Unknown"),
segment_count=data.get("segment_count", len(data.get("segments", []))),
total_words=data.get("total_words", 0),
saved_at=str(data.get("saved_at", ""))[:19],
original_url=data.get("original_url", "")
)
)
except Exception:
continue
# Sort by saved_at descending
history.sort(key=lambda x: x.saved_at, reverse=True)
return history
def delete(self, thread_id: str) -> bool:
"""Deletes a saved thread and all associated format files."""
deleted = False
for ext in [".json", ".md", ".html", ".txt"]:
f = self.threads_dir / f"{thread_id}{ext}"
if f.exists():
f.unlink()
deleted = True
return deleted