Initial: forked from runesleo/x-reader (MIT License) - thank you @runes_leo!
This commit is contained in:
commit
ee2ad83b12
25 changed files with 2512 additions and 0 deletions
0
x_reader/utils/__init__.py
Normal file
0
x_reader/utils/__init__.py
Normal file
88
x_reader/utils/storage.py
Normal file
88
x_reader/utils/storage.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Storage utilities — save content to JSON inbox and optional Markdown file.
|
||||
|
||||
Implements the "atomic archiving" from the tweet:
|
||||
- unified_inbox.json (for AI/programmatic use)
|
||||
- markdown file (for human reading, e.g. Obsidian)
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
|
||||
from x_reader.schema import UnifiedContent
|
||||
|
||||
|
||||
def save_to_json(item: UnifiedContent, filepath: str = "unified_inbox.json"):
|
||||
"""Append content to JSON inbox file."""
|
||||
path = Path(filepath)
|
||||
data = []
|
||||
|
||||
if path.exists():
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except (json.JSONDecodeError, IOError):
|
||||
data = []
|
||||
|
||||
data.append(item.to_dict())
|
||||
|
||||
# Keep last 500 entries to prevent unbounded growth
|
||||
data = data[-500:]
|
||||
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
logger.info(f"Saved to JSON: {path}")
|
||||
|
||||
|
||||
def save_to_markdown(item: UnifiedContent, filepath: str = None):
|
||||
"""
|
||||
Append content to a Markdown file (e.g. Obsidian vault).
|
||||
|
||||
Supports two output modes:
|
||||
- OUTPUT_DIR: Write to {OUTPUT_DIR}/content_hub.md
|
||||
- OBSIDIAN_VAULT: Write to {OBSIDIAN_VAULT}/01-收集箱/x-reader-inbox.md
|
||||
|
||||
If neither is set, skips markdown output.
|
||||
"""
|
||||
if not filepath:
|
||||
# Priority 1: Obsidian vault
|
||||
vault_path = os.getenv("OBSIDIAN_VAULT", "")
|
||||
if vault_path:
|
||||
filepath = os.path.join(vault_path, "01-收集箱", "x-reader-inbox.md")
|
||||
else:
|
||||
# Priority 2: generic output dir
|
||||
output_dir = os.getenv("OUTPUT_DIR", "")
|
||||
if not output_dir:
|
||||
return
|
||||
filepath = os.path.join(output_dir, "content_hub.md")
|
||||
|
||||
path = Path(filepath)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
emoji = {
|
||||
"telegram": "📢", "rss": "📰", "bilibili": "🎬",
|
||||
"xhs": "📕", "twitter": "🐦", "wechat": "💬",
|
||||
"youtube": "▶️", "manual": "✏️",
|
||||
}.get(item.source_type.value, "📄")
|
||||
|
||||
with open(path, 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n## {emoji} {item.title}\n")
|
||||
f.write(f"- Source: {item.source_name} ({item.source_type.value})\n")
|
||||
f.write(f"- URL: {item.url}\n")
|
||||
f.write(f"- Fetched: {item.fetched_at[:16]}\n\n")
|
||||
f.write(f"{item.content[:2000]}\n")
|
||||
f.write("\n---\n")
|
||||
|
||||
logger.info(f"Saved to Markdown: {path}")
|
||||
|
||||
|
||||
def save_content(item: UnifiedContent, json_path: str = None, md_path: str = None):
|
||||
"""Save content to both JSON and Markdown."""
|
||||
inbox_file = json_path or os.getenv("INBOX_FILE", "unified_inbox.json")
|
||||
save_to_json(item, inbox_file)
|
||||
save_to_markdown(item, md_path)
|
||||
Loading…
Add table
Add a link
Reference in a new issue