File size: 6,789 Bytes
3e718bc
b118820
 
3e718bc
b118820
79878e8
b118820
3e718bc
 
b118820
 
3e718bc
b118820
3e718bc
b118820
 
3e718bc
 
b118820
 
3e718bc
b118820
 
 
3e718bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b118820
79878e8
e59ec96
79878e8
 
 
 
 
e59ec96
3e718bc
 
 
e59ec96
3e718bc
 
 
e59ec96
b118820
 
 
3e718bc
b118820
3e718bc
 
 
 
b118820
3e718bc
b118820
 
 
 
 
3e718bc
b118820
3e718bc
 
 
 
 
 
 
 
e59ec96
3e718bc
 
 
e59ec96
3e718bc
 
b118820
 
3e718bc
b118820
 
3e718bc
b118820
3e718bc
 
 
 
 
 
e59ec96
3e718bc
 
 
e59ec96
3e718bc
 
b118820
 
3e718bc
 
 
 
 
 
 
 
 
b118820
 
3e718bc
 
 
c7f8740
e59ec96
c7f8740
e59ec96
3e718bc
 
c7f8740
3e718bc
 
 
 
 
e59ec96
c7f8740
3e718bc
 
 
 
 
 
 
 
b118820
 
 
3e718bc
79878e8
e59ec96
79878e8
e59ec96
3e718bc
 
79878e8
3e718bc
 
 
 
 
e59ec96
79878e8
3e718bc
 
 
 
 
 
 
b118820
 
e59ec96
b118820
 
3e718bc
b118820
e59ec96
b118820
 
3e718bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
"""NBA Buzz - FastAPI Backend"""

from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import HTMLResponse
import threading
import time
from datetime import datetime, timezone

from bluesky_fetcher import BlueskyFetcher, load_handles_from_csv
import player_matcher
import database
from nba_teams import get_player_team, get_team_abbreviation, get_team_players, get_all_teams, PLAYER_TEAMS

app = FastAPI(title="NBA Buzz API")

is_fetching = False
fetch_status = "Ready"


def do_fetch():
    global is_fetching, fetch_status
    if is_fetching:
        return
    
    is_fetching = True
    try:
        handles = load_handles_from_csv("bluesky_handles.csv")
        if handles:
            fetch_status = f"Fetching {len(handles)} accounts..."
            bsky = BlueskyFetcher()
            posts = bsky.fetch_multiple_accounts(handles, posts_per_account=25, delay=0.15)
            print(f"Fetched {len(posts)} posts")
            added, mentions = database.process_and_store_posts(posts, player_matcher, get_player_team)
            print(f"Stored {added} posts, {mentions} mentions")
        
        database.set_last_update()
        database.cleanup_old_data(days=3)
        fetch_status = f"Updated {datetime.now(timezone.utc).strftime('%H:%M UTC')}"
    except Exception as e:
        fetch_status = f"Error: {str(e)[:50]}"
        print(f"Fetch error: {e}")
    finally:
        is_fetching = False


def auto_refresh_loop():
    """Background thread that refreshes data every 15 minutes."""
    while True:
        time.sleep(900)  # 15 minutes
        print("Auto-refresh triggered")
        do_fetch()


# Auto-fetch on startup
thread = threading.Thread(target=do_fetch, daemon=True)
thread.start()

# Start auto-refresh loop
refresh_thread = threading.Thread(target=auto_refresh_loop, daemon=True)
refresh_thread.start()


@app.get("/api/status")
def get_status():
    stats = database.get_database_stats()
    return {
        "total_posts": stats['total_posts'],
        "total_mentions": stats['total_mentions'],
        "unique_players": stats['unique_players'],
        "last_update": database.get_last_update(),
        "is_fetching": is_fetching,
        "fetch_status": fetch_status
    }


@app.get("/api/players")
def get_players(hours: int = 24, limit: int = 50):
    counts = database.get_player_mention_counts(hours=hours, limit=limit)
    result = []
    for i, item in enumerate(counts, 1):
        team = item.get("team_name") or ""
        entry = {
            "rank": i,
            "player": item["player_name"],
            "team": team,
            "team_abbrev": get_team_abbreviation(team),
            "mentions": item["mention_count"]
        }
        # Add latest mention for top 5
        if i <= 5:
            latest = database.get_latest_mention_for_player(item["player_name"], hours=hours)
            if latest:
                entry["latest_mention"] = latest
        result.append(entry)
    return result


@app.get("/api/teams")
def get_teams(hours: int = 24, limit: int = 30):
    counts = database.get_team_mention_counts(hours=hours, limit=limit)
    result = []
    for i, item in enumerate(counts, 1):
        entry = {
            "rank": i,
            "team": item["team_name"],
            "team_abbrev": get_team_abbreviation(item["team_name"]),
            "mentions": item["mention_count"]
        }
        # Add latest mention for top 5
        if i <= 5:
            latest = database.get_latest_mention_for_team(item["team_name"], hours=hours)
            if latest:
                entry["latest_mention"] = latest
        result.append(entry)
    return result


@app.get("/api/search")
def search(q: str):
    q_lower = q.lower()
    players = [p for p in PLAYER_TEAMS.keys() if q_lower in p.lower()][:10]
    teams = [t for t in get_all_teams() if q_lower in t.lower()][:5]
    return {"players": players, "teams": teams}


@app.get("/api/player/{player_name}")
def get_player_info(player_name: str):
    team = get_player_team(player_name)
    teammates = get_team_players(team)[:10] if team else []
    teammates = [t for t in teammates if t != player_name][:5]
    
    # Get period stats
    period_stats = []
    for hours, label in [(6, "6h"), (12, "12h"), (24, "24h"), (48, "48h"), (168, "7d")]:
        counts = database.get_player_mention_counts(hours=hours, limit=100)
        mentions = 0
        rank = None
        for i, item in enumerate(counts, 1):
            if item["player_name"] == player_name:
                mentions = item["mention_count"]
                rank = i
                break
        period_stats.append({"hours": hours, "label": label, "mentions": mentions, "rank": rank})
    
    return {
        "player": player_name, 
        "team": team, 
        "team_abbrev": get_team_abbreviation(team), 
        "teammates": teammates,
        "period_stats": period_stats
    }


@app.get("/api/team/{team_name}")
def get_team_info(team_name: str):
    players = get_team_players(team_name)[:15]
    
    # Get period stats
    period_stats = []
    for hours, label in [(6, "6h"), (12, "12h"), (24, "24h"), (48, "48h"), (168, "7d")]:
        counts = database.get_team_mention_counts(hours=hours, limit=30)
        mentions = 0
        rank = None
        for i, item in enumerate(counts, 1):
            if item["team_name"] == team_name:
                mentions = item["mention_count"]
                rank = i
                break
        period_stats.append({"hours": hours, "label": label, "mentions": mentions, "rank": rank})
    
    return {
        "team": team_name, 
        "team_abbrev": get_team_abbreviation(team_name), 
        "players": players,
        "period_stats": period_stats
    }


@app.get("/api/mentions/{player_name}")
def get_player_mentions(player_name: str, limit: int = 50):
    return database.get_player_recent_mentions(player_name, limit=limit)


@app.get("/api/team-mentions/{team_name}")
def get_team_mentions(team_name: str, limit: int = 50):
    return database.get_team_recent_mentions(team_name, limit=limit)


@app.post("/api/refresh")
def trigger_refresh(background_tasks: BackgroundTasks):
    if is_fetching:
        return {"status": "already_fetching"}
    background_tasks.add_task(do_fetch)
    return {"status": "started"}


@app.get("/", response_class=HTMLResponse)
def serve_index():
    return open("index.html", "r").read()


@app.get("/player/{player_name}", response_class=HTMLResponse)
def serve_player_page(player_name: str):
    return open("player.html", "r").read()


@app.get("/team/{team_name}", response_class=HTMLResponse)
def serve_team_page(team_name: str):
    return open("team.html", "r").read()


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7860)