/
summary.py
148 lines (111 loc) · 4.08 KB
/
summary.py
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
import traceback
from dataclasses import asdict, dataclass
from datetime import UTC, datetime
from time import time
from dacite import Config, from_dict
from tinydb import Query
from config import (CLIPS_PATH, CLIPS_REPLAY_PATH, DB, FRIENDS, MAX_STARS,
SUMMARY_MIN_VOTES, TTV_CHANNEL, FriendConfig)
from vote import Vote, VoteState
@dataclass(frozen=True, kw_only=True, slots=True)
class TopUser:
username: str
stars: int
stars_history: tuple[str, ...]
@dataclass(frozen=True, kw_only=True, slots=True)
class FriendState:
date: int
streamer_stars: int
users_stars: int
top_user: TopUser
@property
def date_str(self) -> str:
return datetime.fromtimestamp(self.date, tz=UTC).strftime('%d %b %Y')
def get_extra_states(self) -> None:
return None
@dataclass(frozen=True, kw_only=True, slots=True)
class SummaryEntry:
date: int
max_stars: int
friend_states: dict[str, FriendState]
@property
def date_str(self) -> str:
return datetime.fromtimestamp(self.date, tz=UTC).strftime('%d %b %Y')
@property
def streamer_stars(self) -> int:
return self.friend_states[TTV_CHANNEL].streamer_stars
@property
def users_stars(self) -> int:
return self.friend_states[TTV_CHANNEL].users_stars
@property
def top_user(self) -> TopUser:
return self.friend_states[TTV_CHANNEL].top_user
def get_extra_states(self) -> list[tuple[FriendConfig, FriendState | None]]:
return [
(config, self.friend_states.get(config.channel, None))
for config in FRIENDS
if config.channel != TTV_CHANNEL
]
def get_summary(channel: str | None = None) -> list[SummaryEntry]:
summary_table = DB.table('summary')
summary = sorted([from_dict(SummaryEntry, d, config=Config(check_types=False)) for d in summary_table.all()],
key=lambda e: e.date,
reverse=True)
if channel is None or channel == TTV_CHANNEL:
return summary
return [state for e in summary if (state := e.friend_states.get(channel, None)) is not None]
def is_game_available(channel: str) -> bool:
summary = get_summary()
if channel == TTV_CHANNEL:
# is host
if not summary:
return True
last = summary[0]
return CLIPS_PATH.stat().st_mtime > last.date
else:
# is friend
if not CLIPS_REPLAY_PATH.is_file() or CLIPS_REPLAY_PATH.stat().st_size == 0:
return False
if not summary:
return False
last = summary[0]
return channel not in last.friend_states
def update_summary(vote: Vote) -> bool:
assert vote.state == VoteState.RESULTS
if vote.total_users_votes < SUMMARY_MIN_VOTES:
return False
now = int(time())
top_user_score = vote.result.top_users[0][1]
summary_table = DB.table('summary')
if vote.friend_config.channel == TTV_CHANNEL:
summary_table.insert(asdict(SummaryEntry(
date=now,
max_stars=len(vote.clips) * MAX_STARS,
friend_states={
TTV_CHANNEL: FriendState(
date=now,
streamer_stars=vote.total_streamer_stars,
users_stars=vote.total_users_stars,
top_user=TopUser(
username=top_user_score.username,
stars=top_user_score.stars,
stars_history=top_user_score.stars_history
)
)
}
)))
else:
last = get_summary()[0]
last.friend_states[vote.friend_config.channel] = FriendState(
date=now,
streamer_stars=vote.total_streamer_stars,
users_stars=vote.total_users_stars,
top_user=TopUser(
username=top_user_score.username,
stars=top_user_score.stars,
stars_history=top_user_score.stars_history
)
)
entry = Query()
summary_table.update(asdict(last), entry.date == last.date)
return True