send_digest.py
This commit is contained in:
177
scripts/news_digest/send_digest.py
Executable file
177
scripts/news_digest/send_digest.py
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Daily News Digest - Fetch news and send email summary
|
||||
Runs news_digest, formats output, sends via himalaya
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Config
|
||||
SCRIPT_DIR = Path.home() / ".openclaw/workspace/scripts/news_digest"
|
||||
DB_PATH = SCRIPT_DIR / "news_digest.db"
|
||||
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
||||
|
||||
# Email config
|
||||
EMAIL_TO = "lu@luyx.org"
|
||||
EMAIL_FROM = "youlu@luyanxin.com"
|
||||
|
||||
def run_news_digest():
|
||||
"""Run news_digest and get articles with summaries"""
|
||||
# Fetch new articles using run.sh (handles uv dependencies)
|
||||
fetch_cmd = [
|
||||
str(SCRIPT_DIR / "run.sh"),
|
||||
"-v"
|
||||
]
|
||||
|
||||
# Run fetch (this saves articles to DB and generates summaries)
|
||||
result = subprocess.run(fetch_cmd, capture_output=True, text=True, cwd=SCRIPT_DIR)
|
||||
if result.returncode != 0:
|
||||
print(f"Fetch failed: {result.stderr}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
# Now query with summary field
|
||||
query_cmd = [
|
||||
str(SCRIPT_DIR / "run.sh"),
|
||||
"--no-fetch",
|
||||
"-f", "id,title,url,summary,feed_name,category"
|
||||
]
|
||||
|
||||
result = subprocess.run(query_cmd, capture_output=True, text=True, cwd=SCRIPT_DIR)
|
||||
if result.returncode != 0:
|
||||
print(f"Query failed: {result.stderr}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
# Parse JSON - find the JSON array in stdout
|
||||
stdout = result.stdout.strip()
|
||||
|
||||
# Find where JSON array starts and ends
|
||||
start_idx = stdout.find('[')
|
||||
end_idx = stdout.rfind(']')
|
||||
|
||||
if start_idx == -1 or end_idx == -1 or start_idx >= end_idx:
|
||||
print("No valid JSON array found", file=sys.stderr)
|
||||
print(f"Debug output: {stdout[:500]}", file=sys.stderr)
|
||||
return []
|
||||
|
||||
json_output = stdout[start_idx:end_idx+1]
|
||||
|
||||
try:
|
||||
articles = json.loads(json_output)
|
||||
return articles
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Failed to parse JSON: {e}", file=sys.stderr)
|
||||
print(f"Raw output: {json_output[:500]}", file=sys.stderr)
|
||||
return []
|
||||
|
||||
def format_email(articles):
|
||||
"""Format articles into email body"""
|
||||
if not articles:
|
||||
return None
|
||||
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
lines = [
|
||||
f"📰 每日新闻摘要 ({today})",
|
||||
"=" * 50,
|
||||
""
|
||||
]
|
||||
|
||||
# Group by category
|
||||
by_category = {}
|
||||
for a in articles:
|
||||
cat = a.get('category', 'Other')
|
||||
if cat not in by_category:
|
||||
by_category[cat] = []
|
||||
by_category[cat].append(a)
|
||||
|
||||
# Sort categories
|
||||
category_order = ['Tech', 'China', 'World', 'Other']
|
||||
|
||||
for cat in category_order:
|
||||
if cat not in by_category:
|
||||
continue
|
||||
|
||||
cat_name = {
|
||||
'Tech': '💻 科技',
|
||||
'China': '🇨🇳 国内',
|
||||
'World': '🌍 国际',
|
||||
'Other': '📄 其他'
|
||||
}.get(cat, cat)
|
||||
|
||||
lines.append(f"\n{cat_name}")
|
||||
lines.append("-" * 30)
|
||||
|
||||
for article in by_category[cat]:
|
||||
title = article.get('title', '无标题')
|
||||
url = article.get('url', '')
|
||||
summary = article.get('summary', '')
|
||||
source = article.get('feed_name', '未知来源')
|
||||
|
||||
lines.append(f"\n• {title}")
|
||||
if summary:
|
||||
# Clean up summary (remove excessive newlines, preserve content)
|
||||
summary_clean = summary.replace('\n', ' ').strip()
|
||||
lines.append(f" {summary_clean}")
|
||||
lines.append(f" 来源: {source} | {url}")
|
||||
|
||||
lines.append("\n" + "=" * 50)
|
||||
lines.append("由 RSS News Digest 自动生成")
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def send_email(subject, body):
|
||||
"""Send email via himalaya"""
|
||||
# Construct raw email message with headers
|
||||
message = f"""From: {EMAIL_FROM}
|
||||
To: {EMAIL_TO}
|
||||
Subject: {subject}
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
{body}"""
|
||||
|
||||
cmd = [
|
||||
str(Path.home() / ".local/bin/himalaya"),
|
||||
"message", "send",
|
||||
"-a", "Youlu" # Account name from config.toml
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, input=message)
|
||||
return result.returncode == 0, result.stderr
|
||||
|
||||
def main():
|
||||
# Fetch and get articles
|
||||
articles = run_news_digest()
|
||||
|
||||
if articles is None:
|
||||
# Fetch failed, don't send email
|
||||
sys.exit(1)
|
||||
|
||||
if not articles:
|
||||
# No new articles, send a "no news" email or skip
|
||||
# Let's skip sending email if no articles
|
||||
print("No articles to send")
|
||||
return
|
||||
|
||||
# Format email
|
||||
body = format_email(articles)
|
||||
if not body:
|
||||
print("Failed to format email")
|
||||
sys.exit(1)
|
||||
|
||||
# Send email
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
subject = f"📰 每日新闻摘要 - {today}"
|
||||
|
||||
success, error = send_email(subject, body)
|
||||
if success:
|
||||
print(f"Email sent successfully: {len(articles)} articles")
|
||||
else:
|
||||
print(f"Failed to send email: {error}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user