diff --git a/daily_top.py b/daily_top.py index 84947f4..92ebf79 100644 --- a/daily_top.py +++ b/daily_top.py @@ -66,12 +66,13 @@ def fetch_daily_timeline(base_url, token): def main(): env = {**load_env(), **os.environ} - for var in ("NOVINKY_TOKEN", "INSTANCE_URL"): + for var in ("NOVINKY_TOKEN", "INSTANCE_URL", "STATS_TOKEN"): if not env.get(var): print(f"Chybí proměnná prostředí: {var}", file=sys.stderr) sys.exit(1) token = env["NOVINKY_TOKEN"] + stats_token = env["STATS_TOKEN"] base_url = env["INSTANCE_URL"].rstrip("/") try: @@ -107,12 +108,36 @@ def main(): top = candidates[:3] tags = [t for t, _ in sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)[:5]] + authors_count = {} + for c in candidates: + authors_count[c["acct"]] = authors_count.get(c["acct"], 0) + 1 + + newest_account = None + try: + accounts = api_get( + f"{base_url}/api/v1/admin/accounts?order=newest&limit=1", stats_token + ) + if accounts and accounts[0].get("account", {}).get("discoverable"): + newest_account = { + "acct": accounts[0]["account"]["acct"], + "created_at": accounts[0]["created_at"], + } + except Exception: + pass + today = datetime.now(timezone.utc).strftime("%Y-%m-%d") os.makedirs("data", exist_ok=True) out_path = os.path.join("data", f"{today}.json") with open(out_path, "w", encoding="utf-8") as f: - json.dump({"date": today, "total_count": len(timeline), "top": top, "tags": tags}, f, ensure_ascii=False, indent=2) + json.dump({ + "date": today, + "total_count": len(timeline), + "authors_count": authors_count, + "newest_account": newest_account, + "top": top, + "tags": tags, + }, f, ensure_ascii=False, indent=2) print(f"Uloženo: {out_path} ({len(timeline)} tootů načteno, {len(top)} top, {len(tags)} hashtagů)") diff --git a/weekly_report.py b/weekly_report.py index 772f194..ed713db 100644 --- a/weekly_report.py +++ b/weekly_report.py @@ -126,7 +126,8 @@ def format_month_cs(dt): ] return f"{months[dt.month - 1]} {dt.year}" -def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, instance_info, total_count=0): +def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, instance_info, + total_count=0, top_author=None, newest_account=None): stats = {m["key"]: int(m["total"]) for m in measures_data} new_users = stats.get("new_users", 0) active_users = stats.get("active_users", 0) @@ -142,9 +143,18 @@ def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, inst hashtags = " ".join(f"#{t['name']}" for t in tags[:5]) if tags else "(žádné)" inst_stats = instance_info.get("stats", {}) if instance_info else {} - user_count = inst_stats.get("user_count", "?") + user_count_val = inst_stats.get("user_count", 0) + user_count = user_count_val if user_count_val else "?" domain_count = inst_stats.get("domain_count", "?") + author_line = f"✍️ Top přispěvatel: @{top_author['acct']} ({top_author['count']} tootů)\n" if top_author else "" + newest_line = f"👋 Nový účet: @{newest_account['acct']}\n" if newest_account else "" + milestone_line = ( + f"🎉 Milník: Mamutovo dosáhlo {user_count_val} uživatelů!\n" + if user_count_val and user_count_val % 10 == 0 else "" + ) + extra = author_line + newest_line + milestone_line + if top_tooty: blocks = "\n\n".join( f"🐘 @{s['acct']}\n\"{truncate(s['text'], 80).replace(chr(10), ' ')}\"\n🔁 {s['reblogs']} ⭐ {s['favourites']}\n🔗 {s.get('url', '')}" @@ -167,11 +177,14 @@ def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, inst f"🌐 Federovaných instancí: {domain_count}\n" f"\n" f"🔥 Top hashtagy měsíce:\n" - f"{hashtags}" + f"{hashtags}\n" + f"\n" + f"{extra}" f"{tooty_sekce}" ) -def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, total_count=0): +def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, + total_count=0, top_author=None, newest_account=None, user_count=0): stats = {m["key"]: int(m["total"]) for m in measures_data} new_users = stats.get("new_users", 0) active_users = stats.get("active_users", 0) @@ -190,6 +203,11 @@ def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, else: toot_tyden = "" + author_line = f"✍️ Top přispěvatel: @{top_author['acct']} ({top_author['count']} tootů)\n" if top_author else "" + newest_line = f"👋 Nový účet: @{newest_account['acct']}\n" if newest_account else "" + milestone_line = f"🎉 Milník: Mamutovo dosáhlo {user_count} uživatelů!\n" if user_count and user_count % 10 == 0 else "" + extra = author_line + newest_line + milestone_line + date_from_str = format_date_cs(date_from) date_to_str = format_date_cs(date_to) year = date_to.year @@ -207,6 +225,7 @@ def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, f"{hashtags}\n" f"\n" f"{toot_tyden}" + f"{extra}" f"💡 Tip týdne: {tip}" ) @@ -262,6 +281,37 @@ def load_total_count_from_data(date_to, days): pass return total +def load_top_author_from_data(date_to, days): + counts = Counter() + for i in range(days): + day = (date_to - timedelta(days=i)).strftime("%Y-%m-%d") + path = os.path.join("data", f"{day}.json") + try: + with open(path, encoding="utf-8") as f: + file_data = json.load(f) + for acct, n in file_data.get("authors_count", {}).items(): + counts[acct] += n + except FileNotFoundError: + pass + if not counts: + return None + acct, n = counts.most_common(1)[0] + return {"acct": acct, "count": n} + +def load_newest_account_from_data(date_to, days): + for i in range(days): + day = (date_to - timedelta(days=i)).strftime("%Y-%m-%d") + path = os.path.join("data", f"{day}.json") + try: + with open(path, encoding="utf-8") as f: + file_data = json.load(f) + acc = file_data.get("newest_account") + if acc: + return acc + except FileNotFoundError: + pass + return None + def main(): parser = argparse.ArgumentParser(description="Statistiky Mamutovo.cz") parser.add_argument("--dry-run", action="store_true", help="Pouze vypíše toot, neodešle") @@ -315,7 +365,12 @@ def main(): top_tooty = load_tooty_from_data(date_to, 30) total_count = load_total_count_from_data(date_to, 30) - toot = build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, instance_info, total_count) + top_author = load_top_author_from_data(date_to, 30) + newest_account = load_newest_account_from_data(date_to, 30) + toot = build_monthly_toot( + measures_data, tags, top_tooty, date_to, prev_stats, instance_info, + total_count, top_author, newest_account, + ) if args.dry_run: print(toot) @@ -359,9 +414,20 @@ def main(): except Exception: tags = [] + try: + instance_info = api_get(f"{base_url}/api/v1/instance") + except Exception: + instance_info = {} + user_count = instance_info.get("stats", {}).get("user_count", 0) + top_tooty = load_tooty_from_data(date_to, 7) total_count = load_total_count_from_data(date_to, 7) - toot = build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, total_count) + top_author = load_top_author_from_data(date_to, 7) + newest_account = load_newest_account_from_data(date_to, 7) + toot = build_toot( + measures_data, tags, top_tooty, date_from, date_to, week_number, + total_count, top_author, newest_account, user_count, + ) if args.dry_run: print(toot)