so many update

Update static_data.json
This commit is contained in:
恍兮惚兮 2024-03-23 18:33:58 +08:00
parent 1a206bc938
commit 973417b48e
33 changed files with 25468 additions and 266 deletions

View File

@ -0,0 +1,73 @@
{
"files.associations": {
"xstring": "cpp",
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"deque": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"format": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"locale": "cpp",
"memory": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"queue": "cpp",
"ranges": "cpp",
"ratio": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xtr1common": "cpp",
"xutility": "cpp"
}
}

View File

@ -109,7 +109,13 @@ class MAINUI() :
return content,(mp1,mp2,mp3) return content,(mp1,mp2,mp3)
def parsemayberegexreplace(self,dict,res):
for item in dict:
if item['regex']:
res=re.sub(codecs.escape_decode(bytes(item['key'], "utf-8"))[0].decode("utf-8"),codecs.escape_decode(bytes(item['value'], "utf-8"))[0].decode("utf-8"),res)
else:
res=res.replace(item['key'],item['value'])
return res
def solveaftertrans(self,res,mp): def solveaftertrans(self,res,mp):
mp1,mp2,mp3=mp mp1,mp2,mp3=mp
#print(res,mp)#hello #print(res,mp)#hello
@ -133,11 +139,7 @@ class MAINUI() :
if key in res: if key in res:
res=res.replace(key,value['text']) res=res.replace(key,value['text'])
if transerrorfixdictconfig['use']: if transerrorfixdictconfig['use']:
for item in transerrorfixdictconfig['dict_v2']: res=self.parsemayberegexreplace(transerrorfixdictconfig['dict_v2'])
if item['regex']:
res=re.sub(codecs.escape_decode(bytes(item['key'], "utf-8"))[0].decode("utf-8"),codecs.escape_decode(bytes(item['value'], "utf-8"))[0].decode("utf-8"),res)
else:
res=res.replace(item['key'],item['value'])
return res return res
def _POSTSOLVE(self,s): def _POSTSOLVE(self,s):
@ -325,7 +327,8 @@ class MAINUI() :
def readcurrent(self,force=False): def readcurrent(self,force=False):
try: try:
if force or globalconfig['autoread']: if force or globalconfig['autoread']:
self.reader.read(self.currentread) text=self.parsemayberegexreplace(globalconfig['ttscommon']['tts_repair_regex'],self.currenttext)
self.reader.read(text)
except: except:
print_exc() print_exc()
@threader @threader

View File

@ -6,9 +6,149 @@ from PyQt5.QtGui import QCloseEvent, QStandardItem, QStandardItemModel
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
import qtawesome,importlib import qtawesome,importlib
from myutils.config import globalconfig ,_TR,_TRL from myutils.config import globalconfig ,_TR,_TRL
from gui.usefulwidget import MySwitch ,selectcolor from gui.usefulwidget import MySwitch ,selectcolor,getsimpleswitch
from myutils.utils import makehtml from myutils.utils import makehtml
from myutils.wrapper import Singleton from myutils.wrapper import Singleton
@Singleton
class noundictconfigdialog1(QDialog):
def newline(self,row,item):
self.model.insertRow(row,[QStandardItem(),QStandardItem(item['key']),QStandardItem(item['value'])])
self.table.setIndexWidget(self.model.index(row, 0),getsimpleswitch(item,'regex'))
def __init__(self,parent,configdict,configkey,title,label) -> None:
super().__init__(parent,Qt.WindowCloseButtonHint)
self.setWindowTitle(_TR(title))
#self.setWindowModality(Qt.ApplicationModal)
formLayout = QVBoxLayout(self) # 配置layout
self.model=QStandardItemModel()
self.model.setHorizontalHeaderLabels(_TRL(label))
table = QTableView(self)
table.setModel(self.model)
table.horizontalHeader().setSectionResizeMode(2,QHeaderView.Stretch)
table.horizontalHeader().setSectionResizeMode(1,QHeaderView.Stretch)
table.horizontalHeader().setSectionResizeMode(0,QHeaderView.ResizeToContents)
self.table=table
for row,item in enumerate(configdict[configkey]):
self.newline(row,item)
search=QHBoxLayout()
searchcontent=QLineEdit()
search.addWidget(searchcontent)
button4=QPushButton()
button4.setText(_TR('搜索'))
def clicked4():
text=searchcontent.text()
rows=self.model.rowCount()
cols=self.model.columnCount()
for row in range(rows):
ishide=True
for c in range(cols):
if text in self.model.item(row,c).text():
ishide=False
break
table.setRowHidden(row,ishide)
button4.clicked.connect(clicked4)
search.addWidget(button4)
button=QPushButton(self)
button.setText(_TR('添加行'))
def clicked1():
self.configdict[configkey].insert(0,{'key':'','value':'','regex':False})
self.newline(0,self.configdict[configkey][0])
button.clicked.connect(clicked1)
button2=QPushButton(self)
button2.setText(_TR('删除选中行'))
def clicked2():
self.model.removeRow(table.currentIndex().row())
self.configdict[configkey].pop(table.currentIndex().row())
button2.clicked.connect(clicked2)
self.button=button
self.configdict=configdict
self.configkey=configkey
formLayout.addWidget(table)
formLayout.addLayout(search)
formLayout.addWidget(button)
formLayout.addWidget(button2)
self.resize(QSize(600,400))
self.show()
def closeEvent(self, a0: QCloseEvent) -> None:
self.button.setFocus()
rows=self.model.rowCount()
rowoffset=0
dedump=set()
for row in range(rows):
k,v=self.model.item(row,1).text(),self.model.item(row,2).text()
if k=="" or k in dedump:
self.configdict[self.configkey].pop(row-rowoffset)
rowoffset+=1
continue
self.configdict[self.configkey][row-rowoffset].update({
'key':k,'value':v
})
dedump.add(k)
@Singleton
class regexedit(QDialog):
def __init__(self,parent,regexlist) -> None:
super().__init__(parent,Qt.WindowCloseButtonHint)
self.regexlist=regexlist
self.setWindowTitle(_TR('正则匹配'))
formLayout = QVBoxLayout(self) # 配置layout
self.model=QStandardItemModel()
self.model.setHorizontalHeaderLabels(_TRL(['正则']))
table = QTableView(self)
table.setModel(self.model)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table=table
for row,regex in enumerate(regexlist):
self.model.insertRow(row,[QStandardItem(regex)])
button=QPushButton(self)
button.setText(_TR('添加行'))
def clicked1():
regexlist.insert(0,'')
self.model.insertRow(0,[QStandardItem()])
button.clicked.connect(clicked1)
button2=QPushButton(self)
button2.setText(_TR('删除选中行'))
def clicked2():
self.model.removeRow(table.currentIndex().row())
regexlist.pop(table.currentIndex().row())
button2.clicked.connect(clicked2)
self.button=button
formLayout.addWidget(table)
formLayout.addWidget(button)
formLayout.addWidget(button2)
self.resize(QSize(600,400))
self.show()
def closeEvent(self,_) -> None:
self.button.setFocus()
rows=self.model.rowCount()
rowoffset=0
dedump=set()
for row in range(rows):
regex=self.model.item(row,0).text()
if regex=="" or regex in dedump:
self.regexlist.pop(row-rowoffset)
rowoffset+=1
continue
self.regexlist[row-rowoffset]=regex
dedump.add(regex)
def autoinitdialog_items(dict): def autoinitdialog_items(dict):
items=[] items=[]
for arg in dict['args']: for arg in dict['args']:

View File

@ -4,41 +4,29 @@ from PyQt5.QtCore import Qt,QSize
import sqlite3 import sqlite3
import json import json
from traceback import print_exc from traceback import print_exc
import os import functools
from myutils.config import globalconfig,_TR from myutils.config import globalconfig,_TR
from myutils.utils import autosql from myutils.utils import autosql
from gui.usefulwidget import getQMessageBox from gui.usefulwidget import getQMessageBox
def sqlite2json(self): def sqlite2json2(self,sqlitefile,targetjson=None):
f=QFileDialog.getOpenFileName(directory='./translation_record', filter="*.sqlite")
if f[0]=='' :
return
try: try:
sql=autosql(sqlite3.connect(f[0],check_same_thread=False)) sql=autosql(sqlite3.connect(sqlitefile,check_same_thread=False))
ret=sql.execute('SELECT * FROM artificialtrans ').fetchall() ret=sql.execute('SELECT * FROM artificialtrans ').fetchall()
js={}
js_format2={} js_format2={}
collect={} collect=set()
for _aret in ret: for _aret in ret:
if len(_aret)==4: if len(_aret)==4:
_id,source,mt,ut=_aret _id,source,mt,realsource=_aret
js[source]={'userTrans':ut,'machineTrans':mt} js_format2[realsource]=mt
js_format2[source]=mt
elif len(_aret)==3: elif len(_aret)==3:
_id,source,mt =_aret _id,source,mt =_aret
js[source]={'userTrans':'','machineTrans':''} js_format2[source]=mt
js_format2[source]=''
mtjs=json.loads(mt) mtjs=json.loads(mt)
for _i,_t in enumerate(mtjs): js_format2[source]=mtjs
if _i==0 :
js[source]['machineTrans']=mtjs[_t]
js_format2[source]=mtjs[_t]
js[source]['result_'+str(_i)]=mtjs[_t]
js[source]['api_'+str(_i)]=_t
collect[_t]='result_'+str(_i)
collect=collect.union(set(mtjs.keys()))
collect=list(collect)
except: except:
print_exc() print_exc()
getQMessageBox(self,"错误","所选文件格式错误!") getQMessageBox(self,"错误","所选文件格式错误!")
@ -57,11 +45,11 @@ def sqlite2json(self):
formLayout.addRow(_TR("首选翻译"),combo) formLayout.addRow(_TR("首选翻译"),combo)
e=QLineEdit(f[0][:-(len('.sqlite'))]) e=QLineEdit(sqlitefile[:-(len('.sqlite'))])
bu=QPushButton(_TR('选择路径') ) bu=QPushButton(_TR('选择路径') )
def __selectsavepath(): def __selectsavepath():
ff=QFileDialog.getSaveFileName(dialog,directory=f[0][:-(len('.sqlite'))]) ff=QFileDialog.getSaveFileName(dialog,directory=sqlitefile[:-(len('.sqlite'))])
if ff[0]=='' : if ff[0]=='' :
return return
e.setText(ff[0]) e.setText(ff[0])
@ -69,25 +57,36 @@ def sqlite2json(self):
hori=QHBoxLayout() hori=QHBoxLayout()
hori.addWidget(e) hori.addWidget(e)
hori.addWidget(bu) hori.addWidget(bu)
if targetjson is None:
formLayout.addRow(_TR("保存路径"),hori) formLayout.addRow(_TR("保存路径"),hori)
button = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) button = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
formLayout.addRow(button) formLayout.addRow(button)
button.rejected.connect(dialog.close) button.rejected.connect(dialog.close)
def __savefunction(): def __savefunction(target):
if len(collect.keys())>0: if len(collect)>0:
transkirokuuse=list(collect.keys())[combo.currentIndex()] transkirokuuse=collect[combo.currentIndex()]
for k in js: for k in js_format2:
if collect[transkirokuuse] in js[k]: js_format2[k]=js_format2[k].get(transkirokuuse,'')
js[k]['machineTrans']=js[k][collect[transkirokuuse]]
# with open(e.text()+'.complex.json','w',encoding='utf8') as ff: # with open(e.text()+'.complex.json','w',encoding='utf8') as ff:
# ff.write(json.dumps(js,ensure_ascii=False,sort_keys=False, indent=4)) # ff.write(json.dumps(js,ensure_ascii=False,sort_keys=False, indent=4))
with open(e.text()+'.json','w',encoding='utf8') as ff:
if target is None:
target=e.text()+'.json'
with open(target,'w',encoding='utf8') as ff:
ff.write(json.dumps(js_format2,ensure_ascii=False,sort_keys=False, indent=4)) ff.write(json.dumps(js_format2,ensure_ascii=False,sort_keys=False, indent=4))
dialog.close() dialog.close()
button.accepted.connect(__savefunction) button.accepted.connect(functools.partial(__savefunction,targetjson))
button.button(QDialogButtonBox.Ok).setText(_TR('确定')) button.button(QDialogButtonBox.Ok).setText(_TR('确定'))
button.button(QDialogButtonBox.Cancel).setText(_TR('取消')) button.button(QDialogButtonBox.Cancel).setText(_TR('取消'))
dialog.show() dialog.show()
def sqlite2json(self):
f=QFileDialog.getOpenFileName(directory='./translation_record', filter="*.sqlite")
if f[0]=='' :
return
sqlite2json2(self,f[0])

View File

@ -1,18 +1,19 @@
import functools,os,shutil import functools,os,shutil,windows,json
from PyQt5.QtGui import QFont,QStandardItem,QStandardItemModel from PyQt5.QtGui import QFont,QStandardItem,QStandardItemModel
from PyQt5.QtCore import Qt,QSize from PyQt5.QtCore import Qt,QSize
from traceback import print_exc from traceback import print_exc
from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QVBoxLayout,QTableView,QHeaderView,QHBoxLayout,QLineEdit from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QVBoxLayout,QTableView,QHeaderView,QHBoxLayout,QLineEdit
from gui.pretransfile import sqlite2json2
from gui.settingpage_ocr import getocrgrid from gui.settingpage_ocr import getocrgrid
from myutils.config import globalconfig ,_TR,_TRL from myutils.config import globalconfig ,_TR,_TRL,savehook_new_data,savehook_new_list
from gui.dialog_savedgame import dialog_savedgame from gui.dialog_savedgame import dialog_savedgame
import threading,gobject,requests,datetime,zipfile import threading,gobject,requests,datetime,zipfile
from gui.inputdialog import autoinitdialog from gui.inputdialog import autoinitdialog,regexedit
from gui.usefulwidget import getsimplecombobox,getspinbox,getcolorbutton,yuitsu_switch,getsimpleswitch,Singleton,getQMessageBox from gui.usefulwidget import getsimplecombobox,getspinbox,getcolorbutton,yuitsu_switch,getsimpleswitch,Singleton,getQMessageBox
from gui.codeacceptdialog import codeacceptdialog from gui.codeacceptdialog import codeacceptdialog
from textsource.fridahook import fridahook from textsource.fridahook import fridahook
from myutils.utils import loadfridascriptslist,checkifnewgame,makehtml from myutils.utils import loadfridascriptslist,checkifnewgame,makehtml,getfilemd5
from myutils.proxy import getproxy from myutils.proxy import getproxy
def gethookgrid(self) : def gethookgrid(self) :
@ -129,59 +130,47 @@ def getfridahookgrid(self) :
return grids return grids
@Singleton def doexportchspatch(exe):
class safeembedcheckdialog(QDialog):
def newline(self,row):
self.model.insertRow(row,[QStandardItem(globalconfig['embedded']['safecheckregexs'][row])])
def __init__(self,parent) -> None:
super().__init__(parent,Qt.WindowCloseButtonHint)
self.setWindowTitle(_TR('正则匹配'))
formLayout = QVBoxLayout(self) # 配置layout b=windows.GetBinaryType(exe)
is64=(b==6)
arch=['32','64'][is64]
self.model=QStandardItemModel() dllhook=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch))
self.model.setHorizontalHeaderLabels(_TRL(['正则'])) dllhost=os.path.abspath('./files/plugins/DLL{}/LunaHost{}.dll'.format(arch,arch))
table = QTableView(self) runner=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch))
table.setModel(self.model)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) windows.CopyFile(dllhook,os.path.join(os.path.dirname(exe),os.path.basename(dllhook)),False)
windows.CopyFile(dllhost,os.path.join(os.path.dirname(exe),os.path.basename(dllhost)),False)
windows.CopyFile(runner,os.path.join(os.path.dirname(exe),'LunaPatch.exe'),False)
self.table=table embedconfig={
for row,regex in enumerate(globalconfig['embedded']['safecheckregexs']): 'translation_file':'translation.json',
self.model.insertRow(row,[QStandardItem(regex)]) 'target_exe':os.path.basename(exe),
'startup_argument':None,
'isbit64':is64,
'inject_timeout':1000,
'embedhook':savehook_new_data[exe]['embedablehook'],
'embedsettings':{
'font':globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '',
'insertspace_policy':globalconfig['embedded']['insertspace_policy'],
'keeprawtext':globalconfig['embedded']['keeprawtext']
}
}
with open(os.path.join(os.path.dirname(exe),'LunaPatch.json'),'w',encoding='utf8') as ff:
ff.write(json.dumps(embedconfig,ensure_ascii=False,indent=4))
def exportchspatch(self):
button=QPushButton(self) f=QFileDialog.getOpenFileName(filter='*.exe')
button.setText(_TR('添加行')) exe=f[0]
def clicked1(): if exe=='':return
globalconfig['embedded']['safecheckregexs'].insert(0,'') exe=exe.replace('/','\\')
self.model.insertRow(0,[QStandardItem()]) if exe not in savehook_new_list:return
button.clicked.connect(clicked1) doexportchspatch(exe)
button2=QPushButton(self) md5=getfilemd5(exe)
button2.setText(_TR('删除选中行')) name= os.path.basename(exe).replace('.'+os.path.basename(exe).split('.')[-1],'')
def clicked2(): sqlfname_all='./translation_record/'+name+'_'+md5+'.sqlite'
self.model.removeRow(table.currentIndex().row()) sqlite2json2(self,sqlfname_all,os.path.join(os.path.dirname(exe),'translation.json'))
globalconfig['embedded']['safecheckregexs'].pop(table.currentIndex().row())
button2.clicked.connect(clicked2)
self.button=button
formLayout.addWidget(table)
formLayout.addWidget(button)
formLayout.addWidget(button2)
self.resize(QSize(600,400))
self.show()
def closeEvent(self,_) -> None:
self.button.setFocus()
rows=self.model.rowCount()
rowoffset=0
dedump=set()
for row in range(rows):
regex=self.model.item(row,0).text()
if regex=="" or regex in dedump:
globalconfig['embedded']['safecheckregexs'].pop(row-rowoffset)
rowoffset+=1
continue
globalconfig['embedded']['safecheckregexs'][row-rowoffset]=regex
dedump.add(regex)
def gethookembedgrid(self) : def gethookembedgrid(self) :
self.gamefont_comboBox = QFontComboBox( ) self.gamefont_comboBox = QFontComboBox( )
def callback(x): def callback(x):
@ -194,6 +183,8 @@ def gethookembedgrid(self) :
self.gamefont_comboBox.setCurrentFont(QFont(globalconfig['embedded']['changefont_font'])) self.gamefont_comboBox.setCurrentFont(QFont(globalconfig['embedded']['changefont_font']))
grids=[ grids=[
[('导出翻译补丁',5),getcolorbutton(globalconfig,'',callback=lambda x:exportchspatch(self),icon='fa.gear',constcolor="#FF69B4")],
[],
[('保留原文',5),(getsimpleswitch( globalconfig['embedded'],'keeprawtext',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()) ,1) ], [('保留原文',5),(getsimpleswitch( globalconfig['embedded'],'keeprawtext',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()) ,1) ],
[('翻译等待时间(s)',5),'',(getspinbox(0,30,globalconfig['embedded'],'timeout_translate',double=True,step=0.1,callback=lambda x:gobject.baseobject.textsource.flashembedsettings()),3) ], [('翻译等待时间(s)',5),'',(getspinbox(0,30,globalconfig['embedded'],'timeout_translate',double=True,step=0.1,callback=lambda x:gobject.baseobject.textsource.flashembedsettings()),3) ],
@ -203,7 +194,7 @@ def gethookembedgrid(self) :
[('在重叠显示的字间插入空格',5),'',(getsimplecombobox(_TRL(['不插入空格','每个字后插入空格','仅在无法编码的字后插入']),globalconfig['embedded'],'insertspace_policy',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),5) ], [('在重叠显示的字间插入空格',5),'',(getsimplecombobox(_TRL(['不插入空格','每个字后插入空格','仅在无法编码的字后插入']),globalconfig['embedded'],'insertspace_policy',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),5) ],
[('修改游戏字体',5),(getsimpleswitch( globalconfig['embedded'] ,'changefont',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),1), (self.gamefont_comboBox,5)], [('修改游戏字体',5),(getsimpleswitch( globalconfig['embedded'] ,'changefont',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),1), (self.gamefont_comboBox,5)],
[], [],
[('内嵌安全性检查',5),getcolorbutton(globalconfig,'',callback=lambda x:safeembedcheckdialog(self),icon='fa.gear',constcolor="#FF69B4")] [('内嵌安全性检查',5),getsimpleswitch(globalconfig['embedded'],'safecheck_use' ),getcolorbutton(globalconfig,'',callback=lambda x:regexedit(self,globalconfig['embedded']['safecheckregexs']),icon='fa.gear',constcolor="#FF69B4")]
#[('修改字体字符集',5),(getsimpleswitch( globalconfig['embedded'] ,'changecharset',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),1) ,(getsimplecombobox(_TRL(static_data["charsetmapshow"]),globalconfig['embedded'],'changecharset_charset',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),5)], #[('修改字体字符集',5),(getsimpleswitch( globalconfig['embedded'] ,'changecharset',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),1) ,(getsimplecombobox(_TRL(static_data["charsetmapshow"]),globalconfig['embedded'],'changecharset_charset',callback=lambda _:gobject.baseobject.textsource.flashembedsettings()),5)],
] ]

View File

@ -9,7 +9,7 @@ from myutils.config import globalconfig ,postprocessconfig,noundictconfig,transe
import functools ,gobject import functools ,gobject
from gui.usefulwidget import getcolorbutton,getsimpleswitch from gui.usefulwidget import getcolorbutton,getsimpleswitch
from gui.codeacceptdialog import codeacceptdialog from gui.codeacceptdialog import codeacceptdialog
from gui.inputdialog import getsomepath1 ,postconfigdialog,autoinitdialog,autoinitdialog_items from gui.inputdialog import getsomepath1 ,postconfigdialog,autoinitdialog,autoinitdialog_items,noundictconfigdialog1
from myutils.utils import selectdebugfile from myutils.utils import selectdebugfile
from myutils.wrapper import Singleton from myutils.wrapper import Singleton
from myutils.config import savehook_new_data from myutils.config import savehook_new_data
@ -44,7 +44,7 @@ def savegameprocesstext():
def settab7direct(self): def settab7direct(self):
self.comparelayout=getcomparelayout(self) self.comparelayout=getcomparelayout(self)
self.button_noundict=getcolorbutton(globalconfig,'' ,callback=lambda x: noundictconfigdialog(self,noundictconfig,'专有名词翻译设置(游戏ID 0表示全局)'),icon='fa.gear',constcolor="#FF69B4") self.button_noundict=getcolorbutton(globalconfig,'' ,callback=lambda x: noundictconfigdialog(self,noundictconfig,'专有名词翻译设置(游戏ID 0表示全局)'),icon='fa.gear',constcolor="#FF69B4")
self.button_fix=getcolorbutton(globalconfig,'',callback=lambda x: noundictconfigdialog1(self,transerrorfixdictconfig,'翻译结果替换设置',['正则','翻译','替换']),icon='fa.gear',constcolor="#FF69B4") self.button_fix=getcolorbutton(globalconfig,'',callback=lambda x: noundictconfigdialog1(self,transerrorfixdictconfig,'dict_v2','翻译结果替换设置',['正则','翻译','替换']),icon='fa.gear',constcolor="#FF69B4")
def setTab7(self) : def setTab7(self) :
self.tabadd_lazy(self.tab_widget, ('文本处理'), lambda :setTab7_lazy(self)) self.tabadd_lazy(self.tab_widget, ('文本处理'), lambda :setTab7_lazy(self))
def getcomparelayout(self): def getcomparelayout(self):
@ -163,92 +163,6 @@ def setTab7_lazy(self) :
]) ])
return self.makevbox([tab,self.comparelayout ]) return self.makevbox([tab,self.comparelayout ])
@Singleton
class noundictconfigdialog1(QDialog):
def newline(self,row,item):
self.model.insertRow(row,[QStandardItem(),QStandardItem(item['key']),QStandardItem(item['value'])])
self.table.setIndexWidget(self.model.index(row, 0),getsimpleswitch(item,'regex'))
def __init__(self,parent,configdict,title,label) -> None:
super().__init__(parent,Qt.WindowCloseButtonHint)
self.setWindowTitle(_TR(title))
#self.setWindowModality(Qt.ApplicationModal)
formLayout = QVBoxLayout(self) # 配置layout
self.model=QStandardItemModel()
self.model.setHorizontalHeaderLabels(_TRL(label))
table = QTableView(self)
table.setModel(self.model)
table.horizontalHeader().setSectionResizeMode(2,QHeaderView.Stretch)
table.horizontalHeader().setSectionResizeMode(1,QHeaderView.Stretch)
table.horizontalHeader().setSectionResizeMode(0,QHeaderView.ResizeToContents)
self.table=table
for row,item in enumerate(configdict['dict_v2']):
self.newline(row,item)
search=QHBoxLayout()
searchcontent=QLineEdit()
search.addWidget(searchcontent)
button4=QPushButton()
button4.setText(_TR('搜索'))
def clicked4():
text=searchcontent.text()
rows=self.model.rowCount()
cols=self.model.columnCount()
for row in range(rows):
ishide=True
for c in range(cols):
if text in self.model.item(row,c).text():
ishide=False
break
table.setRowHidden(row,ishide)
button4.clicked.connect(clicked4)
search.addWidget(button4)
button=QPushButton(self)
button.setText(_TR('添加行'))
def clicked1():
self.configdict['dict_v2'].insert(0,{'key':'','value':'','regex':False})
self.newline(0,self.configdict['dict_v2'][0])
button.clicked.connect(clicked1)
button2=QPushButton(self)
button2.setText(_TR('删除选中行'))
def clicked2():
self.model.removeRow(table.currentIndex().row())
self.configdict['dict_v2'].pop(table.currentIndex().row())
button2.clicked.connect(clicked2)
self.button=button
self.configdict=configdict
formLayout.addWidget(table)
formLayout.addLayout(search)
formLayout.addWidget(button)
formLayout.addWidget(button2)
self.resize(QSize(600,400))
self.show()
def closeEvent(self, a0: QCloseEvent) -> None:
self.button.setFocus()
rows=self.model.rowCount()
rowoffset=0
dedump=set()
for row in range(rows):
k,v=self.model.item(row,1).text(),self.model.item(row,2).text()
if k=="" or k in dedump:
self.configdict['dict_v2'].pop(row-rowoffset)
rowoffset+=1
continue
self.configdict['dict_v2'][row-rowoffset].update({
'key':k,'value':v
})
dedump.add(k)
@Singleton @Singleton
class noundictconfigdialog(QDialog): class noundictconfigdialog(QDialog):
def closeEvent(self, a0: QCloseEvent) -> None: def closeEvent(self, a0: QCloseEvent) -> None:

View File

@ -1,7 +1,7 @@
import functools import functools
from PyQt5.QtWidgets import QComboBox from PyQt5.QtWidgets import QComboBox
from gui.inputdialog import getsomepath1 from gui.inputdialog import getsomepath1,noundictconfigdialog1
from myutils.config import globalconfig ,_TRL from myutils.config import globalconfig ,_TRL
import os,functools import os,functools
import gobject import gobject
@ -59,6 +59,8 @@ def setTab5lz(self) :
[ ('自动朗读',6),(getsimpleswitch(globalconfig,'autoread' ),1)], [ ('自动朗读',6),(getsimpleswitch(globalconfig,'autoread' ),1)],
[ ('朗读原文',6),(getsimpleswitch(globalconfig,'read_raw' ),1),'','',('朗读翻译',6),(getsimpleswitch(globalconfig,'read_trans' ),1)], [ ('朗读原文',6),(getsimpleswitch(globalconfig,'read_raw' ),1),'','',('朗读翻译',6),(getsimpleswitch(globalconfig,'read_trans' ),1)],
[('朗读的翻译',6),(getsimplecombobox(_TRL([globalconfig['fanyi'][x]['name'] for x in globalconfig['fanyi']]),globalconfig,'read_translator'),15) ], [('朗读的翻译',6),(getsimplecombobox(_TRL([globalconfig['fanyi'][x]['name'] for x in globalconfig['fanyi']]),globalconfig,'read_translator'),15) ],
[],
[('语音修正',6),getsimpleswitch(globalconfig['ttscommon'],'tts_repair' ),getcolorbutton(globalconfig,'',callback=lambda x: noundictconfigdialog1(self,globalconfig['ttscommon'],'tts_repair_regex','语音修正',['正则','原文','替换']),icon='fa.gear',constcolor="#FF69B4") ],
] ]
gridlayoutwidget=self.makegrid(grids ) gridlayoutwidget=self.makegrid(grids )
gridlayoutwidget=self.makescroll( gridlayoutwidget ) gridlayoutwidget=self.makescroll( gridlayoutwidget )

View File

@ -142,8 +142,11 @@ if len(globalconfig['toolbutton']['rank'])!=len(globalconfig['toolbutton']['butt
def setlanguage(): def setlanguage():
global language,languageshow global language,languageshow
language=globalconfig['languageuse'] language=globalconfig['languageuse']
try:
with open('./files/lang/{}.json'.format(static_data["language_list_translator_inner"][language]),'r',encoding='utf8') as ff: with open('./files/lang/{}.json'.format(static_data["language_list_translator_inner"][language]),'r',encoding='utf8') as ff:
languageshow=json.load(ff) languageshow=json.load(ff)
except:
languageshow={}
setlanguage() setlanguage()
def _TR(k): def _TR(k):

View File

@ -130,7 +130,7 @@ class texthook(basetext ):
self.Luna_FindHooks_waiting=LunaHost.Luna_FindHooks_waiting self.Luna_FindHooks_waiting=LunaHost.Luna_FindHooks_waiting
self.Luna_FindHooks_waiting.argtypes=POINTER(c_int), self.Luna_FindHooks_waiting.argtypes=POINTER(c_int),
self.Luna_EmbedSettings=LunaHost.Luna_EmbedSettings self.Luna_EmbedSettings=LunaHost.Luna_EmbedSettings
self.Luna_EmbedSettings.argtypes=DWORD,c_uint32,c_uint8,c_bool,c_wchar_p,c_uint32,c_uint32 self.Luna_EmbedSettings.argtypes=DWORD,c_uint32,c_uint8,c_bool,c_wchar_p,c_uint32,c_uint32,c_bool
self.Luna_checkisusingembed=LunaHost.Luna_checkisusingembed self.Luna_checkisusingembed=LunaHost.Luna_checkisusingembed
self.Luna_checkisusingembed.argtypes=DWORD,c_uint64,c_uint64,c_uint64 self.Luna_checkisusingembed.argtypes=DWORD,c_uint64,c_uint64,c_uint64
self.Luna_checkisusingembed.restype=c_bool self.Luna_checkisusingembed.restype=c_bool
@ -204,6 +204,8 @@ class texthook(basetext ):
self.useembed(addr,_ctx1,_ctx2,True) self.useembed(addr,_ctx1,_ctx2,True)
def safeembedcheck(self,text): def safeembedcheck(self,text):
try: try:
if globalconfig['embedded']['safecheck_use']==False:
return True
for regex in (globalconfig['embedded']['safecheckregexs']): for regex in (globalconfig['embedded']['safecheckregexs']):
if re.match(codecs.escape_decode(bytes(regex,"utf-8"))[0].decode("utf-8"),text): if re.match(codecs.escape_decode(bytes(regex,"utf-8"))[0].decode("utf-8"),text):
return False return False
@ -213,6 +215,7 @@ class texthook(basetext ):
def getembedtext(self,text,tp): def getembedtext(self,text,tp):
if self.safeembedcheck(text)==False: if self.safeembedcheck(text)==False:
self.embedcallback(text,text) self.embedcallback(text,text)
self.newline.put((text,False, lambda trans:1,True))
return return
if globalconfig['autorun']==False: if globalconfig['autorun']==False:
self.embedcallback(text,text) self.embedcallback(text,text)
@ -237,7 +240,8 @@ class texthook(basetext ):
False,#globalconfig['embedded']['changecharset'] False,#globalconfig['embedded']['changecharset']
globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '', globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '',
globalconfig['embedded']['insertspace_policy'], globalconfig['embedded']['insertspace_policy'],
globalconfig['embedded']['keeprawtext']) globalconfig['embedded']['keeprawtext'],
True)
def onremovehook(self,tp): def onremovehook(self,tp):
toremove=[] toremove=[]

View File

@ -5,36 +5,65 @@ import os
import windows import windows
from traceback import print_exc from traceback import print_exc
from tts.basettsclass import TTSbase from tts.basettsclass import TTSbase
import ctypes import ctypes,subprocess
from myutils.subproc import subproc_w,autoproc from myutils.subproc import subproc_w,autoproc
class TTS(TTSbase): class TTS(TTSbase):
def init(self): def checkchange(self):
self.rate=globalconfig["ttscommon"]["rate"]
self.voice=self.config["voice"]
fname=str(time.time()) fname=str(time.time())
savepath=os.path.join(os.getcwd(),'cache/tts',fname) savepath=os.path.join(os.getcwd(),'cache/tts',fname)
exepath=os.path.join(os.getcwd(),'files/plugins/shareddllproxy32.exe') exepath=os.path.join(os.getcwd(),'files/plugins/shareddllproxy32.exe')
self.savepath=savepath
t=time.time() t=time.time()
t= str(t) t= str(t)
pipename='\\\\.\\Pipe\\voiceroid2_'+t pipename='\\\\.\\Pipe\\voiceroid2_'+t
waitsignal='voiceroid2waitload_'+t waitsignal='voiceroid2waitload_'+t
self.engine=autoproc(subproc_w('"{}" neospeech {} {} "{}"'.format(exepath,pipename,waitsignal,savepath),name='neospeech')) idx=self.config["voice"].split('_')[-1]
hkey=self.config["voice"][:-len(idx)-1]
if self.voicexx!=(hkey,idx):
self.voicexx=(hkey,idx)
cmd='"{}" neospeech {} {} "{}" {} {} '.format(exepath,pipename,waitsignal,savepath,hkey,idx)
self.engine=autoproc(subproc_w(cmd,name='neospeech'))
windows.WaitForSingleObject(windows.AutoHandle(windows.CreateEvent(False, False, waitsignal)),windows.INFINITE); windows.WaitForSingleObject(windows.AutoHandle(windows.CreateEvent(False, False, waitsignal)),windows.INFINITE);
windows.WaitNamedPipe(pipename,windows.NMPWAIT_WAIT_FOREVER) windows.WaitNamedPipe(pipename,windows.NMPWAIT_WAIT_FOREVER)
self.hPipe = windows.AutoHandle(windows.CreateFile( pipename, windows.GENERIC_READ | windows.GENERIC_WRITE, 0, self.hPipe = windows.AutoHandle(windows.CreateFile( pipename, windows.GENERIC_READ | windows.GENERIC_WRITE, 0,
None, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, None)) None, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, None))
def init(self):
self.voicexx=(0,0)
self.voicelist=self.getvoicelist()
if globalconfig['reader'][self.typename]['voice'] not in self.voicelist:
globalconfig['reader'][self.typename]['voice']=self.voicelist[0]
self.checkchange()
def voiceshowmap(self,voice):
idx=voice.split('_')[-1]
hk=voice[:-len(idx)-1]
return self.mapx[(hk,idx)]
def getvoicelist(self): def getvoicelist(self):
cachefname=os.path.abspath('./cache/{}.txt'.format(time.time()))
exe=os.path.abspath('./files/plugins/shareddllproxy32.exe')
subprocess.run('"{}" neospeechlist "{}"'.format(exe,cachefname))
return ['VW Misaki'] with open(cachefname,'r',encoding='utf-16-le') as ff:
readf=(ff.read())
os.remove(cachefname)
datas=(readf.split('\n'))[:-1]
self.mapx={}
xx=[]
for i in range(len(datas)//3):
self.mapx[(datas[i*3+1],datas[i*3+2])]=datas[i*3]
xx.append('{}_{}'.format(datas[i*3+1],datas[i*3+2]))
return xx
def speak(self,content,rate,voice,voice_idx): def speak(self,content,rate,voice,voice_idx):
self.checkchange()
windows.WriteFile(self.hPipe,bytes(ctypes.c_uint(rate))) windows.WriteFile(self.hPipe,bytes(ctypes.c_uint(rate)))
windows.WriteFile(self.hPipe,content.encode('utf-16-le')) windows.WriteFile(self.hPipe,content.encode('utf-16-le'))
fname=windows.ReadFile(self.hPipe,1024,None).decode('utf-16-le') fname=windows.ReadFile(self.hPipe,1024,None).decode('utf-16-le')

View File

@ -767,3 +767,9 @@ def CreatePipe(lpsecu=None,sz=0):
hwrite=HANDLE() hwrite=HANDLE()
_CreatePipe(pointer(hread),pointer(hwrite),lpsecu,sz) _CreatePipe(pointer(hread),pointer(hwrite),lpsecu,sz)
return AutoHandle(hread.value),AutoHandle(hwrite.value) return AutoHandle(hread.value),AutoHandle(hwrite.value)
_CopyFile=_kernel32.CopyFileW
_CopyFile.argtypes=LPCWSTR,LPCWSTR,BOOL
_CopyFile.restype=BOOL
def CopyFile(src,dst,bFailIfExists):
return _CopyFile(src,dst,bFailIfExists)

View File

@ -17,6 +17,7 @@
"direct_filterrepeat":false, "direct_filterrepeat":false,
"allow_set_text_name":false, "allow_set_text_name":false,
"embedded": { "embedded": {
"safecheck_use":true,
"safecheckregexs": [ "safecheckregexs": [
"(.*?)\\{(.*?)\\}(.*?)", "(.*?)\\{(.*?)\\}(.*?)",
"(.*?)\\[(.*?)\\](.*?)" "(.*?)\\[(.*?)\\](.*?)"
@ -683,7 +684,9 @@
"outputtopasteboard": false, "outputtopasteboard": false,
"ttscommon": { "ttscommon": {
"rate": 1.0, "rate": 1.0,
"volume": 100.0 "volume": 100.0,
"tts_repair":false,
"tts_repair_regex":[]
}, },
"allowmulti": true, "allowmulti": true,
"sourcestatus2": { "sourcestatus2": {

View File

@ -1,8 +1,8 @@
{ {
"version":"v2.39.3", "version":"v2.40.0",
"language_list_show":["简体中文","日本語","English","Русский язык","Español","한국어","Français","繁體中文","Tiếng Việt","Türkçe","Polski","Українська Мова","Italiano","اللغة العربية","ภาษาไทย"] , "language_list_show":["简体中文","日本語","English","Русский язык","Español","한국어","Français","繁體中文","Tiếng Việt","Türkçe","Polski","Українська Мова","Italiano","اللغة العربية","ภาษาไทย","བོད་སྐད།"] ,
"language_list_translator":["简体中文","日文","英文","俄语","西班牙语","韩语","法语","繁体中文","越南语","土耳其语","波兰语","乌克兰语","意大利语","阿拉伯语","泰语"], "language_list_translator":["简体中文","日文","英文","俄语","西班牙语","韩语","法语","繁体中文","越南语","土耳其语","波兰语","乌克兰语","意大利语","阿拉伯语","泰语","藏语"],
"language_list_translator_inner":["zh", "ja", "en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th"], "language_list_translator_inner":["zh", "ja", "en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th","bo"],
"codepage_display":["日语(CP932,SHIFT-JIS)","UTF8(CP65001)","简体中文(CP936,GBK)","繁体中文(CP950,BIG5)","韩语(CP949,EUC-KR)","越南语(CP1258)","泰语(CP874)","阿拉伯语(CP1256)","希伯来语(CP1255)","土耳其语(CP1254)","希腊语(CP1253)","北欧(CP1257)","中东欧(CP1250)","西里尔(CP1251)","拉丁(CP1252)","英语(CP437)"], "codepage_display":["日语(CP932,SHIFT-JIS)","UTF8(CP65001)","简体中文(CP936,GBK)","繁体中文(CP950,BIG5)","韩语(CP949,EUC-KR)","越南语(CP1258)","泰语(CP874)","阿拉伯语(CP1256)","希伯来语(CP1255)","土耳其语(CP1254)","希腊语(CP1253)","北欧(CP1257)","中东欧(CP1250)","西里尔(CP1251)","拉丁(CP1252)","英语(CP437)"],
"codepage_real":[932,65001,936,950,949,1258,874,1256,1255,1254,1253,1257,1250,1251,1252,437], "codepage_real":[932,65001,936,950,949,1258,874,1256,1255,1254,1253,1257,1250,1251,1252,437],
"allkata":"ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヽヾ", "allkata":"ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヽヾ",
@ -125,9 +125,13 @@
"name":"语音合成", "name":"语音合成",
"sources":[ "sources":[
{ {
"name": "NeoSpeech", "name": "NeoSpeech Misaki",
"link": "https://github.com/HIllya51/RESOURCES/releases/download/speech_synthesis_packages/NeoSpeech.Japanese.Misaki.zip" "link": "https://github.com/HIllya51/RESOURCES/releases/download/speech_synthesis_packages/NeoSpeech.Japanese.Misaki.zip"
}, },
{
"name": "NeoSpeech Show",
"link": "https://github.com/HIllya51/RESOURCES/releases/download/speech_synthesis_packages/https://github.com/HIllya51/RESOURCES/releases/download/speech_synthesis_packages/NeoSpeech.TTS.NeoSpeech.Japanese.Show_v3.10.0.0.zip.zip"
},
{ {
"name": "VOICEVOX", "name": "VOICEVOX",
"link": "https://github.com/VOICEVOX/voicevox/releases" "link": "https://github.com/VOICEVOX/voicevox/releases"

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "جزءا لا يتجزأ من فحص السلامة", "内嵌安全性检查": "جزءا لا يتجزأ من فحص السلامة",
"正则匹配": "مطابقة العادية", "正则匹配": "مطابقة العادية",
"非官方": "غير رسمي", "非官方": "غير رسمي",
"离线": "غير متصل" "离线": "غير متصل",
"导出翻译补丁": "تصدير ترجمة التصحيح",
"语音修正": "صوت تصحيح",
"藏语": "التيبتية"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "內嵌安全性檢查", "内嵌安全性检查": "內嵌安全性檢查",
"正则匹配": "正則匹配", "正则匹配": "正則匹配",
"非官方": "非官方", "非官方": "非官方",
"离线": "離線" "离线": "離線",
"导出翻译补丁": "匯出翻譯補丁",
"语音修正": "語音修正",
"藏语": "藏語"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Embedded security check", "内嵌安全性检查": "Embedded security check",
"正则匹配": "Regular matching", "正则匹配": "Regular matching",
"非官方": "Unofficial", "非官方": "Unofficial",
"离线": "off-line" "离线": "off-line",
"导出翻译补丁": "Export translation patches",
"语音修正": "Voice correction",
"藏语": "Tibetan"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Inspección de Seguridad incorporada", "内嵌安全性检查": "Inspección de Seguridad incorporada",
"正则匹配": "Coincidencia regular", "正则匹配": "Coincidencia regular",
"非官方": "No oficial", "非官方": "No oficial",
"离线": "Fuera de línea" "离线": "Fuera de línea",
"导出翻译补丁": "Exportar parches de traducción",
"语音修正": "Corrección de voz",
"藏语": "Tibetano"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Inspection de sécurité intégrée", "内嵌安全性检查": "Inspection de sécurité intégrée",
"正则匹配": "Match régulier", "正则匹配": "Match régulier",
"非官方": "Non officiel", "非官方": "Non officiel",
"离线": "Hors ligne" "离线": "Hors ligne",
"导出翻译补丁": "Exporter le patch de traduction",
"语音修正": "Correction vocale",
"藏语": "Tibétain"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Controllo di sicurezza integrato", "内嵌安全性检查": "Controllo di sicurezza integrato",
"正则匹配": "Corrispondenza regolare", "正则匹配": "Corrispondenza regolare",
"非官方": "Non ufficiale", "非官方": "Non ufficiale",
"离线": "off-line" "离线": "off-line",
"导出翻译补丁": "Esporta patch di traduzione",
"语音修正": "Correzione vocale",
"藏语": "Tibetano"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "インラインセキュリティチェック", "内嵌安全性检查": "インラインセキュリティチェック",
"正则匹配": "正規一致", "正则匹配": "正規一致",
"非官方": "非公式", "非官方": "非公式",
"离线": "オフライン" "离线": "オフライン",
"导出翻译补丁": "翻訳パッチのエクスポート",
"语音修正": "音声修正",
"藏语": "チベット語"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "내장 보안 검사", "内嵌安全性检查": "내장 보안 검사",
"正则匹配": "정규 일치", "正则匹配": "정규 일치",
"非官方": "비공식", "非官方": "비공식",
"离线": null "离线": null,
"导出翻译补丁": "번역 패치 내보내기",
"语音修正": "음성 수정",
"藏语": "티베트어"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Wbudowana kontrola bezpieczeństwa", "内嵌安全性检查": "Wbudowana kontrola bezpieczeństwa",
"正则匹配": "Regularne dopasowanie", "正则匹配": "Regularne dopasowanie",
"非官方": "Nieoficjalne", "非官方": "Nieoficjalne",
"离线": "off-line" "离线": "off-line",
"导出翻译补丁": "Eksportuj łatki tłumaczeniowe",
"语音修正": "Korekta głosu",
"藏语": "Tybetański"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Проверка встроенной безопасности", "内嵌安全性检查": "Проверка встроенной безопасности",
"正则匹配": "Регулярное согласование", "正则匹配": "Регулярное согласование",
"非官方": null, "非官方": null,
"离线": "В автономном режиме" "离线": "В автономном режиме",
"导出翻译补丁": "Экспорт исправлений перевода",
"语音修正": "Голосовая коррекция",
"藏语": "Тибетский язык"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "การตรวจสอบความปลอดภัยแบบอินไลน์", "内嵌安全性检查": "การตรวจสอบความปลอดภัยแบบอินไลน์",
"正则匹配": "จับคู่ปกติ", "正则匹配": "จับคู่ปกติ",
"非官方": "ไม่เป็นทางการ", "非官方": "ไม่เป็นทางการ",
"离线": "ออฟไลน์" "离线": "ออฟไลน์",
"导出翻译补丁": "ส่งออกแพทช์การแปล",
"语音修正": "แก้ไขเสียง",
"藏语": "ทิเบต"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "İçeri giriş güvenlik kontrolü", "内嵌安全性检查": "İçeri giriş güvenlik kontrolü",
"正则匹配": "Normal eşleşme", "正则匹配": "Normal eşleşme",
"非官方": "Resmi olmayan", "非官方": "Resmi olmayan",
"离线": "off line" "离线": "off line",
"导出翻译补丁": "Çeviri örneklerini dışarı aktar",
"语音修正": "Ses düzeltmesi",
"藏语": "TibetanKCharselect unicode block name"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Вбудована перевірка безпеки", "内嵌安全性检查": "Вбудована перевірка безпеки",
"正则匹配": "Регулярне збігання", "正则匹配": "Регулярне збігання",
"非官方": "Неофіційний", "非官方": "Неофіційний",
"离线": "вимкнено" "离线": "вимкнено",
"导出翻译补丁": "Експортувати латки перекладу",
"语音修正": "Виправлення голосу",
"藏语": "Тибетський"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Kiểm tra an ninh nội tuyến", "内嵌安全性检查": "Kiểm tra an ninh nội tuyến",
"正则匹配": "Khớp chính quy", "正则匹配": "Khớp chính quy",
"非官方": null, "非官方": null,
"离线": "Ngoại tuyến" "离线": "Ngoại tuyến",
"导出翻译补丁": "Xuất bản bản vá dịch",
"语音修正": "Sửa giọng nói",
"藏语": "Tây Tạng"
} }

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "", "内嵌安全性检查": "",
"正则匹配": "", "正则匹配": "",
"非官方": "", "非官方": "",
"离线": "" "离线": "",
"导出翻译补丁": "",
"语音修正": "",
"藏语": ""
} }

24674
plugins/libs/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
project(shareddllproxy) project(shareddllproxy)
add_executable(shareddllproxy shareddllproxy.cpp dllinject.cpp ntleas.cpp) add_executable(shareddllproxy shareddllproxy.cpp dllinject.cpp ntleas.cpp aspatch.cpp)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
add_library(x64lib magpie.cpp lossless.cpp) add_library(x64lib magpie.cpp lossless.cpp)
target_link_libraries(shareddllproxy x64lib ${Detours}) target_link_libraries(shareddllproxy x64lib ${Detours})

View File

@ -0,0 +1,291 @@
#include<nlohmann/json.hpp>
#include<filesystem>
#include<fstream>
#include<optional>
#include<thread>
#include<Windows.h>
#include<unordered_set>
#include<set>
#include<tlhelp32.h>
static std::wstring StringToWideString(const std::string& text, UINT encoding=CP_UTF8)
{
std::vector<wchar_t> buffer(text.size() + 1);
int length = MultiByteToWideChar(encoding, 0, text.c_str(), text.size() + 1, buffer.data(), buffer.size());
return std::wstring(buffer.data(), length - 1);
}
std::string WideStringToString(const std::wstring& text,UINT cp=CP_UTF8)
{
std::vector<char> buffer((text.size() + 1) * 4);
WideCharToMultiByte(cp, 0, text.c_str(), -1, buffer.data(), buffer.size(), nullptr, nullptr);
return buffer.data();
}
HANDLE runexe(const std::wstring &exe,const std::optional<std::wstring> &startup_argument)
{
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
std::vector<wchar_t>argu;
if(startup_argument.has_value()){
argu.resize(startup_argument.value().size()+1);
wcscpy(argu.data(),startup_argument.value().c_str());
}
CreateProcessW( exe.c_str(), // No module name (use command line)
startup_argument.has_value()?argu.data(): NULL,
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ); // Pointer to PROCESS_INFORMATION structure
return pi.hProcess;
}
std::wstring stolower(const std::wstring& s1){
auto s=s1;
std::transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}
std::vector<DWORD> EnumerateProcesses(const std::wstring& exe)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return {};
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe32))
{
CloseHandle(hSnapshot);
return {};
}
std::vector<DWORD> pids;
do
{
if(stolower(exe)==stolower(pe32.szExeFile))
pids.push_back(pe32.th32ProcessID);
} while (Process32Next(hSnapshot, &pe32));
CloseHandle(hSnapshot);
return pids;
}
enum { STRING = 12, MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 50000, SHIFT_JIS = 932, MAX_MODULE_SIZE = 120, PATTERN_SIZE = 30, HOOK_NAME_SIZE = 60, FIXED_SPLIT_VALUE = 0x10001 ,
HOOKCODE_LEN=500};
struct ThreadParam
{
bool operator==(ThreadParam other) const { return processId == other.processId && addr == other.addr && ctx == other.ctx && ctx2 == other.ctx2; }
DWORD processId;
uint64_t addr;
uint64_t ctx; // The context of the hook: by default the first value on stack, usually the return address
uint64_t ctx2; // The subcontext of the hook: 0 by default, generated in a method specific to the hook
};
struct messagelist{
bool read;
int type;
DWORD pid;
char name[HOOK_NAME_SIZE];
wchar_t hookcode[HOOKCODE_LEN];
ThreadParam tp;
wchar_t* stringptr;
uint64_t addr;
};
class lunapatch{
public:
HANDLE hMessage;
HANDLE hwait;
std::wstring target_exe;
nlohmann::json config;
std::map<std::string,std::string>translation;
std::unordered_set<DWORD>connectedpids;
void (*Luna_Start)( HANDLE* hRead );
void (*Luna_Inject)(DWORD pid,LPCWSTR basepath);
void (*Luna_EmbedSettings)(DWORD pid,UINT32 waittime,UINT8 fontCharSet,bool fontCharSetEnabled,wchar_t *fontFamily,UINT32 spaceadjustpolicy,UINT32 keeprawtext,bool fastskipignore);
void (*Luna_useembed)(DWORD pid,uint64_t address,uint64_t ctx1,uint64_t ctx2,bool use);
bool (*Luna_checkisusingembed)(DWORD pid,uint64_t address,uint64_t ctx1,uint64_t ctx2);
void (*Luna_embedcallback)(DWORD pid,LPCWSTR text,LPCWSTR trans);
std::set<std::string>notranslation;
lunapatch(std::wstring dll,nlohmann::json&&_translation,nlohmann::json&&_config):translation(_translation),config(_config){
auto LunaHost=LoadLibraryW(dll.c_str());
Luna_Start=(decltype(Luna_Start))GetProcAddress(LunaHost,"Luna_Start");
Luna_EmbedSettings=(decltype(Luna_EmbedSettings))GetProcAddress(LunaHost,"Luna_EmbedSettings");
Luna_Inject=(decltype(Luna_Inject))GetProcAddress(LunaHost,"Luna_Inject");
Luna_useembed=(decltype(Luna_useembed))GetProcAddress(LunaHost,"Luna_useembed");
Luna_checkisusingembed=(decltype(Luna_checkisusingembed))GetProcAddress(LunaHost,"Luna_checkisusingembed");
Luna_embedcallback=(decltype(Luna_embedcallback))GetProcAddress(LunaHost,"Luna_embedcallback");
Luna_Start(&hMessage);
std::thread([&](){Parsehostmessage();}).detach();
}
void run(){
target_exe=StringToWideString(config["target_exe"]);
auto _startup_argument=config["startup_argument"];
std::optional<std::wstring> startup_argument;
if(_startup_argument.is_null())
startup_argument={};
else
startup_argument=StringToWideString(config["startup_argument"]);
hwait=runexe(target_exe,startup_argument);
}
~lunapatch(){
if(notranslation.size()){
for(auto &text:notranslation){
translation[text]="";
}
auto notrs=nlohmann::json(notranslation).dump(4);
std::ofstream of;
of.open("no_translation.json");
of<<notrs;
of.close();
notrs=nlohmann::json(translation).dump(4);
of.open("no_translation_and_translation.json");
of<<notrs;
of.close();
}
}
void wait(){
WaitForSingleObject(hwait,INFINITE);
}
void inject(){
//chrome has multi process
Sleep(config["inject_timeout"]);
auto pids=EnumerateProcesses(target_exe);
for(auto pid:pids){
Luna_Inject(pid,L"");
}
}
std::wstring findtranslation(const std::wstring& text){
auto utf8text=WideStringToString(text);
if(translation.find(utf8text)==translation.end()){
//wprintf(L"%s\n",text.c_str());
notranslation.insert(utf8text);
return {};
}
return StringToWideString(translation.at(utf8text));
}
void Parsehostmessage(){
while (true)
{
messagelist message;
DWORD _;
ReadFile(hMessage,&message,sizeof(message),&_,NULL);
switch (message.type)
{
case 0:
{
auto font =StringToWideString(config["embedsettings"]["font"]);
auto insertspace_policy=config["embedsettings"]["insertspace_policy"];
auto keeprawtext=config["embedsettings"]["keeprawtext"];
Luna_EmbedSettings(message.pid,1000,2,false,font.data(),insertspace_policy,keeprawtext,false);
connectedpids.insert(message.pid);
}
break;
case 1:
{
connectedpids.erase(message.pid);
}
break;
case 7:
{
std::wstring text=message.stringptr;
auto tp=message.tp;
for(auto pid:connectedpids)
{
if((Luna_checkisusingembed(pid,tp.addr,tp.ctx,tp.ctx2)))
{
auto trans=findtranslation(text);
Luna_embedcallback(pid,text.c_str(),trans.c_str());
break;
}
}
}
break;
case 6:
{
std::wstring newhookcode=message.stringptr;
for(auto hook:config["embedhook"]){
auto hookcode= StringToWideString(hook[0]);
uint64_t _addr=hook[1];
uint64_t _ctx1=hook[2];
uint64_t _ctx2=hook[3];
if(hookcode==newhookcode){
for(auto pid:connectedpids){
Luna_useembed(pid,message.addr,_ctx1,_ctx2,true);
}
}
}
}
break;
default:
break;
}
if(message.stringptr)
free(message.stringptr);
}
}
};
std::wstring GetExecutablePath()
{
WCHAR buffer[MAX_PATH];
GetModuleFileNameW(NULL, buffer, MAX_PATH);
std::wstring fullPath(buffer);
size_t pos = fullPath.find_last_of(L"\\/");
if (pos != std::wstring::npos)
{
return fullPath.substr(0, pos);
}
return L"";
}
bool checkisapatch(){
auto curr=std::filesystem::path(GetExecutablePath());
auto config=curr/"LunaPatch.json";
if(std::filesystem::exists(config)==false)
{
return false;
}
std::ifstream jsonfile;
jsonfile.open(config);
auto configjson=nlohmann::json::parse(jsonfile);
jsonfile.close();
std::string translation_file=configjson["translation_file"];
jsonfile.open(translation_file);
std::map<std::string,std::string> translation=nlohmann::json::parse(jsonfile);
jsonfile.close();
bool isbit64=configjson["isbit64"];
auto bitappendix=isbit64?L"64":L"32";
auto LunaHost=(curr/(std::wstring(L"LunaHost")+bitappendix)).wstring();
auto LunaHook=(curr/(std::wstring(L"LunaHook")+bitappendix)).wstring();
lunapatch _lunapatch(LunaHost,std::move(translation),std::move(configjson));
_lunapatch.run();
_lunapatch.inject();
_lunapatch.wait();
return true;
}

View File

@ -1,6 +1,7 @@
 
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#include <iostream> #include <iostream>
#include <fstream>
#include<Windows.h> #include<Windows.h>
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
@ -100,15 +101,31 @@ std::vector<std::wstring>_List(const wchar_t* token) {
} }
int neospeech(int argc, wchar_t* argv[]) { int neospeechlist(int argc, wchar_t* argv[]) {
auto speechs = _List(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices"); FILE* f=_wfopen(argv[1],L"wb");
int idx = -1; for(auto key:{L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices",L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices"})
{
auto speechs=_List(key);
for (int i = 0; i < speechs.size(); i++) { for (int i = 0; i < speechs.size(); i++) {
if (speechs[i] == L"VW Misaki") { if (speechs[i].substr(0,2) == L"VW") {
idx = i; fwrite(speechs[i].c_str(),1,speechs[i].size()*2,f);
fwrite(L"\n",1,2,f);
fwrite(key,1,wcslen(key)*2,f);
fwrite(L"\n",1,2,f);
auto idx=std::to_wstring(i);
fwrite(idx.c_str(),1,idx.size()*2,f);
fwrite(L"\n",1,2,f);
} }
} }
if (idx == -1)return 0; }
fclose(f);
return 0;
}
int neospeech(int argc, wchar_t* argv[]) {
auto hkey=argv[4];
auto idx=std::stoi(argv[5]);
HANDLE hPipe = CreateNamedPipe(argv[1], PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT HANDLE hPipe = CreateNamedPipe(argv[1], PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES, 65535, 65535, NMPWAIT_WAIT_FOREVER, 0); , PIPE_UNLIMITED_INSTANCES, 65535, 65535, NMPWAIT_WAIT_FOREVER, 0);
@ -134,7 +151,7 @@ int neospeech(int argc, wchar_t* argv[]) {
wchar_t newname[1024] = { 0 }; wchar_t newname[1024] = { 0 };
wsprintf(newname, L"%s%d.wav", argv[3], II); wsprintf(newname, L"%s%d.wav", argv[3], II);
std::wstring newname_ = newname; std::wstring newname_ = newname;
_Speak(content, L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices", idx, speed, 100, newname_); _Speak(content, hkey, idx, speed, 100, newname_);
WriteFile(hPipe, newname, wcslen(newname)*2, &_, NULL); WriteFile(hPipe, newname, wcslen(newname)*2, &_, NULL);
} }
return 0; return 0;

View File

@ -9,7 +9,7 @@
int dllinjectwmain(int argc, wchar_t* argv[]); int dllinjectwmain(int argc, wchar_t* argv[]);
int ntleaswmain(int argc, wchar_t* wargv[]); int ntleaswmain(int argc, wchar_t* wargv[]);
bool checkisapatch();
#ifndef _WIN64 #ifndef _WIN64
int LRwmain(int argc, wchar_t* argv[]); int LRwmain(int argc, wchar_t* argv[]);
int jbjwmain(int argc, wchar_t* argv[]); int jbjwmain(int argc, wchar_t* argv[]);
@ -18,6 +18,7 @@ int kingsoftwmain(int argc, wchar_t* argv[]);
int voiceroid2wmain(int argc, wchar_t* argv[]); int voiceroid2wmain(int argc, wchar_t* argv[]);
int lewmain(int argc, wchar_t* argv[]); int lewmain(int argc, wchar_t* argv[]);
int neospeech(int argc, wchar_t* argv[]); int neospeech(int argc, wchar_t* argv[]);
int neospeechlist(int argc, wchar_t* argv[]);
#else #else
int magpiewmain(int argc, wchar_t* wargv[]); int magpiewmain(int argc, wchar_t* wargv[]);
int losslesswmain(int argc, wchar_t* wargv[]); int losslesswmain(int argc, wchar_t* wargv[]);
@ -55,6 +56,7 @@ int listprocessmodule(int argc,wchar_t *argv[]){
int wmain(int argc, wchar_t* argv[]) int wmain(int argc, wchar_t* argv[])
{ {
if(checkisapatch())return 1;
auto argv0 = std::wstring(argv[1]); auto argv0 = std::wstring(argv[1]);
if (argv0 == L"dllinject") if (argv0 == L"dllinject")
return dllinjectwmain(argc - 1, argv + 1); return dllinjectwmain(argc - 1, argv + 1);
@ -78,6 +80,8 @@ int wmain(int argc, wchar_t* argv[])
return voiceroid2wmain(argc - 1, argv + 1); return voiceroid2wmain(argc - 1, argv + 1);
else if (argv0 == L"neospeech") else if (argv0 == L"neospeech")
return neospeech(argc - 1, argv + 1); return neospeech(argc - 1, argv + 1);
else if (argv0 == L"neospeechlist")
return neospeechlist(argc - 1, argv + 1);
#else #else
else if (argv0 == L"magpie") else if (argv0 == L"magpie")
return magpiewmain(argc - 1, argv + 1); return magpiewmain(argc - 1, argv + 1);