Allow switching between old and new rename templates

Show a message dialog explaining that there is a new template format
Add a dynamic label to show the effect of a rename
Add tests for FileRenamer
Remove the filename parameter from the determine_name function
This commit is contained in:
Timmy Welch 2022-04-18 18:59:17 -07:00
parent 028b728d82
commit 6cccf22d54
10 changed files with 384 additions and 94 deletions

View File

@ -259,6 +259,15 @@ class GenericMetadata:
if not found:
self.credits.append(credit)
def get_primary_credit(self, role):
primary = ""
for credit in self.credits:
if (primary == "" and credit["role"].lower() == role.lower()) or (
credit["role"].lower() == role.lower() and credit["primary"]
):
primary = credit["person"]
return primary
def __str__(self):
vals = []
if self.is_empty:

View File

@ -27,7 +27,7 @@ from comicapi.comicarchive import ComicArchive, MetaDataStyle
from comicapi.genericmetadata import GenericMetadata
from comictaggerlib.cbltransformer import CBLTransformer
from comictaggerlib.comicvinetalker import ComicVineTalker, ComicVineTalkerException
from comictaggerlib.filerenamer import FileRenamer
from comictaggerlib.filerenamer import FileRenamer, FileRenamer2
from comictaggerlib.issueidentifier import IssueIdentifier
from comictaggerlib.resulttypes import MultipleMatch, OnlineMatchResults
from comictaggerlib.settings import ComicTaggerSettings
@ -155,6 +155,13 @@ def cli_mode(opts, settings):
logger.error("You must specify at least one filename. Use the -h option for more info")
return
if not settings.hide_rename_message:
print(
"There is a new rename template format available. "
"Please use the settings window to enable and test if you use this feature.\n\n"
"The old rename template format will be removed in the next release, "
"please reference the template help button in the settings or https://github.com/comictagger/comictagger/wiki/UserGuide#rename",
)
match_results = OnlineMatchResults()
for f in opts.file_list:
@ -445,20 +452,23 @@ def process_file_cli(filename, opts, settings, match_results: OnlineMatchResults
elif ca.is_rar():
new_ext = ".cbr"
renamer = FileRenamer(md)
if settings.rename_new_renamer:
renamer = FileRenamer2(md)
else:
renamer = FileRenamer(md)
renamer.set_template(settings.rename_template)
renamer.set_issue_zero_padding(settings.rename_issue_number_padding)
renamer.set_smart_cleanup(settings.rename_use_smart_string_cleanup)
renamer.move = settings.rename_move_dir
try:
new_name = renamer.determine_name(filename, ext=new_ext)
new_name = renamer.determine_name(ext=new_ext)
except Exception as e:
print(
msg_hdr + "Invalid format string!\nYour rename template is invalid!\n\n"
"{}\n\nPlease consult the template help in the settings "
"and the documentation on the format at "
"https://docs.python.org/3/library/string.html#format-string-syntax",
"https://docs.python.org/3/library/string.html#format-string-syntax".format(e),
file=sys.stderr,
)
return

View File

@ -14,9 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import calendar
import datetime
import logging
import os
import re
import string
from pathvalidate import sanitize_filepath
@ -27,6 +29,122 @@ from comicapi.issuestring import IssueString
logger = logging.getLogger(__name__)
class FileRenamer:
def __init__(self, metadata):
self.template = "%series% v%volume% #%issue% (of %issuecount%) (%year%)"
self.smart_cleanup = True
self.issue_zero_padding = 3
self.metadata = metadata
def set_metadata(self, metadata: GenericMetadata):
self.metadata = metadata
def set_issue_zero_padding(self, count):
self.issue_zero_padding = count
def set_smart_cleanup(self, on):
self.smart_cleanup = on
def set_template(self, template: str):
self.template = template
def replace_token(self, text, value, token):
# helper func
def is_token(word):
return word[0] == "%" and word[-1:] == "%"
if value is not None:
return text.replace(token, str(value))
if self.smart_cleanup:
# smart cleanup means we want to remove anything appended to token if it's empty (e.g "#%issue%" or "v%volume%")
# (TODO: This could fail if there is more than one token appended together, I guess)
text_list = text.split()
# special case for issuecount, remove preceding non-token word,
# as in "...(of %issuecount%)..."
if token == "%issuecount%":
for idx, word in enumerate(text_list):
if token in word and not is_token(text_list[idx - 1]):
text_list[idx - 1] = ""
text_list = [x for x in text_list if token not in x]
return " ".join(text_list)
return text.replace(token, "")
def determine_name(self, ext):
md = self.metadata
new_name = self.template
new_name = self.replace_token(new_name, md.series, "%series%")
new_name = self.replace_token(new_name, md.volume, "%volume%")
if md.issue is not None:
issue_str = IssueString(md.issue).as_string(pad=self.issue_zero_padding)
else:
issue_str = None
new_name = self.replace_token(new_name, issue_str, "%issue%")
new_name = self.replace_token(new_name, md.issue_count, "%issuecount%")
new_name = self.replace_token(new_name, md.year, "%year%")
new_name = self.replace_token(new_name, md.publisher, "%publisher%")
new_name = self.replace_token(new_name, md.title, "%title%")
new_name = self.replace_token(new_name, md.month, "%month%")
month_name = None
if md.month is not None:
if (isinstance(md.month, str) and md.month.isdigit()) or isinstance(md.month, int):
if int(md.month) in range(1, 13):
dt = datetime.datetime(1970, int(md.month), 1, 0, 0)
month_name = dt.strftime("%B")
new_name = self.replace_token(new_name, month_name, "%month_name%")
new_name = self.replace_token(new_name, md.genre, "%genre%")
new_name = self.replace_token(new_name, md.language, "%language_code%")
new_name = self.replace_token(new_name, md.critical_rating, "%criticalrating%")
new_name = self.replace_token(new_name, md.alternate_series, "%alternateseries%")
new_name = self.replace_token(new_name, md.alternate_number, "%alternatenumber%")
new_name = self.replace_token(new_name, md.alternate_count, "%alternatecount%")
new_name = self.replace_token(new_name, md.imprint, "%imprint%")
new_name = self.replace_token(new_name, md.format, "%format%")
new_name = self.replace_token(new_name, md.maturity_rating, "%maturityrating%")
new_name = self.replace_token(new_name, md.story_arc, "%storyarc%")
new_name = self.replace_token(new_name, md.series_group, "%seriesgroup%")
new_name = self.replace_token(new_name, md.scan_info, "%scaninfo%")
if self.smart_cleanup:
# remove empty braces,brackets, parentheses
new_name = re.sub(r"\(\s*[-:]*\s*\)", "", new_name)
new_name = re.sub(r"\[\s*[-:]*\s*]", "", new_name)
new_name = re.sub(r"{\s*[-:]*\s*}", "", new_name)
# remove duplicate spaces
new_name = " ".join(new_name.split())
# remove remove duplicate -, _,
new_name = re.sub(r"[-_]{2,}\s+", "-- ", new_name)
new_name = re.sub(r"(\s--)+", " --", new_name)
new_name = re.sub(r"(\s-)+", " -", new_name)
# remove dash or double dash at end of line
new_name = re.sub(r"[-]{1,2}\s*$", "", new_name)
# remove duplicate spaces (again!)
new_name = " ".join(new_name.split())
new_name += ext
# some tweaks to keep various filesystems happy
new_name = new_name.replace("/", "-")
new_name = new_name.replace(" :", " -")
new_name = new_name.replace(": ", " - ")
new_name = new_name.replace(":", "-")
new_name = new_name.replace("?", "")
return new_name
class MetadataFormatter(string.Formatter):
def __init__(self, smart_cleanup=False):
super().__init__()
@ -53,6 +171,7 @@ class MetadataFormatter(string.Formatter):
lstrip = False
# if there's a field, output it
if field_name is not None:
field_name = field_name.lower()
# this is some markup, find the object and do
# the formatting
@ -96,9 +215,9 @@ class MetadataFormatter(string.Formatter):
return "".join(result), auto_arg_index
class FileRenamer:
class FileRenamer2:
def __init__(self, metadata):
self.template = "{publisher}/{series}/{series} v{volume} #{issue} (of {issueCount}) ({year})"
self.template = "{publisher}/{series}/{series} v{volume} #{issue} (of {issue_count}) ({year})"
self.smart_cleanup = True
self.issue_zero_padding = 3
self.metadata = metadata
@ -116,7 +235,7 @@ class FileRenamer:
def set_template(self, template: str):
self.template = template
def determine_name(self, filename, ext=None):
def determine_name(self, ext):
class Default(dict):
def __missing__(self, key):
return "{" + key + "}"
@ -132,19 +251,28 @@ class FileRenamer:
new_name = ""
fmt = MetadataFormatter(self.smart_cleanup)
md_dict = vars(md)
for role in ["writer", "penciller", "inker", "colorist", "letterer", "cover artist", "editor"]:
md_dict[role] = md.get_primary_credit(role)
if (isinstance(md.month, int) or isinstance(md.month, str) and md.month.isdigit()) and 0 < int(md.month) < 13:
md_dict["month_name"] = calendar.month_name[int(md.month)]
md_dict["month_abbr"] = calendar.month_abbr[int(md.month)]
else:
print(md.month)
md_dict["month_name"] = ""
md_dict["month_abbr"] = ""
for Component in path_components:
new_name = os.path.join(
new_name, fmt.vformat(Component, args=[], kwargs=Default(vars(md))).replace("/", "-")
new_name, fmt.vformat(Component, args=[], kwargs=Default(md_dict)).replace("/", "-")
)
if ext is None or ext == "":
ext = os.path.splitext(filename)[1]
new_name += ext
# some tweaks to keep various filesystems happy
new_name = new_name.replace(": ", " - ")
new_name = new_name.replace(":", "-")
# # some tweaks to keep various filesystems happy
# new_name = new_name.replace(": ", " - ")
# new_name = new_name.replace(":", "-")
# remove padding
md.issue = IssueString(md.issue).as_string()

View File

@ -23,7 +23,7 @@ from PyQt5 import QtCore, QtWidgets, uic
import comicapi.comicarchive
from comicapi import utils
from comicapi.comicarchive import MetaDataStyle
from comictaggerlib.filerenamer import FileRenamer
from comictaggerlib.filerenamer import FileRenamer, FileRenamer2
from comictaggerlib.settings import ComicTaggerSettings
from comictaggerlib.settingswindow import SettingsWindow
from comictaggerlib.ui.qtutils import center_window_on_parent
@ -52,7 +52,11 @@ class RenameWindow(QtWidgets.QDialog):
self.rename_list = []
self.btnSettings.clicked.connect(self.modify_settings)
self.renamer = FileRenamer(None)
if self.settings.rename_new_renamer:
self.renamer = FileRenamer2(None)
else:
self.renamer = FileRenamer(None)
self.config_renamer()
self.do_preview()
@ -85,7 +89,7 @@ class RenameWindow(QtWidgets.QDialog):
self.renamer.move = self.settings.rename_move_dir
try:
new_name = self.renamer.determine_name(ca.path, ext=new_ext)
new_name = self.renamer.determine_name(new_ext)
except Exception as e:
QtWidgets.QMessageBox.critical(
self,

View File

@ -83,6 +83,7 @@ class ComicTaggerSettings:
self.show_disclaimer = True
self.dont_notify_about_this_version = ""
self.ask_about_usage_stats = True
self.hide_rename_message = False
# filename parsing settings
self.parse_scan_info = True
@ -110,12 +111,13 @@ class ComicTaggerSettings:
self.apply_cbl_transform_on_bulk_operation = False
# Rename settings
self.rename_template = "{publisher}/{series}/{series} #{issue} - {title} ({year})"
self.rename_template = "%series% #%issue% (%year%)"
self.rename_issue_number_padding = 3
self.rename_use_smart_string_cleanup = True
self.rename_extension_based_on_archive = True
self.rename_dir = ""
self.rename_move_dir = False
self.rename_new_renamer = False
# Auto-tag stickies
self.save_on_low_confidence = False
@ -158,6 +160,7 @@ class ComicTaggerSettings:
self.show_disclaimer = True
self.dont_notify_about_this_version = ""
self.ask_about_usage_stats = True
self.hide_rename_message = False
# filename parsing settings
self.parse_scan_info = True
@ -185,12 +188,13 @@ class ComicTaggerSettings:
self.apply_cbl_transform_on_bulk_operation = False
# Rename settings
self.rename_template = "{publisher}/{series}/{series} #{issue} - {title} ({year})"
self.rename_template = "%series% #%issue% (%year%)"
self.rename_issue_number_padding = 3
self.rename_use_smart_string_cleanup = True
self.rename_extension_based_on_archive = True
self.rename_dir = ""
self.rename_move_dir = False
self.rename_new_renamer = False
# Auto-tag stickies
self.save_on_low_confidence = False
@ -293,6 +297,8 @@ class ComicTaggerSettings:
self.dont_notify_about_this_version = self.config.get("dialogflags", "dont_notify_about_this_version")
if self.config.has_option("dialogflags", "ask_about_usage_stats"):
self.ask_about_usage_stats = self.config.getboolean("dialogflags", "ask_about_usage_stats")
if self.config.has_option("dialogflags", "hide_rename_message"):
self.hide_rename_message = self.config.getboolean("dialogflags", "hide_rename_message")
if self.config.has_option("comicvine", "use_series_start_as_volume"):
self.use_series_start_as_volume = self.config.getboolean("comicvine", "use_series_start_as_volume")
@ -352,6 +358,8 @@ class ComicTaggerSettings:
self.rename_dir = self.config.get("rename", "rename_dir")
if self.config.has_option("rename", "rename_move_dir"):
self.rename_move_dir = self.config.getboolean("rename", "rename_move_dir")
if self.config.has_option("rename", "rename_new_renamer"):
self.rename_new_renamer = self.config.getboolean("rename", "rename_new_renamer")
if self.config.has_option("autotag", "save_on_low_confidence"):
self.save_on_low_confidence = self.config.getboolean("autotag", "save_on_low_confidence")
@ -408,6 +416,7 @@ class ComicTaggerSettings:
self.config.set("dialogflags", "show_disclaimer", self.show_disclaimer)
self.config.set("dialogflags", "dont_notify_about_this_version", self.dont_notify_about_this_version)
self.config.set("dialogflags", "ask_about_usage_stats", self.ask_about_usage_stats)
self.config.set("dialogflags", "hide_rename_message", self.hide_rename_message)
if not self.config.has_section("filenameparser"):
self.config.add_section("filenameparser")
@ -451,6 +460,7 @@ class ComicTaggerSettings:
self.config.set("rename", "rename_extension_based_on_archive", self.rename_extension_based_on_archive)
self.config.set("rename", "rename_dir", self.rename_dir)
self.config.set("rename", "rename_move_dir", self.rename_move_dir)
self.config.set("rename", "rename_new_renamer", self.rename_new_renamer)
if not self.config.has_section("autotag"):
self.config.add_section("autotag")

View File

@ -17,6 +17,7 @@
import logging
import os
import platform
import re
from PyQt5 import QtCore, QtGui, QtWidgets, uic
@ -24,7 +25,7 @@ from comicapi import utils
from comicapi.genericmetadata import md_test
from comictaggerlib.comicvinecacher import ComicVineCacher
from comictaggerlib.comicvinetalker import ComicVineTalker
from comictaggerlib.filerenamer import FileRenamer
from comictaggerlib.filerenamer import FileRenamer, FileRenamer2
from comictaggerlib.imagefetcher import ImageFetcher
from comictaggerlib.settings import ComicTaggerSettings
@ -56,6 +57,82 @@ macRarHelp = """
</p>Once homebrew is installed, run: <b>brew install caskroom/cask/rar</b></body></html>
"""
old_template_tooltip = """
<html><head/><body><p>The template for the new filename. Accepts the following variables:</p><p>%series%<br/>%issue%<br/>%volume%<br/>%issuecount%<br/>%year%<br/>%month%<br/>%month_name%<br/>%publisher%<br/>%title%<br/>
%genre%<br/>
%language_code%<br/>
%criticalrating%<br/>
%alternateseries%<br/>
%alternatenumber%<br/>
%alternatecount%<br/>
%imprint%<br/>
%format%<br/>
%maturityrating%<br/>
%storyarc%<br/>
%seriesgroup%<br/>
%scaninfo%
</p><p>Examples:</p><p><span style=&quot; font-style:italic;&quot;>%series% %issue% (%year%)</span><br/><span style=&quot; font-style:italic;&quot;>%series% #%issue% - %title%</span></p></body></html>
"""
new_template_tooltip = """
<pre>The template for the new filename. Uses python format strings https://docs.python.org/3/library/string.html#format-string-syntax
Accepts the following variables:
{isEmpty} (boolean)
{tagOrigin} (string)
{series} (string)
{issue} (string)
{title} (string)
{publisher} (string)
{month} (integer)
{year} (integer)
{day} (integer)
{issueCount} (integer)
{volume} (integer)
{genre} (string)
{language} (string)
{comments} (string)
{volumeCount} (integer)
{criticalRating} (string)
{country} (string)
{alternateSeries} (string)
{alternateNumber} (string)
{alternateCount} (integer)
{imprint} (string)
{notes} (string)
{webLink} (string)
{format} (string)
{manga} (string)
{blackAndWhite} (boolean)
{pageCount} (integer)
{maturityRating} (string)
{storyArc} (string)
{seriesGroup} (string)
{scanInfo} (string)
{characters} (string)
{teams} (string)
{locations} (string)
{credits} (list of dict({&apos;role&apos;: &apos;str&apos;, &apos;person&apos;: &apos;str&apos;, &apos;primary&apos;: boolean}))
{tags} (list of str)
{pages} (list of dict({&apos;Image&apos;: &apos;str(int)&apos;, &apos;Type&apos;: &apos;str&apos;}))
CoMet-only items:
{price} (float)
{isVersionOf} (string)
{rights} (string)
{identifier} (string)
{lastMark} (string)
{coverImage} (string)
Examples:
{series} {issue} ({year})
Spider-Geddon 1 (2018)
{series} #{issue} - {title}
Spider-Geddon #1 - New Players; Check In
</pre>
"""
class SettingsWindow(QtWidgets.QDialog):
def __init__(self, parent, settings):
@ -107,23 +184,55 @@ class SettingsWindow(QtWidgets.QDialog):
validator = QtGui.QIntValidator(0, 99, self)
self.leNameLengthDeltaThresh.setValidator(validator)
self.settings_to_form()
new_rename = self.settings.rename_new_renamer
self.cbxNewRenamer.setChecked(new_rename)
self.cbxMoveFiles.setEnabled(new_rename)
self.leDirectory.setEnabled(new_rename)
self.lblDirectory.setEnabled(new_rename)
if self.settings.rename_new_renamer:
self.leRenameTemplate.setToolTip(new_template_tooltip)
self.settings_to_form()
self.rename_error = None
self.rename_test(self.leRenameTemplate.text())
self.cbxNewRenamer.clicked.connect(self.new_rename_toggle)
self.btnBrowseRar.clicked.connect(self.select_rar)
self.btnClearCache.clicked.connect(self.clear_cache)
self.btnResetSettings.clicked.connect(self.reset_settings)
self.btnTestKey.clicked.connect(self.test_api_key)
self.btnTemplateHelp.clicked.connect(self.show_template_help)
self.leRenameTemplate.textEdited.connect(self.rename_test)
def config_renamer(self):
def new_rename_toggle(self):
new_rename = self.cbxNewRenamer.isChecked()
if new_rename:
self.leRenameTemplate.setText(re.sub(r"%(\w+)%", r"{\1}", self.leRenameTemplate.text()))
self.leRenameTemplate.setToolTip(new_template_tooltip)
else:
self.leRenameTemplate.setText(re.sub(r"{(\w+)}", r"%\1%", self.leRenameTemplate.text()))
self.leRenameTemplate.setToolTip(old_template_tooltip)
self.cbxMoveFiles.setEnabled(new_rename)
self.leDirectory.setEnabled(new_rename)
self.lblDirectory.setEnabled(new_rename)
self.rename_test(self.leRenameTemplate.text())
self.renamer = FileRenamer(md_test)
self.renamer.set_template(str(self.leRenameTemplate.text()))
self.renamer.set_issue_zero_padding(self.settings.rename_issue_number_padding)
self.renamer.set_smart_cleanup(self.settings.rename_use_smart_string_cleanup)
def rename_test(self, template):
fr = FileRenamer(md_test)
if self.cbxNewRenamer.isChecked():
fr = FileRenamer2(md_test)
fr.set_template(template)
fr.set_issue_zero_padding(int(self.leIssueNumPadding.text()))
fr.set_smart_cleanup(self.cbxSmartCleanup.isChecked())
fr.move = self.cbxMoveFiles.isChecked()
try:
self.lblRenameTest.setText(fr.determine_name(".cbz"))
self.rename_error = None
except Exception as e:
self.rename_error = e
self.lblRenameTest.setText(str(e))
def settings_to_form(self):
# Copy values from settings to form
self.leRarExePath.setText(self.settings.rar_exe_path)
self.leNameLengthDeltaThresh.setText(str(self.settings.id_length_delta_thresh))
@ -181,12 +290,8 @@ class SettingsWindow(QtWidgets.QDialog):
self.leDirectory.setText(self.settings.rename_dir)
def accept(self):
self.config_renamer()
try:
new_name = self.renamer.determine_name("test.cbz")
except Exception as e:
self.rename_test(self.leRenameTemplate.text())
if self.rename_error is not None:
QtWidgets.QMessageBox.critical(
self,
"Invalid format string!",
@ -195,7 +300,7 @@ class SettingsWindow(QtWidgets.QDialog):
"Please consult the template help in the "
"settings and the documentation on the format at "
"<a href='https://docs.python.org/3/library/string.html#format-string-syntax'>"
"https://docs.python.org/3/library/string.html#format-string-syntax</a>".format(e),
"https://docs.python.org/3/library/string.html#format-string-syntax</a>".format(self.rename_error),
)
return
@ -246,6 +351,8 @@ class SettingsWindow(QtWidgets.QDialog):
self.settings.rename_move_dir = self.cbxMoveFiles.isChecked()
self.settings.rename_dir = self.leDirectory.text()
self.settings.rename_new_renamer = self.cbxNewRenamer.isChecked()
self.settings.save()
QtWidgets.QDialog.accept(self)
@ -298,6 +405,8 @@ class SettingsWindow(QtWidgets.QDialog):
def show_template_help(self):
template_help_win = TemplateHelpWindow(self)
template_help_win.setModal(False)
if not self.cbxNewRenamer.isChecked():
template_help_win.textEdit.setHtml(old_template_tooltip)
template_help_win.show()

View File

@ -246,6 +246,15 @@ Have fun!
""",
)
self.settings.show_disclaimer = not checked
if not self.settings.hide_rename_message:
self.settings.hide_rename_message = OptionalMessageDialog.msg(
self,
"New rename template!",
"There is a new rename template format available. "
"Please use the settings window to enable and test if you use this feature.<br><br>"
"The old rename template format will be removed in the next release, "
"please reference the template help button in the settings or <a href='https://github.com/comictagger/comictagger/wiki/UserGuide#rename'>https://github.com/comictagger/comictagger/wiki/UserGuide#rename</a>",
)
if self.settings.check_for_new_version:
# self.checkLatestVersionOnline()

View File

@ -28,7 +28,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -556,62 +556,20 @@
<item row="1" column="1">
<widget class="QLineEdit" name="leRenameTemplate">
<property name="toolTip">
<string>&lt;pre&gt;The template for the new filename. Uses python format strings https://docs.python.org/3/library/string.html#format-string-syntax
Accepts the following variables:
{isEmpty} (boolean)
{tagOrigin} (string)
{series} (string)
{issue} (string)
{title} (string)
{publisher} (string)
{month} (integer)
{year} (integer)
{day} (integer)
{issueCount} (integer)
{volume} (integer)
{genre} (string)
{language} (string)
{comments} (string)
{volumeCount} (integer)
{criticalRating} (string)
{country} (string)
{alternateSeries} (string)
{alternateNumber} (string)
{alternateCount} (integer)
{imprint} (string)
{notes} (string)
{webLink} (string)
{format} (string)
{manga} (string)
{blackAndWhite} (boolean)
{pageCount} (integer)
{maturityRating} (string)
{storyArc} (string)
{seriesGroup} (string)
{scanInfo} (string)
{characters} (string)
{teams} (string)
{locations} (string)
{credits} (list of dict({&amp;apos;role&amp;apos;: &amp;apos;str&amp;apos;, &amp;apos;person&amp;apos;: &amp;apos;str&amp;apos;, &amp;apos;primary&amp;apos;: boolean}))
{tags} (list of str)
{pages} (list of dict({&amp;apos;Image&amp;apos;: &amp;apos;str(int)&amp;apos;, &amp;apos;Type&amp;apos;: &amp;apos;str&amp;apos;}))
CoMet-only items:
{price} (float)
{isVersionOf} (string)
{rights} (string)
{identifier} (string)
{lastMark} (string)
{coverImage} (string)
Examples:
{series} {issue} ({year})
Spider-Geddon 1 (2018)
{series} #{issue} - {title}
Spider-Geddon #1 - New Players; Check In
&lt;/pre&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The template for the new filename. Accepts the following variables:&lt;/p&gt;&lt;p&gt;%series%&lt;br/&gt;%issue%&lt;br/&gt;%volume%&lt;br/&gt;%issuecount%&lt;br/&gt;%year%&lt;br/&gt;%month%&lt;br/&gt;%month_name%&lt;br/&gt;%publisher%&lt;br/&gt;%title%&lt;br/&gt;
%genre%&lt;br/&gt;
%language_code%&lt;br/&gt;
%criticalrating%&lt;br/&gt;
%alternateseries%&lt;br/&gt;
%alternatenumber%&lt;br/&gt;
%alternatecount%&lt;br/&gt;
%imprint%&lt;br/&gt;
%format%&lt;br/&gt;
%maturityrating%&lt;br/&gt;
%storyarc%&lt;br/&gt;
%seriesgroup%&lt;br/&gt;
%scaninfo%
&lt;/p&gt;&lt;p&gt;Examples:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;%series% %issue% (%year%)&lt;/span&gt;&lt;br/&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;%series% #%issue% - %title%&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@ -665,7 +623,7 @@ Spider-Geddon #1 - New Players; Check In
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QCheckBox" name="cbxMoveFiles">
<property name="toolTip">
<string>If checked moves files to specified folder</string>
@ -675,16 +633,36 @@ Spider-Geddon #1 - New Players; Check In
</property>
</widget>
</item>
<item row="7" column="0">
<item row="8" column="0">
<widget class="QLabel" name="lblDirectory">
<property name="text">
<string>Destination Directory:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="QLineEdit" name="leDirectory"/>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="cbxNewRenamer">
<property name="text">
<string>Enable the new renamer</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblRenameTest">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -419,3 +419,15 @@ fnames = [
marks=pytest.mark.xfail,
),
]
rnames = [
(
"{series} #{issue} - {title} ({year})",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
),
pytest.param(
"{series} #{issue} - {title} - {WriteR}, {EDITOR} ({year})",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game - Dara Naraghi, Ted Adams (2007).cbz",
marks=pytest.mark.xfail,
),
]

21
tests/test_rename.py Normal file
View File

@ -0,0 +1,21 @@
import re
import pytest
from filenames import rnames
from comicapi.genericmetadata import md_test
from comictaggerlib.filerenamer import FileRenamer, FileRenamer2
@pytest.mark.parametrize("template,result", rnames)
def test_rename_old(template, result):
fr = FileRenamer(md_test)
fr.set_template(re.sub(r"{(\w+)}", r"%\1%", template))
assert fr.determine_name(".cbz") == result
@pytest.mark.parametrize("template,result", rnames)
def test_rename_new(template, result):
fr = FileRenamer2(md_test)
fr.set_template(template)
assert fr.determine_name(".cbz") == result