chore: tg_filter emoji fix, sprint spec update, tg_digest script
This commit is contained in:
@@ -40,7 +40,7 @@ THRESHOLD = 40
|
|||||||
|
|
||||||
# Scan config
|
# Scan config
|
||||||
MSGS_PER_GROUP = 500
|
MSGS_PER_GROUP = 500
|
||||||
GROUPS_PER_CYCLE = 56
|
GROUPS_PER_CYCLE = 0 # 0 = scan all eligible groups (was 56)
|
||||||
|
|
||||||
# Keywords
|
# Keywords
|
||||||
INTERESTING_KEYWORDS = [
|
INTERESTING_KEYWORDS = [
|
||||||
@@ -146,7 +146,7 @@ async def scan_and_report(dry_run: bool = False) -> list:
|
|||||||
else:
|
else:
|
||||||
sorted_candidates.append((cid, title, ""))
|
sorted_candidates.append((cid, title, ""))
|
||||||
sorted_candidates.sort(key=lambda x: (x[2] == "", x[2]))
|
sorted_candidates.sort(key=lambda x: (x[2] == "", x[2]))
|
||||||
sorted_candidates = sorted_candidates[:GROUPS_PER_CYCLE]
|
sorted_candidates = sorted_candidates[:len(candidates)] if GROUPS_PER_CYCLE == 0 else sorted_candidates[:GROUPS_PER_CYCLE]
|
||||||
|
|
||||||
log.info(f"Scanning {len(sorted_candidates)} groups this cycle")
|
log.info(f"Scanning {len(sorted_candidates)} groups this cycle")
|
||||||
|
|
||||||
@@ -169,7 +169,11 @@ async def scan_and_report(dry_run: bool = False) -> list:
|
|||||||
sender = None
|
sender = None
|
||||||
if msg.from_user:
|
if msg.from_user:
|
||||||
sender = msg.from_user.first_name or msg.from_user.username or str(msg.from_user.id)
|
sender = msg.from_user.first_name or msg.from_user.username or str(msg.from_user.id)
|
||||||
|
try:
|
||||||
text = (msg.text or msg.caption or "")[:2000]
|
text = (msg.text or msg.caption or "")[:2000]
|
||||||
|
except (UnicodeDecodeError, UnicodeEncodeError):
|
||||||
|
# surrogate-pass decode failure on certain emoji sequences
|
||||||
|
text = (str(msg.caption or "")[:2000]) if msg.caption else "[text unreadable]"
|
||||||
item = {
|
item = {
|
||||||
"chat_id": chat_id, "chat_title": chat_title, "message_id": msg.id,
|
"chat_id": chat_id, "chat_title": chat_title, "message_id": msg.id,
|
||||||
"sender": sender, "text": text, "score": score,
|
"sender": sender, "text": text, "score": score,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
sprint-003-agent-digest.md
|
sprint-003.5-agent-frontend.md
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
t-youtube Telegram Digest Cron
|
||||||
|
Sprint 003 AC T3.2 — Daily summary of today's videos by channel
|
||||||
|
Run daily at 09:00 UTC+8 via Hermes cron
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
|
# --- Config ---
|
||||||
|
BASE_URL = os.environ.get("TY_API_URL", "http://127.0.0.1:8080")
|
||||||
|
TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
|
||||||
|
TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "")
|
||||||
|
|
||||||
|
# --- Fetch today's videos ---
|
||||||
|
|
||||||
|
def fetch_videos():
|
||||||
|
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
||||||
|
url = f"{BASE_URL}/api/videos?since={today}"
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(url)
|
||||||
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||||
|
data = json.loads(resp.read().decode())
|
||||||
|
return data.get("videos", data.get("items", []))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[tg_digest] ERROR fetching videos: {e}", file=sys.stderr)
|
||||||
|
return []
|
||||||
|
|
||||||
|
# --- Build digest ---
|
||||||
|
|
||||||
|
def build_digest(videos):
|
||||||
|
if not videos:
|
||||||
|
return "📭 No new videos today."
|
||||||
|
|
||||||
|
# Group by channel
|
||||||
|
channels = {}
|
||||||
|
for v in videos:
|
||||||
|
ch = v.get("channel", v.get("channel_name", "Unknown"))
|
||||||
|
channels.setdefault(ch, []).append(v)
|
||||||
|
|
||||||
|
lines = ["📺 **YouTube Digest — Today's Videos**", "", f"_{datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}_", ""]
|
||||||
|
|
||||||
|
for ch, items in sorted(channels.items()):
|
||||||
|
lines.append(f"### {ch}")
|
||||||
|
lines.append(f"_{len(items)} video(s)_")
|
||||||
|
lines.append("")
|
||||||
|
for v in items:
|
||||||
|
title = v.get("title", "Untitled")
|
||||||
|
url = v.get("url", v.get("watch_url", ""))
|
||||||
|
duration = v.get("duration", "?")
|
||||||
|
lines.append(f"- **{title}** ({duration})")
|
||||||
|
if url:
|
||||||
|
lines.append(f" {url}")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
lines.append("---")
|
||||||
|
lines.append(f"Total: {len(videos)} videos from {len(channels)} channels")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
# --- Send to Telegram ---
|
||||||
|
|
||||||
|
def send_telegram(text):
|
||||||
|
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
|
||||||
|
print("[tg_digest] WARNING: TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID not set — skipping send")
|
||||||
|
print("[tg_digest] Digest would be:\n")
|
||||||
|
print(text)
|
||||||
|
return False
|
||||||
|
|
||||||
|
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
||||||
|
body = json.dumps({
|
||||||
|
"chat_id": TELEGRAM_CHAT_ID,
|
||||||
|
"text": text,
|
||||||
|
"parse_mode": "Markdown",
|
||||||
|
"disable_web_page_preview": False,
|
||||||
|
}).encode()
|
||||||
|
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json"})
|
||||||
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||||
|
result = json.loads(resp.read().decode())
|
||||||
|
if result.get("ok"):
|
||||||
|
print(f"[tg_digest] Sent digest to Telegram chat {TELEGRAM_CHAT_ID}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"[tg_digest] Telegram API error: {result}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[tg_digest] ERROR sending Telegram: {e}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# --- Main ---
|
||||||
|
|
||||||
|
def main():
|
||||||
|
videos = fetch_videos()
|
||||||
|
digest = build_digest(videos)
|
||||||
|
print(digest)
|
||||||
|
print("")
|
||||||
|
send_telegram(digest)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user