From 052e95e53bc7f958fb28476e65e0f004f3ae25d8 Mon Sep 17 00:00:00 2001 From: Timmy Welch Date: Fri, 29 Apr 2022 23:27:58 -0700 Subject: [PATCH] Remove old file renamer Use PureWindowsPath objects in templates and tests, this allows both path separators to be used and compared regardless of platform --- comictaggerlib/cli.py | 14 +--- comictaggerlib/filerenamer.py | 123 +--------------------------- comictaggerlib/renamewindow.py | 7 +- comictaggerlib/settings.py | 10 --- comictaggerlib/settingswindow.py | 53 ++---------- comictaggerlib/taggerwindow.py | 9 -- comictaggerlib/ui/settingswindow.ui | 26 +----- tests/filenames.py | 21 ++--- tests/test_rename.py | 19 ++--- 9 files changed, 29 insertions(+), 253 deletions(-) diff --git a/comictaggerlib/cli.py b/comictaggerlib/cli.py index a8cded2..43e02ae 100644 --- a/comictaggerlib/cli.py +++ b/comictaggerlib/cli.py @@ -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, FileRenamer2 +from comictaggerlib.filerenamer import FileRenamer from comictaggerlib.issueidentifier import IssueIdentifier from comictaggerlib.resulttypes import MultipleMatch, OnlineMatchResults from comictaggerlib.settings import ComicTaggerSettings @@ -155,13 +155,6 @@ 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: @@ -452,10 +445,7 @@ def process_file_cli(filename, opts, settings, match_results: OnlineMatchResults elif ca.is_rar(): new_ext = ".cbr" - if settings.rename_new_renamer: - renamer = FileRenamer2(md, platform="universal" if settings.rename_strict else "auto") - else: - renamer = FileRenamer(md) + renamer = FileRenamer(md, platform="universal" if settings.rename_strict else "auto") 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) diff --git a/comictaggerlib/filerenamer.py b/comictaggerlib/filerenamer.py index a21b0c7..fc44aaa 100644 --- a/comictaggerlib/filerenamer.py +++ b/comictaggerlib/filerenamer.py @@ -15,10 +15,9 @@ # limitations under the License. import calendar -import datetime import logging import os -import re +import pathlib import string import sys @@ -30,121 +29,6 @@ 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, platform="auto"): super().__init__() @@ -224,7 +108,7 @@ class MetadataFormatter(string.Formatter): return "".join(result), auto_arg_index -class FileRenamer2: +class FileRenamer: def __init__(self, metadata, platform="auto"): self.template = "{publisher}/{series}/{series} v{volume} #{issue} (of {issue_count}) ({year})" self.smart_cleanup = True @@ -257,7 +141,6 @@ class FileRenamer2: template = self.template - path_components = template.split(os.sep) new_name = "" fmt = MetadataFormatter(self.smart_cleanup, platform=self.platform) @@ -272,7 +155,7 @@ class FileRenamer2: md_dict["month_name"] = "" md_dict["month_abbr"] = "" - for Component in path_components: + for Component in pathlib.PureWindowsPath(template).parts: if ( self.platform.lower() in ["universal", "windows"] or sys.platform.lower() in ["windows"] ) and self.smart_cleanup: diff --git a/comictaggerlib/renamewindow.py b/comictaggerlib/renamewindow.py index b9bc3d4..a2be891 100644 --- a/comictaggerlib/renamewindow.py +++ b/comictaggerlib/renamewindow.py @@ -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, FileRenamer2 +from comictaggerlib.filerenamer import FileRenamer from comictaggerlib.settings import ComicTaggerSettings from comictaggerlib.settingswindow import SettingsWindow from comictaggerlib.ui.qtutils import center_window_on_parent @@ -52,10 +52,7 @@ class RenameWindow(QtWidgets.QDialog): self.rename_list = [] self.btnSettings.clicked.connect(self.modify_settings) - if self.settings.rename_new_renamer: - self.renamer = FileRenamer2(None, platform="universal" if self.settings.rename_strict else "auto") - else: - self.renamer = FileRenamer(None) + self.renamer = FileRenamer(None, platform="universal" if self.settings.rename_strict else "auto") self.config_renamer() self.do_preview() diff --git a/comictaggerlib/settings.py b/comictaggerlib/settings.py index e1a438c..584e954 100644 --- a/comictaggerlib/settings.py +++ b/comictaggerlib/settings.py @@ -86,7 +86,6 @@ 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 @@ -120,7 +119,6 @@ class ComicTaggerSettings: self.rename_extension_based_on_archive = True self.rename_dir = "" self.rename_move_dir = False - self.rename_new_renamer = False self.rename_strict = False # Auto-tag stickies @@ -161,7 +159,6 @@ 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 @@ -195,7 +192,6 @@ class ComicTaggerSettings: self.rename_extension_based_on_archive = True self.rename_dir = "" self.rename_move_dir = False - self.rename_new_renamer = False self.rename_strict = False # Auto-tag stickies @@ -302,8 +298,6 @@ 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") @@ -363,8 +357,6 @@ 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("rename", "rename_strict"): self.rename_strict = self.config.getboolean("rename", "rename_strict") @@ -423,7 +415,6 @@ 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") @@ -467,7 +458,6 @@ 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) self.config.set("rename", "rename_strict", self.rename_strict) if not self.config.has_section("autotag"): diff --git a/comictaggerlib/settingswindow.py b/comictaggerlib/settingswindow.py index dafd2b1..42302aa 100644 --- a/comictaggerlib/settingswindow.py +++ b/comictaggerlib/settingswindow.py @@ -17,7 +17,6 @@ import logging import os import platform -import re from PyQt5 import QtCore, QtGui, QtWidgets, uic @@ -25,7 +24,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, FileRenamer2 +from comictaggerlib.filerenamer import FileRenamer from comictaggerlib.imagefetcher import ImageFetcher from comictaggerlib.settings import ComicTaggerSettings @@ -57,24 +56,8 @@ macRarHelp = """

Once homebrew is installed, run: brew install caskroom/cask/rar """ -old_template_tooltip = """ -

The template for the new filename. Accepts the following variables:

%series%
%issue%
%volume%
%issuecount%
%year%
%month%
%month_name%
%publisher%
%title%
-%genre%
-%language_code%
-%criticalrating%
-%alternateseries%
-%alternatenumber%
-%alternatecount%
-%imprint%
-%format%
-%maturityrating%
-%storyarc%
-%seriesgroup%
-%scaninfo% -

Examples:

%series% %issue% (%year%)
%series% #%issue% - %title%

-""" -new_template_tooltip = """ +template_tooltip = """
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:
 {is_empty}       (boolean)
@@ -184,19 +167,11 @@ class SettingsWindow(QtWidgets.QDialog):
         validator = QtGui.QIntValidator(0, 99, self)
         self.leNameLengthDeltaThresh.setValidator(validator)
 
-        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.leRenameTemplate.setToolTip(template_tooltip)
         self.settings_to_form()
         self.rename_error = None
         self.rename_test()
 
-        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)
@@ -207,27 +182,12 @@ class SettingsWindow(QtWidgets.QDialog):
         self.cbxRenameStrict.clicked.connect(self.rename_test)
         self.leDirectory.textEdited.connect(self.rename_test)
 
-    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()
-
     def rename_test(self):
         self.rename__test(self.leRenameTemplate.text())
 
     def rename__test(self, template):
-        fr = FileRenamer(md_test)
-        if self.cbxNewRenamer.isChecked():
-            fr = FileRenamer2(md_test, platform="universal" if self.cbxRenameStrict.isChecked() else "auto")
-            fr.move = self.cbxMoveFiles.isChecked()
+        fr = FileRenamer(md_test, platform="universal" if self.cbxRenameStrict.isChecked() else "auto")
+        fr.move = self.cbxMoveFiles.isChecked()
         fr.set_template(template)
         fr.set_issue_zero_padding(int(self.leIssueNumPadding.text()))
         fr.set_smart_cleanup(self.cbxSmartCleanup.isChecked())
@@ -359,7 +319,6 @@ 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.rename_strict = self.cbxRenameStrict.isChecked()
 
         self.settings.save()
@@ -414,8 +373,6 @@ 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()
 
 
diff --git a/comictaggerlib/taggerwindow.py b/comictaggerlib/taggerwindow.py
index e1e87fe..f7c05d9 100644
--- a/comictaggerlib/taggerwindow.py
+++ b/comictaggerlib/taggerwindow.py
@@ -246,15 +246,6 @@ 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.

" - "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", - ) if self.settings.check_for_new_version: # self.checkLatestVersionOnline() diff --git a/comictaggerlib/ui/settingswindow.ui b/comictaggerlib/ui/settingswindow.ui index bfc112d..b8c97bc 100644 --- a/comictaggerlib/ui/settingswindow.ui +++ b/comictaggerlib/ui/settingswindow.ui @@ -554,24 +554,7 @@ - - - <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=" font-style:italic;">%series% %issue% (%year%)</span><br/><span style=" font-style:italic;">%series% #%issue% - %title%</span></p></body></html> - - + @@ -636,13 +619,6 @@ - - - - Enable the new renamer - - - diff --git a/tests/filenames.py b/tests/filenames.py index a29c554..a535afe 100644 --- a/tests/filenames.py +++ b/tests/filenames.py @@ -551,26 +551,29 @@ rnames = [ "universal", "Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001 (2007).cbz", ), - pytest.param( + ( "{series}: {title} #{issue} ({year})", False, "Linux", "Cory Doctorow's Futuristic Tales of the Here and Now: Anda's Game #001 (2007).cbz", - marks=pytest.mark.xfail, ), - pytest.param( + ( "{publisher}/ {series} #{issue} - {title} ({year})", True, "universal", "IDW Publishing/Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz", - marks=pytest.mark.xfail, ), - pytest.param( + ( "{publisher}/ {series} #{issue} - {title} ({year})", False, "universal", "Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz", - marks=pytest.mark.xfail, + ), + ( + r"{publisher}\ {series} #{issue} - {title} ({year})", + False, + "universal", + "Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz", ), ( "{series} # {issue} - {title} ({year})", @@ -578,18 +581,16 @@ rnames = [ "universal", "Cory Doctorow's Futuristic Tales of the Here and Now # 001 - Anda's Game (2007).cbz", ), - pytest.param( + ( "{series} # {issue} - {locations} ({year})", False, "universal", "Cory Doctorow's Futuristic Tales of the Here and Now # 001 - lonely cottage (2007).cbz", - marks=pytest.mark.xfail, ), - pytest.param( + ( "{series} #{issue} - {title} - {WriteR}, {EDITOR} ({year})", False, "universal", "Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game - Dara Naraghi, Ted Adams (2007).cbz", - marks=pytest.mark.xfail, ), ] diff --git a/tests/test_rename.py b/tests/test_rename.py index 9f01aef..585131a 100644 --- a/tests/test_rename.py +++ b/tests/test_rename.py @@ -1,24 +1,15 @@ -import re +import pathlib import pytest from filenames import rnames from comicapi.genericmetadata import md_test -from comictaggerlib.filerenamer import FileRenamer, FileRenamer2 +from comictaggerlib.filerenamer import FileRenamer @pytest.mark.parametrize("template, move, platform, expected", rnames) -def test_rename_old(template, platform, move, expected): - _ = platform - _ = move - fr = FileRenamer(md_test) - fr.set_template(re.sub(r"{(\w+)}", r"%\1%", template)) - assert fr.determine_name(".cbz") == expected - - -@pytest.mark.parametrize("template, move, platform, expected", rnames) -def test_rename_new(template, platform, move, expected): - fr = FileRenamer2(md_test, platform=platform) +def test_rename(template, platform, move, expected): + fr = FileRenamer(md_test, platform=platform) fr.move = move fr.set_template(template) - assert fr.determine_name(".cbz") == expected + assert str(pathlib.PureWindowsPath(fr.determine_name(".cbz"))) == str(pathlib.PureWindowsPath(expected))