diff --git a/daily_top.py b/daily_top.py index c6f9103..a693336 100644 --- a/daily_top.py +++ b/daily_top.py @@ -7,6 +7,9 @@ import sys import urllib.request import urllib.error from datetime import datetime, timezone +from zoneinfo import ZoneInfo + +_TZ_PRAGUE = ZoneInfo("Europe/Prague") def load_env(path=".env"): env = {} @@ -83,7 +86,11 @@ def main(): tag_counts = {} candidates = [] media_count = {"image": 0, "video": 0, "gifv": 0, "audio": 0, "total": 0} + hourly_count = {str(h): 0 for h in range(24)} for toot in timeline: + created_at = datetime.fromisoformat(toot["created_at"].replace("Z", "+00:00")) + local_hour = str(created_at.astimezone(_TZ_PRAGUE).hour) + hourly_count[local_hour] += 1 for att in toot.get("media_attachments", []): att_type = att.get("type", "") media_count["total"] += 1 @@ -158,6 +165,7 @@ def main(): "tags": tags, "top_links": top_links, "media_count": media_count, + "hourly_count": hourly_count, }, 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 1819657..98718e2 100644 --- a/weekly_report.py +++ b/weekly_report.py @@ -128,7 +128,7 @@ def format_month_cs(dt): def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, instance_info, total_count=0, top_author=None, newest_account=None, top_links=None, - media_count=None): + media_count=None, hourly_count=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) @@ -180,6 +180,12 @@ def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, inst else: media_line = "" + if hourly_count and any(hourly_count.values()): + peak_h = max(hourly_count, key=lambda h: hourly_count[h]) + peak_line = f"⏰ Nejaktivnější čas: {int(peak_h):02d}:00–{(int(peak_h) + 1) % 24:02d}:00 ({hourly_count[peak_h]} tootů)\n" + else: + peak_line = "" + return ( f"🐘 Měsíční přehled Mamutovo.cz\n" f"📅 {format_month_cs(date_to)}\n" @@ -189,6 +195,7 @@ def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, inst f"📝 Interakce: {interactions}{fmt_diff(interactions, 'interactions')}\n" f"📝 Tooty měsíce: {total_count}\n" f"{media_line}" + f"{peak_line}" f"\n" f"📊 Celkem uživatelů: {user_count}\n" f"🌐 Federovaných instancí: {domain_count}\n" @@ -203,7 +210,7 @@ def build_monthly_toot(measures_data, tags, top_tooty, date_to, prev_stats, inst 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, top_links=None, - prev_stats=None, media_count=None): + prev_stats=None, media_count=None, hourly_count=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) @@ -249,6 +256,12 @@ def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, else: media_line = "" + if hourly_count and any(hourly_count.values()): + peak_h = max(hourly_count, key=lambda h: hourly_count[h]) + peak_line = f"⏰ Nejaktivnější čas: {int(peak_h):02d}:00–{(int(peak_h) + 1) % 24:02d}:00 ({hourly_count[peak_h]} tootů)\n" + else: + peak_line = "" + date_from_str = format_date_cs(date_from) date_to_str = format_date_cs(date_to) year = date_to.year @@ -262,6 +275,7 @@ def build_toot(measures_data, tags, top_tooty, date_from, date_to, week_number, f"📝 Interakce: {interactions}{fmt_diff(interactions, 'interactions')}\n" f"📝 Tooty týdne: {total_count}\n" f"{media_line}" + f"{peak_line}" f"\n" f"🔥 Populární hashtagy:\n" f"{hashtags}\n" @@ -376,6 +390,21 @@ def load_media_count_from_data(date_to, days): pass return totals +def load_hourly_count_from_data(date_to, days): + totals = {str(h): 0 for h in range(24)} + 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) + hc = file_data.get("hourly_count", {}) + for h in totals: + totals[h] += hc.get(h, 0) + except FileNotFoundError: + pass + return totals + def load_newest_account_from_data(date_to, days): for i in range(days): day = (date_to - timedelta(days=i)).strftime("%Y-%m-%d") @@ -447,9 +476,10 @@ def main(): newest_account = load_newest_account_from_data(date_to, 30) top_links = load_top_links_from_data(date_to, 30) media_count = load_media_count_from_data(date_to, 30) + hourly_count = load_hourly_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, newest_account, top_links, media_count, + total_count, top_author, newest_account, top_links, media_count, hourly_count, ) if args.dry_run: @@ -514,9 +544,11 @@ def main(): newest_account = load_newest_account_from_data(date_to, 7) top_links = load_top_links_from_data(date_to, 7) media_count = load_media_count_from_data(date_to, 7) + hourly_count = load_hourly_count_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, top_links, prev_stats, media_count, + hourly_count, ) if args.dry_run: