Skip to content

Commit

Permalink
feat: Optimize ebook title customization and gap between original and…
Browse files Browse the repository at this point in the history
… translation columns.
  • Loading branch information
bookfere committed Mar 13, 2024
1 parent 7cc8191 commit cd10ef3
Show file tree
Hide file tree
Showing 17 changed files with 559 additions and 337 deletions.
80 changes: 51 additions & 29 deletions advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
Qt, QObject, QDialog, QGroupBox, QWidget, QVBoxLayout, QHBoxLayout,
QPlainTextEdit, QPushButton, QSplitter, QLabel, QThread, QLineEdit,
QGridLayout, QProgressBar, pyqtSignal, pyqtSlot, QPixmap, QEvent,
QStackedWidget, QSpacerItem, QTextCursor, QTabWidget)
QStackedWidget, QSpacerItem, QTextCursor, QTabWidget, QCheckBox)
except ImportError:
from PyQt5.Qt import (
Qt, QObject, QDialog, QGroupBox, QWidget, QVBoxLayout, QHBoxLayout,
QPlainTextEdit, QPushButton, QSplitter, QLabel, QThread, QLineEdit,
QGridLayout, QProgressBar, pyqtSignal, pyqtSlot, QPixmap, QEvent,
QStackedWidget, QSpacerItem, QTextCursor, QTabWidget)
QStackedWidget, QSpacerItem, QTextCursor, QTabWidget, QCheckBox)

load_translations()

Expand Down Expand Up @@ -236,6 +236,7 @@ def show_advanced(self):

class AdvancedTranslation(QDialog):
paragraph_sig = pyqtSignal(Paragraph)
ebook_title = pyqtSignal()
progress_bar = pyqtSignal()

preparation_thread = QThread()
Expand Down Expand Up @@ -526,60 +527,81 @@ def layout_control(self):
layout = QHBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)

cache_group = QGroupBox(_('Cache Status'))
cache_layout = QVBoxLayout(cache_group)
cache_status = QLabel(
_('Enabled') if self.cache.is_persistence() else _('Disabled'))
cache_status.setAlignment(Qt.AlignCenter)
cache_status.setStyleSheet(
'border-radius:2px;color:white;background-color:%s;'
% ('green' if self.cache.is_persistence() else 'grey'))
cache_layout.addWidget(cache_status)

engine_group = QGroupBox(_('Translation Engine'))
engine_layout = QVBoxLayout(engine_group)
engine_list = EngineList(self.current_engine.name)
engine_list.setFixedWidth(150)
engine_list.setMaximumWidth(150)
engine_layout.addWidget(engine_list)

source_group = QGroupBox(_('Source Language'))
source_layout = QVBoxLayout(source_group)
source_lang = SourceLang()
source_lang.setFixedWidth(150)
source_lang.setMaximumWidth(150)
source_layout.addWidget(source_lang)

target_group = QGroupBox(_('Target Language'))
target_layout = QVBoxLayout(target_group)
target_lang = TargetLang()
target_lang.setFixedWidth(150)
target_lang.setMaximumWidth(150)
target_layout.addWidget(target_lang)

cache_group = QGroupBox(_('Cache Status'))
cache_layout = QVBoxLayout(cache_group)
cache_status = QLabel(
_('Enabled') if self.cache.is_persistence() else _('Disabled'))
cache_status.setAlignment(Qt.AlignCenter)
cache_status.setStyleSheet(
'border-radius:2px;color:white;background-color:%s;'
% ('green' if self.cache.is_persistence() else 'grey'))
cache_layout.addWidget(cache_status)
title_group = QGroupBox(_('Custom Ebook Title'))
title_layout = QHBoxLayout(title_group)
custom_title = QCheckBox()
ebook_title = QLineEdit()
ebook_title.setText(self.ebook.title)
ebook_title.setToolTip(
_('By default, title metadata will be translated.'))
ebook_title.setDisabled(True)
# ebook_title.setCursorPosition(0)
title_layout.addWidget(custom_title)
title_layout.addWidget(ebook_title)

def enable_custom_title(checked):
ebook_title.setDisabled(not checked)
self.ebook.set_custom_title(
ebook_title.text() if checked else None)
if checked:
ebook_title.setFocus(Qt.MouseFocusReason)
custom_title.stateChanged.connect(enable_custom_title)

def change_ebook_title():
if ebook_title.text() == '':
ebook_title.undo()
self.ebook.set_custom_title(ebook_title.text())
ebook_title.editingFinished.connect(change_ebook_title)

# if self.config.get('to_library'):
# ebook_title.setDisabled(True)
# ebook_title.setToolTip(_(
# "The ebook's filename is automatically managed by Calibre "
# 'according to metadata since the output path is set to '
# 'Calibre Library.'))
# ebook_title.textChanged.connect(self.ebook.set_custom_title)

save_group = QGroupBox(_('Output Ebook'))
save_layout = QHBoxLayout(save_group)
save_ebook = QPushButton(_('Output'))
ebook_title = QLineEdit()
ebook_title.setText(self.ebook.title)
ebook_title.setCursorPosition(0)
output_format = OutputFormat()
output_format.setFixedWidth(150)
save_layout.addWidget(QLabel(_('Filename')))
save_layout.addWidget(ebook_title, 1)
save_layout.addWidget(QLabel(_('Format')))
# save_layout.addWidget(QLabel(_('Format')))
save_layout.addWidget(output_format)
save_layout.addWidget(save_ebook)

if self.config.get('to_library'):
ebook_title.setDisabled(True)
ebook_title.setToolTip(_(
"The ebook's filename is automatically managed by Calibre "
'according to metadata since the output path is set to '
'Calibre Library.'))
ebook_title.textChanged.connect(self.ebook.set_title)

layout.addWidget(cache_group)
layout.addWidget(engine_group)
layout.addWidget(source_group)
layout.addWidget(target_group)
layout.addWidget(title_group, 1)
layout.addWidget(save_group)

source_lang.currentTextChanged.connect(
Expand Down
5 changes: 3 additions & 2 deletions batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
try:
from qt.core import (
QDialog, QWidget, QPushButton, QHeaderView, QVBoxLayout, QTableWidget,
QTableWidgetItem)
QTableWidgetItem, Qt)
except ImportError:
from PyQt5.Qt import (
QDialog, QWidget, QPushButton, QHeaderView, QVBoxLayout, QTableWidget,
QTableWidgetItem)
QTableWidgetItem, Qt)

load_translations()

Expand Down Expand Up @@ -63,6 +63,7 @@ def layout_translate(self):

for row, ebook in enumerate(self.ebooks):
ebook_title = QTableWidgetItem(ebook.title)
ebook_title.setFlags(Qt.ItemIsEnabled)
ebook_title.setSizeHint(table.sizeHint())
table.setItem(row, 0, ebook_title)

Expand Down
5 changes: 5 additions & 0 deletions lib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
'cache_path': None,
'log_translation': True,
'translation_position': None,
'column_gap': {
'_type': 'percentage',
'percentage': 10,
'space_count': 6,
},
'original_color': None,
'translation_color': None,
'rule_mode': 'normal',
Expand Down
26 changes: 18 additions & 8 deletions lib/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,29 +237,39 @@ def translate_done(self, job):
if not ebook.is_extra_format() and ebook_metadata:
with open(output_path, 'r+b') as file:
metadata = get_metadata(file, ebook.output_format)
if ebook_metadata.get('language'):
ebook_title = metadata.title
if ebook.custom_title is not None:
ebook_title = ebook.custom_title
if ebook_metadata.get('lang_mark'):
ebook_title = '%s [%s]' % (ebook_title, ebook.target_lang)
metadata.title = ebook_title
if ebook_metadata.get('lang_code'):
metadata.language = ebook.lang_code
subjects = ebook_metadata.get('subjects')
metadata.tags += subjects + [
'Translate by Ebook Translator: '
metadata.tags += (subjects or []) + [
'Translated by Ebook Translator: '
'https://translator.bookfere.com']
# metadata.title = 'Custom Title'
# metadata.authors = ['bookfere.com']
# metadata.author_sort = 'bookfere.com'
# metadata.book_producer = 'Ebook Translator'
set_metadata(file, metadata, ebook.output_format)

if self.config.get('to_library'):
with open(output_path, 'rb') as file:
metadata = get_metadata(file, ebook.output_format)
if ebook.is_extra_format():
metadata.title = ebook.title
# with open(output_path, 'rb') as file:
# metadata = get_metadata(file, ebook.output_format)
# if ebook.is_extra_format():
# metadata.title = ebook.title
book_id = self.db.create_book_entry(metadata)
self.api.add_format(
book_id, ebook.output_format, output_path, run_hooks=False)
self.gui.library_view.model().books_added(1)
output_path = self.api.format_abspath(book_id, ebook.output_format)
# os.remove(temp_file)
else:
dirname = os.path.dirname(output_path)
filename = '%s.%s' % (metadata.title, ebook.output_format)
new_output_path = os.path.join(dirname, filename)
os.rename(output_path, new_output_path)

self.gui.status_bar.show_message(
job.description + ' ' + _('completed'), 5000)
Expand Down
8 changes: 5 additions & 3 deletions lib/ebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ def __init__(self, id, title, files, input_format, source_lang,
self.target_lang = None
self.lang_code = None

self.set_title(title)
self.title = title
self.custom_title = None

def set_title(self, title):
self.title = sanitize_file_name(title)
def set_custom_title(self, title):
self.custom_title = None if title is None else \
sanitize_file_name(title)
# self.title = re.sub(r'^\.+|[\/\\\\<>:"|?*\n\t]', '', title)

def set_input_format(self, format):
Expand Down
38 changes: 32 additions & 6 deletions lib/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(self, element, page_id=None):
self.placeholder = None
self.reserve_elements = []
self.original = []
self.column_gap = None

def _element_copy(self):
return copy.deepcopy(self.element)
Expand All @@ -39,6 +40,9 @@ def set_ignored(self, ignored):
def set_placeholder(self, placeholder):
self.placeholder = placeholder

def set_column_gap(self, values):
self.column_gap = values

def get_name(self):
return None

Expand Down Expand Up @@ -281,11 +285,22 @@ def _create_table(self, position, original, translation=None):
table = etree.XML(
'<table xmlns="{}" width="100%"></table>'.format(ns['x']))
tr = etree.SubElement(table, 'tr')
td_left = etree.SubElement(
tr, 'td', attrib={'width': '45%', 'valign': 'top'})
etree.SubElement(tr, 'td', attrib={'width': '10%'})
td_right = etree.SubElement(
tr, 'td', attrib={'width': '45%', 'valign': 'top'})
td_left = etree.SubElement(tr, 'td', attrib={'valign': 'top'})
td_middle = etree.SubElement(tr, 'td')
td_right = etree.SubElement(tr, 'td', attrib={'valign': 'top'})
if self.column_gap is None:
td_left.set('width', '45%')
td_middle.set('width', '10%')
td_right.set('width', '45%')
else:
unit, value = self.column_gap
if unit == 'percentage':
width = '%s%%' % round((100 - value) / 2)
td_left.set('width', width)
td_middle.set('width', '%s%%' % value)
td_right.set('width', width)
else:
td_middle.text = '\xa0' * value
if position == 'left':
if translation is not None:
td_left.append(translation)
Expand Down Expand Up @@ -414,6 +429,7 @@ def __init__(self, placeholder, separator, position, merge_length=0):
self.translation_lang = None
self.original_color = None
self.translation_color = None
self.column_gap = None

self.elements = {}
self.originals = []
Expand All @@ -432,6 +448,9 @@ def set_original_color(self, color):
def set_translation_color(self, color):
self.translation_color = color

def set_column_gap(self, values):
self.column_gap = values

def remove_unused_elements(self):
if self.position == 'only':
for element in self.elements.values():
Expand All @@ -441,6 +460,8 @@ def prepare_original(self, elements):
count = 0
for oid, element in enumerate(elements):
element.set_placeholder(self.placeholder)
if self.column_gap is not None:
element.set_column_gap(self.column_gap)
raw = element.get_raw()
content = element.get_content()
md5 = uid('%s%s' % (oid, content))
Expand Down Expand Up @@ -485,6 +506,8 @@ def prepare_original(self, elements):
if element.ignored:
continue
element.set_placeholder(self.placeholder)
if self.column_gap is not None:
element.set_column_gap(self.column_gap)
self.elements[count] = element
code = element.get_raw()
content = element.get_content()
Expand Down Expand Up @@ -549,7 +572,6 @@ def add_translations(self, paragraphs):
for eid, element in self.elements.copy().items():
if element.ignored:
continue
element.set_placeholder(self.placeholder)
original = element.get_content()
translation = translations.get(original)
if translation is None:
Expand Down Expand Up @@ -632,6 +654,10 @@ def get_element_handler(placeholder, separator):
if config.get('merge_enabled'):
handler = ElementHandlerMerge(
placeholder, separator, position, config.get('merge_length'))
column_gap = config.get('column_gap')
gap_type = column_gap.get('_type')
if gap_type is not None and gap_type in column_gap.keys():
handler.set_column_gap((gap_type, column_gap.get(gap_type)))
handler.set_original_color(config.get('original_color'))
handler.set_translation_color(config.get('translation_color'))
return handler
Loading

0 comments on commit cd10ef3

Please sign in to comment.