更新 ArticleReplaceBatch/txt2md2docx.py
更新打包软件
This commit is contained in:
parent
1d52220187
commit
b0a6e3e3bf
@ -7,6 +7,9 @@ from docx.shared import Inches, Pt
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
import PySimpleGUI as sg
|
||||
from replacestr import replace_text
|
||||
import configparser # 新增:导入配置文件处理模块
|
||||
|
||||
CONFIG_FILE_PATH = os.path.join(os.path.expanduser("~"), ".txt2md2docx.ini")
|
||||
|
||||
# 配置设置
|
||||
class Config:
|
||||
@ -15,9 +18,12 @@ class Config:
|
||||
self.txt_encoding = "utf-8"
|
||||
self.match_pattern = "exact" # exact: 完全匹配, prefix: 前缀匹配, contains: 包含
|
||||
self.output_location = "txt_folder" # txt_folder or custom
|
||||
# 最近使用的文件夹路径 - 新增
|
||||
self.last_txt_folder = ""
|
||||
self.last_images_root = ""
|
||||
self.last_output_root = ""
|
||||
# 文字处理
|
||||
# self.is_replace_str = 'true'
|
||||
self.reverse_text_order = False # 新增:转换文字顺序开关
|
||||
self.reverse_text_order = False # 转换文字顺序开关
|
||||
# 图片处理配置
|
||||
self.image_sort_by = "name" # name or time
|
||||
self.image_resize = "none" # none or width
|
||||
@ -27,14 +33,137 @@ class Config:
|
||||
# 文档格式配置
|
||||
self.line_spacing = 1.5
|
||||
self.title_levels = 6 # 支持的最大标题层级
|
||||
self.replace_punctuation = False # 是否替换标点符号
|
||||
self.add_disclaimer = False # 是否添加免责声明
|
||||
|
||||
# 新增:从配置文件加载配置
|
||||
def load_from_file(self, file_path):
|
||||
if not os.path.exists(file_path):
|
||||
return False
|
||||
|
||||
config_parser = configparser.ConfigParser()
|
||||
config_parser.read(file_path, encoding='utf-8')
|
||||
|
||||
# 加载文件处理配置
|
||||
if 'FileHandling' in config_parser:
|
||||
self.txt_encoding = config_parser.get('FileHandling', 'txt_encoding', fallback=self.txt_encoding)
|
||||
self.match_pattern = config_parser.get('FileHandling', 'match_pattern', fallback=self.match_pattern)
|
||||
self.output_location = config_parser.get('FileHandling', 'output_location',
|
||||
fallback=self.output_location)
|
||||
self.last_txt_folder = config_parser.get('FileHandling', 'last_txt_folder',
|
||||
fallback=self.last_txt_folder)
|
||||
self.last_images_root = config_parser.get('FileHandling', 'last_images_root',
|
||||
fallback=self.last_images_root)
|
||||
self.last_output_root = config_parser.get('FileHandling', 'last_output_root',
|
||||
fallback=self.last_output_root)
|
||||
|
||||
# 加载文字处理配置
|
||||
if 'TextProcessing' in config_parser:
|
||||
self.reverse_text_order = config_parser.getboolean('TextProcessing', 'reverse_text_order',
|
||||
fallback=self.reverse_text_order)
|
||||
self.replace_punctuation = config_parser.getboolean('TextProcessing', 'replace_punctuation',
|
||||
fallback=self.replace_punctuation)
|
||||
self.add_disclaimer = config_parser.getboolean('TextProcessing', 'add_disclaimer',
|
||||
fallback=self.add_disclaimer)
|
||||
|
||||
# 加载图片处理配置
|
||||
if 'ImageProcessing' in config_parser:
|
||||
self.image_sort_by = config_parser.get('ImageProcessing', 'image_sort_by', fallback=self.image_sort_by)
|
||||
self.image_resize = config_parser.get('ImageProcessing', 'image_resize', fallback=self.image_resize)
|
||||
self.image_width = config_parser.getfloat('ImageProcessing', 'image_width', fallback=self.image_width)
|
||||
self.image_alignment = config_parser.get('ImageProcessing', 'image_alignment',
|
||||
fallback=self.image_alignment)
|
||||
self.image_strategy = config_parser.get('ImageProcessing', 'image_strategy',
|
||||
fallback=self.image_strategy)
|
||||
|
||||
# 加载文档格式配置
|
||||
if 'DocumentFormat' in config_parser:
|
||||
self.line_spacing = config_parser.getfloat('DocumentFormat', 'line_spacing', fallback=self.line_spacing)
|
||||
self.title_levels = config_parser.getint('DocumentFormat', 'title_levels', fallback=self.title_levels)
|
||||
|
||||
return True
|
||||
|
||||
# 新增:保存配置到文件
|
||||
def save_to_file(self, file_path):
|
||||
config_parser = configparser.ConfigParser()
|
||||
|
||||
# 保存文件处理配置
|
||||
config_parser['FileHandling'] = {
|
||||
'txt_encoding': self.txt_encoding,
|
||||
'match_pattern': self.match_pattern,
|
||||
'output_location': self.output_location,
|
||||
'last_txt_folder': self.last_txt_folder,
|
||||
'last_images_root': self.last_images_root,
|
||||
'last_output_root': self.last_output_root
|
||||
}
|
||||
|
||||
# 保存文字处理配置
|
||||
config_parser['TextProcessing'] = {
|
||||
'reverse_text_order': str(self.reverse_text_order),
|
||||
'replace_punctuation': str(self.replace_punctuation),
|
||||
'add_disclaimer': str(self.add_disclaimer)
|
||||
}
|
||||
|
||||
# 保存图片处理配置
|
||||
config_parser['ImageProcessing'] = {
|
||||
'image_sort_by': self.image_sort_by,
|
||||
'image_resize': self.image_resize,
|
||||
'image_width': str(self.image_width),
|
||||
'image_alignment': self.image_alignment,
|
||||
'image_strategy': self.image_strategy
|
||||
}
|
||||
|
||||
# 保存文档格式配置
|
||||
config_parser['DocumentFormat'] = {
|
||||
'line_spacing': str(self.line_spacing),
|
||||
'title_levels': str(self.title_levels)
|
||||
}
|
||||
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
config_parser.write(f)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# 全局配置实例
|
||||
config = Config()
|
||||
|
||||
# 新增:尝试加载配置文件
|
||||
config.load_from_file(CONFIG_FILE_PATH)
|
||||
|
||||
|
||||
# 添加文字处理工具类(可放在FileHandler类之后)
|
||||
class TextProcessor:
|
||||
|
||||
@staticmethod
|
||||
def replace_periods(text):
|
||||
# 去除文本首尾的空白字符
|
||||
text = text.strip()
|
||||
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
# 检查最后一个字符是否为句号
|
||||
last_char = text[-1]
|
||||
has_ending_period = (last_char == '。')
|
||||
|
||||
# 如果最后一个字符是句号,先去掉它再处理
|
||||
if has_ending_period:
|
||||
content = text[:-1]
|
||||
else:
|
||||
content = text
|
||||
|
||||
# 将所有句号替换为逗号
|
||||
content = content.replace('。', ',')
|
||||
|
||||
# 如果原文本最后有句号,在处理后的内容末尾加上句号
|
||||
if has_ending_period:
|
||||
result = content + '。'
|
||||
else:
|
||||
result = content
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def reverse_text_order(content):
|
||||
"""反转文本顺序(按字符级反转)"""
|
||||
@ -389,6 +518,7 @@ class ImageProcessor:
|
||||
else:
|
||||
return WD_ALIGN_PARAGRAPH.CENTER
|
||||
|
||||
DISCLAIMER_TEXT = """[免责声明]文章的时间、过程、图片均来自于网络,文章旨在传播正能量,均无低俗等不良引导,请观众勿对号入座,并上升到人身攻击等方面。观众理性看待本事件,切勿留下主观臆断的恶意评论,互联网不是法外之地。本文如若真实性存在争议、事件版权或图片侵权问题,请及时联系作者,我们将予以删除。"""
|
||||
|
||||
# DOCX生成模块
|
||||
class DocxGenerator:
|
||||
@ -460,6 +590,16 @@ class DocxGenerator:
|
||||
for para in paragraphs[1:]:
|
||||
DocxGenerator.add_formatted_paragraph(doc, para)
|
||||
|
||||
# 新增:在文档末尾添加免责声明
|
||||
if config.add_disclaimer:
|
||||
# 添加分隔线
|
||||
doc.add_paragraph("---")
|
||||
# 添加免责声明段落
|
||||
para = doc.add_paragraph()
|
||||
run = para.add_run(DISCLAIMER_TEXT)
|
||||
run.font.size = Pt(10) # 可设置较小字体
|
||||
para.paragraph_format.line_spacing = 1.0 # 紧凑行距
|
||||
|
||||
try:
|
||||
doc.save(output_path)
|
||||
if progress_callback:
|
||||
@ -475,6 +615,10 @@ class DocxGenerator:
|
||||
para_type = paragraph_data['type']
|
||||
formatting = paragraph_data['formatting']
|
||||
|
||||
# 新增:处理标点符号替换
|
||||
if config.replace_punctuation:
|
||||
content = TextProcessor.replace_periods(content)
|
||||
|
||||
if para_type == 'unordered_list':
|
||||
para = doc.add_paragraph(style='List Bullet')
|
||||
text = content[2:].strip()
|
||||
@ -625,7 +769,13 @@ def show_config_window():
|
||||
sg.Radio('包含匹配', 'match',
|
||||
default=config.match_pattern == "contains", key='match_contains')],
|
||||
[sg.HSeparator()],
|
||||
[sg.Checkbox('转换文字顺序', key='-REVERSE_TEXT-', default=False)],
|
||||
[sg.Checkbox('转换文字顺序', key='-REVERSE_TEXT-', default=config.reverse_text_order)],
|
||||
[sg.HSeparator()],
|
||||
[sg.Checkbox('替换标点符号(句号转逗号,保留结尾句号)',
|
||||
key='-REPLACE_PUNCTUATION-',
|
||||
default=config.replace_punctuation)],
|
||||
[sg.HSeparator()],
|
||||
[sg.Checkbox('添加免责声明', key='-ADD_DISCLAIMER-', default=config.add_disclaimer)],
|
||||
[sg.HSeparator()],
|
||||
[sg.Radio('输出到TXT文件所在文件夹', 'output_loc',
|
||||
default=config.output_location == "txt_folder", key='output_txt_folder'),
|
||||
@ -673,10 +823,11 @@ def show_config_window():
|
||||
|
||||
# 保存输出位置设置
|
||||
config.output_location = "txt_folder" if values['output_txt_folder'] else "custom"
|
||||
# config.is_replace_str = "true" if values['is_replace_str'] else "false"
|
||||
config.image_sort_by = "name" if values['sort_name'] else "time"
|
||||
config.image_resize = "none" if values['resize_none'] else "width"
|
||||
config.reverse_text_order = values['-REVERSE_TEXT-']
|
||||
config.replace_punctuation = values['-REPLACE_PUNCTUATION-']
|
||||
config.add_disclaimer = values['-ADD_DISCLAIMER-']
|
||||
|
||||
try:
|
||||
config.image_width = float(values['image_width'])
|
||||
@ -697,6 +848,9 @@ def show_config_window():
|
||||
else:
|
||||
config.image_strategy = "repeat_last"
|
||||
|
||||
# 新增:保存配置到文件
|
||||
config.save_to_file(CONFIG_FILE_PATH)
|
||||
|
||||
break
|
||||
|
||||
window.close()
|
||||
@ -909,6 +1063,12 @@ def main_window():
|
||||
event, values = window.read()
|
||||
|
||||
if event in (sg.WIN_CLOSED, '退出'):
|
||||
# 只有在窗口未关闭时,才尝试读取 values
|
||||
if values is not None:
|
||||
config.last_txt_folder = values.get('txt_folder', '')
|
||||
config.last_images_root = values.get('images_root', '')
|
||||
config.last_output_root = values.get('output_root', '')
|
||||
config.save_to_file(CONFIG_FILE_PATH)
|
||||
break
|
||||
|
||||
if event == '转换设置':
|
||||
@ -936,6 +1096,13 @@ def main_window():
|
||||
sg.popup_error('请选择图片根文件夹')
|
||||
continue
|
||||
|
||||
# 保存当前选择的文件夹路径 - 新增
|
||||
config.last_txt_folder = txt_folder
|
||||
config.last_images_root = images_root
|
||||
if values['output_root']:
|
||||
config.last_output_root = values['output_root']
|
||||
config.save_to_file(CONFIG_FILE_PATH)
|
||||
|
||||
try:
|
||||
status_text.update('正在扫描TXT文件...')
|
||||
window.refresh()
|
||||
@ -959,6 +1126,8 @@ def main_window():
|
||||
status_text.update(f'扫描完成: 找到 {len(matched_pairs)} 个TXT文件')
|
||||
|
||||
# 启用相关按钮
|
||||
window['-PREVIEW_TABLE-'].update(values=table_data)
|
||||
|
||||
window['编辑匹配'].update(disabled=False)
|
||||
window['开始批量转换'].update(disabled=False)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user