This repository has been archived by the owner on Oct 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
stats.py
253 lines (207 loc) · 10.9 KB
/
stats.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
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from datetime import datetime, timedelta
from dataclasses import dataclass
from typing import Optional
import os
import csv
import logging
logger = logging.getLogger(__name__)
@dataclass
class Record:
contenders: bool
min_watched: int
title: str
accountid: str
class Stats(QObject):
changed = pyqtSignal()
def __init__(self, location: str):
super().__init__()
self.file_path = location
self.record = None
def get_record(self) -> Optional[Record]:
return self.record
def set_record(self, contenders: bool, min_watched: int, title: str, accountid: str):
self.record = Record(contenders, min_watched, title, accountid)
self.changed.emit()
def write_record(self):
if self.record:
logger.info("Writting history record")
self._write()
self.record = None
self.changed.emit()
def _write(self):
if os.path.isfile(self.file_path):
write_header = False
write_mode = 'a'
else:
write_header = True
write_mode = 'w'
contenders = 'owc' if self.record.contenders else 'owl'
timestamp = datetime.now().astimezone().isoformat()
with open(self.file_path, write_mode) as f:
writer = csv.writer(f)
if write_header:
writer.writerow(['Timestamp', 'Account', 'Type', 'Title', 'Minutes'])
writer.writerow([
timestamp,
self.record.accountid,
contenders,
self.record.title,
self.record.min_watched
])
class StatsDialog(QDialog):
def __init__(self, stats: Stats, icon_owl: QIcon, icon_owc: QIcon, accountid=None, parent=None):
super().__init__(parent)
self.stats = stats
self.stats_account = accountid
stats_owc = [0, 0, 0]
stats_owl = [0, 0, 0, 0]
self.setWindowTitle("Stats/History")
self.setWindowIcon(icon_owl)
label_owl = QLabel("<h3>Overwatch League</h3>")
label_owl.setPixmap(icon_owl.pixmap(50, 50))
label_owc = QLabel("<h3>Overwatch Contenders</h3>")
label_owc.setPixmap(icon_owc.pixmap(50, 50))
self.button_layout = QHBoxLayout()
self.label_account = QLabel()
self.label_account.setTextFormat(Qt.RichText)
self.label_account.setText(f"<b> Account: </b> {accountid}" if accountid else '')
self.button_layout.addWidget(self.label_account)
btn_box = QDialogButtonBox(QDialogButtonBox.Close)
btn_box.rejected.connect(self.reject)
self.button_layout.addWidget(btn_box)
self.inner_layout = QGridLayout()
self.inner_layout.addWidget(label_owl, 0, 0, 3, 1)
self.inner_layout.addWidget(QLabel("Last 24h"), 0, 1)
self.inner_layout.addWidget(QLabel("Last 7d"), 1, 1)
self.inner_layout.addWidget(QLabel("This month"), 2, 1)
self.inner_layout.addWidget(QLabel("All-time"), 3, 1)
self.inner_layout.addWidget(QLabel(str(stats_owl[0]) + " min"), 0, 2)
self.inner_layout.addWidget(QLabel(str(stats_owl[1]) + " min"), 1, 2)
self.inner_layout.addWidget(QLabel(str(stats_owl[2]) + " min"), 2, 2)
self.inner_layout.addWidget(QLabel(str(stats_owl[3]) + " min"), 3, 2)
self.inner_layout.addWidget(QLabel(str(round(stats_owl[0] / 60, 2)) + "h"), 0, 3)
self.inner_layout.addWidget(QLabel(str(round(stats_owl[1] / 60, 2)) + "h"), 1, 3)
self.inner_layout.addWidget(QLabel(str(round(stats_owl[2] / 60, 2)) + "h"), 2, 3)
self.inner_layout.addWidget(QLabel(str(round(stats_owl[3] / 60, 2)) + "h"), 3, 3)
self.inner_layout.addWidget(QLabel(str(int(stats_owl[0] / 60) * 5) + " tokens"), 0, 4)
self.inner_layout.addWidget(QLabel(str(int(stats_owl[1] / 60) * 5) + " tokens"), 1, 4)
self.inner_layout.addWidget(QLabel(str(int(stats_owl[2] / 60) * 5) + " tokens"), 2, 4)
self.inner_layout.addWidget(QLabel(str(int(stats_owl[3] / 60) * 5) + " tokens"), 3, 4)
line = QFrame()
line.setFrameShape(QFrame.HLine)
line.setLineWidth(3)
self.inner_layout.addWidget(line, 4, 0, 2, 5)
self.inner_layout.addWidget(label_owc, 6, 0, 3, 1)
self.inner_layout.addWidget(QLabel("Last 24h"), 6, 1)
self.inner_layout.addWidget(QLabel("Last 7d"), 7, 1)
self.inner_layout.addWidget(QLabel("This month"), 8, 1)
self.inner_layout.addWidget(QLabel(str(stats_owc[0]) + " min"), 6, 2)
self.inner_layout.addWidget(QLabel(str(stats_owc[1]) + " min"), 7, 2)
self.inner_layout.addWidget(QLabel(str(stats_owc[2]) + " min"), 8, 2)
self.inner_layout.addWidget(QLabel(str(round(stats_owc[0] / 60, 2)) + "h"), 6, 3)
self.inner_layout.addWidget(QLabel(str(round(stats_owc[1] / 60, 2)) + "h"), 7, 3)
self.inner_layout.addWidget(QLabel(str(round(stats_owc[2] / 60, 2)) + "h"), 8, 3)
outer_layout = QVBoxLayout()
outer_layout.addLayout(self.inner_layout)
outer_layout.addLayout(self.button_layout)
outer_layout.setSpacing(20)
self.setLayout(outer_layout)
self.layout().setSizeConstraint(QLayout.SetFixedSize)
def show_dialog(self, accountid: str):
logger.info("Opening stats dialog")
self.stats_account = accountid
self._update_values()
self.show()
self.raise_()
self.activateWindow()
self.stats.changed.connect(self._update_values)
# This below causes crashes due to finished signal returning a int
# self.finished.connect(self.stats.changed.disconnect)
# Use lambda to ignore int returned from finished signal
self.finished.connect(lambda x: self.stats.changed.disconnect)
def _update_values(self):
logger.debug("Updating values on dialog")
stats_owl, stats_owc = self._get_stats_summary(self.stats_account)
self._replace_values(stats_owl, stats_owc, self.stats_account)
def _get_stats_summary(self, accountid: str):
stats_data = []
if self.stats.record:
stats_data.append({
'Timestamp': datetime.now().astimezone().isoformat(),
'Account': self.stats.record.accountid,
'Type': 'owc' if self.stats.record.contenders else 'owl',
'Title': self.stats.record.title,
'Minutes': self.stats.record.min_watched
})
if os.path.isfile(self.stats.file_path):
with open(self.stats.file_path, 'r', newline='') as history_file:
stats_data.extend(csv.DictReader(history_file))
logger.debug("Loaded history file")
stats_owl, stats_owc = self._process_data(stats_data, accountid)
return stats_owl, stats_owc
def _process_data(self, history_data: list, accountid: str) -> (list, list):
range_day = datetime.now().astimezone() - timedelta(hours=24)
range_week = datetime.now().astimezone() - timedelta(days=7)
current_month = datetime.now().astimezone().month
stats_owl = [0, 0, 0, 0]
stats_owc = [0, 0, 0]
for row in history_data:
try:
if row['Account'] == accountid:
stats_owl[3] += int(row['Minutes'])
if datetime.fromisoformat(row['Timestamp']) > range_day:
if row['Type'] == 'owl':
stats_owl[0] += int(row['Minutes'])
stats_owl[1] += int(row['Minutes'])
elif row['Type'] == 'owc':
stats_owc[0] += int(row['Minutes'])
stats_owc[1] += int(row['Minutes'])
elif datetime.fromisoformat(row['Timestamp']) > range_week:
if row['Type'] == 'owl':
stats_owl[1] += int(row['Minutes'])
elif row['Type'] == 'owc':
stats_owc[1] += int(row['Minutes'])
if datetime.fromisoformat(row['Timestamp']).month == current_month:
if row['Type'] == 'owl':
stats_owl[2] += int(row['Minutes'])
elif row['Type'] == 'owc':
stats_owc[2] += int(row['Minutes'])
except (KeyError, ValueError, TypeError) as e:
logger.warning(f"Malformed history file at {row} - {e}")
continue
return stats_owl, stats_owc
def _replace_values(self, stats_owl: list, stats_owc: list, accountid: str):
self.label_account.setText(f"<b> Account: </b> {accountid}")
self.inner_layout.itemAtPosition(0, 2).widget().setText(str(stats_owl[0]) + " min")
self.inner_layout.itemAtPosition(1, 2).widget().setText(str(stats_owl[1]) + " min")
self.inner_layout.itemAtPosition(2, 2).widget().setText(str(stats_owl[2]) + " min")
self.inner_layout.itemAtPosition(3, 2).widget().setText(str(stats_owl[3]) + " min")
self.inner_layout.itemAtPosition(0, 3).widget().setText(str(round(stats_owl[0] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(1, 3).widget().setText(str(round(stats_owl[1] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(2, 3).widget().setText(str(round(stats_owl[2] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(3, 3).widget().setText(str(round(stats_owl[3] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(0, 4).widget().setText(str(int(stats_owl[0] / 60) * 5) + " tokens")
self.inner_layout.itemAtPosition(1, 4).widget().setText(str(int(stats_owl[1] / 60) * 5) + " tokens")
self.inner_layout.itemAtPosition(2, 4).widget().setText(str(int(stats_owl[2] / 60) * 5) + " tokens")
self.inner_layout.itemAtPosition(3, 4).widget().setText(str(int(stats_owl[3] / 60) * 5) + " tokens")
self.inner_layout.itemAtPosition(6, 2).widget().setText(str(stats_owc[0]) + " min")
self.inner_layout.itemAtPosition(7, 2).widget().setText(str(stats_owc[1]) + " min")
self.inner_layout.itemAtPosition(8, 2).widget().setText(str(stats_owc[2]) + " min")
self.inner_layout.itemAtPosition(6, 3).widget().setText(str(round(stats_owc[0] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(7, 3).widget().setText(str(round(stats_owc[1] / 60, 2)) + "h")
self.inner_layout.itemAtPosition(8, 3).widget().setText(str(round(stats_owc[2] / 60, 2)) + "h")
if __name__ == "__main__":
global stats
import os, csv
logging.basicConfig(level=logging.INFO)
app = QApplication([])
icon_owl = QIcon(os.path.join("icons", "iconowl.png"))
icon_owc = QIcon(os.path.join("icons", "iconowc.png"))
accountid = "123456789"
stats = Stats('history.csv', icon_owl, icon_owc)
stats.set_record(contenders=True, min_watched=24, title="Fake OWL test", accountid='123456789')
stats.show(accountid)
app.exec_()