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)
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):
mp1,mp2,mp3=mp
#print(res,mp)#hello
@ -133,11 +139,7 @@ class MAINUI() :
if key in res:
res=res.replace(key,value['text'])
if transerrorfixdictconfig['use']:
for item in 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'])
res=self.parsemayberegexreplace(transerrorfixdictconfig['dict_v2'])
return res
def _POSTSOLVE(self,s):
@ -325,7 +327,8 @@ class MAINUI() :
def readcurrent(self,force=False):
try:
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:
print_exc()
@threader

View File

@ -6,9 +6,149 @@ from PyQt5.QtGui import QCloseEvent, QStandardItem, QStandardItemModel
from PyQt5.QtGui import QColor
import qtawesome,importlib
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.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):
items=[]
for arg in dict['args']:

View File

@ -4,41 +4,29 @@ from PyQt5.QtCore import Qt,QSize
import sqlite3
import json
from traceback import print_exc
import os
import functools
from myutils.config import globalconfig,_TR
from myutils.utils import autosql
from gui.usefulwidget import getQMessageBox
def sqlite2json(self):
f=QFileDialog.getOpenFileName(directory='./translation_record', filter="*.sqlite")
if f[0]=='' :
return
def sqlite2json2(self,sqlitefile,targetjson=None):
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()
js={}
js_format2={}
collect={}
collect=set()
for _aret in ret:
if len(_aret)==4:
_id,source,mt,ut=_aret
js[source]={'userTrans':ut,'machineTrans':mt}
js_format2[source]=mt
_id,source,mt,realsource=_aret
js_format2[realsource]=mt
elif len(_aret)==3:
_id,source,mt =_aret
js[source]={'userTrans':'','machineTrans':''}
js_format2[source]=''
js_format2[source]=mt
mtjs=json.loads(mt)
for _i,_t in enumerate(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)
js_format2[source]=mtjs
collect=collect.union(set(mtjs.keys()))
collect=list(collect)
except:
print_exc()
getQMessageBox(self,"错误","所选文件格式错误!")
@ -57,11 +45,11 @@ def sqlite2json(self):
formLayout.addRow(_TR("首选翻译"),combo)
e=QLineEdit(f[0][:-(len('.sqlite'))])
e=QLineEdit(sqlitefile[:-(len('.sqlite'))])
bu=QPushButton(_TR('选择路径') )
def __selectsavepath():
ff=QFileDialog.getSaveFileName(dialog,directory=f[0][:-(len('.sqlite'))])
ff=QFileDialog.getSaveFileName(dialog,directory=sqlitefile[:-(len('.sqlite'))])
if ff[0]=='' :
return
e.setText(ff[0])
@ -69,25 +57,36 @@ def sqlite2json(self):
hori=QHBoxLayout()
hori.addWidget(e)
hori.addWidget(bu)
formLayout.addRow(_TR("保存路径"),hori)
if targetjson is None:
formLayout.addRow(_TR("保存路径"),hori)
button = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
formLayout.addRow(button)
button.rejected.connect(dialog.close)
def __savefunction():
if len(collect.keys())>0:
transkirokuuse=list(collect.keys())[combo.currentIndex()]
for k in js:
if collect[transkirokuuse] in js[k]:
js[k]['machineTrans']=js[k][collect[transkirokuuse]]
def __savefunction(target):
if len(collect)>0:
transkirokuuse=collect[combo.currentIndex()]
for k in js_format2:
js_format2[k]=js_format2[k].get(transkirokuuse,'')
# with open(e.text()+'.complex.json','w',encoding='utf8') as ff:
# 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))
dialog.close()
button.accepted.connect(__savefunction)
button.accepted.connect(functools.partial(__savefunction,targetjson))
button.button(QDialogButtonBox.Ok).setText(_TR('确定'))
button.button(QDialogButtonBox.Cancel).setText(_TR('取消'))
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.QtCore import Qt,QSize
from traceback import print_exc
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 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
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.codeacceptdialog import codeacceptdialog
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
def gethookgrid(self) :
@ -129,59 +130,47 @@ def getfridahookgrid(self) :
return grids
@Singleton
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('正则匹配'))
def doexportchspatch(exe):
b=windows.GetBinaryType(exe)
is64=(b==6)
arch=['32','64'][is64]
dllhook=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch))
dllhost=os.path.abspath('./files/plugins/DLL{}/LunaHost{}.dll'.format(arch,arch))
runner=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch))
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(globalconfig['embedded']['safecheckregexs']):
self.model.insertRow(row,[QStandardItem(regex)])
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)
button=QPushButton(self)
button.setText(_TR('添加行'))
def clicked1():
globalconfig['embedded']['safecheckregexs'].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())
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)
embedconfig={
'translation_file':'translation.json',
'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):
f=QFileDialog.getOpenFileName(filter='*.exe')
exe=f[0]
if exe=='':return
exe=exe.replace('/','\\')
if exe not in savehook_new_list:return
doexportchspatch(exe)
md5=getfilemd5(exe)
name= os.path.basename(exe).replace('.'+os.path.basename(exe).split('.')[-1],'')
sqlfname_all='./translation_record/'+name+'_'+md5+'.sqlite'
sqlite2json2(self,sqlfname_all,os.path.join(os.path.dirname(exe),'translation.json'))
def gethookembedgrid(self) :
self.gamefont_comboBox = QFontComboBox( )
def callback(x):
@ -194,6 +183,8 @@ def gethookembedgrid(self) :
self.gamefont_comboBox.setCurrentFont(QFont(globalconfig['embedded']['changefont_font']))
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) ],
[('翻译等待时间(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),(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)],
]

View File

@ -9,7 +9,7 @@ from myutils.config import globalconfig ,postprocessconfig,noundictconfig,transe
import functools ,gobject
from gui.usefulwidget import getcolorbutton,getsimpleswitch
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.wrapper import Singleton
from myutils.config import savehook_new_data
@ -44,7 +44,7 @@ def savegameprocesstext():
def settab7direct(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_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) :
self.tabadd_lazy(self.tab_widget, ('文本处理'), lambda :setTab7_lazy(self))
def getcomparelayout(self):
@ -163,92 +163,6 @@ def setTab7_lazy(self) :
])
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
class noundictconfigdialog(QDialog):
def closeEvent(self, a0: QCloseEvent) -> None:

View File

@ -1,7 +1,7 @@
import functools
from PyQt5.QtWidgets import QComboBox
from gui.inputdialog import getsomepath1
from gui.inputdialog import getsomepath1,noundictconfigdialog1
from myutils.config import globalconfig ,_TRL
import os,functools
import gobject
@ -59,6 +59,8 @@ def setTab5lz(self) :
[ ('自动朗读',6),(getsimpleswitch(globalconfig,'autoread' ),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),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.makescroll( gridlayoutwidget )

View File

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

View File

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

View File

@ -5,36 +5,65 @@ import os
import windows
from traceback import print_exc
from tts.basettsclass import TTSbase
import ctypes
import ctypes,subprocess
from myutils.subproc import subproc_w,autoproc
class TTS(TTSbase):
def init(self):
self.rate=globalconfig["ttscommon"]["rate"]
self.voice=self.config["voice"]
def checkchange(self):
fname=str(time.time())
savepath=os.path.join(os.getcwd(),'cache/tts',fname)
exepath=os.path.join(os.getcwd(),'files/plugins/shareddllproxy32.exe')
self.savepath=savepath
exepath=os.path.join(os.getcwd(),'files/plugins/shareddllproxy32.exe')
t=time.time()
t= str(t)
pipename='\\\\.\\Pipe\\voiceroid2_'+t
waitsignal='voiceroid2waitload_'+t
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('"{}" neospeech {} {} "{}"'.format(exepath,pipename,waitsignal,savepath),name='neospeech'))
self.engine=autoproc(subproc_w(cmd,name='neospeech'))
windows.WaitForSingleObject(windows.AutoHandle(windows.CreateEvent(False, False, waitsignal)),windows.INFINITE);
windows.WaitNamedPipe(pipename,windows.NMPWAIT_WAIT_FOREVER)
self.hPipe = windows.AutoHandle(windows.CreateFile( pipename, windows.GENERIC_READ | windows.GENERIC_WRITE, 0,
None, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, None))
def init(self):
windows.WaitForSingleObject(windows.AutoHandle(windows.CreateEvent(False, False, waitsignal)),windows.INFINITE);
windows.WaitNamedPipe(pipename,windows.NMPWAIT_WAIT_FOREVER)
self.hPipe = windows.AutoHandle(windows.CreateFile( pipename, windows.GENERIC_READ | windows.GENERIC_WRITE, 0,
None, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, None))
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):
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):
self.checkchange()
windows.WriteFile(self.hPipe,bytes(ctypes.c_uint(rate)))
windows.WriteFile(self.hPipe,content.encode('utf-16-le'))
fname=windows.ReadFile(self.hPipe,1024,None).decode('utf-16-le')

View File

@ -766,4 +766,10 @@ def CreatePipe(lpsecu=None,sz=0):
hread=HANDLE()
hwrite=HANDLE()
_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,
"allow_set_text_name":false,
"embedded": {
"safecheck_use":true,
"safecheckregexs": [
"(.*?)\\{(.*?)\\}(.*?)",
"(.*?)\\[(.*?)\\](.*?)"
@ -683,7 +684,9 @@
"outputtopasteboard": false,
"ttscommon": {
"rate": 1.0,
"volume": 100.0
"volume": 100.0,
"tts_repair":false,
"tts_repair_regex":[]
},
"allowmulti": true,
"sourcestatus2": {

View File

@ -1,8 +1,8 @@
{
"version":"v2.39.3",
"language_list_show":["简体中文","日本語","English","Русский язык","Español","한국어","Français","繁體中文","Tiếng Việt","Türkçe","Polski","Українська Мова","Italiano","اللغة العربية","ภาษาไทย"] ,
"language_list_translator":["简体中文","日文","英文","俄语","西班牙语","韩语","法语","繁体中文","越南语","土耳其语","波兰语","乌克兰语","意大利语","阿拉伯语","泰语"],
"language_list_translator_inner":["zh", "ja", "en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th"],
"version":"v2.40.0",
"language_list_show":["简体中文","日本語","English","Русский язык","Español","한국어","Français","繁體中文","Tiếng Việt","Türkçe","Polski","Українська Мова","Italiano","اللغة العربية","ภาษาไทย","བོད་སྐད།"] ,
"language_list_translator":["简体中文","日文","英文","俄语","西班牙语","韩语","法语","繁体中文","越南语","土耳其语","波兰语","乌克兰语","意大利语","阿拉伯语","泰语","藏语"],
"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_real":[932,65001,936,950,949,1258,874,1256,1255,1254,1253,1257,1250,1251,1252,437],
"allkata":"ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヽヾ",
@ -125,9 +125,13 @@
"name":"语音合成",
"sources":[
{
"name": "NeoSpeech",
"name": "NeoSpeech Misaki",
"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",
"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",
"正则匹配": "Regular matching",
"非官方": "Unofficial",
"离线": "off-line"
"离线": "off-line",
"导出翻译补丁": "Export translation patches",
"语音修正": "Voice correction",
"藏语": "Tibetan"
}

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "Inspección de Seguridad incorporada",
"正则匹配": "Coincidencia regular",
"非官方": "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",
"正则匹配": "Match régulier",
"非官方": "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",
"正则匹配": "Corrispondenza regolare",
"非官方": "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",
"正则匹配": "Regularne dopasowanie",
"非官方": "Nieoficjalne",
"离线": "off-line"
"离线": "off-line",
"导出翻译补丁": "Eksportuj łatki tłumaczeniowe",
"语音修正": "Korekta głosu",
"藏语": "Tybetański"
}

View File

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

View File

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

View File

@ -717,5 +717,8 @@
"内嵌安全性检查": "İçeri giriş güvenlik kontrolü",
"正则匹配": "Normal eşleşme",
"非官方": "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",
"正则匹配": "Khớp chính quy",
"非官方": 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)
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)
add_library(x64lib magpie.cpp lossless.cpp)
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
#include <iostream>
#include <fstream>
#include<Windows.h>
#include <io.h>
#include <fcntl.h>
@ -100,42 +101,58 @@ std::vector<std::wstring>_List(const wchar_t* token) {
}
int neospeech(int argc, wchar_t* argv[]) {
auto speechs = _List(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices");
int idx = -1;
for (int i = 0; i < speechs.size(); i++) {
if (speechs[i] == L"VW Misaki") {
idx = i;
int neospeechlist(int argc, wchar_t* argv[]) {
FILE* f=_wfopen(argv[1],L"wb");
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++) {
if (speechs[i].substr(0,2) == L"VW") {
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
, PIPE_UNLIMITED_INSTANCES, 65535, 65535, NMPWAIT_WAIT_FOREVER, 0);
SECURITY_DESCRIPTOR sd = {};
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES allAccess = SECURITY_ATTRIBUTES{ sizeof(SECURITY_ATTRIBUTES), &sd, FALSE };
SetEvent(CreateEvent(&allAccess, FALSE, FALSE, argv[2]));
if (ConnectNamedPipe(hPipe, NULL) != NULL) {
DWORD len = 0;
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);
SECURITY_DESCRIPTOR sd = {};
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES allAccess = SECURITY_ATTRIBUTES{ sizeof(SECURITY_ATTRIBUTES), &sd, FALSE };
SetEvent(CreateEvent(&allAccess, FALSE, FALSE, argv[2]));
if (ConnectNamedPipe(hPipe, NULL) != NULL) {
DWORD len = 0;
}
int II = 0;
while (true) {
wchar_t text[10000];
II += 1;
DWORD _;
int speed;
if (!ReadFile(hPipe, (unsigned char*)&speed,4, &_, NULL))break;
if (!ReadFile(hPipe, (unsigned char*)text, 10000*2, &_, NULL))break;
std::wstring content = text;
wchar_t newname[1024] = { 0 };
wsprintf(newname, L"%s%d.wav", argv[3], II);
std::wstring newname_ = newname;
_Speak(content, L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices", idx, speed, 100, newname_);
WriteFile(hPipe, newname, wcslen(newname)*2, &_, NULL);
}
return 0;
}
int II = 0;
while (true) {
wchar_t text[10000];
II += 1;
DWORD _;
int speed;
if (!ReadFile(hPipe, (unsigned char*)&speed,4, &_, NULL))break;
if (!ReadFile(hPipe, (unsigned char*)text, 10000*2, &_, NULL))break;
std::wstring content = text;
wchar_t newname[1024] = { 0 };
wsprintf(newname, L"%s%d.wav", argv[3], II);
std::wstring newname_ = newname;
_Speak(content, hkey, idx, speed, 100, newname_);
WriteFile(hPipe, newname, wcslen(newname)*2, &_, NULL);
}
return 0;
}

View File

@ -9,7 +9,7 @@
int dllinjectwmain(int argc, wchar_t* argv[]);
int ntleaswmain(int argc, wchar_t* wargv[]);
bool checkisapatch();
#ifndef _WIN64
int LRwmain(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 lewmain(int argc, wchar_t* argv[]);
int neospeech(int argc, wchar_t* argv[]);
int neospeechlist(int argc, wchar_t* argv[]);
#else
int magpiewmain(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[])
{
if(checkisapatch())return 1;
auto argv0 = std::wstring(argv[1]);
if (argv0 == L"dllinject")
return dllinjectwmain(argc - 1, argv + 1);
@ -78,6 +80,8 @@ int wmain(int argc, wchar_t* argv[])
return voiceroid2wmain(argc - 1, argv + 1);
else if (argv0 == L"neospeech")
return neospeech(argc - 1, argv + 1);
else if (argv0 == L"neospeechlist")
return neospeechlist(argc - 1, argv + 1);
#else
else if (argv0 == L"magpie")
return magpiewmain(argc - 1, argv + 1);