Skip to content

Commit ea42b63

Browse files
committed
Add word count history tracking and enhance statistics charts UI and storage
1 parent e54304c commit ea42b63

File tree

5 files changed

+114
-79
lines changed

5 files changed

+114
-79
lines changed

src/LunaTranslator/gui/gamemanager/setting.py

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from qtsymbols import *
22
import functools, uuid, os, qtawesome, time
3-
from datetime import datetime, timedelta
3+
from datetime import datetime, timedelta, date
4+
from datetime import time as dttime
45
from traceback import print_exc
56
import gobject, NativeUtils
67
import copy
@@ -333,6 +334,7 @@ def selectexe(self, res):
333334

334335
def __init__(self, parent, gameuid, keepindexobject=None) -> None:
335336
super().__init__(parent)
337+
self.__quanju_wc = False
336338
self.keepindexobject = keepindexobject
337339
vbox = QVBoxLayout(self)
338340
self.lauchpath = None
@@ -636,14 +638,27 @@ def __refresh(self):
636638
cnt, savehook_new_data[self.gameuid].get("statistic_wordcount", 0)
637639
)
638640

641+
def chartwidget_ctxmenu(self, p):
642+
menu = QMenu(self)
643+
quanju = LAction("this" if self.__quanju_wc else "all", menu)
644+
menu.addAction(quanju)
645+
action = menu.exec(self.cursor().pos())
646+
if action == quanju:
647+
self.__quanju_wc = not self.__quanju_wc
648+
639649
def getstatistic(self, formLayout: QVBoxLayout, gameuid):
650+
640651
chart = chartwidget()
641652
chart.xtext = lambda x: (
642653
"0" if x == 0 else str(datetime.fromtimestamp(x)).split(" ")[0]
643654
)
644655
chart.ytext = lambda y: self.formattime(y, False)
645656

646-
self.chart = chart
657+
chart2 = chartwidget()
658+
chart2.xtext = chart.xtext
659+
chart2.ytext = str
660+
chart2.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
661+
chart2.customContextMenuRequested.connect(self.chartwidget_ctxmenu)
647662
self._timelabel = QLabel()
648663
self._wordlabel = QLabel()
649664
self._wordlabel.setSizePolicy(
@@ -652,34 +667,49 @@ def getstatistic(self, formLayout: QVBoxLayout, gameuid):
652667
self._timelabel.setSizePolicy(
653668
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
654669
)
670+
stack = QStackedWidget()
671+
stack.addWidget(chart)
672+
stack.addWidget(chart2)
673+
wc = LPushButton("文字计数")
674+
tm = LPushButton("游戏时间")
675+
wc.setCheckable(True)
676+
tm.setCheckable(True)
677+
678+
def clicktm(b):
679+
stack.setCurrentIndex(1 - b)
680+
globalconfig["statisticvistm"] = b
681+
wc.setChecked(not b)
682+
683+
def clickwc(b):
684+
stack.setCurrentIndex(b)
685+
globalconfig["statisticvistm"] = not b
686+
tm.setChecked(not b)
687+
688+
tm.toggled.connect(clicktm)
689+
wc.toggled.connect(clickwc)
690+
if globalconfig.get("statisticvistm", True):
691+
tm.setChecked(True)
692+
else:
693+
wc.setChecked(True)
655694
formLayout.addLayout(
656695
getboxlayout(
657696
[
658-
"文字计数",
659-
getboxlayout(
660-
[self._wordlabel, getIconButton(self.__refresh, "fa.refresh")]
661-
),
662-
]
663-
)
664-
)
665-
666-
t = QTimer(self)
667-
formLayout.addLayout(
668-
getboxlayout(
669-
[
670-
"游戏时间",
697+
wc,
698+
self._wordlabel,
699+
"",
700+
tm,
671701
self._timelabel,
672702
getIconButton(
673703
icon="fa.edit", callback=functools.partial(timelistediter, self)
674704
),
705+
getIconButton(self.__refresh, "fa.refresh"),
675706
]
676707
)
677708
)
678-
679-
formLayout.addWidget(chart)
709+
formLayout.addWidget(stack)
680710
t = QTimer(self)
681711
t.setInterval(1000)
682-
t.timeout.connect(self.refresh)
712+
t.timeout.connect(functools.partial(self.refresh, chart, chart2, gameuid))
683713
t.timeout.emit()
684714
t.start()
685715

@@ -718,14 +748,30 @@ def split_range_into_days(self, times):
718748
lists.append((k, everyday[k]))
719749
return lists
720750

721-
def refresh(self):
722-
__ = gobject.base.somedatabase.querytraceplaytime(self.gameuid)
751+
def refresh(self, chart: chartwidget, chart2: chartwidget, gameuid):
752+
__ = gobject.base.somedatabase.querytraceplaytime(gameuid)
723753
_cnt = sum([_[1] - _[0] for _ in __])
724754
self._timelabel.setText(self.formattime(_cnt))
725755
self._wordlabel.setText(
726-
str(savehook_new_data[self.gameuid].get("statistic_wordcount", 0))
756+
str(savehook_new_data[gameuid].get("statistic_wordcount", 0))
727757
)
728-
self.chart.setdata(self.split_range_into_days(__))
758+
chart.setdata(self.split_range_into_days(__))
759+
760+
__ = gobject.base.somedatabase.querywordcount(
761+
None if self.__quanju_wc else gameuid
762+
)
763+
chart2.setdata(self.wordcountbydate(__))
764+
765+
def wordcountbydate(self, l: tuple[tuple[float, int]]):
766+
daily_sum: "dict[date, int]" = {}
767+
for timestamp, value in l:
768+
date = datetime.fromtimestamp(timestamp).date()
769+
daily_sum[date] = daily_sum.get(date, 0) + value
770+
lists = []
771+
for k in sorted(daily_sum.keys()):
772+
lists.append((datetime.combine(k, dttime.min).timestamp(), daily_sum[k]))
773+
774+
return lists
729775

730776
def formattime(self, t, usingnotstart=True):
731777
t = int(t)

src/LunaTranslator/gui/specialwidget.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -97,22 +97,6 @@ def setdata(self, data):
9797
data = sorted(data, key=lambda _: _[0])
9898
self.data = data
9999

100-
def formattime(self, t):
101-
t = int(t)
102-
s = t % 60
103-
t = t // 60
104-
m = t % 60
105-
t = t // 60
106-
h = t
107-
string = ""
108-
if h:
109-
string += str(h) + _TR("时")
110-
if m:
111-
string += str(m) + _TR("分")
112-
if s:
113-
string += str(s) + _TR("秒")
114-
return string
115-
116100
def mouseMoveEvent(self, a0):
117101
self.update()
118102
return super().mouseMoveEvent(a0)
@@ -134,7 +118,7 @@ def paintatmouse(
134118
idx = round(idx_f)
135119
idx = max(0, min(idx, len(self.data) - 1))
136120
xt = lambda x: ("" if x == 0 else str(datetime.fromtimestamp(x)).split(" ")[0])
137-
_ = self.formattime(self.data[idx][1])
121+
_ = self.ytext(self.data[idx][1])
138122
t = xt(self.data[idx][0])
139123
if _:
140124
t += "\n" + _

src/LunaTranslator/myutils/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ def getdefaultsavehook(title=None):
164164
# "onloadautochangemode2": 0,
165165
# "embedablehook": [],
166166
# "statistic_wordcount": 0,
167-
# "statistic_wordcount_nodump": 0,
168167
# "hook": [],
169168
# "inserthooktimeout": 250,
170169
# "insertpchooks_string": False,

src/LunaTranslator/myutils/somedatabase.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import time
33
import os
44
from qtsymbols import *
5-
from myutils.config import findgameuidofpath, globalconfig
6-
from myutils.hwnd import ListProcess
5+
from myutils.config import findgameuidofpath
76
from myutils.wrapper import threader
87
import threading
8+
from queue import Queue
99
import windows
1010
import gobject
1111

@@ -40,6 +40,7 @@ def allwords(self):
4040
).fetchall()
4141

4242
def __init__(self):
43+
self.wordcountqueue = Queue()
4344
self.locked = threading.Lock()
4445
self.sqlsavegameinfo = sqlite3.connect(
4546
gobject.getconfig("savegame.db"),
@@ -54,41 +55,27 @@ def __init__(self):
5455
pass
5556
try:
5657
self.sqlsavegameinfo.execute(
57-
"CREATE TABLE traceplaytime_v4(id INTEGER PRIMARY KEY AUTOINCREMENT,gameinternalid INT,timestart BIGINT,timestop BIGINT);"
58+
"CREATE TABLE gameinternalid_v2(gameinternalid INTEGER PRIMARY KEY AUTOINCREMENT,gameuid TEXT);"
5859
)
5960
except:
6061
pass
6162
try:
6263
self.sqlsavegameinfo.execute(
63-
"CREATE TABLE gameinternalid_v2(gameinternalid INTEGER PRIMARY KEY AUTOINCREMENT,gameuid TEXT);"
64+
"CREATE TABLE trace_strict(gameinternalid INT,timestart BIGINT,timestop BIGINT);"
6465
)
65-
self.trycastoldversion()
66+
self.sqlsavegameinfo.commit()
6667
except:
6768
pass
6869
try:
6970
self.sqlsavegameinfo.execute(
70-
"CREATE TABLE trace_strict(gameinternalid INT,timestart BIGINT,timestop BIGINT);"
71-
)
72-
self.sqlsavegameinfo.execute(
73-
"INSERT INTO trace_strict SELECT gameinternalid,timestart,timestop FROM traceplaytime_v4"
71+
"CREATE TABLE game_word_count(gameinternalid INT,time BIGINT,wordcount BIGINT);"
7472
)
7573
self.sqlsavegameinfo.commit()
7674
except:
7775
pass
7876

7977
self.checkgameplayingthread()
80-
81-
def trycastoldversion(self):
82-
for _id, gamepath in self.sqlsavegameinfo.execute(
83-
"SELECT * from gameinternalid"
84-
).fetchall():
85-
gameuid = findgameuidofpath(gamepath)
86-
if not gameuid:
87-
continue
88-
self.sqlsavegameinfo.execute(
89-
"INSERT INTO gameinternalid_v2 VALUES(?,?)", (_id, gameuid[0])
90-
)
91-
self.sqlsavegameinfo.commit()
78+
self.wordcountthread()
9279

9380
def lockdata(self):
9481
self.locked.acquire()
@@ -110,12 +97,26 @@ def settraceplaytime(self, gameuid, lst: "list[tuple[float, float]]"):
11097
self.sqlsavegameinfo.commit()
11198

11299
def querytraceplaytime(self, gameuid) -> "list[tuple[float, float]]":
113-
table = "trace_strict"
114100
gameinternalid = self.__get_gameinternalid(gameuid)
115-
return self.sqlsavegameinfo.execute(
116-
"SELECT timestart,timestop FROM {} WHERE gameinternalid = ?".format(table),
101+
__ = self.sqlsavegameinfo.execute(
102+
"SELECT timestart,timestop FROM trace_strict WHERE gameinternalid = ?",
117103
(gameinternalid,),
118104
).fetchall()
105+
__ = tuple(_ for _ in __ if _[1] > _[0])
106+
return __
107+
108+
def querywordcount(self, gameuid: "str|None") -> "list[tuple[float, float]]":
109+
if gameuid:
110+
gameinternalid = self.__get_gameinternalid(gameuid)
111+
__ = self.sqlsavegameinfo.execute(
112+
"SELECT time,wordcount FROM game_word_count WHERE gameinternalid = ?",
113+
(gameinternalid,),
114+
).fetchall()
115+
else:
116+
__ = self.sqlsavegameinfo.execute(
117+
"SELECT time,wordcount FROM game_word_count"
118+
).fetchall()
119+
return __
119120

120121
def __get_gameinternalid(self, gameuid):
121122
while True:
@@ -188,7 +189,6 @@ def checkgameplayingthread(self):
188189
# 虚拟机暂停
189190
self.trace_strict.clear()
190191
continue
191-
192192
self.tracex(
193193
t,
194194
self.finduids(self.stricttraceexe()),
@@ -197,3 +197,18 @@ def checkgameplayingthread(self):
197197
)
198198
self.sqlsavegameinfo.commit()
199199
time.sleep(5)
200+
201+
@threader
202+
def wordcountthread(self):
203+
lastuid = None
204+
while True:
205+
t, uid, wc = self.wordcountqueue.get()
206+
if not uid:
207+
continue
208+
if lastuid != uid:
209+
gameinternalid = self.__get_gameinternalid(uid)
210+
lastuid = uid
211+
self.sqlsavegameinfo.execute(
212+
"INSERT INTO game_word_count VALUES(?,?,?)",
213+
(gameinternalid, t, wc),
214+
)

src/LunaTranslator/textio/textsource/textsourcebase.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import gobject, queue
2-
import json
2+
import json, time
33
from traceback import print_exc
44
from myutils.config import globalconfig, savehook_new_data
55
from myutils.utils import autosql
@@ -107,6 +107,10 @@ def sqlitethread(self):
107107
savehook_new_data[gobject.base.gameuid][
108108
"statistic_wordcount"
109109
] += lensrc
110+
111+
gobject.base.somedatabase.wordcountqueue.put(
112+
(time.time(), gobject.base.gameuid, lensrc)
113+
)
110114
except:
111115
pass
112116
if ret is None:
@@ -120,19 +124,6 @@ def sqlitethread(self):
120124
"INSERT INTO artificialtrans VALUES(NULL,?,?);",
121125
(src, json.dumps({})),
122126
)
123-
try:
124-
if (
125-
"statistic_wordcount_nodump"
126-
not in savehook_new_data[gobject.base.gameuid]
127-
):
128-
savehook_new_data[gobject.base.gameuid][
129-
"statistic_wordcount_nodump"
130-
] = 0
131-
savehook_new_data[gobject.base.gameuid][
132-
"statistic_wordcount_nodump"
133-
] += lensrc
134-
except:
135-
pass
136127
elif len(task) == 3:
137128
src, clsname, trans = task
138129
ret = self.sqlwrite2.execute(

0 commit comments

Comments
 (0)