187 lines
4.9 KiB
Bash
Executable File
187 lines
4.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Smart Newsletter Digest with Feedback Learning
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
IMAP_SKILL="/home/openclaw/.openclaw/workspace/skills/imap-smtp-email"
|
|
|
|
source "$SCRIPT_DIR/../../.env" 2>/dev/null || true
|
|
source "$IMAP_SKILL/.env" 2>/dev/null || true
|
|
|
|
TELEGRAM_CHAT="${TELEGRAM_CHAT:-1793951355}"
|
|
NTFY_URL="${NTFY_URL:-}"
|
|
NTFY_TOPIC="${NTFY_TOPIC:-}"
|
|
NTFY_MIN_PRIORITY="${NTFY_MIN_PRIORITY:-4}"
|
|
PREFERENCES_FILE="$SCRIPT_DIR/newsletter-preferences.json"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
|
}
|
|
|
|
init_preferences() {
|
|
if [[ ! -f "$PREFERENCES_FILE" ]]; then
|
|
cat > "$PREFERENCES_FILE" << 'EOF'
|
|
{
|
|
"liked_topics": ["AI", "machine learning", "productivity", "automation"],
|
|
"disliked_topics": [],
|
|
"preferred_sources": [],
|
|
"avoided_sources": [],
|
|
"feedback_count": 0
|
|
}
|
|
EOF
|
|
fi
|
|
}
|
|
|
|
fetch_and_build_digest() {
|
|
cd "$IMAP_SKILL"
|
|
|
|
python3 << 'PYEOF'
|
|
import subprocess
|
|
import re
|
|
import json
|
|
from datetime import datetime
|
|
|
|
# Fetch emails
|
|
result = subprocess.run(
|
|
['python3', 'scripts/imap-py.py', 'check', '--limit', '50', '--recent', '24h'],
|
|
capture_output=True, text=True
|
|
)
|
|
|
|
output = result.stdout
|
|
|
|
# Parse emails
|
|
newsletters = []
|
|
current = {}
|
|
|
|
patterns = ['aivalley', 'deepview', 'rundown', 'tldr', 'benedict',
|
|
'newsletter', 'digest', 'daily', 'weekly', 'briefing']
|
|
|
|
for line in output.split('\n'):
|
|
line = line.strip()
|
|
|
|
if line.startswith('● UID:'):
|
|
if current.get('uid'):
|
|
newsletters.append(current)
|
|
current = {'uid': line.split(':')[1].strip()}
|
|
elif line.startswith('From:'):
|
|
current['from'] = line.replace('From:', '').strip()
|
|
elif line.startswith('Subject:'):
|
|
current['subject'] = line.replace('Subject:', '').strip()
|
|
elif line.startswith('Date:'):
|
|
current['date'] = line.replace('Date:', '').strip()
|
|
|
|
if current.get('uid'):
|
|
newsletters.append(current)
|
|
|
|
# Filter for newsletters
|
|
filtered = []
|
|
for email in newsletters:
|
|
sender = email.get('from', '').lower()
|
|
subject = email.get('subject', '').lower()
|
|
|
|
for p in patterns:
|
|
if p in sender or p in subject:
|
|
filtered.append(email)
|
|
break
|
|
|
|
# Load preferences
|
|
try:
|
|
with open('/home/openclaw/.openclaw/workspace/automations/newsletter-digest/newsletter-preferences.json') as f:
|
|
prefs = json.load(f)
|
|
except:
|
|
prefs = {'liked_topics': [], 'disliked_topics': [], 'preferred_sources': []}
|
|
|
|
# Score
|
|
for nl in filtered:
|
|
score = 0
|
|
subject = nl.get('subject', '').lower()
|
|
sender = nl.get('from', '').lower()
|
|
|
|
for topic in prefs.get('liked_topics', []):
|
|
if topic.lower() in subject:
|
|
score += 2
|
|
for topic in prefs.get('disliked_topics', []):
|
|
if topic.lower() in subject:
|
|
score -= 2
|
|
for src in prefs.get('preferred_sources', []):
|
|
if src.lower() in sender:
|
|
score += 3
|
|
|
|
nl['score'] = score
|
|
|
|
filtered.sort(key=lambda x: x.get('score', 0), reverse=True)
|
|
|
|
# Build message
|
|
lines = []
|
|
lines.append("📬 *Newsletter Digest*")
|
|
lines.append(f"_({datetime.now().strftime('%B %d, %Y')})_")
|
|
lines.append("")
|
|
lines.append(f"Found *{len(filtered)}* newsletters in past 24h")
|
|
lines.append("")
|
|
|
|
for nl in filtered[:8]:
|
|
score = nl.get('score', 0)
|
|
emoji = "🔥" if score >= 3 else "📌" if score > 0 else "📄"
|
|
subject = nl.get('subject', 'No subject')[:70]
|
|
sender = nl.get('from', 'Unknown')[:35]
|
|
|
|
lines.append(f"{emoji} *{subject}*")
|
|
lines.append(f" _{sender}_")
|
|
lines.append("")
|
|
|
|
if not filtered:
|
|
lines.append("No newsletters found! 📭")
|
|
|
|
lines.append("━━━━━━━━━━━━━━━━")
|
|
lines.append("💭 Reply: 👍/👎 or `more X`/`less X`")
|
|
|
|
print('\n'.join(lines))
|
|
PYEOF
|
|
}
|
|
|
|
send_telegram() {
|
|
local message="$1"
|
|
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"chat_id\": \"$TELEGRAM_CHAT\", \"text\": \"$message\", \"parse_mode\": \"Markdown\", \"disable_web_page_preview\": true}" > /dev/null
|
|
}
|
|
|
|
send_ntfy() {
|
|
local title="$1"
|
|
local msg="$2"
|
|
local priority="${3:-4}"
|
|
local sound="${4:-default}"
|
|
|
|
[[ -z "$NTFY_URL" ]] && return 0
|
|
[[ -z "$NTFY_TOPIC" ]] && return 0
|
|
|
|
# Enforce minimum priority (default 4)
|
|
if [[ "$priority" =~ ^[0-9]+$ ]] && [[ "$NTFY_MIN_PRIORITY" =~ ^[0-9]+$ ]]; then
|
|
if (( priority < NTFY_MIN_PRIORITY )); then
|
|
priority="$NTFY_MIN_PRIORITY"
|
|
fi
|
|
fi
|
|
|
|
curl -s -X POST "${NTFY_URL}/$NTFY_TOPIC" \
|
|
-H "Title: $title" \
|
|
-H "Priority: $priority" \
|
|
-H "Sound: $sound" \
|
|
-d "$msg" > /dev/null 2>&1 || true
|
|
}
|
|
|
|
main() {
|
|
log "Starting newsletter digest..."
|
|
init_preferences
|
|
|
|
local digest
|
|
digest=$(fetch_and_build_digest)
|
|
|
|
send_telegram "$digest"
|
|
send_ntfy "🦀 Newsletter digest" "Digest sent to Telegram" 4 default
|
|
|
|
log "Done!"
|
|
}
|
|
|
|
main "$@"
|