This commit is contained in:
恍兮惚兮 2024-12-24 15:22:04 +08:00
parent f982f96af6
commit 9f038b3c1e
70 changed files with 1771 additions and 1033 deletions

1
.gitignore vendored
View File

@ -49,3 +49,4 @@ cpp/LunaHook/.vscode/settings.json
cpp/LunaHook/scripts/YY-Thunks-1.0.7-Binary.zip
cpp/libs/YY-Thunks
py/LunaTranslator/.vscode/settings.json
py/files/yearsummary/yearsummary.value.js

View File

@ -1517,6 +1517,8 @@ namespace ppsspp
{0x88F09F4, {CODEC_UTF16, 0, 0, 0, ULJM05976, "ULJM05976"}},
// オメルタ~沈黙の掟~ THE LEGACY
{0x88861C8, {0, 3, 0, 0, 0, "ULJM06393"}},
{0x8885fd8, {0, 0, 0, 0, 0, "ULJM06393"}},
{0x88ac3a8, {0, 1, 0, 0, 0, "ULJM06393"}},
// L.G.S新説 封神演義~
{0x888A358, {0, 0, 0, 0, ULJM05943F, "ULJM06131"}}, // NAME+TEXT
{0x88DB214, {0, 0, 0, 0, ULJM05943F, "ULJM06131"}}, // TEXT
@ -1534,6 +1536,7 @@ namespace ppsspp
{0x886E094, {0, 0, 0, 0, ULJM06129, "ULJM06129"}}, // name+text
// 十鬼の絆 花結綴り
{0x886E354, {0, 0, 0, 0, ULJM06289, "ULJM06301"}}, // name+text
{0x88f878c, {0, 0, 0, 0, ULJM06289, "ULJM06301"}},
// ティンクル☆くるせいだーす STARLIT BRAVE!!
{0x88A94BC, {0, 4, 0, 0, 0, "ULJS00315"}}, // text
// ティンクル☆くるせいだーす GoGo!

View File

@ -236,8 +236,7 @@ int PyStand::DetectScript()
//---------------------------------------------------------------------
const auto init_script =
LR"(
import sys
import os
import os,functools, locale, sys
PYSTAND = os.environ['PYSTAND']
PYSTAND_HOME = os.environ['PYSTAND_HOME']
PYSTAND_RUNTIME = os.environ['PYSTAND_RUNTIME']
@ -253,26 +252,40 @@ def MessageBox(msg, info = 'Message'):
os.MessageBox = MessageBox
#sys.stdout=sys.stderr
sys.path.insert(0, './LunaTranslator')
)"
#ifndef PYSTAND_CONSOLE
LR"(
def fuckwrite(origin, message):
try:
if isinstance(message, str):
code=locale.getpreferredencoding()
origin(message.encode(encoding=code, errors='replace').decode(encoding=code, errors='replace'))
else:
origin(message)
except:
return
import traceback, io
sio = io.StringIO()
traceback.print_exc(file = sio)
os.MessageBox(sio.getvalue(), message)
try:
fd = os.open('CONOUT$', os.O_RDWR | os.O_BINARY)
fp = os.fdopen(fd, 'w')
sys.stdout = fp
sys.stderr = fp
attached = True
sys.stdout.write = functools.partial(fuckwrite,sys.stdout.write)
sys.stderr.write = functools.partial(fuckwrite,sys.stderr.write)
except Exception as e:
try:
fp = open(os.devnull, 'w', errors='ignore') # sometimes FileNotFound Error: [Errno 2]No such file or directory: 'nul'
fp = open(os.devnull, 'w', errors='replace') # sometimes FileNotFound Error: [Errno 2]No such file or directory: 'nul'
sys.stdout = fp
sys.stderr = fp
attached = False
except:
pass
)"
#endif
LR"(
sys.argv = [PYSTAND_SCRIPT] + sys.argv[1:]
text = open(PYSTAND_SCRIPT, 'rb').read()
environ = {'__file__': PYSTAND_SCRIPT, '__name__': '__main__'}
@ -324,41 +337,13 @@ int main()
{
return 3;
}
#ifndef PYSTAND_CONSOLE
// winmain下的stderr没有任何卵用对于崩溃时的stderr根本显示不出来所以还是用控制台来保存log吧。
// print cmd无法显示的字符时如果使用cmd打开不论debug还是普通都会error31崩溃。如果双击打开debug却不会崩溃
// 但因为无法区分是使用cmd打开debug还是双击打开debug所以干脆都这样吧。
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
int fd = _fileno(stdout);
if (fd >= 0)
{
std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDOUT", fn.c_str());
}
fd = _fileno(stdin);
if (fd >= 0)
{
std::string fn = std::to_string(fd);
SetEnvironmentVariableA("PYSTAND_STDIN", fn.c_str());
}
}
#else
SetConsoleOutputCP(CP_UTF8);
/*
auto getCurrentTimestamp = []
{
auto now = std::chrono::system_clock::now();
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_time_t);
std::ostringstream oss;
oss << std::put_time(&now_tm, "log_%Y-%m-%d-%H-%M-%S.txt");
return oss.str();
};
auto curr = getCurrentTimestamp();
freopen(curr.c_str(), "a", stderr);
*/
#endif
int hr = ps.RunString(init_script);
return hr;
}

View File

@ -531,28 +531,8 @@ wchar_t *TranslateFullLog(wchar_t *otext)
struct AtlasConfig atlcfg;
static void writestring(wchar_t *text, HANDLE hPipe)
{
DWORD _;
auto len = text ? (2 * wcslen(text)) : 0;
if (!WriteFile(hPipe, &len, 4, &_, NULL))
return;
if (text)
if (!WriteFile(hPipe, text, len, &_, NULL))
return;
}
static wchar_t *readstring(HANDLE hPipe)
{
DWORD _;
int len;
if (!ReadFile(hPipe, &len, 4, &_, NULL))
return nullptr;
wchar_t *otext = new wchar_t[len / 2 + 1];
if (!ReadFile(hPipe, otext, len, &_, NULL))
return nullptr;
otext[len / 2] = 0;
return otext;
}
void writestring(const wchar_t *text, HANDLE hPipe);
wchar_t *readstring(HANDLE hPipe);
HANDLE mutex = NULL;
int atlaswmain(int argc, wchar_t *argv[])
{

View File

@ -678,6 +678,7 @@ std::optional<std::wstring> CTextProcess::eztrans_proc(const std::wstring &input
output = HangulDecode(output);
return output;
}
void writestring(const wchar_t *text, HANDLE hPipe);
int eztrans(int argc, wchar_t *argv[])
{
@ -700,12 +701,10 @@ int eztrans(int argc, wchar_t *argv[])
if (!ReadFile(hPipe, buff, 12000, &_, NULL))
break;
auto trans = CTextProcess::eztrans_proc(buff);
std::wstring res;
if (trans)
res = trans.value();
writestring(trans.value().c_str(), hPipe);
else
res = L"translate failed";
WriteFile(hPipe, res.data(), 2 * res.size(), &_, NULL);
writestring(0, hPipe);
}
return 0;

View File

@ -149,7 +149,7 @@ void SetUpLEC()
RegCloseKey(key);
}
}
static void writestring(wchar_t *text, HANDLE hPipe)
void writestring(const wchar_t *text, HANDLE hPipe)
{
DWORD _;
auto len = text ? (2 * wcslen(text)) : 0;
@ -159,7 +159,7 @@ static void writestring(wchar_t *text, HANDLE hPipe)
if (!WriteFile(hPipe, text, len, &_, NULL))
return;
}
static wchar_t *readstring(HANDLE hPipe)
wchar_t *readstring(HANDLE hPipe)
{
DWORD _;
int len;

View File

@ -1,7 +1,7 @@
set(VERSION_MAJOR 6)
set(VERSION_MINOR 14)
set(VERSION_PATCH 13)
set(VERSION_MINOR 15)
set(VERSION_PATCH 0)
set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp)

View File

@ -223,26 +223,7 @@ def urlprotocol():
print_exc()
def is64_bit_os():
import ctypes
is64bit = ctypes.c_bool()
handle = ctypes.windll.kernel32.GetCurrentProcess()
success = ctypes.windll.kernel32.IsWow64Process(handle, ctypes.byref(is64bit))
return (success and is64bit).value
def disablestdio():
import platform
if (int(platform.version().split(".")[0]) <= 6) and (not is64_bit_os()):
# win7 32位有时候print会谜之报错PermissionError WinError 31
sys.stdout = None
sys.stderr = None
if __name__ == "__main__":
disablestdio()
switchdir()
prepareqtenv()
from qtsymbols import QApplication

View File

@ -4,11 +4,11 @@ from qtsymbols import *
import os, functools, uuid
from traceback import print_exc
import gobject, qtawesome
from gui.dynalang import LPushButton, LAction
from gui.dynalang import LAction
from gui.dialog_savedgame_v3 import dialog_savedgame_v3
from gui.dialog_savedgame_legacy import dialog_savedgame_legacy
from gui.dialog_savedgame_setting import dialog_setting_game, userlabelset
from myutils.wrapper import Singleton_close
from myutils.wrapper import Singleton_close, tryprint
from gui.specialwidget import lazyscrollflow
from myutils.utils import str2rgba
from myutils.config import (
@ -25,12 +25,13 @@ from gui.usefulwidget import (
Prompt_dialog,
IconButton,
getsimplecombobox,
FQLineEdit,
FocusCombo,
)
from gui.dialog_savedgame_common import (
ItemWidget,
dialog_syssetting,
tagitem,
TagWidget,
startgamecheck,
loadvisinternal,
getalistname,
@ -150,6 +151,108 @@ class dialog_savedgame_integrated(saveposwindow):
)
class TagWidget(QWidget):
tagschanged = pyqtSignal(tuple) # ((tag,type,refdata),)
linepressedenter = pyqtSignal(str)
tagclicked = pyqtSignal(tuple) # tag,type,refdata
def __init__(self, parent=None, exfoucus=True):
super().__init__(parent)
tagitem.setstyles(self)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
self.lineEdit = FocusCombo()
if exfoucus:
self.lineEdit.setLineEdit(FQLineEdit())
# FQLineEdit导致游戏管理页面里点击编辑框后下边界消失。
# FQLineEdit仅用于和webview同一窗口内焦点缺失问题所以既然用不到那就不要多此一举了
else:
self.lineEdit.setEditable(True)
self.lineEdit.lineEdit().returnPressed.connect(
lambda: self.linepressedenter.emit(self.lineEdit.currentText())
)
self.lineEdit.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum
)
self.tagtypes = ["usertags", "developers", "webtags", "usertags"]
self.tagtypes_zh = ["全部", "开发商", "标签", "自定义"]
self.tagtypes_1 = [
tagitem.TYPE_SEARCH,
tagitem.TYPE_DEVELOPER,
tagitem.TYPE_TAG,
tagitem.TYPE_USERTAG,
]
layout.addWidget(self.lineEdit)
def __(idx):
t = self.lineEdit.currentText()
self.lineEdit.clear()
self.lineEdit.addItems(userlabelset(self.tagtypes[idx]))
self.lineEdit.setCurrentText(t)
self.typecombo = getsimplecombobox(self.tagtypes_zh, callback=__)
layout.addWidget(self.typecombo)
self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
self.tag2widget = {}
def callback(t):
if not t:
return
self.addTag(t, self.tagtypes_1[self.typecombo.currentIndex()])
self.lineEdit.clearEditText()
self.linepressedenter.connect(callback)
self.typecombo.currentIndexChanged.emit(0)
def addTags(self, tags, signal=True):
for key in tags:
self.__addTag(key)
self.__calltagschanged(signal)
@tryprint
def __addTag(self, key):
tag, _type, refdata = key
if not tag:
return
if key in self.tag2widget:
return
qw = tagitem(tag, _type=_type, refdata=refdata)
qw.removesignal.connect(self.removeTag)
qw.labelclicked.connect(self.tagclicked.emit)
layout = self.layout()
layout.insertWidget(layout.count() - 2, qw)
self.tag2widget[key] = qw
self.lineEdit.setFocus()
def addTag(self, tag, _type, refdata=None, signal=True):
self.__addTag((tag, _type, refdata))
self.__calltagschanged(signal)
@tryprint
def __removeTag(self, key):
_w = self.tag2widget[key]
self.layout().removeWidget(_w)
self.tag2widget.pop(key)
def removeTag(self, key, signal=True):
self.__removeTag(key)
self.__calltagschanged(signal)
def __calltagschanged(self, signal):
if signal:
self.tagschanged.emit(tuple(self.tag2widget.keys()))
def clearTag(self, signal=True):
for key in self.tag2widget.copy():
self.__removeTag(key)
self.__calltagschanged(signal)
class dialog_savedgame_new(QWidget):
def dragEnterEvent(self, event: QDragEnterEvent):
@ -222,6 +325,10 @@ class dialog_savedgame_new(QWidget):
if newtags != self.currtags:
break
notshow = False
webtags = [
globalconfig["tagNameRemap"].get(tag, tag)
for tag in savehook_new_data[k]["webtags"]
]
for tag, _type, _ in tags:
if _type == tagitem.TYPE_EXISTS:
if os.path.exists(get_launchpath(k)) == False:
@ -232,16 +339,16 @@ class dialog_savedgame_new(QWidget):
notshow = True
break
elif _type == tagitem.TYPE_TAG:
if tag not in savehook_new_data[k]["webtags"]:
if tag not in webtags:
notshow = True
break
elif _type == tagitem.TYPE_USERTAG:
if tag not in savehook_new_data[k]["usertags"]:
notshow = True
break
elif _type == tagitem.TYPE_RAND:
elif _type == tagitem.TYPE_SEARCH:
if (
tag not in savehook_new_data[k]["webtags"]
tag not in webtags
and tag not in savehook_new_data[k]["usertags"]
and tag not in savehook_new_data[k]["title"]
and tag not in savehook_new_data[k]["developers"]
@ -431,24 +538,8 @@ class dialog_savedgame_new(QWidget):
self.reflist = getreflist(globalconfig["currvislistuid"])
self.reftagid = globalconfig["currvislistuid"]
def callback(t):
if not t:
return
labelset = userlabelset()
if t in labelset:
tp = tagitem.TYPE_USERTAG
else:
tp = tagitem.TYPE_RAND
self.tagswidget.addTag(t, tp)
self.tagswidget.lineEdit.clear()
self.tagswidget.lineEdit.addItems(labelset)
self.tagswidget.lineEdit.clearEditText()
self.tagswidget = TagWidget(self, exfoucus=False)
self.tagswidget.lineEdit.addItems(userlabelset())
self.tagswidget.lineEdit.setCurrentText("")
self.tagswidget.linepressedenter.connect(callback)
self.currtags = tuple()
self.tagswidget.tagschanged.connect(self.tagschanged)
_ = QLabel()
@ -500,16 +591,40 @@ class dialog_savedgame_new(QWidget):
getreflist(uid).insert(0, getreflist(uid).pop(idx))
def keyPressEvent(self, e: QKeyEvent):
if e.key() == Qt.Key.Key_Return:
startgamecheck(self, getreflist(self.reftagid), self.currentfocusuid)
elif e.key() == Qt.Key.Key_Delete:
self.clicked2()
elif e.key() == Qt.Key.Key_Left:
self.moverank(-1)
elif e.key() == Qt.Key.Key_Right:
self.moverank(1)
if self.currentfocusuid:
if e.key() == Qt.Key.Key_Return:
startgamecheck(self, getreflist(self.reftagid), self.currentfocusuid)
elif e.key() == Qt.Key.Key_Delete:
self.clicked2()
elif e.key() == Qt.Key.Key_Left:
if e.modifiers() == Qt.KeyboardModifier.ControlModifier:
self.moverank(-1)
else:
self.movefocus(-1)
elif e.key() == Qt.Key.Key_Right:
if e.modifiers() == Qt.KeyboardModifier.ControlModifier:
self.moverank(1)
else:
self.movefocus(1)
super().keyPressEvent(e)
def movefocus(self, dx):
game = self.currentfocusuid
idx1 = self.idxsave.index(game)
idx2 = (idx1 + dx) % len(self.idxsave)
if idx1 == 0 and dx == -1:
self.flow.verticalScrollBar().setValue(
self.flow.verticalScrollBar().maximum()
)
else:
self.flow.ensureWidgetVisible(self.flow.widget(idx2))
try:
self.flow.widget(idx2).click()
except:
pass
def moverank(self, dx):
game = self.currentfocusuid
@ -518,7 +633,7 @@ class dialog_savedgame_new(QWidget):
game2 = self.idxsave[idx2]
self.idxsave.insert(idx2, self.idxsave.pop(idx1))
self.flow.switchidx(idx1, idx2)
# self.flow.ensureWidgetVisible(self.flow.widget(idx2))
idx1 = self.reflist.index(game)
idx2 = self.reflist.index(game2)
self.reflist.insert(idx2, self.reflist.pop(idx1))

View File

@ -1,8 +1,8 @@
from qtsymbols import *
import os, functools
from traceback import print_exc
from myutils.wrapper import tryprint, threader, Singleton_close
from myutils.utils import str2rgba, find_or_create_uid, duplicateconfig
from myutils.wrapper import threader, Singleton_close
from myutils.utils import find_or_create_uid, duplicateconfig
from myutils.hwnd import getExeIcon
import gobject, hashlib
from gui.inputdialog import autoinitdialog
@ -19,13 +19,11 @@ from myutils.config import (
)
from gui.usefulwidget import (
getIconButton,
FocusCombo,
getsimplecombobox,
getspinbox,
getcolorbutton,
getsimpleswitch,
getsimplepatheditor,
FQLineEdit,
getspinbox,
selectcolor,
SplitLine,
@ -211,12 +209,9 @@ class ClickableLabel(QLabel):
clicked = pyqtSignal()
class tagitem(QWidget):
# website
TYPE_GLOABL_LIKE = 3
TYPE_GAME_LIKE = 1
class tagitem(QFrame):
# search game
TYPE_RAND = 0
TYPE_SEARCH = 0
TYPE_DEVELOPER = 1
TYPE_TAG = 2
TYPE_USERTAG = 3
@ -224,132 +219,58 @@ class tagitem(QWidget):
removesignal = pyqtSignal(tuple)
labelclicked = pyqtSignal(tuple)
def remove(self):
self.hide()
_lay = self.layout()
_ws = []
for i in range(_lay.count()):
witem = _lay.itemAt(i)
_ws.append(witem.widget())
for w in _ws:
_lay.removeWidget(w)
@staticmethod
def setstyles(parent: QWidget):
parent.setStyleSheet(
"""
tagitem#red {
border: 1px solid red;
}
tagitem#black {
border: 1px solid black;
}
tagitem#green {
border: 1px solid green;
}
tagitem#blue {
border: 1px solid blue;
}
tagitem#yellow {
border: 1px solid yellow;
}
"""
)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
if self._type == tagitem.TYPE_RAND:
border_color = Qt.GlobalColor.black
elif self._type == tagitem.TYPE_DEVELOPER:
border_color = Qt.GlobalColor.red
elif self._type == tagitem.TYPE_TAG:
border_color = Qt.GlobalColor.green
elif self._type == tagitem.TYPE_USERTAG:
border_color = Qt.GlobalColor.blue
elif self._type == tagitem.TYPE_EXISTS:
border_color = Qt.GlobalColor.yellow
border_width = 1
pen = QPen(border_color)
pen.setWidth(border_width)
painter.setPen(pen)
painter.drawRect(self.rect())
def __init__(self, tag, removeable=True, _type=TYPE_RAND, refdata=None) -> None:
def __init__(self, tag, removeable=True, _type=TYPE_SEARCH, refdata=None) -> None:
super().__init__()
if _type == tagitem.TYPE_SEARCH:
border_color = "black"
elif _type == tagitem.TYPE_DEVELOPER:
border_color = "red"
elif _type == tagitem.TYPE_TAG:
border_color = "green"
elif _type == tagitem.TYPE_USERTAG:
border_color = "blue"
elif _type == tagitem.TYPE_EXISTS:
border_color = "yellow"
self.setObjectName(border_color)
tagLayout = QHBoxLayout()
tagLayout.setContentsMargins(0, 0, 0, 0)
tagLayout.setSpacing(0)
self._type = _type
key = (tag, _type, refdata)
self.setLayout(tagLayout)
lb = ClickableLabel()
lb.setStyleSheet("background: transparent;")
lb.setText(tag)
lb.clicked.connect(functools.partial(self.labelclicked.emit, key))
tagLayout.addWidget(lb)
if removeable:
button = getIconButton(
functools.partial(self.removesignal.emit, key), icon="fa.times"
)
tagLayout.addWidget(button)
class TagWidget(QWidget):
tagschanged = pyqtSignal(tuple) # ((tag,type,refdata),)
linepressedenter = pyqtSignal(str)
tagclicked = pyqtSignal(tuple) # tag,type,refdata
def __init__(self, parent=None, exfoucus=True):
super().__init__(parent)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
self.lineEdit = FocusCombo()
if exfoucus:
self.lineEdit.setLineEdit(FQLineEdit())
# FQLineEdit导致游戏管理页面里点击编辑框后下边界消失。
# FQLineEdit仅用于和webview同一窗口内焦点缺失问题所以既然用不到那就不要多此一举了
else:
self.lineEdit.setEditable(True)
self.lineEdit.lineEdit().returnPressed.connect(
lambda: self.linepressedenter.emit(self.lineEdit.currentText())
)
self.lineEdit.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum
)
layout.addWidget(self.lineEdit)
self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
self.tag2widget = {}
def addTags(self, tags, signal=True):
for key in tags:
self.__addTag(key)
self.__calltagschanged(signal)
@tryprint
def __addTag(self, key):
tag, _type, refdata = key
if not tag:
return
if key in self.tag2widget:
return
qw = tagitem(tag, _type=_type, refdata=refdata)
qw.removesignal.connect(self.removeTag)
qw.labelclicked.connect(self.tagclicked.emit)
layout = self.layout()
layout.insertWidget(layout.count() - 1, qw)
self.tag2widget[key] = qw
self.lineEdit.setFocus()
def addTag(self, tag, _type, refdata=None, signal=True):
self.__addTag((tag, _type, refdata))
self.__calltagschanged(signal)
@tryprint
def __removeTag(self, key):
_w = self.tag2widget[key]
_w.remove()
self.layout().removeWidget(_w)
self.tag2widget.pop(key)
def removeTag(self, key, signal=True):
self.__removeTag(key)
self.__calltagschanged(signal)
def __calltagschanged(self, signal):
if signal:
self.tagschanged.emit(tuple(self.tag2widget.keys()))
def clearTag(self, signal=True):
for key in self.tag2widget.copy():
self.__removeTag(key)
self.__calltagschanged(signal)
tagLayout.addWidget(lb)
def opendirforgameuid(gameuid):

View File

@ -4,7 +4,7 @@ from qtsymbols import *
import functools, uuid
from datetime import datetime, timedelta
from traceback import print_exc
import gobject
import gobject, winsharedutils
from myutils.config import (
savehook_new_data,
uid2gamepath,
@ -16,7 +16,7 @@ from myutils.config import (
)
from myutils.localetools import getgamecamptools, maycreatesettings
from myutils.hwnd import getExeIcon
from myutils.wrapper import Singleton, Singleton_close, trypass
from myutils.wrapper import Singleton, Singleton_close
from myutils.utils import (
gamdidchangedtask,
checkpostlangmatch,
@ -34,9 +34,10 @@ from gui.inputdialog import (
autoinitdialog_items,
postconfigdialog,
)
from gui.specialwidget import ScrollFlow, chartwidget
from gui.specialwidget import chartwidget
from gui.usefulwidget import (
TableViewW,
FlowWidget,
getsimpleswitch,
getsimplepatheditor,
getboxlayout,
@ -50,6 +51,8 @@ from gui.usefulwidget import (
getspinbox,
getsmalllabel,
listediterline,
editswitchTextBrowser,
FocusCombo,
)
from gui.dynalang import (
LFormLayout,
@ -61,6 +64,7 @@ from gui.dynalang import (
LGroupBox,
)
from gui.dialog_savedgame_common import tagitem
from gui.inputdialog import postconfigdialog_
@Singleton
@ -183,11 +187,11 @@ def maybehavebutton(self, gameuid, post):
return None
def userlabelset():
def userlabelset(key="usertags"):
s = set()
for gameuid in savehook_new_data:
s = s.union(savehook_new_data[gameuid]["usertags"])
return list(s)
s = s.union(savehook_new_data[gameuid][key])
return sorted(list(s))
class dialog_setting_game_internal(QWidget):
@ -199,8 +203,9 @@ class dialog_setting_game_internal(QWidget):
if self.lauchpath:
self.lauchpath.clear.clicked.emit()
def __init__(self, parent, gameuid) -> None:
def __init__(self, parent, gameuid, keepindexobject=None) -> None:
super().__init__(parent)
self.keepindexobject = keepindexobject
vbox = QVBoxLayout(self)
self.lauchpath = None
formLayout = LFormLayout()
@ -253,6 +258,11 @@ class dialog_setting_game_internal(QWidget):
[_[0] for _ in functs],
[functools.partial(self.doaddtab, _[1], gameuid) for _ in functs],
delay=True,
initial=(
(self.keepindexobject, "p1")
if (self.keepindexobject is not None)
else None
),
)
vbox.addLayout(formLayout)
vbox.addWidget(methodtab)
@ -285,12 +295,17 @@ class dialog_setting_game_internal(QWidget):
functs = [
("元数据", functools.partial(self.___tabf, self.metadataorigin)),
("统计", functools.partial(self.___tabf2, self.getstatistic)),
("标签", functools.partial(self.___tabf2, self.getlabelsetting)),
("信息", functools.partial(self.___tabf2, self.getlabelsetting)),
]
methodtab, do = makesubtab_lazy(
[_[0] for _ in functs],
[functools.partial(self.doaddtab, _[1], gameuid) for _ in functs],
delay=True,
initial=(
(self.keepindexobject, "gamedata")
if (self.keepindexobject is not None)
else None
),
)
vbox.addWidget(methodtab)
do()
@ -310,6 +325,11 @@ class dialog_setting_game_internal(QWidget):
[_[0] for _ in functs],
[functools.partial(self.doaddtab, _[1], gameuid) for _ in functs],
delay=True,
initial=(
(self.keepindexobject, "gamesetting")
if (self.keepindexobject is not None)
else None
),
)
self.methodtab = methodtab
@ -556,74 +576,106 @@ class dialog_setting_game_internal(QWidget):
string = "0"
return string
def tagenewitem(
self,
gameuid,
text,
refkey,
first=False,
_type=tagitem.TYPE_SEARCH,
):
if _type == tagitem.TYPE_TAG:
text = globalconfig["tagNameRemap"].get(text, text)
qw = tagitem(text, True, _type)
def __(gameuid, _qw, refkey, _):
t, _, _ = _
try:
savehook_new_data[gameuid][refkey].remove(t)
self.flowwidget.removeWidget(_qw)
except:
print_exc()
qw.removesignal.connect(functools.partial(__, gameuid, qw, refkey))
def safeaddtags(_):
try:
gobject.global_dialog_savedgame_new.tagswidget.addTag(*_)
except:
winsharedutils.clipboard_set(_[0])
qw.labelclicked.connect(safeaddtags)
if first:
self.flowwidget.insertWidget(self.labelflowmap[refkey], 1, qw)
else:
self.flowwidget.addWidget(self.labelflowmap[refkey], qw)
def getlabelsetting(self, formLayout: QVBoxLayout, gameuid):
self.labelflow = ScrollFlow()
self.labelflowmap = {}
flowwidget = FlowWidget(groups=4)
tagitem.setstyles(flowwidget)
self.flowwidget = flowwidget
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setWidget(flowwidget)
formLayout.addWidget(scroll)
self.tagtypes = ["developers", "webtags", "usertags"]
self.tagtypes_zh = ["开发商", "标签", "自定义"]
self.tagtypes_1 = [
tagitem.TYPE_DEVELOPER,
tagitem.TYPE_TAG,
tagitem.TYPE_USERTAG,
]
def newitem(text, refkey, first=False, _type=tagitem.TYPE_RAND):
qw = tagitem(text, True, _type)
def createflows(label, key, _t, index):
self.labelflowmap[key] = index
flowwidget.addWidget(index, LLabel(label))
for tag in savehook_new_data[gameuid][key]:
self.tagenewitem(gameuid, tag, key, _type=_t)
def __(gameuid, _qw, refkey, _):
t, _type, _ = _
try:
_qw.remove()
savehook_new_data[gameuid][refkey].remove(t)
self.labelflow.removewidget(_qw)
except:
print_exc()
for i in range(len(self.tagtypes)):
createflows(self.tagtypes_zh[i], self.tagtypes[i], self.tagtypes_1[i], i)
flowwidget.addWidget(3, LLabel("简介"))
edit = editswitchTextBrowser()
edit.settext(savehook_new_data[gameuid].get("description", ""))
qw.removesignal.connect(functools.partial(__, gameuid, qw, refkey))
def safeaddtags(_):
try:
gobject.global_dialog_savedgame_new.tagswidget.addTag(*_)
except:
pass
qw.labelclicked.connect(safeaddtags)
if first:
self.labelflow.insertwidget(0, qw)
def __():
if not edit.text().strip():
savehook_new_data[gameuid]["description"] = ""
else:
self.labelflow.addwidget(qw)
savehook_new_data[gameuid]["description"] = edit.text().strip()
for tag in savehook_new_data[gameuid]["usertags"]:
newitem(tag, "usertags", _type=tagitem.TYPE_USERTAG)
for tag in savehook_new_data[gameuid]["developers"]:
newitem(tag, "developers", _type=tagitem.TYPE_DEVELOPER)
for tag in savehook_new_data[gameuid]["webtags"]:
newitem(tag, "webtags", _type=tagitem.TYPE_TAG)
formLayout.addWidget(self.labelflow)
_dict = {"new": 0}
edit.textChanged.connect(__)
flowwidget.addWidget(3, edit)
formLayout.addWidget(self.labelflow)
button = LPushButton("添加")
combo = getsimplecombobox(userlabelset(), _dict, "new", static=True)
typecombo = getsimplecombobox(self.tagtypes_zh, initial=2)
combo = FocusCombo()
combo.setEditable(True)
combo.clearEditText()
def __(idx):
t = combo.currentText()
combo.clear()
combo.addItems(userlabelset(self.tagtypes[idx]))
combo.setCurrentText(t)
typecombo.currentIndexChanged.connect(__)
__(2)
def _add(_):
labelset = userlabelset()
tag = combo.currentText()
if (not tag) or (tag in savehook_new_data[gameuid]["usertags"]):
tp = self.tagtypes[typecombo.currentIndex()]
if (not tag) or (tag in savehook_new_data[gameuid][tp]):
return
savehook_new_data[gameuid]["usertags"].insert(0, tag)
newitem(tag, "usertags", first=True, _type=tagitem.TYPE_USERTAG)
savehook_new_data[gameuid][tp].insert(0, tag)
self.tagenewitem(
gameuid,
tag,
tp,
first=True,
_type=self.tagtypes_1[typecombo.currentIndex()],
)
combo.clearEditText()
combo.clear()
combo.addItems(labelset)
try:
_ = (
gobject.global_dialog_savedgame_new.tagswidget.lineEdit.currentText()
)
gobject.global_dialog_savedgame_new.tagswidget.lineEdit.clear()
gobject.global_dialog_savedgame_new.tagswidget.lineEdit.addItems(
labelset
)
gobject.global_dialog_savedgame_new.tagswidget.lineEdit.setCurrentText(
_
)
except:
pass
button.clicked.connect(_add)
@ -631,11 +683,18 @@ class dialog_setting_game_internal(QWidget):
getboxlayout(
[
combo,
typecombo,
button,
getIconButton(callback=self.edittagremap, icon="fa.gear"),
]
)
)
def edittagremap(self):
postconfigdialog_(
self, globalconfig["tagNameRemap"], "标签映射", ["From", "To"]
)
def createfollowdefault(
self,
dic: dict,
@ -1111,7 +1170,7 @@ def calculate_centered_rect(original_rect: QRect, size: QSize) -> QRect:
@Singleton_close
class dialog_setting_game(LDialog):
class dialog_setting_game(QDialog):
def __init__(self, parent, gameuid, setindexhook=0) -> None:
super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)

View File

@ -669,7 +669,11 @@ class dialog_savedgame_v3(QWidget):
tabadd_lazy(
self.righttop,
"设置",
lambda v: v.addWidget(dialog_setting_game_internal(self, k)),
lambda v: v.addWidget(
dialog_setting_game_internal(
self, k, keepindexobject=self.keepindexobject
)
),
)
self.righttop.setCurrentIndex(currvis)
except:
@ -835,6 +839,22 @@ class dialog_savedgame_v3(QWidget):
)
self.setStyleSheet(style)
def movefocus(self, dx):
uid = self.currentfocusuid
idx1 = self.reallist[self.reftagid].index(uid)
idx2 = (idx1 + dx) % len(self.reallist[self.reftagid])
group0 = self.stack.w(calculatetagidx(self.reftagid))
if idx1 == 0 and dx == -1:
self.stack.verticalScrollBar().setValue(
self.stack.verticalScrollBar().maximum()
)
else:
self.stack.ensureWidgetVisible(group0.w(idx2))
try:
group0.w(idx2).click()
except:
pass
def __init__(self, parent) -> None:
super().__init__(parent)
parent.setWindowTitle("游戏管理")
@ -842,21 +862,29 @@ class dialog_savedgame_v3(QWidget):
self.currentfocusuid = None
self.reftagid = None
self.reallist = {}
self.keepindexobject = {}
class ___(stackedlist):
def keyPressEvent(self, e: QKeyEvent):
if e.key() == Qt.Key.Key_Return:
startgamecheck(
self.ref,
getreflist(self.ref.reftagid),
self.ref.currentfocusuid,
)
elif e.key() == Qt.Key.Key_Delete:
self.ref.shanchuyouxi()
elif e.key() == Qt.Key.Key_Left:
self.ref.moverank(-1)
elif e.key() == Qt.Key.Key_Right:
self.ref.moverank(1)
if self.ref.currentfocusuid:
if e.key() == Qt.Key.Key_Return:
startgamecheck(
self.ref,
getreflist(self.ref.reftagid),
self.ref.currentfocusuid,
)
elif e.key() == Qt.Key.Key_Delete:
self.ref.shanchuyouxi()
elif e.key() == Qt.Key.Key_Left:
self.ref.moverank(-1)
elif e.key() == Qt.Key.Key_Right:
self.ref.moverank(1)
elif e.key() == Qt.Key.Key_Down:
self.ref.movefocus(1)
return e.ignore()
elif e.key() == Qt.Key.Key_Up:
self.ref.movefocus(-1)
return e.ignore()
super().keyPressEvent(e)
self.stack = ___()
@ -1047,6 +1075,9 @@ class dialog_savedgame_v3(QWidget):
)
self.stack.w(calculatetagidx(self.reftagid)).switchidx(idx1, idx2)
self.stack.ensureWidgetVisible(
self.stack.w(calculatetagidx(self.reftagid)).w(idx2)
)
idx1 = getreflist(self.reftagid).index(uid)
idx2 = getreflist(self.reftagid).index(uid2)
getreflist(self.reftagid).insert(idx2, getreflist(self.reftagid).pop(idx1))

View File

@ -452,19 +452,6 @@ class autoinitdialog__(LDialog):
super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)
self.setWindowTitle(title)
self.resize(QSize(width, 10))
for line in lines:
if line["type"] != "program":
continue
try:
func = getattr(
importlib.import_module(line["route"][0]),
line["route"][1],
)
func(self)
except:
print_exc()
self.show()
return
formLayout = VisLFormLayout()
self.setLayout(formLayout)
regist = {}

View File

@ -5,7 +5,7 @@ from myutils.config import globalconfig, static_data, _TR, get_platform
from myutils.wrapper import threader, tryprint
from myutils.hwnd import getcurrexe
from myutils.utils import makehtml, getlanguse, dynamiclink
import requests, sys
import requests, importlib
import shutil, gobject
from myutils.proxy import getproxy
import zipfile, os
@ -13,12 +13,15 @@ import subprocess
from gui.usefulwidget import (
D_getsimpleswitch,
makescrollgrid,
CollapsibleBox,
makesubtab_lazy,
D_getsimplecombobox,
makegrid,
D_getIconButton,
WebivewWidget,
)
from gui.dynalang import LLabel
from gui.setting_year import yearsummary
versionchecktask = queue.Queue()
@ -248,39 +251,6 @@ def versionlabelmaybesettext(self, x):
self.versionlabel_cache = x
def solvelinkitems(grid, source):
name = source["name"]
link = source["link"]
grid.append([name, (makehtml(link), 2, "link")])
def resourcegrid(self, l):
titles = []
makewidgetsfunctions = []
for sourcetype in static_data["aboutsource"]:
titles.append(sourcetype["name"])
sources = sourcetype["sources"]
grid = []
for source in sources:
__grid = []
for link in source["links"]:
__grid.append([link["name"], (makehtml(link["link"]), 2, "link")])
grid.append(
[
(
dict(title=source.get("name", None), type="grid", grid=__grid),
0,
"group",
)
]
)
makewidgetsfunctions.append(functools.partial(makescrollgrid, grid))
tab, dotab = makesubtab_lazy(titles, makewidgetsfunctions, delay=True)
l.addWidget(tab)
dotab()
def createimageview(self):
lb = QLabel()
img = QPixmap.fromImage(QImage("./files/zan.jpg"))
@ -295,17 +265,60 @@ def createimageview(self):
return lb
def setTab_aboutlazy(self, basel):
resourcegrid(self, basel)
def changelog(self, basel: QHBoxLayout):
_ = WebivewWidget(self)
_.navigate(dynamiclink("{main_server}/ChangeLog"))
basel.addWidget(_)
def delayloadlinks(key, box):
sources = static_data["aboutsource"][key]
grid = []
for source in sources:
__grid = []
function = source.get("function")
if function:
func = getattr(
importlib.import_module(function[0]),
function[1],
)
__grid.append([(func, 0)])
else:
for link in source["links"]:
__grid.append(
[link["name"], (makehtml(link["link"]), 2, "link")]
+ ([link.get("about")] if link.get("about") else [])
)
grid.append(
[
(
dict(title=source.get("name", None), type="grid", grid=__grid),
0,
"group",
)
]
)
grid = [
[
(
dict(type="grid", grid=grid),
0,
"group",
)
]
]
w, do = makegrid(grid, delay=True, w=False)
w.setContentsMargins(0, 0, 0, 0)
box.content_area.setLayout(w)
do()
def offlinelinks(key):
box = CollapsibleBox("下载")
box.setdelayload(functools.partial(delayloadlinks, key))
return box
def setTab_about1(self, basel):
shuominggrid = [
@ -363,12 +376,12 @@ def setTab_about1(self, basel):
def setTab_about(self, basel):
tab_widget, do = makesubtab_lazy(
["关于软件", "其他设置", "资源下载", "更新记录"],
["关于软件", "其他设置", "更新记录", "年度总结"],
[
functools.partial(setTab_about1, self),
functools.partial(setTab_update, self),
functools.partial(setTab_aboutlazy, self),
functools.partial(changelog, self),
functools.partial(yearsummary, self),
],
delay=True,
)
@ -384,6 +397,7 @@ def changeUIlanguage(_):
except:
pass
def setTab_update(self, basel):
version = winsharedutils.queryversion(getcurrexe())
if version is None:

View File

@ -22,6 +22,7 @@ from gui.usefulwidget import (
D_getsimplecombobox,
)
from gui.showword import showdiction
from gui.setting_about import offlinelinks
def setTabcishu(self, basel):
@ -217,6 +218,7 @@ def setTabcishu_l(self):
)
]
grids = [
[(functools.partial(offlinelinks, "dict"), 0)],
grids_1,
grids2,
[],

View File

@ -11,6 +11,7 @@ from gui.usefulwidget import (
makescrollgrid,
D_getsimpleswitch,
)
from gui.setting_about import offlinelinks
def makescalew(self, lay: QVBoxLayout):
@ -333,6 +334,7 @@ def makescalew(self, lay: QVBoxLayout):
),
("", 10),
],
[(functools.partial(offlinelinks, "magpie"),0)],
]
commonfsgrid = [

View File

@ -98,7 +98,7 @@ def makegridW(grid, lay, save=False, savelist=None, savelay=None):
def makeproxytab():
lixians, pre, mianfei, develop, shoufei = splittranslatortypes()
lixians, pre, mianfei, shoufei = splittranslatortypes()
mianfei = getall(l=mianfei, item="fanyi", name="./Lunatranslator/translator/%s.py")
shoufei = getall(l=shoufei, item="fanyi", name=translate_exits)

View File

@ -28,6 +28,7 @@ import gobject, qtawesome
from gui.dynalang import LFormLayout, LDialog, LAction
from myutils.ocrutil import ocr_end, ocr_init, ocr_run
from myutils.wrapper import threader, Singleton_close
from gui.setting_about import offlinelinks
def __label1(self):
@ -385,14 +386,17 @@ class showocrimage(saveposwindow):
def internal(self):
offline, online = splitocrtypes(globalconfig["ocr"])
offgrids = initgridsources(self, offline)
offgrids += [
[(functools.partial(offlinelinks, "ocr"), 0)],
]
engines = [
[
(
dict(
title="离线",
type="grid",
grid=initgridsources(self, offline),
grid=offgrids,
),
0,
"group",

View File

@ -1,7 +1,7 @@
from qtsymbols import *
import functools, os
import gobject, qtawesome, uuid, shutil
from myutils.config import globalconfig, translatorsetting
from myutils.config import globalconfig, translatorsetting, static_data
from myutils.utils import (
selectdebugfile,
splittranslatortypes,
@ -26,6 +26,7 @@ from gui.usefulwidget import (
makescrollgrid,
)
from gui.dynalang import LPushButton, LLabel, LAction
from gui.setting_about import offlinelinks
def deepcopydict(d):
@ -58,7 +59,7 @@ def splitapillm(l):
def loadvisinternal(btnplus, copy):
__vis = []
__uid = []
lixians, pre, mianfei, develop, shoufei = splittranslatortypes()
lixians, pre, mianfei, shoufei = splittranslatortypes()
if btnplus == "api":
is_gpt_likes, not_is_gpt_like = splitapillm(shoufei)
elif btnplus == "offline":
@ -161,6 +162,8 @@ def loadbutton(self, fanyi):
aclass = "translator." + fanyi
elif which == 1:
aclass = "userconfig.copyed." + fanyi
else:
return
return autoinitdialogx(
self,
translatorsetting[fanyi]["args"],
@ -222,18 +225,18 @@ def selectllmcallback(self, countnum, btnplus, fanyi, name):
),
)
if len(countnum) % 3 == 0:
offset = 5 * (len(countnum) % 3)
layout.addWidget(name, layout.rowCount() - 1, offset + 0)
layout.addWidget(swc, layout.rowCount() - 1, offset + 1)
layout.addWidget(color, layout.rowCount() - 1, offset + 2)
layout.addWidget(last, layout.rowCount() - 1, offset + 3)
if len(countnum) % 3 != 2:
layout.addWidget(QLabel(), layout.rowCount() - 1, offset + 4)
else:
layout.addWidget(
getattr(self, "btnmany" + btnplus), layout.rowCount(), 5 * 2, 1, 4
)
offset = 5 * (len(countnum) % 3)
layout.addWidget(name, layout.rowCount() - 2, offset + 0)
layout.addWidget(swc, layout.rowCount() - 2, offset + 1)
layout.addWidget(color, layout.rowCount() - 2, offset + 2)
layout.addWidget(last, layout.rowCount() - 2, offset + 3)
if len(countnum) % 3 != 2:
layout.addWidget(QLabel(), layout.rowCount() - 2, offset + 4)
countnum.append(uid)
@ -393,12 +396,12 @@ def initsome11(self, l, label=None, btnplus=False):
if len(line):
grids.append(line)
if btnplus:
grids.append(
[
("", 10),
(functools.partial(createmanybtn, self, countnum, btnplus), 4),
]
)
if i % 3 == 0:
grids.append([])
if i % 3 != 2:
grids[-1].append(("", 5 * (2 - i % 3)))
grids[-1].append((functools.partial(createmanybtn, self, countnum, btnplus), 4))
return grids
@ -434,7 +437,6 @@ def initsome2(self, l, label=None, btnplus=None):
return grids
def createbtnexport(self):
bt = LPushButton("导出翻译记录为json文件")
@ -512,20 +514,11 @@ def setTabTwo_lazy(self, basel: QVBoxLayout):
],
[],
]
_items = [
{
"type": "file",
"dir": False,
"filter": "*.exe",
"name": "Chromium_路径",
"k": "chromepath",
},
{"type": "okcancel"},
]
lixians, pre, mianfei, develop, shoufei = splittranslatortypes()
lixians, pre, mianfei, shoufei = splittranslatortypes()
offlinegrid = initsome2(self, lixians, btnplus="offline")
offlinegrid += [[functools.partial(offlinelinks, "translate")]]
onlinegrid = initsome11(self, mianfei)
online_reg_grid += initsome2(self, shoufei, btnplus="api")
pretransgrid += initsome11(self, pre)

View File

@ -9,6 +9,7 @@ from gui.inputdialog import (
autoinitdialog,
yuyinzhidingsetting,
)
from gui.setting_about import offlinelinks
from gui.setting_textinput import loadvalidtss
from gui.usefulwidget import (
D_getsimplecombobox,
@ -131,6 +132,10 @@ def setTab5lz(self):
grids = []
offline, online = splitocrtypes(globalconfig["reader"])
alltrans, alltransvis = loadvalidtss()
offilesgrid = getttsgrid(self, offline)
offilesgrid += [
[(functools.partial(offlinelinks, "tts"), 0)],
]
grids += [
[
(
@ -143,7 +148,7 @@ def setTab5lz(self):
dict(
title="离线",
type="grid",
grid=getttsgrid(self, offline),
grid=offilesgrid,
),
0,
"group",

View File

@ -0,0 +1,223 @@
from qtsymbols import *
import queue
import gobject
import os
from gui.usefulwidget import WebivewWidget
from datetime import datetime, timedelta
from myutils.config import savehook_new_data, globalconfig
timestamps = [1609459200, 1672531200, 1704067200, 1720032000]
def split_range_into_days(times):
everyday = {}
for start, end in times:
if start == 0:
everyday[0] = end
continue
start_date = datetime.fromtimestamp(start)
end_date = datetime.fromtimestamp(end)
current_date = start_date
while current_date <= end_date:
end_of_day = current_date.replace(
hour=23, minute=59, second=59, microsecond=0
)
end_of_day = end_of_day.timestamp() + 1
if end_of_day >= end_date.timestamp():
useend = end_date.timestamp()
else:
useend = end_of_day
duration = useend - current_date.timestamp()
today = end_of_day - 1
if today not in everyday:
everyday[today] = 0
everyday[today] += duration
current_date += timedelta(days=1)
current_date = current_date.replace(
hour=0, minute=0, second=0, microsecond=0
)
return everyday
def calc_uid_times(inf):
everytimes = {}
for uid, ls in inf.items():
x = 0
for s, e in ls:
x += e - s
if int(x):
everytimes[uid] = x
return everytimes
def spliteverygameinmothon(yearinfos):
allmonths = []
for uid in yearinfos:
everydays = split_range_into_days(yearinfos, uidx=uid)
everymonth = group_by_month(everydays)
def getthisyearinfo(allinfos):
current_year = datetime.now().year
yearinfos = {}
for uid, ls in allinfos.items():
yearinfos[uid] = []
for s, e in ls:
if datetime.fromtimestamp(s).year == current_year:
yearinfos[uid].append((s, e))
if len(yearinfos[uid]) == 0:
yearinfos.pop(uid)
return yearinfos
def geteverygameeveryday(yearinfos):
x = {}
for uid, ls in yearinfos.items():
x[uid] = split_range_into_days(ls)
return x
def group_by_month(timerangeindays):
every = {}
for uid, ls in timerangeindays.items():
inmonths = {}
for day, time in ls.items():
# 将时间戳转换为日期对象时间戳为毫秒需要除以1000
date = datetime.fromtimestamp(day)
if date.month not in inmonths:
inmonths[date.month] = 0
inmonths[date.month] += time
every[uid] = inmonths
return every
def have_game_days_count(everydays):
days = set()
for info in everydays.values():
for d in info:
days.add(d)
return len(days)
def everymonths_game_images(everymonth):
months = {}
for i in range(1, 13):
months[i] = {}
for uid in everymonth:
for m, tm in everymonth[uid].items():
months[m][uid] = tm
return months
def getuidimage(uid):
data = savehook_new_data.get(uid)
if not data:
return
main = savehook_new_data[uid].get("currentmainimage")
if (main in savehook_new_data[uid]["imagepath_all"]) and os.path.exists(main):
return os.path.abspath(main)
else:
for _ in savehook_new_data[uid]["imagepath_all"]:
if os.path.exists(_):
return os.path.abspath(_)
def guji_word(everytimes, alleverytimes):
cnt_zishu = 0
for uid in everytimes:
data = savehook_new_data.get(uid)
if not data:
continue
if not everytimes[uid]:
return
cnt_zishu += (
data.get("statistic_wordcount", 0) * everytimes[uid] / alleverytimes[uid]
)
return cnt_zishu
def getimages(xx):
uids = list(xx.keys())
uids.sort(key=lambda x: -xx[x])
tu = []
for uid in uids:
img = getuidimage(uid)
if img:
tu.append(img)
return tu
def getallgamelabels(yearinfos):
developers = {}
webtags = {}
# 可以考虑玩的最多的游戏的标签,和玩的时间最长的标签
for uid in yearinfos:
data = savehook_new_data.get(uid)
if not data:
continue
img = getuidimage(uid)
if not img:
continue
for dev in data["developers"]:
if dev not in developers:
developers[dev] = []
developers[dev].append(img)
for tag in data["webtags"]:
tag = globalconfig["tagNameRemap"].get(tag, tag)
if tag not in webtags:
webtags[tag] = []
webtags[tag].append(img)
return developers, webtags
def yearsummary(self, basel: QHBoxLayout):
allinfos = gobject.baseobject.playtimemanager.all() # {uid:[[s,e]]}
yearinfos = getthisyearinfo(allinfos) # {uid:[[s,e]]}
alleverytimes = calc_uid_times(allinfos) # {uid:time}
everytimes = calc_uid_times(yearinfos) # {uid:time}
everydays = geteverygameeveryday(yearinfos) # {uid:{day_tms:time}}
everymonth = group_by_month(everydays) # {uid:{month:time}}
everymonth_uid_time = everymonths_game_images(everymonth) # {month:{uid:time}}
everymonth_time = {
k: sum(v.values()) for k, v in everymonth_uid_time.items()
} # {month:time}
uids = list(everytimes.keys())
uids.sort(key=lambda x: -everytimes[x])
tu = getimages(everytimes)
tu_m = {}
for m, info in everymonth_uid_time.items():
tu_m[m] = getimages(info)
developer, webtags = getallgamelabels(yearinfos)
_ = WebivewWidget(self)
with open("files/yearsummary/yearsummary.value.js", "w", encoding="utf8") as ff2:
ff2.write(
r"""
GAMES_YEAR_PLAYED={GAMES_YEAR_PLAYED}
TIME_YEAR_PLAYED={TIME_YEAR_PLAYED}
COUNT_ZISHU_YEAR_PLAYED={COUNT_ZISHU_YEAR_PLAYED}
TIME_YEAR_PLAYED_DAY={TIME_YEAR_PLAYED_DAY}
TOP25_TIME_IMAGE={TOP25_TIME_IMAGE}
TOP25_TIME_IMAGE_M={TOP25_TIME_IMAGE_M}
everymonth_time={everymonth_time}
developer={developer}
webtags={webtags}
""".format(
developer=developer,
webtags=webtags,
GAMES_YEAR_PLAYED=len(everytimes),
TIME_YEAR_PLAYED=int(sum(everytimes.values()) / 3600),
COUNT_ZISHU_YEAR_PLAYED=int(guji_word(everytimes, alleverytimes)),
TIME_YEAR_PLAYED_DAY=have_game_days_count(everydays),
TOP25_TIME_IMAGE=tu,
TOP25_TIME_IMAGE_M=tu_m,
everymonth_time=everymonth_time,
)
)
_.navigate(os.path.abspath("files/yearsummary/yearsummary.html"))
basel.addWidget(_)

View File

@ -153,165 +153,6 @@ class ScrollArea(QScrollArea):
super().keyPressEvent(e)
class ScrollFlow(QWidget):
bgclicked = pyqtSignal()
def resizeEvent(self, a0) -> None:
self.qscrollarea.resize(self.size())
return super().resizeEvent(a0)
def __init__(self):
super(ScrollFlow, self).__init__()
class qw(QWidget):
def mousePressEvent(_, _2) -> None:
self.bgclicked.emit()
self.listWidget = qw(self)
# self.listWidget.setFixedWidth(600)
self.lazyitems = []
self.lazydoneidx = []
self.l = FlowLayout()
self.listWidget.setLayout(self.l)
self.qscrollarea = QScrollArea(self)
self.qscrollarea.setWidgetResizable(True)
self.qscrollarea.setWidget(self.listWidget)
@trypass
def addwidget(self, wid):
self.l.addWidget(wid)
@trypass
def insertwidget(self, idx, wid):
self.l.insertWidget(idx, wid)
@trypass
def removewidget(self, wid):
self.l.removeWidget(wid)
@trypass
def removeidx(self, index):
_ = self.l.takeAt(index)
_.widget().hide()
@trypass
def setfocus(self, idx):
self.widget(idx).setFocus()
@trypass
def widget(self, idx):
idx = min(idx, len(self.l._item_list) - 1)
idx = max(idx, 0)
return self.l._item_list[idx].widget()
class FlowLayout(QLayout):
heightChanged = pyqtSignal(int)
def __init__(self, parent=None, margin=0, spacing=-1):
super().__init__(parent)
if parent is not None:
self.setContentsMargins(margin, margin, margin, margin)
self.setSpacing(spacing)
self._item_list = []
def __del__(self):
while self.count():
self.takeAt(0)
def insertWidget(self, idx, widget):
item = QWidgetItem(widget)
widget.setParent(self.parentWidget())
widget.adjustSize()
widget.setVisible(True)
self._item_list.insert(idx, item)
self._do_layout(self.geometry(), False)
def addItem(self, item): # pylint: disable=invalid-name
self._item_list.append(item)
def addSpacing(self, size): # pylint: disable=invalid-name
self.addItem(
QSpacerItem(size, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
)
def count(self):
return len(self._item_list)
def itemAt(self, index): # pylint: disable=invalid-name
if 0 <= index < len(self._item_list):
return self._item_list[index]
return None
def takeAt(self, index): # pylint: disable=invalid-name
if 0 <= index < len(self._item_list):
return self._item_list.pop(index)
return None
def setGeometry(self, rect): # pylint: disable=invalid-name
super().setGeometry(rect)
self._do_layout(rect, False)
def sizeHint(self): # pylint: disable=invalid-name
return self.minimumSize()
def minimumSize(self): # pylint: disable=invalid-name
size = QSize()
for item in self._item_list:
minsize = item.minimumSize()
extent = item.geometry().bottomRight()
size = size.expandedTo(QSize(minsize.width(), extent.y()))
margin = self.contentsMargins().left()
size += QSize(2 * margin, 2 * margin)
return size
def _do_layout(self, rect, test_only=False):
m = self.contentsMargins()
effective_rect = rect.adjusted(+m.left(), +m.top(), -m.right(), -m.bottom())
x = effective_rect.x()
y = effective_rect.y()
line_height = 0
for item in self._item_list:
wid = item.widget()
space_x = self.spacing()
space_y = self.spacing()
if wid is not None:
space_x += wid.style().layoutSpacing(
QSizePolicy.ControlType.PushButton,
QSizePolicy.ControlType.PushButton,
Qt.Orientation.Horizontal,
)
space_y += wid.style().layoutSpacing(
QSizePolicy.ControlType.PushButton,
QSizePolicy.ControlType.PushButton,
Qt.Orientation.Vertical,
)
next_x = x + item.sizeHint().width() + space_x
if next_x - space_x > effective_rect.right() and line_height > 0:
x = effective_rect.x()
y = y + line_height + space_y
next_x = x + item.sizeHint().width() + space_x
line_height = 0
if not test_only:
sz = item.sizeHint()
item.setGeometry(QRect(QPoint(x, y), sz))
x = next_x
line_height = max(line_height, item.sizeHint().height())
new_height = y + line_height - rect.y()
self.heightChanged.emit(new_height)
return new_height
class lazyscrollflow(ScrollArea):
bgclicked = pyqtSignal()

View File

@ -1,9 +1,9 @@
from qtsymbols import *
import os, platform, functools, uuid, json, math, csv, io, pickle
import os, re, functools, uuid, json, math, csv, io, pickle
from traceback import print_exc
import windows, qtawesome, winsharedutils, gobject
from webviewpy import webview_native_handle_kind_t, Webview
from myutils.config import _TR, globalconfig, _TRL
from myutils.config import _TR, globalconfig
from myutils.wrapper import Singleton_close, tryprint
from myutils.utils import nowisdark, checkportavailable, checkisusingwine
from gui.dynalang import (
@ -913,8 +913,19 @@ def comboboxcallbackwrap(s: SuperCombo, d, k, call, _):
def getsimplecombobox(
lst, d, k, callback=None, fixedsize=False, internal=None, static=False, emit=False
lst,
d=None,
k=None,
callback=None,
fixedsize=False,
internal=None,
static=False,
initial=None,
):
if d is None:
d = {}
if initial is not None:
d[k] = initial
s = SuperCombo(static=static)
s.addItems(lst, internal)
@ -1772,8 +1783,14 @@ def makegroupingrid(args):
if title:
group.setTitle(title)
else:
_id = "luna" + str(uuid.uuid4())
group.setObjectName(_id)
group.setStyleSheet(
"QGroupBox{ margin-top:0px;} QGroupBox:title {margin-top: 0px;}"
"QGroupBox#"
+ _id
+ "{ margin-top:0px;} QGroupBox#"
+ _id
+ ":title {margin-top: 0px;}"
)
if _type == "grid":
@ -1858,16 +1875,18 @@ def automakegrid(grid: QGridLayout, lis, save=False, savelist=None):
grid.setRowMinimumHeight(nowr, 25)
def makegrid(grid=None, save=False, savelist=None, savelay=None, delay=False):
def makegrid(grid=None, save=False, savelist=None, savelay=None, delay=False, w=True):
class gridwidget(QWidget):
pass
gridlayoutwidget = gridwidget()
if w:
gridlayoutwidget = gridwidget()
gridlay = QGridLayout()
gridlay.setAlignment(Qt.AlignmentFlag.AlignTop)
gridlayoutwidget.setLayout(gridlay)
gridlayoutwidget.setStyleSheet("gridwidget{background-color:transparent;}")
if w:
gridlayoutwidget.setLayout(gridlay)
gridlayoutwidget.setStyleSheet("gridwidget{background-color:transparent;}")
def do(gridlay, grid, save, savelist, savelay):
automakegrid(gridlay, grid, save, savelist)
@ -1875,6 +1894,8 @@ def makegrid(grid=None, save=False, savelist=None, savelay=None, delay=False):
savelay.append(gridlay)
__do = functools.partial(do, gridlay, grid, save, savelist, savelay)
if not w:
gridlayoutwidget = gridlay
if not delay:
__do()
return gridlayoutwidget
@ -1899,14 +1920,17 @@ def makescrollgrid(grid, lay, save=False, savelist=None, savelay=None):
def makesubtab_lazy(
titles=None, functions=None, klass=None, callback=None, delay=False
titles=None, functions=None, klass=None, callback=None, delay=False, initial=None
):
if klass:
tab = klass()
tab: LTabWidget = klass()
else:
tab = LTabWidget()
def __(t, i):
def __(t: LTabWidget, initial, i):
if initial:
object, key = initial
object[key] = i
try:
w = t.currentWidget()
if "lazyfunction" in dir(w):
@ -1917,14 +1941,20 @@ def makesubtab_lazy(
if callback:
callback(i)
tab.currentChanged.connect(functools.partial(__, tab))
can = initial and (initial[1] in initial[0])
if not can:
tab.currentChanged.connect(functools.partial(__, tab, initial))
def __do(tab, titles, functions):
def __do(tab: LTabWidget, titles, functions, initial):
if titles and functions:
for i, func in enumerate(functions):
tabadd_lazy(tab, titles[i], func)
if can:
tab.setCurrentIndex(initial[0][initial[1]])
tab.currentChanged.connect(functools.partial(__, tab, initial))
tab.currentChanged.emit(initial[0][initial[1]])
___do = functools.partial(__do, tab, titles, functions)
___do = functools.partial(__do, tab, titles, functions, initial)
if not delay:
___do()
return tab
@ -2561,3 +2591,152 @@ class VisLFormLayout(LFormLayout):
label.widget().deleteLater()
tres.fieldItem.widget().hide()
self._row_vis[row_index] = visible
class CollapsibleBox(QWidget):
def setdelayload(self, func):
self.func = func
def __init__(self, title="", parent=None):
super(CollapsibleBox, self).__init__(parent)
self.toggle_button = QToolButton(text=title, checkable=True, checked=False)
self.toggle_button.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextBesideIcon
)
self.toggle_button.toggled.connect(self.on_toggled)
self.content_area = QWidget()
lay = QVBoxLayout(self)
lay.setSpacing(0)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.toggle_button)
lay.addWidget(self.content_area)
self.func = None
self.collapse()
def on_toggled(self, checked):
if checked:
if self.func:
self.func(self)
self.func = None
self.toggle_button.setIcon(qtawesome.icon("fa.chevron-down"))
self.content_area.setVisible(True)
else:
self.toggle_button.setIcon(qtawesome.icon("fa.chevron-right"))
self.content_area.setVisible(False)
def expand(self):
self.toggle_button.setChecked(True)
self.on_toggled(True)
def collapse(self):
self.toggle_button.setChecked(False)
self.on_toggled(False)
class editswitchTextBrowser(QWidget):
textChanged = pyqtSignal(str)
def heightForWidth(self, w):
return self.browser.heightForWidth(w)
def resizeEvent(self, a0):
self.switch.move(self.width() - self.switch.width(), 0)
return super().resizeEvent(a0)
def __init__(self, parent=None):
super().__init__(parent)
stack = QStackedWidget()
self.edit = QPlainTextEdit()
self.browser = QLabel()
self.browser.setAlignment(Qt.AlignmentFlag.AlignTop)
self.browser.setWordWrap(True)
self.browser.setTextInteractionFlags(
Qt.TextInteractionFlag.TextSelectableByMouse
)
self.edit.textChanged.connect(
lambda: (
self.browser.setText(
"<html>"
+ re.sub(
r'href="([^"]+)"',
"",
re.sub(r'src="([^"]+)"', "", self.edit.toPlainText()),
)
+ "</html>"
),
self.textChanged.emit(self.edit.toPlainText()),
)
)
stack.addWidget(self.browser)
stack.addWidget(self.edit)
l = QHBoxLayout()
self.setLayout(l)
l.setContentsMargins(0, 0, 0, 0)
l.addWidget(stack)
self.switch = MySwitch(self, icon="fa.edit")
self.switch.setFixedSize(QSize(25, 25))
self.switch.raise_()
self.switch.clicked.connect(lambda c: stack.setCurrentIndex(not c))
def settext(self, text):
self.edit.setPlainText(text)
def text(self):
return self.edit.toPlainText()
class FlowWidget(QWidget):
def __init__(self, parent=None, groups=3):
super().__init__(parent)
self.margin = QMargins(5, 5, 5, 5)
self.spacing = 5
self._item_list = [[] for _ in range(groups)]
def insertWidget(self, group, index, w: QWidget):
w.setParent(self)
w.show()
self._item_list[group].insert(index, w)
self.doresize()
def addWidget(self, group, w: QWidget):
self.insertWidget(group, len(self._item_list[group]), w)
def removeWidget(self, w: QWidget):
for _ in self._item_list:
if w in _:
_.remove(w)
w.deleteLater()
self.doresize()
break
def doresize(self):
line_height = 0
spacing = self.spacing
y = self.margin.left()
for listi in self._item_list:
x = self.margin.top()
for i, item in enumerate(listi):
next_x = x + item.sizeHint().width() + spacing
if (
next_x - spacing + self.margin.right() > self.width()
and line_height > 0
):
x = self.margin.top()
y = y + line_height + spacing
next_x = x + item.sizeHint().width() + spacing
size = item.sizeHint()
if (i == len(listi) - 1) and isinstance(item, editswitchTextBrowser):
w = self.width() - self.margin.right() - x
size = QSize(w, max(size.height(), item.heightForWidth(w)))
item.setGeometry(QRect(QPoint(x, y), size))
line_height = max(line_height, size.height())
x = next_x
y = y + line_height + spacing
self.setFixedHeight(y + self.margin.bottom() - spacing)
def resizeEvent(self, a0):
self.doresize()

View File

@ -157,6 +157,7 @@ class common:
developers = data.get("developers", [])
webtags = data.get("webtags", [])
imagepath_all = data.get("imagepath_all", [])
description=data.get('description',None)
normaled = [
os.path.abspath(_) for _ in savehook_new_data[gameuid]["imagepath_all"]
]
@ -175,6 +176,8 @@ class common:
_urls = [_[1] for _ in savehook_new_data[gameuid]["relationlinks"]]
if _url not in _urls:
savehook_new_data[gameuid]["relationlinks"].append((_vis, _url))
if description and not savehook_new_data[gameuid].get('description'):
savehook_new_data[gameuid]['description']=description
if namemap:
dedump = set()
for _ in savehook_new_data[gameuid]["namemap2"]:

View File

@ -346,7 +346,6 @@ class searcher(common):
response = self.proxysession.get(
"https://api.bgm.tv/v0/subjects/{}".format(sid), headers=headers
)
print(response.text)
try:
response = response.json()
except:
@ -384,4 +383,5 @@ class searcher(common):
"imagepath_all": [imagepath],
"webtags": vndbtags,
"developers": developers,
"description": response["summary"].replace("\n", "<br>"),
}

View File

@ -113,10 +113,14 @@ class searcher(common):
"https:" + _[0] for _ in re.findall('<div data-src="(.*?)"(.*?)>', inner)
]
print(imags1)
description = simplehtmlparser(
response.text, "div", '<div itemprop="description"'
)
print(description)
return {
"title": title,
"imagepath_all": [self.dispatchdownloadtask(_) for _ in imags1 + imags2],
"webtags": tags,
"developers": [devp],
"description": description,
}

View File

@ -170,6 +170,9 @@ class searcher(common):
inner = simplehtmlparser(response.text, "div", '<div ref="product_slider_data"')
description = simplehtmlparser(
response.text, "div", '<div class="area-detail-read">'
)
return {
"title": title,
"imagepath_all": [
@ -177,4 +180,5 @@ class searcher(common):
],
"webtags": tags,
"developers": [devp],
'description':description
}

View File

@ -172,7 +172,6 @@ class searcher(common):
"https://store.steampowered.com/api/appdetails?appids={}".format(_id),
proxies=self.proxy,
).json()[str(_id)]["data"]
devs = data.get("developers", []) + data.get("publishers", [])
tagsofficial = [
_["description"] for _ in data.get("genres", [])
@ -191,4 +190,5 @@ class searcher(common):
],
"webtags": tagsofficial,
"developers": devs,
"description":data['detailed_description']
}

View File

@ -126,7 +126,7 @@ def getinfosbyvid(proxy, vid):
"vn",
{
"filters": ["id", "=", vid],
"fields": "tags.rating,tags.name,title,titles.title,titles.main,screenshots.url,image.url,developers.name,developers.original",
"fields": "tags.rating,tags.name,title,titles.title,titles.main,screenshots.url,image.url,developers.name,developers.original,description",
},
)
if js:
@ -152,6 +152,7 @@ def getinfosbyvid(proxy, vid):
sc=imgs,
dev=dev,
tags=sorted(tags, key=lambda x: -rates[tags.index(x)]),
description=js["results"][0]['description']
)
@ -379,4 +380,5 @@ class searcher(common):
"imagepath_all": img + sc,
"webtags": infos["tags"],
"developers": infos["dev"],
"description":infos['description']
}

View File

@ -200,6 +200,7 @@ def getdefaultsavehook(title=None):
"imagepath_all": [],
"developers": [],
"webtags": [], # 标签
# "description": "", # 简介
# "infopath": None, # 离线存储的主页
}
if title and len(title):

View File

@ -1,6 +1,6 @@
import windows, os, winsharedutils, re, functools
from qtsymbols import *
from myutils.config import savehook_new_data, get_launchpath, globalconfig, get_platform
from myutils.config import savehook_new_data, get_launchpath, globalconfig, get_platform, _TR
from gui.usefulwidget import getlineedit, getsimplecombobox, getsimplepatheditor
from traceback import print_exc
import xml.etree.ElementTree as ET
@ -50,9 +50,11 @@ class le_internal(LEbase):
LCID=0x11, CodePage=932, RedirectRegistry=False, HookUILanguageAPI=False
)
def getlrpath(self):
def getlrpath(self, show=False):
LEProc = globalconfig.get("le_extra_path", "")
if not (LEProc and os.path.exists(LEProc)):
if show:
return _TR("内置")
LEProc = os.path.abspath("files/plugins/Locale/Locale.Emulator/LEProc.exe")
return LEProc
@ -129,14 +131,12 @@ class le_internal(LEbase):
layout.addRow(
"路径",
getsimplepatheditor(
self.getlrpath(),
self.getlrpath(show=True),
False,
False,
filter1="LEProc.exe",
callback=functools.partial(self.reselect, config, Guids),
clearset=lambda: os.path.abspath(
"files/plugins/Locale/Locale.Emulator/LEProc.exe"
),
clearset=lambda: _TR("内置"),
icons=("fa.gear", "fa.refresh"),
),
)
@ -167,9 +167,11 @@ class NTLEAS64(LEbase):
continue
config[k] = v
def getlrpath(self):
def getlrpath(self, show=False):
LEProc = globalconfig.get("ntleas_extra_path", "")
if not (LEProc and os.path.exists(LEProc)):
if show:
return _TR("内置")
LEProc = os.path.abspath("files/plugins/Locale/ntleas046_x64/Placeholder")
return LEProc
@ -204,14 +206,12 @@ class NTLEAS64(LEbase):
layout.addRow(
"路径",
getsimplepatheditor(
self.getlrpath(),
self.getlrpath(show=True),
False,
False,
filter1="ntleasWin.exe",
callback=self.reselect,
clearset=lambda: os.path.abspath(
"files/plugins/Locale/ntleas046_x64/Placeholder"
),
clearset=lambda: _TR("内置"),
icons=("fa.gear", "fa.refresh"),
),
)
@ -265,9 +265,11 @@ class lr_internal(LEbase):
print_exc()
return Names, Guids, run_as_admins
def getlrpath(self):
def getlrpath(self, show=False):
LEProc = globalconfig.get("lr_extra_path", "")
if not (LEProc and os.path.exists(LEProc)):
if show:
return _TR("内置")
LEProc = os.path.abspath("files/plugins/Locale/Locale_Remulator/LRProc.exe")
return LEProc
@ -303,14 +305,12 @@ class lr_internal(LEbase):
layout.addRow(
"路径",
getsimplepatheditor(
self.getlrpath(),
self.getlrpath(show=True),
False,
False,
filter1="LRProc.exe",
callback=functools.partial(self.reselect, config, Guids),
clearset=lambda: os.path.abspath(
"files/plugins/Locale/Locale_Remulator/LRProc.exe"
),
clearset=lambda: _TR("内置"),
icons=("fa.gear", "fa.refresh"),
),
)

View File

@ -10,6 +10,17 @@ import gobject
class playtimemanager:
def all(self):
res = self.sqlsavegameinfo.execute(
"SELECT gameinternalid_v2.gameuid, trace_strict.timestart, trace_strict.timestop FROM gameinternalid_v2 JOIN trace_strict ON gameinternalid_v2.gameinternalid = trace_strict.gameinternalid "
).fetchall()
mp = {}
for uid, s, e in res:
if uid not in mp:
mp[uid] = []
mp[uid].append((s, e))
return mp
def __init__(self):
self.sqlsavegameinfo = sqlite3.connect(
@ -111,7 +122,9 @@ class playtimemanager:
gameinternalid = self.get_gameinternalid(uid)
if uid in dic:
self.sqlsavegameinfo.execute(
"UPDATE {} SET timestop = ? WHERE (gameinternalid = ? and timestart = ?)".format(table),
"UPDATE {} SET timestop = ? WHERE (gameinternalid = ? and timestart = ?)".format(
table
),
(_t, gameinternalid, dic[uid]),
)

View File

@ -356,7 +356,7 @@ def checkportavailable(port):
def splittranslatortypes():
pre, offline, free, dev, api = [], [], [], [], []
pre, offline, free, api = [], [], [], []
for k in globalconfig["fanyi"]:
try:
{"pre": pre, "offline": offline, "free": free, "api": api}[
@ -365,7 +365,7 @@ def splittranslatortypes():
except:
pass
return offline, pre, free, dev, api
return offline, pre, free, api
def splitocrtypes(dic):

View File

@ -13,8 +13,9 @@ class OCR(baseocr):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
}
cookies = {"SOCS": "CAESEwgDEgk0ODE3Nzk3MjQaAmVuIAEaBgiA_LyaBg"}
files = {"encoded_image": ("screenshot.png", imagebinary, "image/png")}
res = self.proxysession.post(url, files=files, headers=headers)
res = self.proxysession.post(url, files=files, headers=headers, cookies=cookies)
match = regex.search(res.text)
if not match:
return

View File

@ -114,6 +114,8 @@ def getallsupports():
def dodownload(combo: QComboBox, allsupports: list):
if not allsupports:
return
lang = allsupports[combo.currentIndex()]
gobject.baseobject.openlink(
dynamiclink("{main_server}/Resource/ocr_models/" + lang + ".zip")
@ -121,6 +123,8 @@ def dodownload(combo: QComboBox, allsupports: list):
def doinstall(self, combo: QComboBox, allsupports: list, parent, callback):
if not allsupports:
return
lang = allsupports[combo.currentIndex()]
f = QFileDialog.getOpenFileName(parent, filter=lang + ".zip")
fn = f[0]
@ -135,8 +139,10 @@ def doinstall(self, combo: QComboBox, allsupports: list, parent, callback):
print_exc()
def question(dialog: QDialog):
def question():
dialog = QWidget()
formLayout = LFormLayout()
formLayout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(formLayout)
supportlang = LLabel()
formLayout.addRow("当前支持的语言", supportlang)
@ -166,6 +172,7 @@ def question(dialog: QDialog):
"添加语言包",
getboxlayout([combo, btndownload, btninstall], makewidget=True),
)
return dialog
class OCR(baseocr):

View File

@ -4,8 +4,7 @@ from myutils.config import _TR, static_data, getlang_inner2show
from myutils.utils import dynamiclink
from ocrengines.baseocrclass import baseocr
from qtsymbols import *
from gui.usefulwidget import getboxlayout
from gui.dynalang import LPushButton, LFormLayout, LLabel
from gui.dynalang import LPushButton, LLabel
from myutils.utils import getlanguagespace
@ -31,8 +30,10 @@ def initsupports():
return supportmap
def question(dialog: QDialog):
formLayout = LFormLayout()
def question():
dialog = QWidget()
formLayout = QHBoxLayout()
formLayout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(formLayout)
_allsupport = initsupports()
supportlang = LLabel()
@ -43,9 +44,10 @@ def question(dialog: QDialog):
dynamiclink("{docs_server}/#/zh/windowsocr")
)
)
formLayout.addRow(
"当前支持的语言", getboxlayout([supportlang, btndownload], makewidget=True)
)
formLayout.addWidget(LLabel("当前支持的语言"))
formLayout.addWidget(supportlang)
formLayout.addWidget(btndownload)
return dialog
class OCR(baseocr):
@ -85,7 +87,9 @@ class OCR(baseocr):
)
else:
uselang = self.srclang
ret = winrtutils.OCR_f(imagebinary, self.supportmap[uselang], getlanguagespace(uselang))
ret = winrtutils.OCR_f(
imagebinary, self.supportmap[uselang], getlanguagespace(uselang)
)
boxs = [_[1:] for _ in ret]
texts = [_[0] for _ in ret]
return {"box": boxs, "text": texts}

View File

@ -1,8 +1,8 @@
try:
from PyQt5 import QtSvg
from PyQt5.QtWidgets import QFrame,QListView,QCheckBox,QAbstractItemView,QTextEdit,QTableView,QHeaderView,QColorDialog,QSpinBox,QDoubleSpinBox,QComboBox,QDialogButtonBox,QMainWindow,QMessageBox,QDialog,QGridLayout,QTextBrowser,QGraphicsDropShadowEffect,QWidget,QSizePolicy,QScrollArea,QApplication,QPushButton,QSystemTrayIcon,QPlainTextEdit,QAction,QMenu,QFileDialog,QKeySequenceEdit,QLabel,QSpacerItem,QWidgetItem,QLayout,QTextBrowser,QLineEdit,QFormLayout,QSizePolicy,QTabWidget,QTabBar,QSplitter,QListWidget,QListWidgetItem,QHBoxLayout,QVBoxLayout,QSizeGrip,QFontComboBox,QProgressBar,QRadioButton,QButtonGroup,QSlider,QToolTip,QGroupBox,QGraphicsOpacityEffect,QStackedWidget,QStyledItemDelegate,QStyleOptionViewItem,QFontDialog,QTreeView
from PyQt5.QtWidgets import QFrame,QListView,QCheckBox,QAbstractItemView,QTextEdit,QTableView,QHeaderView,QColorDialog,QSpinBox,QDoubleSpinBox,QComboBox,QDialogButtonBox,QMainWindow,QMessageBox,QDialog,QGridLayout,QTextBrowser,QGraphicsDropShadowEffect,QWidget,QSizePolicy,QScrollArea,QApplication,QPushButton,QSystemTrayIcon,QPlainTextEdit,QAction,QMenu,QFileDialog,QKeySequenceEdit,QLabel,QSpacerItem,QWidgetItem,QLayout,QTextBrowser,QLineEdit,QFormLayout,QSizePolicy,QTabWidget,QTabBar,QSplitter,QListWidget,QListWidgetItem,QHBoxLayout,QVBoxLayout,QSizeGrip,QFontComboBox,QProgressBar,QRadioButton,QButtonGroup,QSlider,QToolTip,QGroupBox,QGraphicsOpacityEffect,QStackedWidget,QStyledItemDelegate,QStyleOptionViewItem,QFontDialog,QTreeView,QToolButton
from PyQt5.QtGui import QIconEngine,QIntValidator,QStandardItem,QStandardItemModel,QImageWriter,QIcon,QTextCharFormat,QTextBlockFormat,QResizeEvent,QTextCursor,QFontMetricsF,QMouseEvent,QImage,QPainter,QRegion,QCloseEvent,QFontDatabase,QKeySequence,QPixmap,QCursor,QColor,QFont,QPen,QPainterPath,QBrush,QFontMetrics,QShowEvent,QWheelEvent,QPaintEvent,QTextLayout, QTextOption,QDragEnterEvent, QDropEvent,QTransform,QKeyEvent,QInputMethodEvent,QValidator
from PyQt5.QtCore import QObject,pyqtSignal,Qt,QSize,QByteArray,QBuffer,QPointF,QPoint,QRect,QEvent,QModelIndex,QTimer,QRectF,QVariantAnimation,QUrl,QPropertyAnimation,QLocale,QSignalBlocker
from PyQt5.QtCore import QObject,pyqtSignal,Qt,QSize,QByteArray,QBuffer,QPointF,QPoint,QRect,QEvent,QModelIndex,QTimer,QRectF,QVariantAnimation,QUrl,QPropertyAnimation,QLocale,QSignalBlocker,QMargins
isqt5 = True
class LineHeightTypes:
LineDistanceHeight=QTextBlockFormat.LineHeightTypes.LineDistanceHeight
@ -11,9 +11,9 @@ except:
#from traceback import print_exc
#print_exc()
from PyQt6 import QtSvg
from PyQt6.QtWidgets import QFrame,QListView,QCheckBox,QAbstractItemView,QTextEdit,QTableView,QHeaderView,QColorDialog,QSpinBox,QDoubleSpinBox,QComboBox,QDialogButtonBox,QMainWindow,QMessageBox,QDialog,QGridLayout,QTextBrowser,QGraphicsDropShadowEffect,QWidget,QSizePolicy,QScrollArea,QApplication,QPushButton,QSystemTrayIcon,QPlainTextEdit,QMenu,QFileDialog,QKeySequenceEdit,QLabel,QSpacerItem,QWidgetItem,QLayout,QTextBrowser,QLineEdit,QFormLayout,QSizePolicy,QTabWidget,QTabBar,QSplitter,QListWidget,QListWidgetItem,QHBoxLayout,QVBoxLayout,QSizeGrip,QFontComboBox,QProgressBar,QRadioButton,QButtonGroup,QSlider,QToolTip,QGroupBox,QGraphicsOpacityEffect,QStackedWidget,QTreeView
from PyQt6.QtWidgets import QFrame,QListView,QCheckBox,QAbstractItemView,QTextEdit,QTableView,QHeaderView,QColorDialog,QSpinBox,QDoubleSpinBox,QComboBox,QDialogButtonBox,QMainWindow,QMessageBox,QDialog,QGridLayout,QTextBrowser,QGraphicsDropShadowEffect,QWidget,QSizePolicy,QScrollArea,QApplication,QPushButton,QSystemTrayIcon,QPlainTextEdit,QMenu,QFileDialog,QKeySequenceEdit,QLabel,QSpacerItem,QWidgetItem,QLayout,QTextBrowser,QLineEdit,QFormLayout,QSizePolicy,QTabWidget,QTabBar,QSplitter,QListWidget,QListWidgetItem,QHBoxLayout,QVBoxLayout,QSizeGrip,QFontComboBox,QProgressBar,QRadioButton,QButtonGroup,QSlider,QToolTip,QGroupBox,QGraphicsOpacityEffect,QStackedWidget,QTreeView,QToolButton
from PyQt6.QtGui import QIconEngine,QIntValidator,QAction,QStandardItem,QStandardItemModel,QImageWriter,QIcon,QTextCharFormat,QTextBlockFormat,QResizeEvent,QTextCursor,QFontMetricsF,QMouseEvent,QImage,QPainter,QRegion,QCloseEvent,QFontDatabase,QKeySequence,QPixmap,QCursor,QColor,QFont,QPen,QPainterPath,QBrush,QFontMetrics,QShowEvent,QWheelEvent,QPaintEvent,QTextLayout, QTextOption,QKeyEvent,QInputMethodEvent,QValidator
from PyQt6.QtCore import QObject,pyqtSignal,Qt,QSize,QByteArray,QBuffer,QPointF,QPoint,QRect,QEvent,QModelIndex,QTimer,QRectF,QVariantAnimation,QUrl,QPropertyAnimation,QLocale
from PyQt6.QtCore import QObject,pyqtSignal,Qt,QSize,QByteArray,QBuffer,QPointF,QPoint,QRect,QEvent,QModelIndex,QTimer,QRectF,QVariantAnimation,QUrl,QPropertyAnimation,QLocale,QMargins
isqt5 = False
class LineHeightTypes:

View File

@ -1,6 +1,6 @@
from textsource.textsourcebase import basetext
from myutils.wrapper import threader
import json, time, os, gobject, re
import json, time, os, gobject, winsharedutils
from myutils.config import globalconfig
@ -29,8 +29,9 @@ class parsejson:
def load(self):
for i, k in enumerate(self.data):
if self.data[k]:
yield i, None
if not isinstance(self.data[k], str):
continue
if winsharedutils.distance_ratio(self.data[k], k) < 0.2:
continue
yield i, k

View File

@ -43,7 +43,7 @@ class TS(basetrans):
)
return True
def x64(self, content):
def translate(self, content):
self.checkpath()
l = content.encode("utf-16-le")
@ -53,6 +53,3 @@ class TS(basetrans):
if not size:
raise Exception("not installed")
return windows.ReadFile(self.hPipe, size).decode("utf-16-le")
def translate(self, content):
return self.x64(content)

View File

@ -62,7 +62,7 @@ class TS(basetrans):
)
return True
def x64(self, content):
def translate(self, content):
if self.checkpath() == False:
raise Exception(_TR("翻译器加载失败"))
@ -74,6 +74,3 @@ class TS(basetrans):
windows.WriteFile(self.hPipe, line.encode(codes[self.srclang]))
ress.append(windows.ReadFile(self.hPipe, 4096).decode(codes[self.tgtlang]))
return "\n".join(ress)
def translate(self, content):
return self.x64(content)

View File

@ -1,7 +1,7 @@
from translator.basetranslator import basetrans
from myutils.config import _TR
import os, time
import windows
import windows, ctypes
from myutils.subproc import subproc_w, autoproc
@ -54,7 +54,7 @@ class TS(basetrans):
)
return True
def x64(self, content: str):
def translate(self, content):
if self.checkpath() == False:
raise Exception(_TR("翻译器加载失败"))
@ -62,14 +62,7 @@ class TS(basetrans):
code1 = content.encode("utf-16-le")
windows.WriteFile(self.hPipe, code1)
xx = windows.ReadFile(self.hPipe, 65535)
xx = xx.decode("utf-16-le", errors="ignore")
return xx
def translate(self, content):
return self.x64(content)
def langmap(self):
return {"zh": "936", "cht": "950"}
size = ctypes.c_int.from_buffer_copy(windows.ReadFile(self.hPipe, 4)).value
if not size:
raise Exception("not installed")
return windows.ReadFile(self.hPipe, size).decode("utf-16-le")

View File

@ -67,7 +67,7 @@ class TS(basetrans):
)
return True
def x64(self, content: str):
def translate(self, content):
if self.tgtlang not in ["936", "950"]:
return ""
if self.checkpath() == False:
@ -86,42 +86,5 @@ class TS(basetrans):
ress.append(xx)
return "\n".join(ress)
def x86(self, content):
CODEPAGE_JA = 932
CODEPAGE_GB = 936
CODEPAGE_BIG5 = 950
BUFFER_SIZE = 3000
# if globalconfig['fanjian'] in [0,1,4]:
# code=CODEPAGE_GB
# else:
# code=CODEPAGE_BIG5
code = CODEPAGE_GB
size = BUFFER_SIZE
out = ctypes.create_unicode_buffer(size)
buf = ctypes.create_unicode_buffer(size)
outsz = ctypes.c_int(size)
bufsz = ctypes.c_int(size)
try:
self.dll.JC_Transfer_Unicode(
0, # int, unknown
CODEPAGE_JA, # uint from, supposed to be 0x3a4 (cp932)
code, # uint to, eighter cp950 or cp932
1, # int, unknown
1, # int, unknown
content, # python 默认unicode 所有不用u'
out, # wchar_t*
ctypes.byref(outsz), # ∫
buf, # wchar_t*
ctypes.byref(bufsz),
) # ∫
except:
pass
return out.value
def translate(self, content):
return self.x64(content)
def langmap(self):
return {"zh": "936", "cht": "950"}

View File

@ -64,7 +64,7 @@ class TS(basetrans):
)
return True
def x64(self, content):
def translate(self, content):
if self.checkpath() == False:
raise Exception(_TR("翻译器加载失败"))
ress = []
@ -77,8 +77,5 @@ class TS(basetrans):
return "\n".join(ress)
def translate(self, content):
return self.x64(content)
def langmap(self):
return {"zh": "SChinese", "cht": "TChinese", "en": "English", "ja": "Japanese", "auto": "Japanese"}

View File

@ -49,7 +49,7 @@ class TS(basetrans):
)
)
def x64(self, content: str):
def translate(self, content):
self.checkpath()
l = content.encode("utf-16-le")
@ -59,6 +59,3 @@ class TS(basetrans):
if not size:
raise Exception("not installed")
return windows.ReadFile(self.hPipe, size).decode("utf-16-le")
def translate(self, content):
return self.x64(content)

View File

@ -10,13 +10,11 @@ from ctypes import (
POINTER,
c_char,
)
from ctypes.wintypes import HANDLE
import platform, gobject, threading
try:
if platform.system() != "Windows" or int(platform.version().split(".")[0]) <= 6:
raise Exception()
winrtutilsdll = CDLL(gobject.GetDllpath(("winrtutils32.dll", "winrtutils64.dll")))
except:
winrtutilsdll = 0
@ -33,11 +31,6 @@ if winrtutilsdll:
_getlanguagelist = winrtutilsdll.getlanguagelist
_getlanguagelist.argtypes = (c_void_p,)
def getlanguagelist():
ret = []
_getlanguagelist(CFUNCTYPE(None, c_wchar_p)(ret.append))
return ret
def OCR_f(data, lang, space):
ret = []
@ -62,13 +55,24 @@ if winrtutilsdll:
_winrt_capture_window = winrtutilsdll.winrt_capture_window
_winrt_capture_window.argtypes = c_void_p, c_void_p
def winrt_capture_window(hwnd):
ret = []
def cb(ptr, size):
ret.append(cast(ptr, POINTER(c_char))[:size])
def getlanguagelist():
if not winrtutilsdll:
return []
ret = []
_getlanguagelist(CFUNCTYPE(None, c_wchar_p)(ret.append))
return ret
_winrt_capture_window(hwnd, CFUNCTYPE(None, c_void_p, c_size_t)(cb))
if len(ret):
return ret[0]
return None
def winrt_capture_window(hwnd):
if not winrtutilsdll:
return
ret = []
def cb(ptr, size):
ret.append(cast(ptr, POINTER(c_char))[:size])
_winrt_capture_window(hwnd, CFUNCTYPE(None, c_void_p, c_size_t)(cb))
if len(ret):
return ret[0]
return None

View File

@ -521,6 +521,7 @@
"useproxy": true,
"usesysproxy": true,
"fullscreenmethod_4": 0,
"tagNameRemap": {},
"dialog_savegame_layout": {
"itemw": 250,
"itemh": 350,
@ -532,6 +533,7 @@
"transparent": 25,
"transparentselect": 25,
"transparentnotexits": 25,
"listitemheight": 30,
"listitemwidth_2": [
300,
500
@ -1181,19 +1183,13 @@
"use": true,
"name": "MeCab",
"args": {
"path": "",
"downloadlink": "{main_server}/Resource/dictionary/Mecab.zip"
"path": ""
},
"argstype": {
"path": {
"type": "file",
"name": "路径",
"dir": true
},
"downloadlink": {
"type": "label",
"islink": true,
"name": "下载"
}
},
"type": "offline"
@ -1670,7 +1666,7 @@
"type": "offline",
"use": false,
"color": "#1839f0",
"name": "Jbeijing7"
"name": "J北京7"
},
"eztrans": {
"type": "offline",

View File

@ -1,18 +1,4 @@
{
"local": {
"args": {
"": ""
},
"argstype": {
"": {
"type": "program",
"route": [
"ocrengines.local",
"question"
]
}
}
},
"youdaodictocr": {
"args": {
"Translate": false
@ -24,20 +10,6 @@
}
}
},
"windowsocr": {
"args": {
"": ""
},
"argstype": {
"": {
"type": "program",
"route": [
"ocrengines.windowsocr",
"question"
]
}
}
},
"baiduocr_X": {
"args": {
"API Key": "",
@ -322,10 +294,7 @@
},
"mangaocr": {
"args": {
"Port": 5665,
"项目仓库": "https://github.com/kha-white/manga-ocr",
"整合包_CPU": "{main_server}/Resource/IntegrationPack/manga_ocr/cpu",
"整合包_GPU": "{main_server}/Resource/IntegrationPack/manga_ocr/gpu"
"Port": 5665
},
"argstype": {
"Port": {
@ -333,18 +302,6 @@
"min": 1,
"max": 65535,
"step": 1
},
"项目仓库": {
"type": "label",
"islink": true
},
"整合包_CPU": {
"type": "label",
"islink": true
},
"整合包_GPU": {
"type": "label",
"islink": true
}
}
}

View File

@ -452,236 +452,295 @@
"北欧",
"西里尔"
],
"aboutsource": [
{
"name": "辞书",
"sources": [
{
"name": "MeCab",
"links": [
{
"name": "MeCab",
"link": "{main_server}/Resource/dictionary/Mecab.zip"
},
{
"name": "Unidic",
"link": "https://clrd.ninjal.ac.jp/unidic/"
}
]
},
{
"name": "MDict",
"links": [
{
"name": "论坛",
"link": "https://forum.freemdict.com/"
},
{
"name": "freemdict",
"link": "https://search.freemdict.com/"
}
]
}
]
},
{
"name": "语音合成",
"sources": [
{
"name": "NeoSpeech",
"links": [
{
"name": "Misaki",
"link": "{main_server}/Resource/voice/NeoSpeech.Japanese.Misaki.zip"
},
{
"name": "Show",
"link": "{main_server}/Resource/voice/NeoSpeech.TTS.NeoSpeech.Japanese.Show_v3.10.0.0.zip"
}
]
},
{
"name": "VOICEVOX",
"links": [
{
"name": "Github",
"link": "https://github.com/VOICEVOX/voicevox/releases"
}
]
},
{
"name": "vits-simple-api",
"links": [
{
"name": "Github",
"link": "https://github.com/Artrajz/vits-simple-api/releases"
},
{
"name": "整合包_CPU",
"link": "{main_server}/Resource/IntegrationPack/vits-simple-api/cpu"
},
{
"name": "整合包_GPU",
"link": "{main_server}/Resource/IntegrationPack/vits-simple-api/gpu"
}
]
},
{
"name": "VoiceRoid+",
"links": [
{
"name": "東北ずん子/东北俊子",
"link": "{main_server}/Resource/voice/VOICEROID+zunko.7z"
}
]
},
{
"name": "VoiceRoid2",
"links": [
{
"name": "SFE_結月ゆかり/结月缘",
"link": "{main_server}/Resource/voice/Yukari2.zip"
},
{
"name": "結月ゆかり/结月缘",
"link": "{main_server}/Resource/voice/VOICEROID2_Yuzuki_Yukari.zip"
},
{
"name": "紲星あかり/绁星灯",
"link": "{main_server}/Resource/voice/VOICEROID2_Kizuna_Akari.zip"
},
{
"name": "琴葉 茜・葵",
"link": "{main_server}/Resource/voice/VOICEROID2_Kotonoha_Akane_Aoi.zip"
},
{
"name": "伊織弓鶴",
"link": "{main_server}/Resource/voice/VOICEROID2_Iori_Yuzuru.zip"
},
{
"name": "ついなちゃん",
"link": "{main_server}/Resource/voice/VOICEROID2_tsuina-chan_dl_e.zip"
},
{
"name": "東北イタコ/东北伊达子",
"link": "{main_server}/Resource/voice/VOICEROID2_Tohoku_Itako.zip"
},
{
"name": "附加音源_結月ゆかり",
"link": "{main_server}/Resource/voice/yukari_emo_44.zip"
},
{
"name": "附加音源_紲星あかり",
"link": "{main_server}/Resource/voice/akari_44.zip"
},
{
"name": "附加音源_東北きりたん",
"link": "{main_server}/Resource/voice/kiritan_44.zip"
},
{
"name": "附加音源_東北イタコ",
"link": "{main_server}/Resource/voice/itako_emo_44.zip"
},
{
"name": "附加音源_東北ずん子",
"link": "{main_server}/Resource/voice/zunko_44.zip"
},
{
"name": "附加音源_伊織弓鶴",
"link": "{main_server}/Resource/voice/yuzuru_emo_44.zip"
},
{
"name": "附加音源_ついなちゃん",
"link": "{main_server}/Resource/voice/tsuina_44.zip"
},
{
"name": "附加音源_ついなちゃん関西弁",
"link": "{main_server}/Resource/voice/tsuina_west_44.zip"
},
{
"name": "附加音源_琴葉茜",
"link": "{main_server}/Resource/voice/akane_west_emo_44.zip"
},
{
"name": "附加音源_琴葉葵",
"link": "{main_server}/Resource/voice/aoi_emo_44.zip"
},
{
"name": "附加音源_水奈瀬コウ",
"link": "{main_server}/Resource/voice/kou_44.zip"
},
{
"name": "附加音源_桜乃そら",
"link": "{main_server}/Resource/voice/sora_44.zip"
},
{
"name": "附加音源_民安ともえ",
"link": "{main_server}/Resource/voice/tamiyasu_44.zip"
},
{
"name": "附加音源_月読アイ",
"link": "{main_server}/Resource/voice/ai_44.zip"
},
{
"name": "附加音源_月読ショウタ",
"link": "{main_server}/Resource/voice/shouta_44.zip"
},
{
"name": "附加音源_京町セイカ",
"link": "{main_server}/Resource/voice/seika_44.zip"
},
{
"name": "附加音源_音街ウナ",
"link": "{main_server}/Resource/voice/una_44.zip"
},
{
"name": "附加音源_鷹の爪吉田",
"link": "{main_server}/Resource/voice/yoshidakun_44.zip"
},
{
"name": "附加音源_ギャラ子",
"link": "{main_server}/Resource/voice/galaco_44.zip"
}
]
}
]
},
{
"name": "其他工具",
"sources": [
{
"name": "转区",
"links": [
{
"name": "Locale-Emulator",
"link": "https://github.com/xupefei/Locale-Emulator/releases/download/v2.5.0.1/Locale.Emulator.2.5.0.1.zip"
},
{
"name": "Locale_Remulator",
"link": "https://github.com/InWILL/Locale_Remulator/releases/download/v1.5.3-beta.1/Locale_Remulator.1.5.3-beta.1.zip"
},
{
"name": "Ntleas",
"link": "https://github.com/zxyacb/ntlea/releases/download/0.46/ntleas046_x64.7z"
}
]
},
{
"name": "Magpie",
"links": [
{
"name": "Github",
"link": "https://github.com/Blinue/Magpie/releases"
},
{
"name": "win7适配版",
"link": "{main_server}/Resource/Magpie9_Win7"
}
]
}
]
}
],
"aboutsource": {
"translate": [
{
"name": "大模型",
"links": [
{
"name": "Sakura大模型",
"link": "https://github.com/SakuraLLM/SakuraLLM",
"about": "日语_->_简体中文"
}
]
},
{
"name": "过时的翻译器",
"links": [
{
"name": "J北京7",
"link": "{main_server}/Resource/translate/JBeijing7.zip",
"about": "日语_->_简体中文"
},
{
"name": "金山快译",
"link": "{main_server}/Resource/translate/FastAIT09_Setup.25269.4101.zip",
"about": "日语_->_简体中文"
},
{
"name": "快译通",
"link": "{main_server}/Resource/translate/DR.eye.zip",
"about": "日语_->_简体中文"
},
{
"name": "Sugoi",
"link": "{main_server}/Resource/translate/Sugoi_Translator_V10.1.7z",
"about": "日语_->_英语"
},
{
"name": "LEC",
"link": "{main_server}/Resource/translate/LEC",
"about": "日语_->_英语"
},
{
"name": "Atlas",
"link": "{main_server}/Resource/translate/Atlas",
"about": "日语_->_英语"
},
{
"name": "ezTrans",
"link": "{main_server}/Resource/translate/ezTrans",
"about": "日语_->_韩语"
}
]
}
],
"ocr": [
{
"name": "本地OCR",
"function": [
"ocrengines.local",
"question"
]
},
{
"name": "WindowsOCR",
"function": [
"ocrengines.windowsocr",
"question"
]
},
{
"name": "manga-ocr",
"links": [
{
"name": "项目仓库",
"link": "https://github.com/kha-white/manga-ocr"
},
{
"name": "整合包_CPU",
"link": "{main_server}/Resource/IntegrationPack/manga_ocr/cpu"
},
{
"name": "整合包_GPU",
"link": "{main_server}/Resource/IntegrationPack/manga_ocr/gpu"
}
]
}
],
"dict": [
{
"name": "MeCab",
"links": [
{
"name": "MeCab",
"link": "{main_server}/Resource/dictionary/Mecab.zip"
},
{
"name": "Unidic",
"link": "https://clrd.ninjal.ac.jp/unidic/"
}
]
},
{
"name": "MDict",
"links": [
{
"name": "论坛",
"link": "https://forum.freemdict.com/"
},
{
"name": "freemdict",
"link": "https://search.freemdict.com/"
}
]
}
],
"tts": [
{
"name": "NeoSpeech",
"links": [
{
"name": "Misaki",
"link": "{main_server}/Resource/voice/NeoSpeech.Japanese.Misaki.zip"
},
{
"name": "Show",
"link": "{main_server}/Resource/voice/NeoSpeech.TTS.NeoSpeech.Japanese.Show_v3.10.0.0.zip"
}
]
},
{
"name": "VOICEVOX",
"links": [
{
"name": "Github",
"link": "https://github.com/VOICEVOX/voicevox/releases"
}
]
},
{
"name": "vits-simple-api",
"links": [
{
"name": "Github",
"link": "https://github.com/Artrajz/vits-simple-api/releases"
},
{
"name": "整合包_CPU",
"link": "{main_server}/Resource/IntegrationPack/vits-simple-api/cpu"
},
{
"name": "整合包_GPU",
"link": "{main_server}/Resource/IntegrationPack/vits-simple-api/gpu"
}
]
},
{
"name": "VoiceRoid+",
"links": [
{
"name": "東北ずん子/东北俊子",
"link": "{main_server}/Resource/voice/VOICEROID+zunko.7z"
}
]
},
{
"name": "VoiceRoid2",
"links": [
{
"name": "SFE_結月ゆかり/结月缘",
"link": "{main_server}/Resource/voice/Yukari2.zip"
},
{
"name": "結月ゆかり/结月缘",
"link": "{main_server}/Resource/voice/VOICEROID2_Yuzuki_Yukari.zip"
},
{
"name": "紲星あかり/绁星灯",
"link": "{main_server}/Resource/voice/VOICEROID2_Kizuna_Akari.zip"
},
{
"name": "琴葉 茜・葵",
"link": "{main_server}/Resource/voice/VOICEROID2_Kotonoha_Akane_Aoi.zip"
},
{
"name": "伊織弓鶴",
"link": "{main_server}/Resource/voice/VOICEROID2_Iori_Yuzuru.zip"
},
{
"name": "ついなちゃん",
"link": "{main_server}/Resource/voice/VOICEROID2_tsuina-chan_dl_e.zip"
},
{
"name": "東北イタコ/东北伊达子",
"link": "{main_server}/Resource/voice/VOICEROID2_Tohoku_Itako.zip"
},
{
"name": "附加音源_結月ゆかり",
"link": "{main_server}/Resource/voice/yukari_emo_44.zip"
},
{
"name": "附加音源_紲星あかり",
"link": "{main_server}/Resource/voice/akari_44.zip"
},
{
"name": "附加音源_東北きりたん",
"link": "{main_server}/Resource/voice/kiritan_44.zip"
},
{
"name": "附加音源_東北イタコ",
"link": "{main_server}/Resource/voice/itako_emo_44.zip"
},
{
"name": "附加音源_東北ずん子",
"link": "{main_server}/Resource/voice/zunko_44.zip"
},
{
"name": "附加音源_伊織弓鶴",
"link": "{main_server}/Resource/voice/yuzuru_emo_44.zip"
},
{
"name": "附加音源_ついなちゃん",
"link": "{main_server}/Resource/voice/tsuina_44.zip"
},
{
"name": "附加音源_ついなちゃん関西弁",
"link": "{main_server}/Resource/voice/tsuina_west_44.zip"
},
{
"name": "附加音源_琴葉茜",
"link": "{main_server}/Resource/voice/akane_west_emo_44.zip"
},
{
"name": "附加音源_琴葉葵",
"link": "{main_server}/Resource/voice/aoi_emo_44.zip"
},
{
"name": "附加音源_水奈瀬コウ",
"link": "{main_server}/Resource/voice/kou_44.zip"
},
{
"name": "附加音源_桜乃そら",
"link": "{main_server}/Resource/voice/sora_44.zip"
},
{
"name": "附加音源_民安ともえ",
"link": "{main_server}/Resource/voice/tamiyasu_44.zip"
},
{
"name": "附加音源_月読アイ",
"link": "{main_server}/Resource/voice/ai_44.zip"
},
{
"name": "附加音源_月読ショウタ",
"link": "{main_server}/Resource/voice/shouta_44.zip"
},
{
"name": "附加音源_京町セイカ",
"link": "{main_server}/Resource/voice/seika_44.zip"
},
{
"name": "附加音源_音街ウナ",
"link": "{main_server}/Resource/voice/una_44.zip"
},
{
"name": "附加音源_鷹の爪吉田",
"link": "{main_server}/Resource/voice/yoshidakun_44.zip"
},
{
"name": "附加音源_ギャラ子",
"link": "{main_server}/Resource/voice/galaco_44.zip"
}
]
}
],
"magpie": [
{
"name": "Magpie",
"links": [
{
"name": "Github",
"link": "https://github.com/Blinue/Magpie/releases"
},
{
"name": "win7适配版",
"link": "{main_server}/Resource/Magpie9_Win7"
}
]
}
]
},
"mod_map": {
"CTRL": 2,
"SHIFT": 4,

View File

@ -276,19 +276,7 @@
},
"sugoix": {
"args": {
"api": "http://127.0.0.1:14366/",
"V8": "{main_server}/Resource/translate/Sugoi_Translator_V8.7z",
"V10.1": "{main_server}/Resource/translate/Sugoi_Translator_V10.1.7z"
},
"argstype": {
"V8": {
"type": "label",
"islink": true
},
"V10.1": {
"type": "label",
"islink": true
}
"api": "http://127.0.0.1:14366/"
}
},
"huoshanapi": {
@ -668,36 +656,26 @@
},
"jb7": {
"args": {
"path": "",
"下载": "{main_server}/Resource/translate/JBeijing7.zip"
"path": ""
},
"argstype": {
"path": {
"type": "file",
"dir": true,
"name": "路径"
},
"下载": {
"type": "label",
"islink": true
}
}
}
},
"kingsoft": {
"args": {
"path": "",
"下载": "{main_server}/Resource/translate/FastAIT09_Setup.25269.4101.zip"
"path": ""
},
"argstype": {
"path": {
"name": "路径",
"type": "file",
"dir": true
},
"下载": {
"type": "label",
"islink": true
}
}
}
},
"eztrans": {
@ -715,19 +693,14 @@
},
"dreye": {
"args": {
"path": "",
"下载": "{main_server}/Resource/translate/DR.eye.zip"
"path": ""
},
"argstype": {
"path": {
"name": "路径",
"type": "file",
"dir": true
},
"下载": {
"type": "label",
"islink": true
}
}
}
},
"rengong": {

View File

@ -756,5 +756,12 @@
"成功": "النجاح .",
"Win32通用钩子": "win32 هوك العالمي",
"特殊码无效": "رمز خاص غير صالح",
"显示模式": "طريقة العرض"
"显示模式": "طريقة العرض",
"内置": "مدمجة",
"信息": "معلومات",
"开发商": "المطور",
"标签映射": "تسمية الخريطة",
"简介": "مقدمة",
"全部": "كامل",
"年度总结": "ملخص سنوي"
}

View File

@ -756,5 +756,12 @@
"成功": "成功",
"Win32通用钩子": "Win32通用鉤子",
"特殊码无效": "特殊碼無效",
"显示模式": "顯示模式"
"显示模式": "顯示模式",
"内置": "內寘",
"信息": "訊息",
"开发商": "開發商",
"标签映射": "標籤映射",
"简介": "簡介",
"全部": "全部",
"年度总结": "年度總結"
}

View File

@ -756,5 +756,12 @@
"成功": "úspěch",
"Win32通用钩子": "Univerzální hák Win32",
"特殊码无效": "Speciální kód je neplatný",
"显示模式": "režim zobrazení"
"显示模式": "režim zobrazení",
"内置": "vestavěné",
"信息": "informace",
"开发商": "Vývojáři",
"标签映射": "Mapování štítků",
"简介": "stručný úvod",
"全部": "celý",
"年度总结": "Roční shrnutí"
}

View File

@ -756,5 +756,12 @@
"成功": "Erfolg",
"Win32通用钩子": "Win32 Universal Hook",
"特殊码无效": "Der spezielle Code ist ungültig",
"显示模式": "Anzeigemodus"
"显示模式": "Anzeigemodus",
"内置": "eingebaut",
"信息": "Informationen",
"开发商": "Entwickler",
"标签映射": "Beschriftung",
"简介": "kurze Einführung",
"全部": "ganz",
"年度总结": "Jahreszusammenfassung"
}

View File

@ -756,5 +756,12 @@
"成功": "success",
"Win32通用钩子": "Win32 Universal Hook",
"特殊码无效": "The special code is invalid",
"显示模式": "display mode"
"显示模式": "display mode",
"内置": "built-in",
"信息": "information",
"开发商": "Developers",
"标签映射": "Label Mapping",
"简介": "brief introduction",
"全部": "all",
"年度总结": "Annual Summary"
}

View File

@ -756,5 +756,12 @@
"成功": "éxito",
"Win32通用钩子": "Gancho universal Win32",
"特殊码无效": "El código especial no es válido",
"显示模式": "Modo de visualización"
"显示模式": "Modo de visualización",
"内置": "Incorporado",
"信息": "Información",
"开发商": "Desarrolladores",
"标签映射": "Mapeo de etiquetas",
"简介": "Introducción",
"全部": "Todo",
"年度总结": "Resumen Anual"
}

View File

@ -756,5 +756,12 @@
"成功": "Succès",
"Win32通用钩子": "Win32 crochet universel",
"特殊码无效": "Code spécial invalide",
"显示模式": "Mode d'affichage"
"显示模式": "Mode d'affichage",
"内置": "Intégré",
"信息": "Informations",
"开发商": "Développeur",
"标签映射": "Mappage des étiquettes",
"简介": "Introduction",
"全部": "Tous",
"年度总结": "Résumé annuel"
}

View File

@ -756,5 +756,12 @@
"成功": "successo",
"Win32通用钩子": "Win32 Universal Hook",
"特殊码无效": "Il codice speciale non è valido",
"显示模式": "modalità di visualizzazione"
"显示模式": "modalità di visualizzazione",
"内置": "integrato",
"信息": "informazioni",
"开发商": "Sviluppatori",
"标签映射": "Mappatura etichette",
"简介": "breve introduzione",
"全部": "intero",
"年度总结": "Sintesi annuale"
}

View File

@ -756,5 +756,12 @@
"成功": "成功",
"Win32通用钩子": "Win 32汎用フック",
"特殊码无效": "特殊コードが無効です",
"显示模式": "表示モード"
"显示模式": "表示モード",
"内置": "組み込み",
"信息": "情報#ジョウホウ#",
"开发商": "開発者",
"标签映射": "ラベルマッピング",
"简介": "概要",
"全部": "すべて",
"年度总结": "年度まとめ"
}

View File

@ -756,5 +756,12 @@
"成功": "성공",
"Win32通用钩子": "Win32 범용 갈고리",
"特殊码无效": "잘못된 특수 코드",
"显示模式": "디스플레이 모드"
"显示模式": "디스플레이 모드",
"内置": "내장형",
"信息": "정보",
"开发商": "개발업자",
"标签映射": "태그 매핑",
"简介": "소개",
"全部": "모두",
"年度总结": "연간 요약"
}

View File

@ -756,5 +756,12 @@
"成功": "succes",
"Win32通用钩子": "Win32 universele haak",
"特殊码无效": "De speciale code is ongeldig",
"显示模式": "weergavemodus"
"显示模式": "weergavemodus",
"内置": "ingebouwd",
"信息": "informatie",
"开发商": "Ontwikkelaars",
"标签映射": "Label toewijzing",
"简介": "korte inleiding",
"全部": "geheel",
"年度总结": "Jaarlijkse samenvatting"
}

View File

@ -756,5 +756,12 @@
"成功": "sukces",
"Win32通用钩子": "Uniwersalny hak Win32",
"特殊码无效": "Kod specjalny jest nieprawidłowy",
"显示模式": "tryb wyświetlania"
"显示模式": "tryb wyświetlania",
"内置": "wbudowany",
"信息": "informacje",
"开发商": "Deweloperzy",
"标签映射": "Mapowanie etykiet",
"简介": "krótkie wprowadzenie",
"全部": "całość",
"年度总结": "Roczne podsumowanie"
}

View File

@ -756,5 +756,12 @@
"成功": "sucesso",
"Win32通用钩子": "Gancho Universal Win32",
"特殊码无效": "O código especial é inválido",
"显示模式": "modo de visualização"
"显示模式": "modo de visualização",
"内置": "embutido",
"信息": "informação",
"开发商": "Desenvolvedores",
"标签映射": "Mapeamento de Etiquetas",
"简介": "breve introdução",
"全部": "inteiro",
"年度总结": "Resumo anual"
}

View File

@ -756,5 +756,12 @@
"成功": "Успех",
"Win32通用钩子": "Win32 Универсальный крюк",
"特殊码无效": "Специальный код не работает.",
"显示模式": "Показать режим"
"显示模式": "Показать режим",
"内置": "Встроенные",
"信息": "Информация",
"开发商": "Разработчики",
"标签映射": "Отображение метки",
"简介": "Введение",
"全部": "Все.",
"年度总结": "Ежегодное резюме"
}

View File

@ -756,5 +756,12 @@
"成功": "framgång",
"Win32通用钩子": "Win32 universalkrok",
"特殊码无效": "Specialkoden är ogiltig",
"显示模式": "visningsläge"
"显示模式": "visningsläge",
"内置": "inbyggd",
"信息": "information",
"开发商": "Utvecklare",
"标签映射": "Etikettmappning",
"简介": "kort inledning",
"全部": "hela",
"年度总结": "Årlig sammanfattning"
}

View File

@ -756,5 +756,12 @@
"成功": "ความสำเร็จ",
"Win32通用钩子": "ตะขอสากล Win32",
"特殊码无效": "รหัสพิเศษไม่ถูกต้อง",
"显示模式": "โหมดการแสดงผล"
"显示模式": "โหมดการแสดงผล",
"内置": "สร้างขึ้นใน",
"信息": "ข้อมูล",
"开发商": "นักพัฒนา",
"标签映射": "แผนที่ป้ายกำกับ",
"简介": "บทนำ",
"全部": "ทั้งหมด",
"年度总结": "สรุปรายปี"
}

View File

@ -756,5 +756,12 @@
"成功": "başarılı",
"Win32通用钩子": "Win32 Universal Hook",
"特殊码无效": "Özel kodu geçersiz.",
"显示模式": "Görüntü modusu"
"显示模式": "Görüntü modusu",
"内置": "in şa edilmiş",
"信息": "bilgi",
"开发商": "Geliştiriciler",
"标签映射": "Etiket Haritası",
"简介": "kısa tanıtım",
"全部": "Tüm",
"年度总结": "Yıllık Toplantı"
}

View File

@ -756,5 +756,12 @@
"成功": "успіх",
"Win32通用钩子": "Win32 Universal Hook",
"特殊码无效": "Некоректний особливий код",
"显示模式": "режим показу"
"显示模式": "режим показу",
"内置": "вбудований",
"信息": "інформація",
"开发商": "Розробники",
"标签映射": "Мапування мітки",
"简介": "коротке введення",
"全部": "цілий",
"年度总结": "Річне резюме"
}

View File

@ -756,5 +756,12 @@
"成功": "Thành công",
"Win32通用钩子": "Win32 phổ Hook",
"特殊码无效": "Mã đặc biệt không hợp lệ",
"显示模式": "Chế độ hiển thị"
"显示模式": "Chế độ hiển thị",
"内置": "Được xây dựng trong",
"信息": "Thông tin",
"开发商": "Nhà phát triển",
"标签映射": "Bản đồ nhãn",
"简介": "Giới thiệu",
"全部": "Tất cả",
"年度总结": "Tóm tắt hàng năm"
}

View File

@ -756,5 +756,12 @@
"成功": "",
"Win32通用钩子": "",
"特殊码无效": "",
"显示模式": ""
"显示模式": "",
"内置": "",
"信息": "",
"开发商": "",
"标签映射": "",
"简介": "",
"全部": "",
"年度总结": ""
}

View File

@ -0,0 +1,300 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>...</title>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/wordcloud@1.1.1/src/wordcloud2.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-wordcloud@latest/dist/echarts-wordcloud.min.js"></script>
<script src="yearsummary.value.js"></script>
<style>
.page {
display: none;
}
.active {
display: block;
}
.buttons {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: pink;
color: white;
text-align: center;
padding: 15px 0;
border: none;
font-size: 18px;
cursor: pointer;
}
.page {
height: calc(100vh - 100px);
}
#wordcloud,
#wordcloud2 {
width: 100%;
height: 100%;
}
.container {
overflow: hide;
display: flex;
padding: 10px;
gap: 20px;
height: 100%;
}
.left-box h1 {
margin: 0;
font-size: 24px;
}
.left-box p {
line-height: 1.6;
}
/* Right Boxes (Detail boxes) */
.right-box {
height: 100%;
flex: 3;
display: flex;
flex-direction: column;
gap: 20px;
}
/* Right Boxes (Detail boxes) */
.left-box {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.box {
background-color: #ffffff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.bigbox {
background-color: #ffffff;
margin-left: 10px;
margin-right: 10px;
margin-top: 20px;
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.right-box .box h3 {
margin-top: 0;
font-size: 18px;
}
.right-box .box p {
line-height: 1.4;
}
.zitiupup {
font-size: 1.5em;
display: inline-block;
}
.imagecontainer {
width: 20%;
height: auto;
aspect-ratio: 1 / 1.618;
}
.imagexx {
height: 100%;
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 100%);
}
#imagetop25 {
line-height: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div class="page active" id="page1">
<div class="container">
<!-- Left Box (Main content) -->
<div class="left-box">
<div class="box">
<h1>今年你一共总玩了 <div class="zitiupup" id="GAMES_YEAR_PLAYED"></div> 个游戏
</h1>
</div>
<div class="box" style="flex: 10;">
<h3>今年你的累计游戏时长 <div class="zitiupup" id="TIME_YEAR_PLAYED"></div> 小时,有 <div class="zitiupup"
id="TIME_YEAR_PLAYED_DAY"></div> 天玩了游戏,累计阅读字数达 <div class="zitiupup"
id="COUNT_ZISHU_YEAR_PLAYED"></div>
</h3>
<canvas id="everymonth" width="100%" height="100%"></canvas>
</div>
</div>
<!-- Right Box (Detail Boxes) -->
<div class="right-box">
<div class="box" style="height: 100%;">
<div class=" imagexx">
<div id="imagetop25"></div>
</div>
</div>
</div>
</div>
</div>
<div class="page bigbox" id="page2" style="display: flex; flex-direction: column;">
<h1 style="text-align: center; flex:1">你所玩的游戏的标签</h1>
<div style="flex:10;"><div id="wordcloud"></div></div>
</div>
<div class="page bigbox" id="page3" style="display: flex; flex-direction: column;">
<h1 style="text-align: center; flex:1">你所玩的游戏的开发商</h1>
<div style="flex:10;"><div id="wordcloud2"></div></div>
</div>
<div class="buttons"> Next</div>
<script>
havedatamonth = []
havedatamonth_v = []
for (let i = 1; i <= 12; i += 1) {
if (everymonth_time[i]) {
havedatamonth.push(i)
havedatamonth_v.push(everymonth_time[i] / 3600)
}
}
var ctx = document.getElementById('everymonth').getContext('2d');
let lastshowmonth = 0;
TOP25_TIME_IMAGE_M[0] = TOP25_TIME_IMAGE
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: havedatamonth,
datasets: [{
label: '每月游戏时长',
data: havedatamonth_v,
borderWidth: 1
}]
},
options: {
scales: {
x: {
title: {
display: true,
text: '月'
}
},
y: {
display: true,
text: '小时',
beginAtZero: true
}
},
onHover: function (event, chartElement) {
let month = 0
if (chartElement.length > 0) {
month = havedatamonth[chartElement[0].index]
}
if (lastshowmonth == month)
return
lastshowmonth = month
document.getElementById('imagetop25').innerHTML = ''
TOP25_TIME_IMAGE_M[month].forEach((path) => {
let img = document.createElement('img')
img.src = path
img.classList.add('imagecontainer')
document.getElementById('imagetop25').appendChild(img)
})
},
}
});
document.getElementById('TIME_YEAR_PLAYED_DAY').innerText = TIME_YEAR_PLAYED_DAY
document.getElementById('GAMES_YEAR_PLAYED').innerText = GAMES_YEAR_PLAYED
document.getElementById('TIME_YEAR_PLAYED').innerText = TIME_YEAR_PLAYED
document.getElementById('COUNT_ZISHU_YEAR_PLAYED').innerText = COUNT_ZISHU_YEAR_PLAYED
TOP25_TIME_IMAGE.forEach((path) => {
let img = document.createElement('img')
img.src = path
img.classList.add('imagecontainer')
document.getElementById('imagetop25').appendChild(img)
})
</script>
<script>
document.querySelector('.buttons').addEventListener('click', () => {
nextPage()
})
developer_cnt = []
webtags_cnt = []
for (k in developer) {
developer_cnt.push([k,
10 * developer[k].length
])
}
for (k in webtags) {
webtags_cnt.push([k,
webtags[k].length
])
}
let currentPage = 1;
const totalPages = 3;
window.addEventListener('resize', () => {
WordCloud(document.getElementById('wordcloud'), {
list: webtags_cnt
});
WordCloud(document.getElementById('wordcloud2'), {
list: developer_cnt
});
});
function showPage(page) {
// Hide all pages
const pages = document.querySelectorAll('.page');
pages.forEach(p => p.classList.remove('active'));
// Show the current page
document.getElementById('page' + page).classList.add('active');
if (page == 2) {
WordCloud(document.getElementById('wordcloud'), {
list: webtags_cnt
});
}
if (page == 3) {
WordCloud(document.getElementById('wordcloud2'), {
list: developer_cnt
});
}
}
function nextPage() {
if (currentPage < totalPages) {
currentPage++;
showPage(currentPage);
}
else {
const pages = document.querySelectorAll('.page');
pages.forEach(p => p.classList.add('active'));
document.querySelector('.buttons').style.display = 'none';
}
}
// Initialize the first page
showPage(currentPage);
</script>
</body>
</html>