1+ import requests
2+ from datetime import datetime , timedelta
3+ from zoneinfo import ZoneInfo
4+
5+ class VLRService :
6+ MATCHES_URL = "https://vlr.orlandomm.net/api/v1/matches"
7+ RESULTS_URL = "https://vlr.orlandomm.net/api/v1/results"
8+ WHITELIST = "VCT 2026"
9+ LONDON_TZ = ZoneInfo ("Europe/London" )
10+ TIME_OFFSET_HOURS = 6
11+
12+ @classmethod
13+ def get_vct_dashboard_data (cls ):
14+ """Main entry point: Orchestrates the data flow."""
15+ now = datetime .now (cls .LONDON_TZ )
16+
17+ # 1. Fetch raw data
18+ raw_matches = cls ._fetch_data (cls .MATCHES_URL )
19+ raw_results = cls ._fetch_data (cls .RESULTS_URL , params = {"page" : "1" })
20+
21+ # 2. Process and Filter
22+ # We split these so you can debug 'Matches' and 'Results' independently.
23+ matches = cls ._process_matches (raw_matches , now )
24+ results = cls ._process_results (raw_results , now )
25+
26+ return {
27+ ** results , # Contains y_res and t_res
28+ ** matches , # Contains live, t_up, and tom_up
29+ "last_updated" : now .strftime ("%H:%M" )
30+ }
31+
32+ # --- Private Logic: Processing ---
33+
34+ @classmethod
35+ def _process_matches (cls , raw_data , now ):
36+ """Handles LIVE and UPCOMING match logic."""
37+ buckets = {"live" : [], "t_up" : [], "tom_up" : []}
38+
39+ for item in raw_data :
40+ if not cls ._is_whitelisted (item ): continue
41+
42+ match = cls ._normalize_item (item )
43+ utc_date = item .get ('utc' , '' )
44+ status = item .get ('status' , '' ).upper ()
45+
46+ if cls ._is_date (utc_date , now ): # Today
47+ if status == "LIVE" :
48+ buckets ["live" ].append (match )
49+ else :
50+ buckets ["t_up" ].append (match )
51+ elif cls ._is_date (utc_date , now + timedelta (days = 1 )): # Tomorrow
52+ buckets ["tom_up" ].append (match )
53+
54+ return buckets
55+
56+ @classmethod
57+ def _process_results (cls , raw_data , now ):
58+ """Handles COMPLETED match logic using the 'ago' field."""
59+ buckets = {"y_res" : [], "t_res" : []}
60+
61+ for item in raw_data :
62+ if not cls ._is_whitelisted (item ): continue
63+
64+ match = cls ._normalize_item (item )
65+ ago_str = item .get ('ago' , '' ) # Results use 'ago' instead of 'utc'
66+
67+ if 'd' not in ago_str : # Happened today
68+ buckets ["t_res" ].append (match )
69+ elif '1d' in ago_str : # Happened yesterday
70+ buckets ["y_res" ].append (match )
71+
72+ return buckets
73+
74+ # --- Private Logic: Helpers (The "Readable" Part) ---
75+
76+ @staticmethod
77+ def _fetch_data (url , params = None ):
78+ """Simple wrapper for requests to handle the API wrapper key."""
79+ try :
80+ resp = requests .get (url , params = params , timeout = 10 )
81+ return resp .json ().get ('data' , [])
82+ except Exception :
83+ return []
84+
85+ @staticmethod
86+ def _is_whitelisted (item ):
87+ """Centralized check for your tournament whitelist."""
88+ return VLRService .WHITELIST in item .get ('tournament' , '' )
89+
90+ @staticmethod
91+ def _is_date (utc_string , target_dt ):
92+ """Check if the API's UTC string matches our target date string."""
93+ return target_dt .strftime ('%Y-%m-%d' ) in utc_string
94+
95+ @staticmethod
96+ def _normalize_item (data ):
97+ """Turns messy API objects into clean, display-ready dictionaries."""
98+ ts = data .get ('timestamp' )
99+ time_str = ""
100+
101+ if ts :
102+ corrected_ts = ts + (VLRService .TIME_OFFSET_HOURS * 3600 )
103+ dt_utc = datetime .fromtimestamp (corrected_ts , tz = ZoneInfo ("UTC" ))
104+ dt_london = dt_utc .astimezone (VLRService .LONDON_TZ )
105+ time_str = dt_london .strftime ("%H:%M" )
106+
107+ return {
108+ "t1" : data ['teams' ][0 ]['name' ],
109+ "s1" : data ['teams' ][0 ].get ('score' ),
110+ "t2" : data ['teams' ][1 ]['name' ],
111+ "s2" : data ['teams' ][1 ].get ('score' ),
112+ "tournament" : data .get ('tournament' ),
113+ "event" : data .get ('event' ),
114+ "status" : data .get ('status' ),
115+ "time" : time_str
116+ }
0 commit comments