mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2024-12-28 08:04:13 +08:00
many
1 Update websocket.py
This commit is contained in:
parent
1b6503bb70
commit
fd9049e714
@ -69,6 +69,7 @@ class MAINUI:
|
||||
self.currentsignature = None
|
||||
self.isrunning = True
|
||||
self.solvegottextlock = threading.Lock()
|
||||
self.outputers = {}
|
||||
|
||||
@property
|
||||
def textsource(self):
|
||||
@ -248,13 +249,8 @@ class MAINUI:
|
||||
except:
|
||||
pass
|
||||
if onlytrans == False:
|
||||
self.dispatchoutputer(text)
|
||||
self.currenttext = text
|
||||
if (
|
||||
globalconfig["outputtopasteboard"]
|
||||
and globalconfig["sourcestatus2"]["copy"]["use"] == False
|
||||
):
|
||||
winsharedutils.clipboard_set(text)
|
||||
|
||||
if globalconfig["read_raw"]:
|
||||
self.currentread = text
|
||||
self.autoreadcheckname()
|
||||
@ -556,16 +552,32 @@ class MAINUI:
|
||||
else:
|
||||
self.hira_ = None
|
||||
|
||||
@threader
|
||||
def startoutputer_re(self, klass):
|
||||
self.outputers[klass].init()
|
||||
|
||||
@threader
|
||||
def startoutputer(self):
|
||||
for classname in globalconfig["textoutputer"]:
|
||||
if not os.path.exists("./LunaTranslator/textoutput/" + classname + ".py"):
|
||||
continue
|
||||
aclass = importlib.import_module("textoutput." + classname).Outputer
|
||||
self.outputers[classname] = aclass(classname)
|
||||
|
||||
def dispatchoutputer(self, text):
|
||||
for _, kls in self.outputers.items():
|
||||
if kls.config["use"]:
|
||||
kls.puttask(text)
|
||||
|
||||
def fanyiinitmethod(self, classname):
|
||||
try:
|
||||
if classname == "selfbuild":
|
||||
if os.path.exists("./userconfig/selfbuild.py") == False:
|
||||
if not os.path.exists("./userconfig/selfbuild.py"):
|
||||
return None
|
||||
aclass = importlib.import_module("selfbuild").TS
|
||||
else:
|
||||
if (
|
||||
os.path.exists("./LunaTranslator/translator/" + classname + ".py")
|
||||
== False
|
||||
if not os.path.exists(
|
||||
"./LunaTranslator/translator/" + classname + ".py"
|
||||
):
|
||||
return None
|
||||
aclass = importlib.import_module("translator." + classname).TS
|
||||
@ -783,7 +795,7 @@ class MAINUI:
|
||||
self.prepare()
|
||||
self.startxiaoxueguan()
|
||||
self.starthira()
|
||||
|
||||
self.startoutputer()
|
||||
self.settin_ui = Settin(self.translation_ui)
|
||||
self.transhis = gui.transhist.transhist(self.settin_ui)
|
||||
gobject.baseobject.Prompt = Prompt()
|
||||
|
@ -54,7 +54,7 @@ import gobject
|
||||
from myutils.config import _TR, _TRL, globalconfig, static_data
|
||||
import winsharedutils
|
||||
from myutils.wrapper import Singleton_close, Singleton, threader
|
||||
from myutils.utils import checkifnewgame
|
||||
from myutils.utils import checkifnewgame, vidchangedtask
|
||||
from myutils.proxy import getproxy
|
||||
from gui.usefulwidget import yuitsu_switch, saveposwindow, getboxlayout
|
||||
from myutils.vndb import parsehtmlmethod
|
||||
@ -533,6 +533,7 @@ class dialog_setting_game(QDialog):
|
||||
|
||||
def _titlechange(x):
|
||||
savehook_new_data[exepath]["title"] = x
|
||||
savehook_new_data[exepath]["istitlesetted"] = True
|
||||
savehook_new_data[exepath]["searchnoresulttime"] = 0
|
||||
self.setWindowTitle(x)
|
||||
gametitleitme.settitle(x)
|
||||
@ -553,6 +554,7 @@ class dialog_setting_game(QDialog):
|
||||
_pixmap = QPixmap(res)
|
||||
if _pixmap.isNull() == False:
|
||||
savehook_new_data[exepath]["imagepath"] = res
|
||||
savehook_new_data[exepath]["isimagepathusersetted"] = True
|
||||
imgpath.setText(res)
|
||||
gametitleitme.setimg(_pixmap)
|
||||
|
||||
@ -572,13 +574,7 @@ class dialog_setting_game(QDialog):
|
||||
vndbid.setValidator(QIntValidator())
|
||||
vndbid.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
||||
|
||||
def changevid(exepath, text):
|
||||
savehook_new_data[exepath]["vid"] = int(text)
|
||||
savehook_new_data[exepath]["infopath"] = None
|
||||
savehook_new_data[exepath]["searchnoresulttime"] = 0
|
||||
# savehook_new_data[exepath]['imagepath']=None
|
||||
|
||||
vndbid.textEdited.connect(functools.partial(changevid, exepath))
|
||||
vndbid.textEdited.connect(functools.partial(vidchangedtask, exepath))
|
||||
|
||||
statiswids = [
|
||||
QLabel(_TR("统计信息")),
|
||||
@ -691,8 +687,8 @@ class dialog_setting_game(QDialog):
|
||||
|
||||
methodtab = QTabWidget()
|
||||
methodtab.addTab(self.gethooktab(exepath), "HOOK")
|
||||
methodtab.addTab(self.getpretranstab(exepath), "预翻译")
|
||||
methodtab.addTab(self.getttssetting(exepath), "语音")
|
||||
methodtab.addTab(self.getpretranstab(exepath), _TR("预翻译"))
|
||||
methodtab.addTab(self.getttssetting(exepath), _TR("语音"))
|
||||
formLayout.addWidget(methodtab)
|
||||
|
||||
self.show()
|
||||
|
@ -334,17 +334,55 @@ def gethookembedgrid(self):
|
||||
return grids
|
||||
|
||||
|
||||
def setTabclip(self):
|
||||
def getTabclip(self):
|
||||
|
||||
grids = [
|
||||
[
|
||||
("提取的文本自动复制到剪贴板", 5),
|
||||
(getsimpleswitch(globalconfig, "outputtopasteboard"), 1),
|
||||
("排除复制自翻译器的文本", 3),
|
||||
getsimpleswitch(globalconfig, "excule_from_self"),
|
||||
("", 3),
|
||||
]
|
||||
]
|
||||
return grids
|
||||
|
||||
|
||||
def outputgrid(self):
|
||||
|
||||
grids = [
|
||||
[("自动输出提取的文本", 10)],
|
||||
[],
|
||||
[("剪贴板", 10)],
|
||||
[
|
||||
"",
|
||||
("输出到剪贴板", 5),
|
||||
(getsimpleswitch(globalconfig["textoutputer"]["clipboard"], "use"), 1),
|
||||
],
|
||||
[("WebSocket", 10)],
|
||||
[
|
||||
"",
|
||||
("输出到WebSocket", 5),
|
||||
(
|
||||
getsimpleswitch(
|
||||
globalconfig["textoutputer"]["websocket"],
|
||||
"use",
|
||||
callback=lambda _: gobject.baseobject.startoutputer_re("websocket"),
|
||||
),
|
||||
1,
|
||||
),
|
||||
],
|
||||
[
|
||||
("排除复制自翻译器的文本", 5),
|
||||
(getsimpleswitch(globalconfig, "excule_from_self"), 1),
|
||||
"",
|
||||
("端口号", 5),
|
||||
(
|
||||
getspinbox(
|
||||
0,
|
||||
65535,
|
||||
globalconfig["textoutputer"]["websocket"],
|
||||
"port",
|
||||
callback=lambda _: gobject.baseobject.startoutputer_re("websocket"),
|
||||
),
|
||||
3,
|
||||
),
|
||||
],
|
||||
]
|
||||
return grids
|
||||
@ -462,12 +500,13 @@ def setTabOne(self):
|
||||
def setTabOne_lazy(self):
|
||||
|
||||
tab = self.makesubtab_lazy(
|
||||
["HOOK设置", "OCR设置", "剪贴板", "内嵌翻译"],
|
||||
["HOOK设置", "OCR设置", "剪贴板", "内嵌翻译", "文本输出"],
|
||||
[
|
||||
lambda: self.makescroll(self.makegrid(gethookgrid(self))),
|
||||
lambda: self.makescroll(self.makegrid(getocrgrid(self))),
|
||||
lambda: self.makescroll(self.makegrid(setTabclip(self))),
|
||||
lambda: self.makescroll(self.makegrid(getTabclip(self))),
|
||||
lambda: self.makescroll(self.makegrid(gethookembedgrid(self))),
|
||||
lambda: self.makescroll(self.makegrid(outputgrid(self))),
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -280,6 +280,13 @@ def setTab7_lazy(self):
|
||||
"",
|
||||
],
|
||||
]
|
||||
if globalconfig["languageuse"] == 2: # en
|
||||
grids2 += [
|
||||
[
|
||||
(("使用VNDB数据替换人名"), 6),
|
||||
getsimpleswitch(globalconfig, "vndbmapname"),
|
||||
]
|
||||
]
|
||||
|
||||
def __():
|
||||
_w = self.makescroll(self.makegrid(grids, True, savelist, savelay))
|
||||
|
@ -93,6 +93,8 @@ def resourcegrid(self):
|
||||
else:
|
||||
if link[-8:] == "releases":
|
||||
__ = False
|
||||
elif link[-1] == "/":
|
||||
__ = False
|
||||
else:
|
||||
__ = True
|
||||
grid.append([(_TR(name), 1, ""), (makehtml(link, __), 2, "link")])
|
||||
|
@ -60,8 +60,11 @@ def getdefaultsavehook(gamepath, title=None):
|
||||
"needinserthookcode": [],
|
||||
"embedablehook": [],
|
||||
"imagepath": None,
|
||||
"isimagepathusersetted": False,
|
||||
"istitlesetted": False,
|
||||
"infopath": None,
|
||||
"vid": 0,
|
||||
"namemap": {},
|
||||
"statistic_playtime": 0,
|
||||
"statistic_wordcount": 0,
|
||||
"statistic_wordcount_nodump": 0,
|
||||
|
@ -311,6 +311,31 @@ _selfdefpost = None
|
||||
_selfdefpostmd5 = None
|
||||
|
||||
|
||||
def trymapnameofvndb(s):
|
||||
if not ((globalconfig["languageuse"] == 2) and globalconfig["vndbmapname"]):
|
||||
return s
|
||||
|
||||
try:
|
||||
exepath = gobject.baseobject.textsource.pname
|
||||
namemap = savehook_new_data[exepath]["namemap"]
|
||||
bettermap = {}
|
||||
for k, v in namemap.items():
|
||||
spja = k.split("・")
|
||||
spen = v.split(" ")
|
||||
if len(spja) == len(spen) and len(spen) > 1:
|
||||
for i in range(len(spja)):
|
||||
if len(spja[i]) >= 2:
|
||||
bettermap[spja[i]] = spen[i]
|
||||
|
||||
for k, v in namemap.items():
|
||||
s = s.replace(k, v)
|
||||
for k, v in bettermap.items():
|
||||
s = s.replace(k, v)
|
||||
except:
|
||||
pass
|
||||
return s
|
||||
|
||||
|
||||
def POSTSOLVE(line):
|
||||
global _selfdefpostmd5, _selfdefpost
|
||||
if line == "":
|
||||
@ -399,4 +424,5 @@ def POSTSOLVE(line):
|
||||
print_exc()
|
||||
if postitem == "_11":
|
||||
raise e
|
||||
line = trymapnameofvndb(line)
|
||||
return line
|
||||
|
@ -18,10 +18,29 @@ from myutils.config import (
|
||||
getdefaultsavehook,
|
||||
)
|
||||
import threading, queue
|
||||
import re
|
||||
import re, heapq
|
||||
from myutils.vndb import searchforidimage
|
||||
|
||||
|
||||
class PriorityQueue:
|
||||
def __init__(self):
|
||||
self._heap = []
|
||||
self._sema = threading.Semaphore(0)
|
||||
self._idx = 0
|
||||
|
||||
def put(self, item, priority=0):
|
||||
heapq.heappush(self._heap, (-priority, self._idx, item))
|
||||
self._idx += 1
|
||||
self._sema.release()
|
||||
|
||||
def get(self):
|
||||
self._sema.acquire()
|
||||
return heapq.heappop(self._heap)[-1]
|
||||
|
||||
def empty(self):
|
||||
return bool(len(self._heap) == 0)
|
||||
|
||||
|
||||
def checkimage(gamepath):
|
||||
return (savehook_new_data[gamepath]["imagepath"] is None) or (
|
||||
os.path.exists(savehook_new_data[gamepath]["imagepath"]) == False
|
||||
@ -49,7 +68,7 @@ def checkneed(gamepath):
|
||||
return (gamepath in savehook_new_data) and (checkvid(gamepath))
|
||||
|
||||
|
||||
searchvndbqueue = queue.Queue()
|
||||
searchvndbqueue = PriorityQueue()
|
||||
|
||||
|
||||
def dispatachtask(gamepath):
|
||||
@ -57,7 +76,7 @@ def dispatachtask(gamepath):
|
||||
return
|
||||
__t = []
|
||||
if savehook_new_data[gamepath]["vid"]:
|
||||
searchvndbqueue.put((gamepath, [savehook_new_data[gamepath]["vid"]]))
|
||||
searchvndbqueue.put((gamepath, [savehook_new_data[gamepath]["vid"]]), 0)
|
||||
else:
|
||||
for _ in [
|
||||
savehook_new_data[gamepath]["title"],
|
||||
@ -82,7 +101,7 @@ def dispatachtask(gamepath):
|
||||
if (len(t) < 10) and (all(ord(c) < 128 for c in t)):
|
||||
continue
|
||||
lst.append(t)
|
||||
searchvndbqueue.put((gamepath, lst))
|
||||
searchvndbqueue.put((gamepath, lst), 0)
|
||||
|
||||
|
||||
def everymethodsthread():
|
||||
@ -102,13 +121,21 @@ def everymethodsthread():
|
||||
saveimg = data.get("imagepath", None)
|
||||
saveinfo = data.get("infopath", None)
|
||||
vid = data.get("vid", None)
|
||||
print(data)
|
||||
title = data.get("title", None)
|
||||
namemap = data.get("namemap", None)
|
||||
|
||||
if not vid:
|
||||
continue
|
||||
savehook_new_data[gamepath]["vid"] = int(vid[1:])
|
||||
if checkimage(gamepath):
|
||||
if saveimg and (not savehook_new_data[gamepath]["isimagepathusersetted"]):
|
||||
savehook_new_data[gamepath]["imagepath"] = saveimg
|
||||
savehook_new_data[gamepath]["infopath"] = saveinfo
|
||||
if title and (not savehook_new_data[gamepath]["istitlesetted"]):
|
||||
savehook_new_data[gamepath]["title"] = title
|
||||
if saveinfo:
|
||||
savehook_new_data[gamepath]["infopath"] = saveinfo
|
||||
if namemap:
|
||||
savehook_new_data[gamepath]["namemap"] = namemap
|
||||
print(namemap)
|
||||
succ = True
|
||||
break
|
||||
if succ == False:
|
||||
@ -118,6 +145,17 @@ def everymethodsthread():
|
||||
threading.Thread(target=everymethodsthread).start()
|
||||
|
||||
|
||||
def vidchangedtask(gamepath, vid):
|
||||
try:
|
||||
vid = int(vid)
|
||||
except:
|
||||
return
|
||||
savehook_new_data[gamepath]["vid"] = vid
|
||||
savehook_new_data[gamepath]["infopath"] = None
|
||||
savehook_new_data[gamepath]["searchnoresulttime"] = 0
|
||||
searchvndbqueue.put((gamepath, [vid]), 1)
|
||||
|
||||
|
||||
def checkifnewgame(gamepath, title=None):
|
||||
if gamepath not in savehook_new_list:
|
||||
savehook_new_list.insert(0, gamepath)
|
||||
|
@ -72,69 +72,103 @@ def vndbdowloadinfo(vid):
|
||||
return savepath
|
||||
|
||||
|
||||
def searchforidimage(title):
|
||||
if isinstance(title, str):
|
||||
if os.path.exists("./cache/vndb") == False:
|
||||
os.mkdir("./cache/vndb")
|
||||
js = requests.post(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
json={
|
||||
"filters": ["search", "=", title],
|
||||
"fields": "image.url",
|
||||
"sort": "searchrank",
|
||||
},
|
||||
def safegetvndbjson(url, json, getter):
|
||||
try:
|
||||
_ = requests.post(
|
||||
url,
|
||||
json=json,
|
||||
proxies=getproxy(),
|
||||
)
|
||||
try:
|
||||
results = js.json()["results"]
|
||||
return getter(_.json())
|
||||
except:
|
||||
print(js.text)
|
||||
return {}
|
||||
if len(results) == 0:
|
||||
js = requests.post(
|
||||
"https://api.vndb.org/kana/release",
|
||||
json={
|
||||
"filters": ["search", "=", title],
|
||||
"fields": "vns.id",
|
||||
"sort": "searchrank",
|
||||
},
|
||||
proxies=getproxy(),
|
||||
)
|
||||
results = js.json()["results"]
|
||||
if len(results) == 0:
|
||||
return {}
|
||||
vns = results[0]["vns"]
|
||||
if len(vns) == 0:
|
||||
return {}
|
||||
vid = vns[0]["id"]
|
||||
js = requests.post(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
json={"filters": ["id", "=", vid], "fields": "image.url"},
|
||||
proxies=getproxy(),
|
||||
)
|
||||
try:
|
||||
results = js.json()["results"]
|
||||
except:
|
||||
print(js.text)
|
||||
return {}
|
||||
img = results[0]["image"]["url"]
|
||||
else:
|
||||
img = results[0]["image"]["url"]
|
||||
vid = results[0]["id"]
|
||||
elif isinstance(title, int):
|
||||
vid = "v{}".format(title)
|
||||
js = requests.post(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
json={"filters": ["id", "=", vid], "fields": "image.url"},
|
||||
proxies=getproxy(),
|
||||
)
|
||||
print(_.text)
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def gettitlebyid(vid):
|
||||
def _getter(js):
|
||||
try:
|
||||
results = js.json()["results"]
|
||||
return js["results"][0]["titles"][0]["title"] # ja title
|
||||
except:
|
||||
print(js.text)
|
||||
return {}
|
||||
img = results[0]["image"]["url"]
|
||||
return js["results"][0]["title"] # en title
|
||||
|
||||
return safegetvndbjson(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
{"filters": ["id", "=", vid], "fields": "title,titles.title"},
|
||||
_getter,
|
||||
)
|
||||
|
||||
|
||||
def getimgbyid(vid):
|
||||
return safegetvndbjson(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
{"filters": ["id", "=", vid], "fields": "image.url"},
|
||||
lambda js: js["results"][0]["image"]["url"],
|
||||
)
|
||||
|
||||
|
||||
def getvidbytitle_vn(title):
|
||||
return safegetvndbjson(
|
||||
"https://api.vndb.org/kana/vn",
|
||||
{"filters": ["search", "=", title], "fields": "id", "sort": "searchrank"},
|
||||
lambda js: js["results"][0]["id"],
|
||||
)
|
||||
|
||||
|
||||
def getvidbytitle_release(title):
|
||||
return safegetvndbjson(
|
||||
"https://api.vndb.org/kana/release",
|
||||
{"filters": ["search", "=", title], "fields": "id", "sort": "searchrank"},
|
||||
lambda js: js["results"][0]["id"],
|
||||
)
|
||||
|
||||
|
||||
def getvidbytitle(title):
|
||||
vid = getvidbytitle_vn(title)
|
||||
if vid:
|
||||
return vid
|
||||
return getvidbytitle_release(title)
|
||||
|
||||
|
||||
def getcharnamemapbyid(vid):
|
||||
res = safegetvndbjson(
|
||||
"https://api.vndb.org/kana/character",
|
||||
{
|
||||
"filters": [
|
||||
"vn",
|
||||
"=",
|
||||
["id", "=", vid],
|
||||
],
|
||||
"fields": "name,original",
|
||||
},
|
||||
lambda js: js["results"],
|
||||
)
|
||||
namemap = {}
|
||||
try:
|
||||
for r in res:
|
||||
namemap[r["original"]] = r["name"]
|
||||
except:
|
||||
pass
|
||||
return namemap
|
||||
|
||||
|
||||
def searchforidimage(titleorid):
|
||||
print(titleorid)
|
||||
if os.path.exists("./cache/vndb") == False:
|
||||
os.mkdir("./cache/vndb")
|
||||
if isinstance(titleorid, str):
|
||||
vid = getvidbytitle(titleorid)
|
||||
elif isinstance(titleorid, int):
|
||||
vid = "v{}".format(titleorid)
|
||||
img = getimgbyid(vid)
|
||||
title = gettitlebyid(vid)
|
||||
namemap = getcharnamemapbyid(vid)
|
||||
return {
|
||||
"namemap": namemap,
|
||||
"title": title,
|
||||
"vid": vid,
|
||||
"infopath": vndbdowloadinfo(vid),
|
||||
"imagepath": vndbdownloadimg(img),
|
||||
|
11
LunaTranslator/LunaTranslator/textoutput/clipboard.py
Normal file
11
LunaTranslator/LunaTranslator/textoutput/clipboard.py
Normal file
@ -0,0 +1,11 @@
|
||||
from textoutput.outputerbase import Base
|
||||
from myutils.config import globalconfig
|
||||
import winsharedutils
|
||||
|
||||
|
||||
class Outputer(Base):
|
||||
def dispatch(self, text):
|
||||
if globalconfig["sourcestatus2"]["copy"]["use"]:
|
||||
return
|
||||
|
||||
winsharedutils.clipboard_set(text)
|
29
LunaTranslator/LunaTranslator/textoutput/outputerbase.py
Normal file
29
LunaTranslator/LunaTranslator/textoutput/outputerbase.py
Normal file
@ -0,0 +1,29 @@
|
||||
from myutils.config import globalconfig
|
||||
from threading import Thread
|
||||
from queue import Queue
|
||||
|
||||
|
||||
class Base:
|
||||
@property
|
||||
def config(self):
|
||||
return globalconfig["textoutputer"][self.classname]
|
||||
|
||||
def dispatch(self, text):
|
||||
pass
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def __init__(self, classname):
|
||||
self.classname = classname
|
||||
self.queue = Queue()
|
||||
self.init()
|
||||
Thread(target=self.dothread).start()
|
||||
|
||||
def dothread(self):
|
||||
while True:
|
||||
text = self.queue.get()
|
||||
self.dispatch(text)
|
||||
|
||||
def puttask(self, text):
|
||||
self.queue.put(text)
|
105
LunaTranslator/LunaTranslator/textoutput/websocket.py
Normal file
105
LunaTranslator/LunaTranslator/textoutput/websocket.py
Normal file
@ -0,0 +1,105 @@
|
||||
from textoutput.outputerbase import Base
|
||||
from traceback import print_exc
|
||||
import socket
|
||||
from base64 import encodebytes as base64encode
|
||||
import hashlib
|
||||
from myutils.wrapper import threader
|
||||
|
||||
|
||||
class websocketserver:
|
||||
def stop(self):
|
||||
self.server_socket.close()
|
||||
for sock in self.connectedsockets:
|
||||
try:
|
||||
sock.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def __init__(self, port):
|
||||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.server_socket.bind(("localhost", port))
|
||||
self.connectedsockets = []
|
||||
self.errorsocks = []
|
||||
self.listen()
|
||||
|
||||
@threader
|
||||
def listen(self):
|
||||
|
||||
self.server_socket.listen(1)
|
||||
while True:
|
||||
client_socket, address = self.server_socket.accept()
|
||||
print(f"Client connected: {address}")
|
||||
|
||||
self.handle_client(client_socket)
|
||||
|
||||
@threader
|
||||
def handle_client(self, client_socket: socket.socket):
|
||||
# 接收客户端的握手请求
|
||||
request = client_socket.recv(1024).decode()
|
||||
|
||||
# 解析握手请求中的 WebSocket 关键信息
|
||||
key = ""
|
||||
for line in request.split("\r\n"):
|
||||
if "Sec-WebSocket-Key:" in line:
|
||||
key = line.split(":")[1].strip()
|
||||
break
|
||||
value = f"{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11".encode("utf-8")
|
||||
hashed = base64encode(hashlib.sha1(value).digest()).strip().lower().decode()
|
||||
# 构造握手响应
|
||||
response = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
response += "Upgrade: websocket\r\n"
|
||||
response += "Connection: Upgrade\r\n"
|
||||
response += "sec-websocket-protocol: 111\r\n"
|
||||
response += f"Sec-WebSocket-Accept: {hashed}\r\n\r\n"
|
||||
|
||||
# 发送握手响应给客户端
|
||||
client_socket.send(response.encode())
|
||||
self.connectedsockets.append(client_socket)
|
||||
|
||||
def maketextframe(self, message):
|
||||
|
||||
fin = 1
|
||||
opcode = 0x1
|
||||
payload = message.encode("utf-8")
|
||||
length = len(payload)
|
||||
|
||||
frame = bytearray()
|
||||
frame.append((fin << 7) | opcode)
|
||||
|
||||
if length <= 125:
|
||||
frame.append(length)
|
||||
elif length <= 65535:
|
||||
frame.extend([126, (length >> 8) & 0xFF, length & 0xFF])
|
||||
else:
|
||||
frame.extend([127] + [(length >> (8 * i)) & 0xFF for i in range(7, -1, -1)])
|
||||
|
||||
frame.extend(payload)
|
||||
return frame
|
||||
|
||||
def sendtext(self, text):
|
||||
frame = self.maketextframe(text)
|
||||
for i, sock in enumerate(self.connectedsockets):
|
||||
if i in self.errorsocks:
|
||||
continue
|
||||
try:
|
||||
sock.send(frame)
|
||||
except:
|
||||
self.errorsocks.append(i)
|
||||
|
||||
|
||||
class Outputer(Base):
|
||||
def init(self):
|
||||
|
||||
try:
|
||||
self.server.stop()
|
||||
except:
|
||||
pass
|
||||
if not self.config["use"]:
|
||||
return
|
||||
try:
|
||||
self.server = websocketserver(self.config["port"])
|
||||
except:
|
||||
print_exc()
|
||||
|
||||
def dispatch(self, text):
|
||||
self.server.sendtext(text)
|
@ -3,12 +3,12 @@ from queue import Queue
|
||||
|
||||
from myutils.config import globalconfig, translatorsetting, static_data
|
||||
from threading import Thread
|
||||
import threading, time, types, heapq
|
||||
import time, types
|
||||
import zhconv, gobject
|
||||
import sqlite3
|
||||
from myutils.commonbase import commonbase
|
||||
import functools
|
||||
from myutils.utils import stringfyerror, autosql
|
||||
from myutils.utils import stringfyerror, autosql, PriorityQueue
|
||||
from myutils.commonbase import ArgsEmptyExc
|
||||
|
||||
|
||||
@ -57,25 +57,6 @@ def timeoutfunction(
|
||||
return t.get_result(timeout, checktutukufunction)
|
||||
|
||||
|
||||
class PriorityQueue:
|
||||
def __init__(self):
|
||||
self._heap = []
|
||||
self._sema = threading.Semaphore(0)
|
||||
self._idx = 0
|
||||
|
||||
def put(self, item, priority=0):
|
||||
heapq.heappush(self._heap, (-priority, self._idx, item))
|
||||
self._idx += 1
|
||||
self._sema.release()
|
||||
|
||||
def get(self):
|
||||
self._sema.acquire()
|
||||
return heapq.heappop(self._heap)[-1]
|
||||
|
||||
def empty(self):
|
||||
return bool(len(self._heap) == 0)
|
||||
|
||||
|
||||
class basetrans(commonbase):
|
||||
def langmap(self):
|
||||
return {}
|
||||
|
@ -11,11 +11,21 @@
|
||||
"read_trans": false,
|
||||
"read_translator": 0,
|
||||
"disappear_delay": 5,
|
||||
"vndbmapname":false,
|
||||
"network":1,
|
||||
"hookmagpie":true,
|
||||
"hooklossless":true,
|
||||
"direct_filterrepeat":false,
|
||||
"allow_set_text_name":false,
|
||||
"textoutputer":{
|
||||
"clipboard":{
|
||||
"use":false
|
||||
},
|
||||
"websocket":{
|
||||
"use":false,
|
||||
"port":2333
|
||||
}
|
||||
},
|
||||
"embedded": {
|
||||
"safecheck_use":true,
|
||||
"safecheckregexs": [
|
||||
@ -682,7 +692,6 @@
|
||||
"lighttheme":0,
|
||||
"usesearchword": false,
|
||||
"usecopyword":false,
|
||||
"outputtopasteboard": false,
|
||||
"ttscommon": {
|
||||
"rate": 1.0,
|
||||
"volume": 100.0,
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version":"v2.42.1",
|
||||
"version":"v2.43.0",
|
||||
"themes":{
|
||||
"dark":[
|
||||
{"file":"dark1.qss","name":"PyQtDarkTheme"},
|
||||
@ -101,6 +101,10 @@
|
||||
"name": "MeCab",
|
||||
"link": "https://github.com/HIllya51/RESOURCES/releases/download/dictionary/Mecab.zip"
|
||||
},
|
||||
{
|
||||
"name": "MeCab_unidic_latest",
|
||||
"link": "https://clrd.ninjal.ac.jp/unidic/"
|
||||
},
|
||||
{
|
||||
"name": "Unidic",
|
||||
"link": "https://clrd.ninjal.ac.jp/unidic_archive/2302/unidic-cwj-202302.zip"
|
||||
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "لا يقاطع",
|
||||
"显示/隐藏历史翻译": "إظهار / إخفاء التاريخ",
|
||||
"全屏/恢复游戏窗口": "كامل الشاشة / استعادة نافذة اللعبة",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "لا تحميل نموذج التعرف الضوئي على الحروف في هذه اللغة ، يرجى [ إعدادات أخرى ] - > [ تحميل الموارد ] - > [ التعرف الضوئي على الحروف حزمة اللغة ] تحميل نموذج استخراج الملفات / التعرف الضوئي على الحروف الطريق بعد استخدام"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "لا تحميل نموذج التعرف الضوئي على الحروف في هذه اللغة ، يرجى [ إعدادات أخرى ] - > [ تحميل الموارد ] - > [ التعرف الضوئي على الحروف حزمة اللغة ] تحميل نموذج استخراج الملفات / التعرف الضوئي على الحروف الطريق بعد استخدام",
|
||||
"使用VNDB数据替换人名": "استبدال اسم الشخص مع بيانات فندب"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "不被打斷",
|
||||
"显示/隐藏历史翻译": "顯示/隱藏歷史翻譯",
|
||||
"全屏/恢复游戏窗口": "全屏/恢復遊戲視窗",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "未下載該語言的OCR模型,請在[其他設定]->[資源下載]->[OCR語言包]下載模型解壓到files/ocr路徑後使用"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "未下載該語言的OCR模型,請在[其他設定]->[資源下載]->[OCR語言包]下載模型解壓到files/ocr路徑後使用",
|
||||
"使用VNDB数据替换人名": "使用VNDB數據替換人名"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Not interrupted",
|
||||
"显示/隐藏历史翻译": "Show/hide historical translations",
|
||||
"全屏/恢复游戏窗口": "Full screen/restore game window",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "The OCR model for this language has not been downloaded. Please unzip the model to the files/ocr path in [Other Settings] ->[Resource Download] ->[OCR Language Pack] and use it"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "The OCR model for this language has not been downloaded. Please unzip the model to the files/ocr path in [Other Settings] ->[Resource Download] ->[OCR Language Pack] and use it",
|
||||
"使用VNDB数据替换人名": "Replace person names with VNDB data"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Sin ser interrumpido",
|
||||
"显示/隐藏历史翻译": "Mostrar / ocultar la traducción histórica",
|
||||
"全屏/恢复游戏窗口": "Pantalla completa / restaurar la ventana del juego",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "El modelo OCR del idioma no se ha descargado, por favor use después de descargar el modelo a la ruta files / OCR [configuración adicional] - > descarga de recursos] - > paquete de lenguaje ocr]"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "El modelo OCR del idioma no se ha descargado, por favor use después de descargar el modelo a la ruta files / OCR [configuración adicional] - > descarga de recursos] - > paquete de lenguaje ocr]",
|
||||
"使用VNDB数据替换人名": "Reemplazar nombres con datos vndb"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Ne pas être interrompu",
|
||||
"显示/隐藏历史翻译": "Afficher / masquer les traductions historiques",
|
||||
"全屏/恢复游戏窗口": "Plein écran / restaurer la fenêtre de jeu",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Le modèle OCR pour cette langue n'a pas été téléchargé, utilisez - le après [autres paramètres] - > [ressources télécharger] - > [OCR Language Pack] télécharger le modèle Décompresser le chemin files / ocr"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Le modèle OCR pour cette langue n'a pas été téléchargé, utilisez - le après [autres paramètres] - > [ressources télécharger] - > [OCR Language Pack] télécharger le modèle Décompresser le chemin files / ocr",
|
||||
"使用VNDB数据替换人名": "Remplacement des noms de personnes par des données vndb"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Non interrotto",
|
||||
"显示/隐藏历史翻译": "Mostra/nasconde traduzioni storiche",
|
||||
"全屏/恢复游戏窗口": "Finestra di gioco a schermo intero/ripristino",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Il modello OCR per questa lingua non è stato scaricato. Si prega di decomprimere il modello nel percorso file/ocr in [Altre impostazioni] ->[Scaricare risorse] ->[OCR Language Pack] e utilizzarlo"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Il modello OCR per questa lingua non è stato scaricato. Si prega di decomprimere il modello nel percorso file/ocr in [Altre impostazioni] ->[Scaricare risorse] ->[OCR Language Pack] e utilizzarlo",
|
||||
"使用VNDB数据替换人名": "Sostituisci i nomi delle persone con dati VNDB"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "中断されない",
|
||||
"显示/隐藏历史翻译": "履歴翻訳の表示/非表示",
|
||||
"全屏/恢复游戏窗口": "フルスクリーン/リカバリゲームウィンドウ",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "この言語のOCRモデルはダウンロードされていません。[その他の設定]->[リソースダウンロード]->[OCR言語パック]ダウンロードモデルをfiles/ocrパスに解凍した後に使用してください"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "この言語のOCRモデルはダウンロードされていません。[その他の設定]->[リソースダウンロード]->[OCR言語パック]ダウンロードモデルをfiles/ocrパスに解凍した後に使用してください",
|
||||
"使用VNDB数据替换人名": "VNDBデータを使用した人名の置換"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"离线": "오프라인",
|
||||
"显示/隐藏历史翻译": "히스토리 번역 표시 / 숨기기",
|
||||
"全屏/恢复游戏窗口": "전체 화면 / 게임 창 복원",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "이 언어의 OCR 모델을 다운로드하지 않았습니다. [기타 설정] -> [에셋 다운로드] -> [OCR 언어 팩] 모델을 다운로드하여 files/ocr 경로로 압축을 푼 후 사용하십시오."
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "이 언어의 OCR 모델을 다운로드하지 않았습니다. [기타 설정] -> [에셋 다운로드] -> [OCR 언어 팩] 모델을 다운로드하여 files/ocr 경로로 압축을 푼 후 사용하십시오.",
|
||||
"使用VNDB数据替换人名": "VNDB 데이터로 사람 이름 바꾸기"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Bez przerwy",
|
||||
"显示/隐藏历史翻译": "Pokaż/ukryj tłumaczenia historyczne",
|
||||
"全屏/恢复游戏窗口": "Pełny ekran/przywróć okno gry",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Model OCR dla tego języka nie został pobrany. Proszę rozpakować model do ścieżki plików/ocr w [Inne ustawienia] ->[Pobieranie zasobów] ->[OCR Language Pack] i użyć go"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Model OCR dla tego języka nie został pobrany. Proszę rozpakować model do ścieżki plików/ocr w [Inne ustawienia] ->[Pobieranie zasobów] ->[OCR Language Pack] i użyć go",
|
||||
"使用VNDB数据替换人名": "Zastąp nazwiska osób na dane VNDB"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"非官方": "Неофициальные",
|
||||
"显示/隐藏历史翻译": "Показать / скрыть исторический перевод",
|
||||
"全屏/恢复游戏窗口": "Полноэкранное / Восстановление игрового окна",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Модель OCR для этого языка не загружена, используйте ее после того, как [другие настройки] - > [загрузка ресурсов] - > [языковой пакет OCR] загрузит модель на путь files / ocr"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Модель OCR для этого языка не загружена, используйте ее после того, как [другие настройки] - > [загрузка ресурсов] - > [языковой пакет OCR] загрузит модель на путь files / ocr",
|
||||
"使用VNDB数据替换人名": "Использование данных VNDB для замены имен"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "ไม่ถูกขัดจังหวะ",
|
||||
"显示/隐藏历史翻译": "แสดง/ซ่อนการแปลประวัติ",
|
||||
"全屏/恢复游戏窗口": "เต็มหน้าจอ/กู้คืนหน้าต่างเกม",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "ไม่มีการดาวน์โหลดรุ่น OCR สำหรับภาษาโปรดใช้หลังจาก [การตั้งค่าอื่น ๆ] -> [ดาวน์โหลดทรัพยากร] -> [ชุดภาษา OCR] ดาวน์โหลดแบบจำลองเปิดเส้นทางไฟล์ / OCR"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "ไม่มีการดาวน์โหลดรุ่น OCR สำหรับภาษาโปรดใช้หลังจาก [การตั้งค่าอื่น ๆ] -> [ดาวน์โหลดทรัพยากร] -> [ชุดภาษา OCR] ดาวน์โหลดแบบจำลองเปิดเส้นทางไฟล์ / OCR",
|
||||
"使用VNDB数据替换人名": "แทนที่ชื่อบุคคลด้วยข้อมูล VNDB"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Bırakılmadı",
|
||||
"显示/隐藏历史翻译": "Tarihi çevirimleri göster/gizle",
|
||||
"全屏/恢复游戏窗口": "Full screen/restore game window",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Bu dilin OCR modeli indirilmedi. Lütfen modelini [Diğer Ayarlar] ->[Kaynak İndirme] ->[OCR Dil Paketi] içindeki dosyalara/ikiyüzlü yola bağlayın ve kullanın"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Bu dilin OCR modeli indirilmedi. Lütfen modelini [Diğer Ayarlar] ->[Kaynak İndirme] ->[OCR Dil Paketi] içindeki dosyalara/ikiyüzlü yola bağlayın ve kullanın",
|
||||
"使用VNDB数据替换人名": "İnsan isimlerini VNDB veriyle değiştir"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"不被打断": "Не перервано",
|
||||
"显示/隐藏历史翻译": "Показувати/сховати історичні переклади",
|
||||
"全屏/恢复游戏窗口": "Повний екран / відновити вікно гри",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Модель OCR для цієї мови не було звантажено. Будь ласка, відкрийте модель до шляху до файлів/ocr у [Інші параметри] ->[Звантаження ресурсів] ->[Пакет мови OCR] і скористайтеся ним"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Модель OCR для цієї мови не було звантажено. Будь ласка, відкрийте модель до шляху до файлів/ocr у [Інші параметри] ->[Звантаження ресурсів] ->[Пакет мови OCR] і скористайтеся ним",
|
||||
"使用VNDB数据替换人名": "Замінити назви людей даними VNDB"
|
||||
}
|
@ -743,5 +743,6 @@
|
||||
"非官方": "Không chính thức",
|
||||
"显示/隐藏历史翻译": "Hiện/ẩn bản dịch lịch sử",
|
||||
"全屏/恢复游戏窗口": "Toàn màn hình/Khôi phục cửa sổ trò chơi",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Mô hình OCR cho ngôn ngữ này chưa được tải xuống, vui lòng sử dụng sau khi [Cài đặt bổ sung] ->[Tải xuống tài nguyên] ->[Gói ngôn ngữ OCR] mô hình tải xuống đã được giải nén vào đường dẫn files/ocr"
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "Mô hình OCR cho ngôn ngữ này chưa được tải xuống, vui lòng sử dụng sau khi [Cài đặt bổ sung] ->[Tải xuống tài nguyên] ->[Gói ngôn ngữ OCR] mô hình tải xuống đã được giải nén vào đường dẫn files/ocr",
|
||||
"使用VNDB数据替换人名": "Thay tên người bằng dữ liệu VNDB"
|
||||
}
|
@ -129,7 +129,6 @@
|
||||
"其他": "",
|
||||
"设置所有词条为全局词条": "",
|
||||
"过滤数字和英文字母": "",
|
||||
"提取的文本自动复制到剪贴板": "",
|
||||
"Unicode范围": "",
|
||||
"原文颜色": "",
|
||||
"未开始": "",
|
||||
@ -743,5 +742,10 @@
|
||||
"不被打断": "",
|
||||
"显示/隐藏历史翻译": "",
|
||||
"全屏/恢复游戏窗口": "",
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": ""
|
||||
"未下载该语言的OCR模型,请在[其他设置]->[资源下载]->[OCR语言包]下载模型解压到files/ocr路径后使用": "",
|
||||
"使用VNDB数据替换人名": "",
|
||||
"文本输出": "",
|
||||
"自动输出提取的文本": "",
|
||||
"输出到剪贴板": "",
|
||||
"输出到WebSocket": ""
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user