Compare commits
2 Commits
7784eaf9ce
...
108b77ed39
| Author | SHA1 | Date | |
|---|---|---|---|
| 108b77ed39 | |||
| 61202b2a70 |
+9
-2
@@ -76,6 +76,7 @@ def parse_games(scoreboard_data):
|
||||
"total": total_priority,
|
||||
},
|
||||
"Start Time": get_start_time(game),
|
||||
"Start Time UTC": game.get("startTimeUTC", ""),
|
||||
"Home Record": format_record(game["homeTeam"]["record"])
|
||||
if game["gameState"] in ["PRE", "FUT"]
|
||||
else "N/A",
|
||||
@@ -98,8 +99,14 @@ def parse_games(scoreboard_data):
|
||||
}
|
||||
)
|
||||
|
||||
# Sort games based on priority
|
||||
return sorted(extracted_info, key=lambda x: x["Priority"], reverse=True)
|
||||
def _sort_key(g):
|
||||
if g["Game State"] == "PRE":
|
||||
# Earliest start first — ISO-8601 sorts correctly as a string
|
||||
return (0, g["Start Time UTC"], 0)
|
||||
# LIVE / FINAL — highest priority first
|
||||
return (1, "", -g["Priority"])
|
||||
|
||||
return sorted(extracted_info, key=_sort_key)
|
||||
|
||||
|
||||
def get_comeback_bonus(game):
|
||||
|
||||
@@ -69,12 +69,12 @@ function renderLiveGame(game) {
|
||||
<div class="badges">
|
||||
${periodLabel}
|
||||
<span class="badge" ${clockAttrs}>${time}</span>
|
||||
${ppBadge(game)}
|
||||
</div>
|
||||
${dot}
|
||||
</div>
|
||||
${teamRow(game, 'Away', 'live')}
|
||||
${teamRow(game, 'Home', 'live')}
|
||||
${ppIndicator(game)}
|
||||
${hype}
|
||||
</div>`;
|
||||
}
|
||||
@@ -134,7 +134,7 @@ function teamRow(game, side, state) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function ppIndicator(game) {
|
||||
function ppBadge(game) {
|
||||
const awayPP = game['Away Power Play'];
|
||||
const homePP = game['Home Power Play'];
|
||||
const pp = awayPP || homePP;
|
||||
@@ -145,12 +145,7 @@ function ppIndicator(game) {
|
||||
const seconds = timeToSeconds(timeStr);
|
||||
const attrs = `data-seconds="${seconds}" data-received-at="${Date.now()}" data-pp-clock`;
|
||||
|
||||
return `
|
||||
<div class="pp-indicator">
|
||||
<span class="pp-label">PP</span>
|
||||
<span class="pp-team">${team}</span>
|
||||
<span class="pp-clock" ${attrs}>${timeStr}</span>
|
||||
</div>`;
|
||||
return `<span class="badge badge-pp">PP ${team} <span ${attrs}>${timeStr}</span></span>`;
|
||||
}
|
||||
|
||||
// ── Gauge ────────────────────────────────────────────
|
||||
|
||||
+4
-36
@@ -212,44 +212,12 @@ main {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ── Power Play Indicator ───────────────────────── */
|
||||
/* ── Power Play Badge (inline in card header) ─── */
|
||||
|
||||
.pp-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.pp-label {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
.badge-pp {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
color: var(--red);
|
||||
text-transform: uppercase;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pp-team {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.pp-clock {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: var(--red);
|
||||
flex-shrink: 0;
|
||||
border: 1px solid rgba(239, 68, 68, 0.35);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,124 @@ class TestParseGames:
|
||||
def test_returns_empty_list_for_empty_dict(self):
|
||||
assert parse_games({}) == []
|
||||
|
||||
def test_pre_games_sorted_by_start_time_ascending(self, mocker):
|
||||
mocker.patch(
|
||||
"app.games.get_team_standings",
|
||||
return_value={
|
||||
"league_sequence": 16,
|
||||
"league_l10_sequence": 16,
|
||||
"division_abbrev": "ATL",
|
||||
"conference_abbrev": "E",
|
||||
"games_played": 40,
|
||||
"wildcard_sequence": 16,
|
||||
},
|
||||
)
|
||||
late = make_game(
|
||||
game_state="FUT",
|
||||
home_name="Rangers",
|
||||
away_name="Devils",
|
||||
start_time_utc="2024-04-10T22:00:00Z",
|
||||
)
|
||||
early = make_game(
|
||||
game_state="FUT",
|
||||
home_name="Bruins",
|
||||
away_name="Canadiens",
|
||||
start_time_utc="2024-04-10T19:00:00Z",
|
||||
)
|
||||
next_day = make_game(
|
||||
game_state="FUT",
|
||||
home_name="Kings",
|
||||
away_name="Ducks",
|
||||
start_time_utc="2024-04-11T00:30:00Z",
|
||||
)
|
||||
|
||||
result = parse_games({"games": [late, next_day, early]})
|
||||
pre_games = [g for g in result if g["Game State"] == "PRE"]
|
||||
names = [g["Home Team"] for g in pre_games]
|
||||
assert names == ["Bruins", "Rangers", "Kings"]
|
||||
|
||||
def test_live_games_still_sorted_by_priority_descending(self, mocker):
|
||||
mocker.patch(
|
||||
"app.games.get_team_standings",
|
||||
return_value={
|
||||
"league_sequence": 16,
|
||||
"league_l10_sequence": 16,
|
||||
"division_abbrev": "ATL",
|
||||
"conference_abbrev": "E",
|
||||
"games_played": 40,
|
||||
"wildcard_sequence": 16,
|
||||
},
|
||||
)
|
||||
# Late P3 tied — high priority
|
||||
high = make_game(
|
||||
game_state="LIVE",
|
||||
home_name="Rangers",
|
||||
away_name="Devils",
|
||||
home_score=2,
|
||||
away_score=2,
|
||||
period=3,
|
||||
seconds_remaining=60,
|
||||
)
|
||||
# Early P1 blowout — low priority
|
||||
low = make_game(
|
||||
game_state="LIVE",
|
||||
home_name="Bruins",
|
||||
away_name="Canadiens",
|
||||
home_score=5,
|
||||
away_score=0,
|
||||
period=1,
|
||||
seconds_remaining=900,
|
||||
)
|
||||
|
||||
result = parse_games({"games": [low, high]})
|
||||
live_games = [g for g in result if g["Game State"] == "LIVE"]
|
||||
assert live_games[0]["Home Team"] == "Rangers"
|
||||
assert live_games[1]["Home Team"] == "Bruins"
|
||||
|
||||
def test_pre_games_ignore_priority_even_if_nonzero(self, mocker):
|
||||
# Give one team standings that maximize importance, another that minimize it
|
||||
def fake_standings(name):
|
||||
if name == "Bruins":
|
||||
return {
|
||||
"league_sequence": 1,
|
||||
"league_l10_sequence": 1,
|
||||
"division_abbrev": "ATL",
|
||||
"conference_abbrev": "E",
|
||||
"games_played": 80,
|
||||
"wildcard_sequence": 18,
|
||||
}
|
||||
return {
|
||||
"league_sequence": 32,
|
||||
"league_l10_sequence": 32,
|
||||
"division_abbrev": "PAC",
|
||||
"conference_abbrev": "W",
|
||||
"games_played": 10,
|
||||
"wildcard_sequence": 30,
|
||||
}
|
||||
|
||||
mocker.patch("app.games.get_team_standings", side_effect=fake_standings)
|
||||
|
||||
# Bruins game starts later but will have higher importance
|
||||
high_hype_late = make_game(
|
||||
game_state="FUT",
|
||||
home_name="Bruins",
|
||||
away_name="Maple Leafs",
|
||||
start_time_utc="2024-04-10T23:00:00Z",
|
||||
)
|
||||
low_hype_early = make_game(
|
||||
game_state="FUT",
|
||||
home_name="Kings",
|
||||
away_name="Ducks",
|
||||
start_time_utc="2024-04-10T19:00:00Z",
|
||||
)
|
||||
|
||||
result = parse_games({"games": [high_hype_late, low_hype_early]})
|
||||
pre_games = [g for g in result if g["Game State"] == "PRE"]
|
||||
# Lower-hype-but-earlier game must still appear first
|
||||
assert pre_games[0]["Home Team"] == "Kings"
|
||||
assert pre_games[1]["Home Team"] == "Bruins"
|
||||
assert pre_games[1]["Priority"] > pre_games[0]["Priority"]
|
||||
|
||||
|
||||
class TestGetPowerPlayInfo:
|
||||
def test_returns_empty_when_no_situation(self):
|
||||
|
||||
Reference in New Issue
Block a user