diff --git a/scripts/news_digest/send_digest.py b/scripts/news_digest/send_digest.py new file mode 100755 index 0000000..b2dc9e6 --- /dev/null +++ b/scripts/news_digest/send_digest.py @@ -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()