This commit is contained in:
恍兮惚兮 2024-08-07 00:18:10 +08:00
parent 0a0e53f5f2
commit 57c912f919
41 changed files with 425 additions and 251 deletions

View File

@ -42,6 +42,7 @@ from gui.codeacceptdialog import codeacceptdialog
from gui.inputdialog import ( from gui.inputdialog import (
noundictconfigdialog1, noundictconfigdialog1,
yuyinzhidingsetting, yuyinzhidingsetting,
postconfigdialog2x,
autoinitdialog, autoinitdialog,
autoinitdialog_items, autoinitdialog_items,
postconfigdialog, postconfigdialog,
@ -591,7 +592,19 @@ def maybehavebutton(self, gameuid, post):
icon="fa.gear", callback=lambda: codeacceptdialog(self) icon="fa.gear", callback=lambda: codeacceptdialog(self)
) )
elif "args" in postprocessconfig[post]: elif "args" in postprocessconfig[post]:
if isinstance(list(postprocessconfig[post]["args"].values())[0], dict): if post == "stringreplace":
callback = functools.partial(
postconfigdialog2x,
self,
savehook_new_data[gameuid]["save_text_process_info"][
"postprocessconfig"
][post]["args"]["internal"],
savehook_new_data[gameuid]["save_text_process_info"][
"postprocessconfig"
][post]["name"],
["正则", "转义", "原文内容", "替换为"],
)
elif isinstance(list(postprocessconfig[post]["args"].values())[0], dict):
callback = functools.partial( callback = functools.partial(
postconfigdialog, postconfigdialog,
self, self,
@ -1081,7 +1094,7 @@ class dialog_setting_game_internal(QWidget):
self, self,
savehook_new_data[gameuid]["tts_repair_regex"], savehook_new_data[gameuid]["tts_repair_regex"],
"语音修正", "语音修正",
["正则", "原文", "替换"], ["正则", "转义", "原文", "替换"],
), ),
icon="fa.gear", icon="fa.gear",
), ),

View File

@ -36,40 +36,22 @@ class noundictconfigdialog1(LDialog):
self.model.insertRow( self.model.insertRow(
row, row,
[ [
QStandardItem(),
QStandardItem(), QStandardItem(),
QStandardItem(item["key"]), QStandardItem(item["key"]),
QStandardItem(item["value"]), QStandardItem(item["value"]),
], ],
) )
if "regex" not in item:
item["regex"] = False
if "escape" not in item:
item["escape"] = item["regex"]
self.table.setIndexWidget( self.table.setIndexWidget(
self.model.index(row, 0), getsimpleswitch(item, "regex") self.model.index(row, 0), getsimpleswitch(item, "regex")
) )
self.table.setIndexWidget(
def showmenu(self, table: TableViewW, _): self.model.index(row, 1), getsimpleswitch(item, "escape")
r = table.currentIndex().row() )
if r < 0:
return
menu = QMenu(table)
up = LAction("上移")
down = LAction("下移")
copy = LAction("复制")
paste = LAction("粘贴")
menu.addAction(up)
menu.addAction(down)
menu.addAction(copy)
menu.addAction(paste)
action = menu.exec(table.cursor().pos())
if action == up:
table.moverank(-1)
elif action == down:
table.moverank(1)
elif action == copy:
table.copytable()
elif action == paste:
table.pastetable()
def __init__(self, parent, reflist, title, label) -> None: def __init__(self, parent, reflist, title, label) -> None:
super().__init__(parent, Qt.WindowType.WindowCloseButtonHint) super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)
@ -82,15 +64,15 @@ class noundictconfigdialog1(LDialog):
self.model.setHorizontalHeaderLabels(label) self.model.setHorizontalHeaderLabels(label)
table = TableViewW(self) table = TableViewW(self)
table.setModel(self.model) table.setModel(self.model)
table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) table.horizontalHeader().setSectionResizeMode(
1, QHeaderView.ResizeMode.ResizeToContents
)
table.horizontalHeader().setSectionResizeMode( table.horizontalHeader().setSectionResizeMode(
0, QHeaderView.ResizeMode.ResizeToContents 0, QHeaderView.ResizeMode.ResizeToContents
) )
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) table.setsimplemenu()
table.customContextMenuRequested.connect(
functools.partial(self.showmenu, table)
)
self.table = table self.table = table
for row, item in enumerate(reflist): for row, item in enumerate(reflist):
@ -141,18 +123,39 @@ class noundictconfigdialog1(LDialog):
def __setindexwidget(self, index: QModelIndex, data): def __setindexwidget(self, index: QModelIndex, data):
if index.column() == 0: if index.column() == 0:
self.table.setIndexWidget(index, getsimpleswitch(data, "regex")) self.table.setIndexWidget(index, getsimpleswitch(data, "regex"))
if index.column() == 1:
self.table.setIndexWidget(index, getsimpleswitch(data, "escape"))
def __getindexwidgetdata(self, index: QModelIndex): def __getindexwidgetdata(self, index: QModelIndex):
if index.column() == 0:
return {"regex": self.table.indexWidgetX(index).isChecked()} return {"regex": self.table.indexWidgetX(index).isChecked()}
if index.column() == 1:
return {"escape": self.table.indexWidgetX(index).isChecked()}
def apply(self): def apply(self):
self.table.dedumpmodel(1) def __check(row):
k = self.model.item(row, 2).text()
if k == "":
return ""
switch = self.table.indexWidgetX(row, 0).isChecked()
es = self.table.indexWidgetX(row, 1).isChecked()
return (switch, es, k)
self.table.dedumpmodel(__check)
self.reflist.clear() self.reflist.clear()
for row in range(self.model.rowCount()): for row in range(self.model.rowCount()):
k = self.model.item(row, 1).text() k = self.model.item(row, 2).text()
v = self.model.item(row, 2).text() v = self.model.item(row, 3).text()
switch = self.table.indexWidgetX(row, 0) switch = self.table.indexWidgetX(row, 0)
self.reflist.append({"key": k, "value": v, "regex": switch.isChecked()}) es = self.table.indexWidgetX(row, 1)
self.reflist.append(
{
"key": k,
"value": v,
"escape": es.isChecked(),
"regex": switch.isChecked(),
}
)
def closeEvent(self, a0: QCloseEvent) -> None: def closeEvent(self, a0: QCloseEvent) -> None:
self.button.setFocus() self.button.setFocus()
@ -261,24 +264,6 @@ class yuyinzhidingsetting(LDialog):
self.table.setIndexWidget(self.model.index(row, 1), com) self.table.setIndexWidget(self.model.index(row, 1), com)
self.table.setIndexWidget(self.model.index(row, 3), self.createacombox(item)) self.table.setIndexWidget(self.model.index(row, 3), self.createacombox(item))
def showmenu(self, table: TableViewW, _):
r = table.currentIndex().row()
if r < 0:
return
menu = QMenu(table)
up = LAction("上移")
down = LAction("下移")
menu.addAction(up)
menu.addAction(down)
action = menu.exec(table.cursor().pos())
if action == up:
table.moverank(-1)
elif action == down:
table.moverank(1)
def createacombox(self, config): def createacombox(self, config):
com = LFocusCombo() com = LFocusCombo()
com.addItems(["跳过", "默认", "选择声音"]) com.addItems(["跳过", "默认", "选择声音"])
@ -348,10 +333,7 @@ class yuyinzhidingsetting(LDialog):
table.horizontalHeader().setSectionResizeMode( table.horizontalHeader().setSectionResizeMode(
0, QHeaderView.ResizeMode.ResizeToContents 0, QHeaderView.ResizeMode.ResizeToContents
) )
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) table.setsimplemenu({"copypaste": False})
table.customContextMenuRequested.connect(
functools.partial(self.showmenu, table)
)
self.table = table self.table = table
for row, item in enumerate(reflist): for row, item in enumerate(reflist):
@ -695,38 +677,8 @@ class multicolorset(LDialog):
@Singleton_close @Singleton_close
class postconfigdialog_(LDialog): class postconfigdialog_(LDialog):
def closeEvent(self, a0: QCloseEvent) -> None: def closeEvent(self, a0: QCloseEvent) -> None:
if self.closeevent:
self.button.setFocus() self.button.setFocus()
self.apply() self.apply()
if self.closecallback:
self.closecallback()
def showmenu(self, table: TableViewW, pos):
r = table.currentIndex().row()
if r < 0:
return
menu = QMenu(table)
up = LAction("上移")
down = LAction("下移")
copy = LAction("复制")
paste = LAction("粘贴")
menu.addAction(up)
menu.addAction(down)
menu.addAction(copy)
menu.addAction(paste)
action = menu.exec(table.cursor().pos())
if action == up:
table.moverank(-1)
elif action == down:
table.moverank(1)
elif action == copy:
table.copytable()
elif action == paste:
table.pastetable()
def apply(self): def apply(self):
self.table.dedumpmodel(0) self.table.dedumpmodel(0)
@ -747,14 +699,9 @@ class postconfigdialog_(LDialog):
else: else:
raise raise
def __init__( def __init__(self, parent, configdict, title, headers, dictkeys=None) -> None:
self, parent, configdict, title, headers, closecallback=None, dictkeys=None
) -> None:
super().__init__(parent, Qt.WindowType.WindowCloseButtonHint) super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)
self.closecallback = closecallback
self.setWindowTitle(title) self.setWindowTitle(title)
# self.setWindowModality(Qt.ApplicationModal)
self.closeevent = False
formLayout = QVBoxLayout(self) # 配置layout formLayout = QVBoxLayout(self) # 配置layout
self.dictkeys = dictkeys self.dictkeys = dictkeys
model = LStandardItemModel(len(configdict), 1, self) model = LStandardItemModel(len(configdict), 1, self)
@ -781,10 +728,7 @@ class postconfigdialog_(LDialog):
table.setModel(model) table.setModel(model)
table.setWordWrap(False) table.setWordWrap(False)
table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) table.setsimplemenu()
table.customContextMenuRequested.connect(
functools.partial(self.showmenu, table)
)
button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"]) button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"])
self.table = table self.table = table
button.btn1clicked.connect(table.insertplainrow) button.btn1clicked.connect(table.insertplainrow)
@ -796,7 +740,6 @@ class postconfigdialog_(LDialog):
self.button = button self.button = button
self.model = model self.model = model
self.configdict = configdict self.configdict = configdict
self.closeevent = True
search = QHBoxLayout() search = QHBoxLayout()
searchcontent = QLineEdit() searchcontent = QLineEdit()
search.addWidget(searchcontent) search.addWidget(searchcontent)
@ -827,3 +770,7 @@ class postconfigdialog_(LDialog):
def postconfigdialog(parent, configdict, title, header): def postconfigdialog(parent, configdict, title, header):
postconfigdialog_(parent, configdict, title, header) postconfigdialog_(parent, configdict, title, header)
def postconfigdialog2x(parent, reflist, title, header):
noundictconfigdialog1(parent, reflist, title, header)

View File

@ -16,7 +16,12 @@ from gui.usefulwidget import (
getvboxwidget, getvboxwidget,
makesubtab_lazy, makesubtab_lazy,
) )
from gui.inputdialog import postconfigdialog, autoinitdialog, autoinitdialog_items from gui.inputdialog import (
postconfigdialog,
autoinitdialog,
autoinitdialog_items,
postconfigdialog2x,
)
def delaysetcomparetext(self, s): def delaysetcomparetext(self, s):
@ -101,7 +106,16 @@ def setTab7_lazy(self, basel):
callback=lambda: codeacceptdialog(self), callback=lambda: codeacceptdialog(self),
) )
elif "args" in postprocessconfig[post]: elif "args" in postprocessconfig[post]:
if isinstance(list(postprocessconfig[post]["args"].values())[0], dict):
if post=='stringreplace':
callback = functools.partial(
postconfigdialog2x,
self,
postprocessconfig[post]["args"]['internal'],
postprocessconfig[post]["name"],
["正则", "转义", "原文内容", "替换为"],
)
elif isinstance(list(postprocessconfig[post]["args"].values())[0], dict):
callback = functools.partial( callback = functools.partial(
postconfigdialog, postconfigdialog,
self, self,

View File

@ -234,7 +234,7 @@ def setTab5lz(self):
self, self,
globalconfig["ttscommon"]["tts_repair_regex"], globalconfig["ttscommon"]["tts_repair_regex"],
"语音修正", "语音修正",
["正则", "原文", "替换"], ["正则",'转义', "原文", "替换"],
), ),
icon="fa.gear", icon="fa.gear",
), ),

View File

@ -95,6 +95,36 @@ class TableViewW(QTableView):
super().__init__(*argc) super().__init__(*argc)
self.setSelectionMode(QAbstractItemView.SelectionMode.ContiguousSelection) self.setSelectionMode(QAbstractItemView.SelectionMode.ContiguousSelection)
def showmenu(self, info, pos):
r = self.currentIndex().row()
if r < 0:
return
menu = QMenu(self)
up = LAction("上移")
down = LAction("下移")
copy = LAction("复制")
paste = LAction("粘贴")
menu.addAction(up)
menu.addAction(down)
if info.get("copypaste", True):
menu.addAction(copy)
menu.addAction(paste)
action = menu.exec(self.cursor().pos())
if action == up:
self.moverank(-1)
elif action == down:
self.moverank(1)
elif action == copy:
self.copytable()
elif action == paste:
self.pastetable()
def setsimplemenu(self, info=None):
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
if info is None:
info = {}
self.customContextMenuRequested.connect(functools.partial(self.showmenu, info))
def insertplainrow(self, row=0): def insertplainrow(self, row=0):
self.model().insertRow( self.model().insertRow(
row, [QStandardItem() for _ in range(self.model().columnCount())] row, [QStandardItem() for _ in range(self.model().columnCount())]
@ -106,11 +136,15 @@ class TableViewW(QTableView):
dedump = set() dedump = set()
needremoves = [] needremoves = []
for row in range(rows): for row in range(rows):
if isinstance(col, int):
k = self.safetext(row, col) k = self.safetext(row, col)
elif callable(col):
k = col(row)
if k == "" or k in dedump: if k == "" or k in dedump:
needremoves.append(row) needremoves.append(row)
continue continue
dedump.add(k) dedump.add(k)
for row in reversed(needremoves): for row in reversed(needremoves):
self.model().removeRow(row) self.model().removeRow(row)

View File

@ -2,7 +2,7 @@ import os, hashlib, queue, gobject
from myutils.proxy import getproxy from myutils.proxy import getproxy
from threading import Thread from threading import Thread
from myutils.commonbase import proxysession from myutils.commonbase import proxysession
from myutils.config import globalconfig, savehook_new_data from myutils.config import globalconfig, savehook_new_data, namemapcast
from traceback import print_exc from traceback import print_exc
from requests import RequestException from requests import RequestException
@ -176,11 +176,21 @@ class common:
if _url not in _urls: if _url not in _urls:
savehook_new_data[gameuid]["relationlinks"].append((_vis, _url)) savehook_new_data[gameuid]["relationlinks"].append((_vis, _url))
if namemap: if namemap:
if (len(savehook_new_data[gameuid]["namemap"]) == 0) or ( dedump = set()
not savehook_new_data[gameuid]["vndbnamemap_modified"] for _ in savehook_new_data[gameuid]["namemap2"]:
): dedump.add(_.get("key", ""))
savehook_new_data[gameuid]["namemap"] = namemap namemap = namemapcast(namemap)
savehook_new_data[gameuid]["vndbnamemap_modified"] = False for name in namemap:
if name in dedump:
continue
savehook_new_data[gameuid]["namemap2"].append(
{
"key": name,
"value": namemap[name],
"regex": False,
"escape": False,
}
)
for _ in webtags: for _ in webtags:
if _ in savehook_new_data[gameuid]["webtags"]: if _ in savehook_new_data[gameuid]["webtags"]:

View File

@ -210,7 +210,6 @@ class searcher(common):
elif isinstance(__, dict): elif isinstance(__, dict):
developers.append(__["v"]) developers.append(__["v"])
return { return {
# "namemap": namemap,
"title": response["name"], "title": response["name"],
"imagepath_all": [imagepath], "imagepath_all": [imagepath],
"webtags": vndbtags, "webtags": vndbtags,

View File

@ -113,7 +113,6 @@ class searcher(common):
print(imags1) print(imags1)
return { return {
# "namemap": namemap,
"title": title, "title": title,
"imagepath_all": [self.dispatchdownloadtask(_) for _ in imags1 + imags2], "imagepath_all": [self.dispatchdownloadtask(_) for _ in imags1 + imags2],
"webtags": tags, "webtags": tags,

View File

@ -171,7 +171,6 @@ class searcher(common):
inner = simplehtmlparser(response.text, "div", '<div ref="product_slider_data"') inner = simplehtmlparser(response.text, "div", '<div ref="product_slider_data"')
return { return {
# "namemap": namemap,
"title": title, "title": title,
"imagepath_all": [ "imagepath_all": [
self.dispatchdownloadtask(_.replace("js-", "jp-")) for _ in imags2 self.dispatchdownloadtask(_.replace("js-", "jp-")) for _ in imags2

View File

@ -185,7 +185,6 @@ class searcher(common):
+ [data.get("background_raw", None)] + [data.get("background_raw", None)]
) )
return { return {
# "namemap": namemap,
"title": data["name"], "title": data["name"],
"imagepath_all": [ "imagepath_all": [
self.dispatchdownloadtask(re.sub("\\?t=(\\d+)", "", _)) for _ in images self.dispatchdownloadtask(re.sub("\\?t=(\\d+)", "", _)) for _ in images

View File

@ -4,6 +4,19 @@ from traceback import print_exc
from qtsymbols import * from qtsymbols import *
def namemapcast(namemap):
bettermap = namemap.copy()
for k, v in namemap.items():
for sp in ["", " "]:
spja = k.split(sp)
spen = v.split(" ")
if len(spja) == len(spen) and len(spen) > 1:
for i in range(len(spja)):
if len(spja[i]) >= 2:
bettermap[spja[i]] = spen[i]
return bettermap
def tryreadconfig(path, default=None): def tryreadconfig(path, default=None):
path = os.path.join("userconfig", path) path = os.path.join("userconfig", path)
try: try:
@ -165,9 +178,9 @@ def getdefaultsavehook(title=None):
"gptpromptdict_use": False, "gptpromptdict_use": False,
"gptpromptdict_merge": False, "gptpromptdict_merge": False,
"gptpromptdict": [], "gptpromptdict": [],
"vndbnamemap_modified": False,
# 元数据 # 元数据
"namemap": {}, # 人名翻译映射vndb独占用于优化翻译 "namemap2": [],
# "namemap": {}, # 人名翻译映射vndb独占用于优化翻译
# #
# "vid": 0, # "vid": 0,
# "bgmsid": 0, # "bgmsid": 0,
@ -187,6 +200,11 @@ def getdefaultsavehook(title=None):
return default return default
needcast = False
if "xxxcast" not in globalconfig:
globalconfig["xxxcast"] = True
needcast = True
# fmt: off # fmt: off
oldlanguage = ["zh","ja","en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th","bo","de","sv","nl"] oldlanguage = ["zh","ja","en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th","bo","de","sv","nl"]
# fmt: on # fmt: on
@ -212,6 +230,14 @@ for gameconfig in savehook_new_data.values():
if ("private_srclang" in gameconfig) and ("private_srclang_2" not in gameconfig): if ("private_srclang" in gameconfig) and ("private_srclang_2" not in gameconfig):
gameconfig["private_srclang_2"] = oldlanguage[gameconfig["private_srclang"]] gameconfig["private_srclang_2"] = oldlanguage[gameconfig["private_srclang"]]
gameconfig["private_tgtlang_2"] = oldlanguage[gameconfig["private_tgtlang"]] gameconfig["private_tgtlang_2"] = oldlanguage[gameconfig["private_tgtlang"]]
if "namemap" in gameconfig:
gameconfig["namemap2"] = []
for k, v in namemapcast(gameconfig.pop("namemap")).items():
gameconfig["namemap2"].append(
{"key": k, "value": v, "regex": False, "escape": False}
)
for __k, __v in _dfsavehook.items(): for __k, __v in _dfsavehook.items():
if __k not in gameconfig: if __k not in gameconfig:
if isinstance(__v, (list, dict)): if isinstance(__v, (list, dict)):
@ -221,6 +247,84 @@ for gameconfig in savehook_new_data.values():
if not gameconfig.get("leuse", True): if not gameconfig.get("leuse", True):
gameconfig.pop("leuse") gameconfig.pop("leuse")
gameconfig["launch_method"] = "direct" gameconfig["launch_method"] = "direct"
if needcast:
if "save_text_process_info" not in gameconfig:
continue
if "rank" not in gameconfig["save_text_process_info"]:
continue
if "postprocessconfig" not in gameconfig["save_text_process_info"]:
continue
items = []
try:
ifuse = False
for post in gameconfig["save_text_process_info"]["rank"]:
# 简单
if post == "_7":
ifuse = (
ifuse
or gameconfig["save_text_process_info"]["postprocessconfig"][
"_7"
]["use"]
)
gameconfig["save_text_process_info"]["postprocessconfig"]["_7"][
"use"
] = False
for k, v in gameconfig["save_text_process_info"][
"postprocessconfig"
]["_7"]["args"]["替换内容"].items():
items.append(
{"regex": False, "escape": False, "key": k, "value": v}
)
if post == "_7_zhuanyi":
ifuse = (
ifuse
or gameconfig["save_text_process_info"]["postprocessconfig"][
"_7_zhuanyi"
]["use"]
)
gameconfig["save_text_process_info"]["postprocessconfig"][
"_7_zhuanyi"
]["use"] = False
for k, v in gameconfig["save_text_process_info"][
"postprocessconfig"
]["_7_zhuanyi"]["args"]["替换内容"].items():
items.append(
{"regex": False, "escape": True, "key": k, "value": v}
)
# 正则
if post == "_8":
ifuse = (
ifuse
or gameconfig["save_text_process_info"]["postprocessconfig"][
"_8"
]["use"]
)
gameconfig["save_text_process_info"]["postprocessconfig"]["_8"][
"use"
] = False
for k, v in gameconfig["save_text_process_info"][
"postprocessconfig"
]["_8"]["args"]["替换内容"].items():
items.append(
{"regex": True, "escape": True, "key": k, "value": v}
)
if len(items):
gameconfig["save_text_process_info"]["rank"].append("stringreplace")
gameconfig["save_text_process_info"]["postprocessconfig"][
"stringreplace"
] = {
"args": {"internal": items},
"use": ifuse,
"name": "字符串替换",
}
except:
print_exc()
if "global_namemap" in globalconfig:
globalconfig["global_namemap2"] = []
for k, v in namemapcast(globalconfig.pop("global_namemap")).items():
globalconfig["global_namemap2"].append(
{"key": k, "value": v, "regex": False, "escape": False}
)
class __uid2gamepath: class __uid2gamepath:
@ -325,6 +429,35 @@ if ocrerrorfix == {}:
ocrerrorfix = ocrerrorfixdefault ocrerrorfix = ocrerrorfixdefault
syncconfig(postprocessconfig, defaultpost, True, 3) syncconfig(postprocessconfig, defaultpost, True, 3)
if needcast:
ifuse = False
for post in globalconfig["postprocess_rank"]:
# 简单
if post == "_7":
ifuse = ifuse or postprocessconfig["_7"]["use"]
postprocessconfig["_7"]["use"] = False
for k, v in postprocessconfig["_7"]["args"]["替换内容"].items():
postprocessconfig["stringreplace"]["args"]["internal"].append(
{"regex": False, "escape": False, "key": k, "value": v}
)
if post == "_7_zhuanyi":
ifuse = ifuse or postprocessconfig["_7_zhuanyi"]["use"]
postprocessconfig["_7_zhuanyi"]["use"] = False
for k, v in postprocessconfig["_7_zhuanyi"]["args"]["替换内容"].items():
postprocessconfig["stringreplace"]["args"]["internal"].append(
{"regex": False, "escape": True, "key": k, "value": v}
)
# 正则
if post == "_8":
ifuse = ifuse or postprocessconfig["_8"]["use"]
postprocessconfig["_8"]["use"] = False
for k, v in postprocessconfig["_8"]["args"]["替换内容"].items():
postprocessconfig["stringreplace"]["args"]["internal"].append(
{"regex": True, "escape": True, "key": k, "value": v}
)
postprocessconfig["stringreplace"]["use"] = ifuse
for key in defaultglobalconfig["toolbutton"]["buttons"]: for key in defaultglobalconfig["toolbutton"]["buttons"]:
if key not in globalconfig["toolbutton"]["rank2"]: if key not in globalconfig["toolbutton"]["rank2"]:
globalconfig["toolbutton"]["rank2"].append(key) globalconfig["toolbutton"]["rank2"].append(key)

View File

@ -2,7 +2,7 @@ import re, codecs, inspect
from traceback import print_exc from traceback import print_exc
from collections import Counter from collections import Counter
import gobject import gobject
from myutils.utils import checkchaos, checkmd5reloadmodule, LRUCache, getlangsrc from myutils.utils import checkchaos, checkmd5reloadmodule, LRUCache, getlangsrc, parsemayberegexreplace
from myutils.config import ( from myutils.config import (
postprocessconfig, postprocessconfig,
globalconfig, globalconfig,
@ -219,6 +219,11 @@ def _92_f(line):
return line return line
def stringreplace(line, args):
filters = args["internal"]
return parsemayberegexreplace(filters, line)
def _7_zhuanyi_f(line, args): def _7_zhuanyi_f(line, args):
filters = args["替换内容"] filters = args["替换内容"]
for fil in filters: for fil in filters:
@ -370,6 +375,7 @@ def POSTSOLVE(line):
"length_threshold": length_threshold, "length_threshold": length_threshold,
"lines_threshold": lines_threshold, "lines_threshold": lines_threshold,
"_11": _mypostloader, "_11": _mypostloader,
"stringreplace": stringreplace,
} }
useranklist = globalconfig["postprocess_rank"] useranklist = globalconfig["postprocess_rank"]
usedpostprocessconfig = postprocessconfig usedpostprocessconfig = postprocessconfig

View File

@ -493,17 +493,34 @@ class autosql(sqlite3.Connection):
@tryprint @tryprint
def parsemayberegexreplace(dic: dict, res: str): def parsemayberegexreplace(lst: list, line: str):
for item in dic: for fil in lst:
if item["regex"]: regex = fil.get("regex", False)
res = re.sub( escape = fil.get("escape", regex)
codecs.escape_decode(bytes(item["key"], "utf-8"))[0].decode("utf-8"), key = fil.get("key", "")
codecs.escape_decode(bytes(item["value"], "utf-8"))[0].decode("utf-8"), value = fil.get("value", "")
res, if key == "":
continue
if regex:
if escape:
line = re.sub(
codecs.escape_decode(bytes(key, "utf-8"))[0].decode("utf-8"),
codecs.escape_decode(bytes(value, "utf-8"))[0].decode("utf-8"),
)
else:
line = re.sub(key, value)
else:
if escape:
line = line.replace(
codecs.escape_decode(bytes(key, "utf-8"))[0].decode("utf-8"),
codecs.escape_decode(bytes(value, "utf-8"))[0].decode("utf-8"),
) )
else: else:
res = res.replace(item["key"], item["value"]) line = line.replace(key, value)
return res
return line
def checkpostlangmatch(name): def checkpostlangmatch(name):

View File

@ -16,33 +16,6 @@ class noundictconfigdialog(LDialog):
self.button.setFocus() self.button.setFocus()
self.apply() self.apply()
def showmenu(self, table: TableViewW, pos):
r = table.currentIndex().row()
if r < 0:
return
menu = QMenu(table)
up = LAction("上移")
down = LAction("下移")
copy = LAction("复制")
paste = LAction("粘贴")
menu.addAction(up)
menu.addAction(down)
menu.addAction(copy)
menu.addAction(paste)
action = menu.exec(table.cursor().pos())
if action == up:
table.moverank(-1)
elif action == down:
table.moverank(1)
elif action == copy:
table.copytable()
elif action == paste:
table.pastetable()
def apply(self): def apply(self):
rows = self.model.rowCount() rows = self.model.rowCount()
self.configdict.clear() self.configdict.clear()
@ -84,10 +57,7 @@ class noundictconfigdialog(LDialog):
table = TableViewW(self) table = TableViewW(self)
table.setModel(model) table.setModel(model)
table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) table.setsimplemenu()
table.customContextMenuRequested.connect(
functools.partial(self.showmenu, table)
)
button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"]) button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"])
self.table = table self.table = table
@ -154,34 +124,6 @@ class noundictconfigdialog_private(LDialog):
self.button.setFocus() self.button.setFocus()
self.apply() self.apply()
def showmenu(self, table: TableViewW, pos):
r = table.currentIndex().row()
if r < 0:
return
menu = QMenu(table)
up = LAction("上移")
down = LAction("下移")
copy = LAction("复制")
paste = LAction("粘贴")
menu.addAction(up)
menu.addAction(down)
menu.addAction(copy)
menu.addAction(paste)
action = menu.exec(table.cursor().pos())
if action == up:
table.moverank(-1)
elif action == down:
table.moverank(1)
elif action == copy:
table.copytable()
elif action == paste:
table.pastetable()
def apply(self): def apply(self):
self.table.dedumpmodel(0) self.table.dedumpmodel(0)
rows = self.model.rowCount() rows = self.model.rowCount()
@ -214,10 +156,7 @@ class noundictconfigdialog_private(LDialog):
table = TableViewW(self) table = TableViewW(self)
table.setModel(model) table.setModel(model)
table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) table.setsimplemenu()
table.customContextMenuRequested.connect(
functools.partial(self.showmenu, table)
)
button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"]) button = threebuttons(texts=["添加行", "删除行", "上移", "下移", "立即应用"])
self.table = table self.table = table
button.btn1clicked.connect(table.insertplainrow) button.btn1clicked.connect(table.insertplainrow)

View File

@ -13,7 +13,7 @@ class Process:
parent_window, parent_window,
transerrorfixdictconfig["dict_v2"], transerrorfixdictconfig["dict_v2"],
"翻译结果修正_设置", "翻译结果修正_设置",
["正则", "翻译", "替换"], ["正则",'转义', "翻译", "替换"],
) )
@staticmethod @staticmethod
@ -23,7 +23,7 @@ class Process:
parent_window, parent_window,
savehook_new_data[gameuid]["transerrorfix"], savehook_new_data[gameuid]["transerrorfix"],
"翻译结果修正_设置", "翻译结果修正_设置",
["正则", "翻译", "替换"], ["正则",'转义', "翻译", "替换"],
).setWindowIcon(getExeIcon(uid2gamepath[gameuid], cache=True)) ).setWindowIcon(getExeIcon(uid2gamepath[gameuid], cache=True))
def process_after(self, res, mp1): def process_after(self, res, mp1):

View File

@ -1,6 +1,6 @@
from myutils.config import globalconfig, savehook_new_data, uid2gamepath from myutils.config import globalconfig, savehook_new_data, uid2gamepath
from myutils.utils import postusewhich from myutils.utils import postusewhich, parsemayberegexreplace
from gui.inputdialog import postconfigdialog_ from gui.inputdialog import noundictconfigdialog1
import gobject, json, functools import gobject, json, functools
from myutils.hwnd import getExeIcon from myutils.hwnd import getExeIcon
@ -10,29 +10,22 @@ class Process:
@staticmethod @staticmethod
def get_setting_window(parent_window): def get_setting_window(parent_window):
return ( return (
postconfigdialog_( noundictconfigdialog1(
parent_window, parent_window,
globalconfig["global_namemap"], globalconfig["global_namemap2"],
"专有名词翻译_直接替换_设置", "专有名词翻译_直接替换_设置",
["原文", "翻译"], ["正则",'转义', "原文", "翻译"],
), ),
) )
@staticmethod @staticmethod
def get_setting_window_gameprivate(parent_window, gameuid): def get_setting_window_gameprivate(parent_window, gameuid):
def checkchange(gameuid, __): noundictconfigdialog1(
__2 = json.dumps(savehook_new_data[gameuid]["namemap"])
if __ != __2:
savehook_new_data[gameuid]["vndbnamemap_modified"] = True
__ = json.dumps(savehook_new_data[gameuid]["namemap"])
postconfigdialog_(
parent_window, parent_window,
savehook_new_data[gameuid]["namemap"], savehook_new_data[gameuid]["namemap2"],
"专有名词翻译_直接替换_设置", "专有名词翻译_直接替换_设置",
["原文", "翻译"], ["正则",'转义', "原文", "翻译"],
closecallback=functools.partial(checkchange, gameuid, __),
).setWindowIcon(getExeIcon(uid2gamepath[gameuid], cache=True)) ).setWindowIcon(getExeIcon(uid2gamepath[gameuid], cache=True))
@property @property
@ -42,20 +35,17 @@ class Process:
def usewhich(self) -> dict: def usewhich(self) -> dict:
which = postusewhich("vndbnamemap") which = postusewhich("vndbnamemap")
if which == 1: if which == 1:
return globalconfig["global_namemap"] return globalconfig["global_namemap2"]
elif which == 2: elif which == 2:
gameuid = gobject.baseobject.textsource.gameuid gameuid = gobject.baseobject.textsource.gameuid
return savehook_new_data[gameuid]["namemap"] return savehook_new_data[gameuid]["namemap2"]
elif which == 3: elif which == 3:
_ = {} return savehook_new_data[gameuid]["namemap2"] + globalconfig["global_namemap2"]
_.update(globalconfig["global_namemap"])
gameuid = gobject.baseobject.textsource.gameuid
_.update(savehook_new_data[gameuid]["namemap"])
return _
def process_before(self, s): def process_before(self, s):
namemap = self.usewhich() namemap = self.usewhich()
s=parsemayberegexreplace(namemap,s)
bettermap = {} bettermap = {}
for k, v in namemap.items(): for k, v in namemap.items():
for sp in ["", " "]: for sp in ["", " "]:

View File

@ -499,7 +499,7 @@
1200, 1200,
600 600
], ],
"global_namemap": {}, "global_namemap2": [],
"settingfontsize": 12, "settingfontsize": 12,
"filter_chaos_code": false, "filter_chaos_code": false,
"accept_encoding": [ "accept_encoding": [

View File

@ -1,4 +1,11 @@
{ {
"stringreplace": {
"use": false,
"name": "字符串替换",
"args": {
"internal":[]
}
},
"_remove_non_shiftjis_char": { "_remove_non_shiftjis_char": {
"use": false, "use": false,
"name": "过滤文本中的非日语字符集字符" "name": "过滤文本中的非日语字符集字符"
@ -157,21 +164,21 @@
}, },
"_7": { "_7": {
"use": true, "use": true,
"name": "简单字符串替换", "name": "!_不推荐使用_简单字符串替换_!",
"args": { "args": {
"替换内容": {} "替换内容": {}
} }
}, },
"_7_zhuanyi": { "_7_zhuanyi": {
"use": true, "use": true,
"name": "转义字符串替换", "name": "!_不推荐使用_转义字符串替换_!",
"args": { "args": {
"替换内容": {} "替换内容": {}
} }
}, },
"_8": { "_8": {
"use": false, "use": false,
"name": "正则表达式替换", "name": "!_不推荐使用_正则表达式替换_!",
"args": { "args": {
"替换内容": {} "替换内容": {}
} }

View File

@ -849,5 +849,8 @@
"语音指定": "صوت محدد", "语音指定": "صوت محدد",
"指定为": "تعيين", "指定为": "تعيين",
"跳过": "تخطي", "跳过": "تخطي",
"作用于翻译": "العمل على الترجمة" "作用于翻译": "العمل على الترجمة",
"字符串替换": "سلسلة استبدال",
"转义": "هروب",
"不推荐使用": "لا ينصح باستخدام"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "語音指定", "语音指定": "語音指定",
"指定为": "指定為", "指定为": "指定為",
"跳过": "跳過", "跳过": "跳過",
"作用于翻译": "作用於翻譯" "作用于翻译": "作用於翻譯",
"字符串替换": "字串替換",
"转义": "轉義",
"不推荐使用": "不推薦使用"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Označení hlasu", "语音指定": "Označení hlasu",
"指定为": "Určeno jako", "指定为": "Určeno jako",
"跳过": "přeskočit", "跳过": "přeskočit",
"作用于翻译": "Použití na překlad" "作用于翻译": "Použití na překlad",
"字符串替换": "Náhrada řetězce",
"转义": "Útěk",
"不推荐使用": "Nedoporučuje se k použití"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Sprachbezeichnung", "语音指定": "Sprachbezeichnung",
"指定为": "Bestimmt als", "指定为": "Bestimmt als",
"跳过": "überspringen", "跳过": "überspringen",
"作用于翻译": "Auf Übersetzungen angewendet" "作用于翻译": "Auf Übersetzungen angewendet",
"字符串替换": "Zeichenfolgenersatz",
"转义": "Flucht",
"不推荐使用": "Nicht empfohlen für die Anwendung"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Voice designation", "语音指定": "Voice designation",
"指定为": "Designated as", "指定为": "Designated as",
"跳过": "skip", "跳过": "skip",
"作用于翻译": "Applied to translation" "作用于翻译": "Applied to translation",
"字符串替换": "String replacement",
"转义": "Escaping",
"不推荐使用": "Not recommended for use"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Designación de voz", "语音指定": "Designación de voz",
"指定为": "Designado como", "指定为": "Designado como",
"跳过": "Saltar", "跳过": "Saltar",
"作用于翻译": "Actuar sobre la traducción" "作用于翻译": "Actuar sobre la traducción",
"字符串替换": "Reemplazo de cadenas",
"转义": "Transliteración",
"不推荐使用": "No se recomienda usar"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Désignation vocale", "语音指定": "Désignation vocale",
"指定为": "Désigné comme", "指定为": "Désigné comme",
"跳过": "Sauter", "跳过": "Sauter",
"作用于翻译": "Agir sur la traduction" "作用于翻译": "Agir sur la traduction",
"字符串替换": "Remplacement de chaîne",
"转义": "échappement",
"不推荐使用": "Utilisation non recommandée"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Denominazione vocale", "语音指定": "Denominazione vocale",
"指定为": "Designato come", "指定为": "Designato come",
"跳过": "salta", "跳过": "salta",
"作用于翻译": "Applicato alla traduzione" "作用于翻译": "Applicato alla traduzione",
"字符串替换": "Sostituzione stringa",
"转义": "Scappare",
"不推荐使用": "Non raccomandato per l'uso"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "音声指定", "语音指定": "音声指定",
"指定为": "指定#シテイ#", "指定为": "指定#シテイ#",
"跳过": "スキップ", "跳过": "スキップ",
"作用于翻译": "翻訳に役立つ" "作用于翻译": "翻訳に役立つ",
"字符串替换": "文字列置換",
"转义": "エスケープ",
"不推荐使用": "使用を推奨しない"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "음성 지정", "语音指定": "음성 지정",
"指定为": "다음으로 지정", "指定为": "다음으로 지정",
"跳过": "건너뛰기", "跳过": "건너뛰기",
"作用于翻译": "번역에 적용" "作用于翻译": "번역에 적용",
"字符串替换": "문자열 대체",
"转义": "전의",
"不推荐使用": "권장하지 않음"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Stembepaling", "语音指定": "Stembepaling",
"指定为": "Aangeduid als", "指定为": "Aangeduid als",
"跳过": "overslaan", "跳过": "overslaan",
"作用于翻译": "Toegepast op vertaling" "作用于翻译": "Toegepast op vertaling",
"字符串替换": "Vervanging van tekenreeks",
"转义": "Ontsnappen",
"不推荐使用": "Niet aanbevolen voor gebruik"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Oznaczenie głosu", "语音指定": "Oznaczenie głosu",
"指定为": "Wyznaczony jako", "指定为": "Wyznaczony jako",
"跳过": "pominięcie", "跳过": "pominięcie",
"作用于翻译": "Zastosowanie do tłumaczenia" "作用于翻译": "Zastosowanie do tłumaczenia",
"字符串替换": "Zastąpienie ciągu",
"转义": "Ucieczka",
"不推荐使用": "Nie zaleca się stosowania"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Designação da voz", "语音指定": "Designação da voz",
"指定为": "Designado como", "指定为": "Designado como",
"跳过": "pular", "跳过": "pular",
"作用于翻译": "Aplicado à tradução" "作用于翻译": "Aplicado à tradução",
"字符串替换": "Substituição de strings",
"转义": "Escapar",
"不推荐使用": "Não recomendado para utilização"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Голосовое назначение", "语音指定": "Голосовое назначение",
"指定为": "Назначено", "指定为": "Назначено",
"跳过": "Пропустить", "跳过": "Пропустить",
"作用于翻译": "Роль перевода" "作用于翻译": "Роль перевода",
"字符串替换": "Замена строки",
"转义": "Транслитерация",
"不推荐使用": "Не рекомендуется использовать"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Röstbeteckning", "语音指定": "Röstbeteckning",
"指定为": "Utnämnd som", "指定为": "Utnämnd som",
"跳过": "hoppa över", "跳过": "hoppa över",
"作用于翻译": "Tillämpad på översättning" "作用于翻译": "Tillämpad på översättning",
"字符串替换": "Strängersättning",
"转义": "Flykt",
"不推荐使用": "Rekommenderas inte för användning"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "การกำหนดเสียง", "语音指定": "การกำหนดเสียง",
"指定为": "กำหนดให้เป็น", "指定为": "กำหนดให้เป็น",
"跳过": "ข้าม", "跳过": "ข้าม",
"作用于翻译": "บทบาทในการแปล" "作用于翻译": "บทบาทในการแปล",
"字符串替换": "การแทนที่สตริง",
"转义": "แปลความหมาย",
"不推荐使用": "ไม่แนะนำให้ใช้"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Ses tasarımı", "语音指定": "Ses tasarımı",
"指定为": "Şöyle tasarlanmıştır", "指定为": "Şöyle tasarlanmıştır",
"跳过": "atla", "跳过": "atla",
"作用于翻译": "Çevirmeye uygulandı" "作用于翻译": "Çevirmeye uygulandı",
"字符串替换": "String Replacement",
"转义": "Kaçmak",
"不推荐使用": "Kullanmak için önerilmez"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Визначення голосу", "语音指定": "Визначення голосу",
"指定为": "Визначено як", "指定为": "Визначено як",
"跳过": "пропустити", "跳过": "пропустити",
"作用于翻译": "Застосовано до перекладу" "作用于翻译": "Застосовано до перекладу",
"字符串替换": "Заміна рядків",
"转义": "Бег",
"不推荐使用": "Не рекомендується використовувати"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "Chỉ định giọng nói", "语音指定": "Chỉ định giọng nói",
"指定为": "Xác định là", "指定为": "Xác định là",
"跳过": "Bỏ qua", "跳过": "Bỏ qua",
"作用于翻译": "Hành động để dịch" "作用于翻译": "Hành động để dịch",
"字符串替换": "Thay thế chuỗi",
"转义": "Thoát",
"不推荐使用": "Không khuyến khích sử dụng"
} }

View File

@ -849,5 +849,8 @@
"语音指定": "", "语音指定": "",
"指定为": "", "指定为": "",
"跳过": "", "跳过": "",
"作用于翻译": "" "作用于翻译": "",
"字符串替换": "",
"转义": "",
"不推荐使用": ""
} }

View File

@ -85,19 +85,19 @@
**18. 简单字符串替换** ~~**18. 简单字符串替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
不止是替换,主要也可以用来过滤。可以将固定的若干乱码字符、反复刷新的倒三角字符等通过替换成空白来进行过滤。 ~~不止是替换,主要也可以用来过滤。可以将固定的若干乱码字符、反复刷新的倒三角字符等通过替换成空白来进行过滤。~~
**19. 转义字符串替换** ~~**19. 转义字符串替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
主要是可以支持`\n`来表示换行符,从而实现可以过滤仅在换行符前后出现的字符。 ~~主要是可以支持`\n`来表示换行符,从而实现可以过滤仅在换行符前后出现的字符。~~
**20. 正则表达式替换** ~~**20. 正则表达式替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
注:**这个输入的内容都是转义字符串**也就是说比如你在外面写python代码`re.sub(r"\n","")`来测试再填入,想把`\n`这两个字符替换掉,实际上这里会替换掉**换行符**,你想在外面测试的话请用`re.sub("\\n","")`这样来测试 ~~注:**这个输入的内容都是转义字符串**也就是说比如你在外面写python代码`re.sub(r"\n","")`来测试再填入,想把`\n`这两个字符替换掉,实际上这里会替换掉**换行符**,你想在外面测试的话请用`re.sub("\\n","")`这样来测试~~
**21. 去除重复行_ABCDBCDCDD->ABCD** **21. 去除重复行_ABCDBCDCDD->ABCD**
@ -123,3 +123,11 @@ def POSTSOLVE(line):
# 请在这里编写自定义处理 # 请在这里编写自定义处理
return line return line
``` ```
**25. 字符串替换**
原`简单字符串替换` `转义字符串替换` `正则表达式替换`的整合,同时可设置`正则`和`转义`两个选项。
原正则表达式替换存在一定缺陷,输入的表达式是默认转义的,因此输入起来非常麻烦。
该处理添加时将默认使用简单替换,激活正则后将使用字符串字面量进行正则处理。仅激活转义后才使用转义字符串进行处理。
旧的处理词典在更新后首次运行将自动迁移到新的处理词典中。在之后的很长一段时间中,旧的处理不会被删除,但不会再进行维护。

View File

@ -2,7 +2,7 @@
#### **1. 专有名词翻译 直接替换** #### **1. 专有名词翻译 直接替换**
这种方法会在翻译之前,直接用译文将原文进行替换。 这种方法会在翻译之前,直接用译文将原文进行替换。支持使用`正则` `转义`进行更复杂的替换。
当游戏从VNDB加载元数据时会查询游戏中的人名信息作为预设的词典。不过译文由于VNDB的原因是英文可以自行进行修改译文成中文。 当游戏从VNDB加载元数据时会查询游戏中的人名信息作为预设的词典。不过译文由于VNDB的原因是英文可以自行进行修改译文成中文。

View File

@ -28,8 +28,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version)
include(generate_product_version) include(generate_product_version)
set(VERSION_MAJOR 5) set(VERSION_MAJOR 5)
set(VERSION_MINOR 22) set(VERSION_MINOR 23)
set(VERSION_PATCH 2) set(VERSION_PATCH 0)
add_library(pch pch.cpp) add_library(pch pch.cpp)
target_precompile_headers(pch PUBLIC pch.h) target_precompile_headers(pch PUBLIC pch.h)