Allow preserving the original filename when moving

This commit is contained in:
Timmy Welch 2024-04-27 19:25:33 -07:00
parent d98f815ce0
commit 8b4bf8d51f
9 changed files with 118 additions and 37 deletions

View File

@ -573,14 +573,16 @@ class CLI:
new_ext = ca.extension()
renamer = FileRenamer(
md,
None,
platform="universal" if self.config.File_Rename__strict else "auto",
replacements=self.config.File_Rename__replacements,
)
renamer.set_metadata(md, ca.path.name)
renamer.set_template(self.config.File_Rename__template)
renamer.set_issue_zero_padding(self.config.File_Rename__issue_number_padding)
renamer.set_smart_cleanup(self.config.File_Rename__use_smart_string_cleanup)
renamer.move = self.config.File_Rename__move_to_dir
renamer.move = self.config.File_Rename__move
renamer.move_only = self.config.File_Rename__only_move
try:
new_name = renamer.determine_name(ext=new_ext)
@ -600,7 +602,7 @@ class CLI:
logger.exception("Formatter failure: %s metadata: %s", self.config.File_Rename__template, renamer.metadata)
return Result(Action.rename, Status.rename_failure, original_path, md=md)
folder = get_rename_dir(ca, self.config.File_Rename__dir if self.config.File_Rename__move_to_dir else None)
folder = get_rename_dir(ca, self.config.File_Rename__dir if self.config.File_Rename__move else None)
full_path = folder / new_name

View File

@ -201,11 +201,16 @@ def rename(parser: settngs.Manager) -> None:
parser.add_setting("--dir", default="", help="The directory to move renamed files to")
parser.add_setting(
"--move",
dest="move_to_dir",
default=False,
action=argparse.BooleanOptionalAction,
help="Enables moving renamed files to a separate directory",
)
parser.add_setting(
"--only-move",
default=False,
action=argparse.BooleanOptionalAction,
help="Ignores the filename when moving renamed files to a separate directory",
)
parser.add_setting(
"--strict",
default=False,

View File

@ -88,7 +88,8 @@ class SettngsNS(settngs.TypedNS):
File_Rename__use_smart_string_cleanup: bool
File_Rename__auto_extension: bool
File_Rename__dir: str
File_Rename__move_to_dir: bool
File_Rename__move: bool
File_Rename__only_move: bool
File_Rename__strict: bool
File_Rename__replacements: comictaggerlib.defaults.Replacements
@ -205,7 +206,8 @@ class File_Rename(typing.TypedDict):
use_smart_string_cleanup: bool
auto_extension: bool
dir: str
move_to_dir: bool
move: bool
only_move: bool
strict: bool
replacements: comictaggerlib.defaults.Replacements

View File

@ -38,8 +38,8 @@ def get_rename_dir(ca: ComicArchive, rename_dir: str | pathlib.Path | None) -> p
folder = ca.path.parent.absolute()
if rename_dir is not None:
if isinstance(rename_dir, str):
rename_dir = rename_dir.strip()
folder = pathlib.Path(rename_dir).absolute()
rename_dir = pathlib.Path(rename_dir.strip())
folder = rename_dir.absolute()
return folder
@ -192,9 +192,12 @@ class FileRenamer:
self.move = False
self.platform = platform
self.replacements = replacements
self.original_name = ""
self.move_only = False
def set_metadata(self, metadata: GenericMetadata) -> None:
def set_metadata(self, metadata: GenericMetadata, original_name: str) -> None:
self.metadata = metadata
self.original_name = original_name
def set_issue_zero_padding(self, count: int) -> None:
self.issue_zero_padding = count
@ -240,9 +243,9 @@ class FileRenamer:
).strip()
new_name = os.path.join(new_name, new_basename)
new_name += ext
new_basename += ext
if self.move_only:
new_folder = os.path.join(new_name, os.path.splitext(self.original_name)[0])
return new_folder + ext
if self.move:
return new_name.strip()
return new_basename.strip()
return new_name.strip() + ext
return new_basename.strip() + ext

View File

@ -75,6 +75,7 @@ class RenameWindow(QtWidgets.QDialog):
self.renamer.set_issue_zero_padding(self.config[0].File_Rename__issue_number_padding)
self.renamer.set_smart_cleanup(self.config[0].File_Rename__use_smart_string_cleanup)
self.renamer.replacements = self.config[0].File_Rename__replacements
self.renamer.move_only = self.config[0].File_Rename__only_move
new_ext = ca.path.suffix # default
if self.config[0].File_Rename__auto_extension:
@ -89,8 +90,8 @@ class RenameWindow(QtWidgets.QDialog):
self.config[0].Filename_Parsing__remove_fcbd,
self.config[0].Filename_Parsing__remove_publisher,
)
self.renamer.set_metadata(md)
self.renamer.move = self.config[0].File_Rename__move_to_dir
self.renamer.set_metadata(md, ca.path.name)
self.renamer.move = self.config[0].File_Rename__move
return new_ext
def do_preview(self) -> None:
@ -192,7 +193,7 @@ class RenameWindow(QtWidgets.QDialog):
folder = get_rename_dir(
comic[0],
self.config[0].File_Rename__dir if self.config[0].File_Rename__move_to_dir else None,
self.config[0].File_Rename__dir if self.config[0].File_Rename__move else None,
)
full_path = folder / comic[1]

View File

@ -210,6 +210,7 @@ class SettingsWindow(QtWidgets.QDialog):
self.btnResetSettings.clicked.connect(self.reset_settings)
self.btnTemplateHelp.clicked.connect(self.show_template_help)
self.cbxMoveFiles.clicked.connect(self.dir_test)
self.cbxMoveOnly.clicked.connect(self.move_only_clicked)
self.leDirectory.textEdited.connect(self.dir_test)
self.cbFilenameParser.currentIndexChanged.connect(self.switch_parser)
@ -220,6 +221,7 @@ class SettingsWindow(QtWidgets.QDialog):
self.leRenameTemplate.textEdited.connect(self.rename_test)
self.cbxMoveFiles.clicked.connect(self.rename_test)
self.cbxMoveOnly.clicked.connect(self.rename_test)
self.cbxRenameStrict.clicked.connect(self.rename_test)
self.cbxSmartCleanup.clicked.connect(self.rename_test)
self.cbxChangeExtension.clicked.connect(self.rename_test)
@ -248,6 +250,7 @@ class SettingsWindow(QtWidgets.QDialog):
self.cbxChangeExtension.clicked.disconnect()
self.cbFilenameParser.currentIndexChanged.disconnect()
self.cbxMoveFiles.clicked.disconnect()
self.cbxMoveOnly.clicked.disconnect()
self.cbxRenameStrict.clicked.disconnect()
self.cbxSmartCleanup.clicked.disconnect()
self.leDirectory.textEdited.disconnect()
@ -336,19 +339,31 @@ class SettingsWindow(QtWidgets.QDialog):
def rename_test(self, *args: Any, **kwargs: Any) -> None:
self._rename_test(self.leRenameTemplate.text())
def move_only_clicked(self, *args: Any, **kwargs: Any) -> None:
if self.cbxMoveOnly.isChecked():
self.cbxMoveFiles.setEnabled(False)
self.cbxMoveFiles.setChecked(True)
else:
self.cbxMoveFiles.setEnabled(True)
self.dir_test()
def dir_test(self) -> None:
self.lblDir.setText(
str(pathlib.Path(self.leDirectory.text().strip()).resolve()) if self.cbxMoveFiles.isChecked() else ""
str(pathlib.Path(self.leDirectory.text().strip()).resolve())
if self.cbxMoveFiles.isChecked() or self.cbxMoveOnly.isChecked()
else ""
)
def _rename_test(self, template: str) -> None:
if not str(self.leIssueNumPadding.text()).isdigit():
self.leIssueNumPadding.setText("0")
fr = FileRenamer(
md_test,
None,
platform="universal" if self.cbxRenameStrict.isChecked() else "auto",
replacements=self.get_replacements(),
)
fr.set_metadata(md_test, "cory doctorow #1.cbz")
fr.move_only = self.cbxMoveOnly.isChecked()
fr.move = self.cbxMoveFiles.isChecked()
fr.set_template(template)
fr.set_issue_zero_padding(int(self.leIssueNumPadding.text()))
@ -418,7 +433,8 @@ class SettingsWindow(QtWidgets.QDialog):
self.leIssueNumPadding.setText(str(self.config[0].File_Rename__issue_number_padding))
self.cbxSmartCleanup.setChecked(self.config[0].File_Rename__use_smart_string_cleanup)
self.cbxChangeExtension.setChecked(self.config[0].File_Rename__auto_extension)
self.cbxMoveFiles.setChecked(self.config[0].File_Rename__move_to_dir)
self.cbxMoveFiles.setChecked(self.config[0].File_Rename__move)
self.cbxMoveOnly.setChecked(self.config[0].File_Rename__only_move)
self.leDirectory.setText(self.config[0].File_Rename__dir)
self.cbxRenameStrict.setChecked(self.config[0].File_Rename__strict)
@ -543,7 +559,8 @@ class SettingsWindow(QtWidgets.QDialog):
self.config[0].File_Rename__issue_number_padding = int(self.leIssueNumPadding.text())
self.config[0].File_Rename__use_smart_string_cleanup = self.cbxSmartCleanup.isChecked()
self.config[0].File_Rename__auto_extension = self.cbxChangeExtension.isChecked()
self.config[0].File_Rename__move_to_dir = self.cbxMoveFiles.isChecked()
self.config[0].File_Rename__move = self.cbxMoveFiles.isChecked()
self.config[0].File_Rename__only_move = self.cbxMoveOnly.isChecked()
self.config[0].File_Rename__dir = self.leDirectory.text()
self.config[0].File_Rename__strict = self.cbxRenameStrict.isChecked()

View File

@ -658,7 +658,7 @@
</property>
</widget>
</item>
<item row="9" column="0">
<item row="11" column="0">
<widget class="QLabel" name="lblDirectory">
<property name="text">
<string>Destination Directory:</string>
@ -668,10 +668,10 @@
</property>
</widget>
</item>
<item row="9" column="1">
<item row="11" column="1">
<widget class="QLineEdit" name="leDirectory"/>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QCheckBox" name="cbxRenameStrict">
<property name="toolTip">
<string>If checked will ensure reserved characters and filenames are removed for all Operating Systems.&lt;br/&gt;By default only removes restricted characters and filenames for the current Operating System.</string>
@ -681,9 +681,16 @@
</property>
</widget>
</item>
<item row="10" column="1">
<item row="12" column="1">
<widget class="QLabel" name="lblDir"/>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="cbxMoveOnly">
<property name="text">
<string>Only Move files when renaming</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">

View File

@ -1032,10 +1032,11 @@ for p in names:
)
)
rnames = [
file_renames = [
(
"{series!c} {price} {year}", # Capitalize
False,
False,
"universal",
"Cory doctorow's futuristic tales of the here and now 2007.cbz",
does_not_raise(),
@ -1043,6 +1044,7 @@ rnames = [
(
"{series!t} {price} {year}", # Title Case
False,
False,
"universal",
"Cory Doctorow'S Futuristic Tales Of The Here And Now 2007.cbz",
does_not_raise(),
@ -1050,6 +1052,7 @@ rnames = [
(
"{series!S} {price} {year}", # Swap Case
False,
False,
"universal",
"cORY dOCTOROW'S fUTURISTIC tALES OF THE hERE AND nOW 2007.cbz",
does_not_raise(),
@ -1057,6 +1060,7 @@ rnames = [
(
"{title!l} {price} {year}", # Lowercase
False,
False,
"universal",
"anda's game 2007.cbz",
does_not_raise(),
@ -1064,6 +1068,7 @@ rnames = [
(
"{title!u} {price} {year}", # Upper Case
False,
False,
"universal",
"ANDA'S GAME 2007.cbz",
does_not_raise(),
@ -1071,6 +1076,7 @@ rnames = [
(
"{title} {price} {year+}", # Empty alternate value
False,
False,
"universal",
"Anda's Game.cbz",
does_not_raise(),
@ -1078,6 +1084,7 @@ rnames = [
(
"{title} {price} {year+year!u}", # Alternate value Upper Case
False,
False,
"universal",
"Anda's Game YEAR.cbz",
does_not_raise(),
@ -1085,6 +1092,7 @@ rnames = [
(
"{title} {price} {year+year}", # Alternate Value
False,
False,
"universal",
"Anda's Game year.cbz",
does_not_raise(),
@ -1092,6 +1100,7 @@ rnames = [
(
"{title} {price-0} {year}", # Default value
False,
False,
"universal",
"Anda's Game 0 2007.cbz",
does_not_raise(),
@ -1099,6 +1108,7 @@ rnames = [
(
"{title} {price+0} {year}", # Alternate Value
False,
False,
"universal",
"Anda's Game 2007.cbz",
does_not_raise(),
@ -1106,6 +1116,7 @@ rnames = [
(
"{series} #{issue} - {title} ({year}) ({price})", # price should be none
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1113,6 +1124,7 @@ rnames = [
(
"{series} #{issue} - {title} {volume:02} ({year})", # Ensure format specifier works
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game 01 (2007).cbz",
does_not_raise(),
@ -1120,6 +1132,7 @@ rnames = [
(
"{series} #{issue} - {title} ({year})({price})", # price should be none, test no space between ')('
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1127,6 +1140,7 @@ rnames = [
(
"{series} #{issue} - {title} ({year}) ({price})", # price should be none, test double space ') ('
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1134,6 +1148,7 @@ rnames = [
(
"{series} #{issue} - {title} ({year})",
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1141,6 +1156,7 @@ rnames = [
(
"{title} {web_link}", # Ensure colon is replaced in metadata
False,
False,
"universal",
"Anda's Game https---comicvine.gamespot.com-cory-doctorows-futuristic-tales-of-the-here-and-no-4000-140529-.cbz",
does_not_raise(),
@ -1148,6 +1164,7 @@ rnames = [
(
"{title} {web_link}", # Ensure slashes are replaced in metadata on linux/macos
False,
False,
"Linux",
"Anda's Game https:--comicvine.gamespot.com-cory-doctorows-futuristic-tales-of-the-here-and-no-4000-140529-.cbz",
does_not_raise(),
@ -1155,6 +1172,7 @@ rnames = [
(
"{title} {web_links!j}", # Test that join forces str conversion
False,
False,
"Linux",
"Anda's Game https:--comicvine.gamespot.com-cory-doctorows-futuristic-tales-of-the-here-and-no-4000-140529-.cbz",
does_not_raise(),
@ -1162,6 +1180,7 @@ rnames = [
(
"{series}:{title} #{issue} ({year})", # on windows the ':' is replaced
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now-Anda's Game #001 (2007).cbz",
does_not_raise(),
@ -1169,6 +1188,7 @@ rnames = [
(
"{series}: {title} #{issue} ({year})", # on windows the ':' is replaced
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001 (2007).cbz",
does_not_raise(),
@ -1176,6 +1196,7 @@ rnames = [
(
"{series}: {title} #{issue} ({year})", # on linux the ':' is preserved
False,
False,
"Linux",
"Cory Doctorow's Futuristic Tales of the Here and Now: Anda's Game #001 (2007).cbz",
does_not_raise(),
@ -1183,6 +1204,7 @@ rnames = [
(
"{publisher}/ {series} #{issue} - {title} ({year})", # leading whitespace is removed when moving
True,
False,
"universal",
"IDW Publishing/Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1190,6 +1212,7 @@ rnames = [
(
"{publisher}/ {series} #{issue} - {title} ({year})", # leading whitespace is removed when only renaming
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1197,6 +1220,7 @@ rnames = [
(
r"{publisher}\ {series} #{issue} - {title} ({year})", # backslashes separate directories
False,
False,
"Linux",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1204,6 +1228,7 @@ rnames = [
(
"{series} # {issue} - {title} ({year})", # double spaces are reduced to one
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now # 001 - Anda's Game (2007).cbz",
does_not_raise(),
@ -1211,6 +1236,7 @@ rnames = [
(
"{series} #{issue} - {locations!j} ({year})",
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - lonely cottage (2007).cbz",
does_not_raise(),
@ -1218,6 +1244,7 @@ rnames = [
(
"{series} #{issue} - {title} - {WriteR}, {EDITOR} ({year})", # fields are case in-sensitive
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 - Anda's Game - Dara Naraghi, Ted Adams (2007).cbz",
does_not_raise(),
@ -1225,6 +1252,7 @@ rnames = [
(
"{series} v{price} #{issue} ({year})", # Remove previous text if value is ""
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 (2007).cbz",
does_not_raise(),
@ -1232,6 +1260,7 @@ rnames = [
(
"{series} {price} #{issue} ({year})", # Ensure that a single space remains
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now #001 (2007).cbz",
does_not_raise(),
@ -1239,6 +1268,7 @@ rnames = [
(
"{series} - {title}{price} #{issue} ({year})", # Ensure removal before None values only impacts literal text
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001 (2007).cbz",
does_not_raise(),
@ -1246,6 +1276,7 @@ rnames = [
(
"{series} - {title} {test} #{issue} ({year})", # Test non-existent key
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game {test} #001 (2007).cbz",
does_not_raise(),
@ -1253,6 +1284,7 @@ rnames = [
(
"{series} - {title} #{issue} ({year} {price})", # Test null value in parenthesis with a non-null value
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001 (2007).cbz",
does_not_raise(),
@ -1260,6 +1292,7 @@ rnames = [
(
"{series} - {title} #{issue} (of {price})", # null value with literal text in parenthesis
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001.cbz",
does_not_raise(),
@ -1267,15 +1300,24 @@ rnames = [
(
"{series} - {title} {1} #{issue} ({year})", # Test numeric key
False,
False,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game {test} #001 (2007).cbz",
pytest.raises(ValueError),
),
(
"{series} - {title} #{issue} ({year})",
False,
True,
"universal",
"Cory Doctorow's Futuristic Tales of the Here and Now - Anda's Game #001 (2007)/cory doctorow #1.cbz",
does_not_raise(),
),
]
rfnames = [
(None, lambda x: x.path.parent.absolute()),
("", lambda x: pathlib.Path(os.getcwd())),
("test", lambda x: (pathlib.Path(os.getcwd()) / "test")),
(pathlib.Path(os.getcwd()) / "test", lambda x: pathlib.Path(os.getcwd()) / "test"),
folder_names = [
(None, lambda: pathlib.Path(str(cbz_path)).parent.absolute()),
("", lambda: pathlib.Path(os.getcwd())),
("test", lambda: (pathlib.Path(os.getcwd()) / "test")),
(pathlib.Path(os.getcwd()) / "test", lambda: pathlib.Path(os.getcwd()) / "test"),
]

View File

@ -6,18 +6,20 @@ import pytest
from comicapi.genericmetadata import md_test
from comictaggerlib import filerenamer
from testing.filenames import rfnames, rnames
from testing.filenames import file_renames, folder_names
@pytest.mark.parametrize("template, move, platform, expected, exception", rnames)
def test_rename(template, platform, move, expected, exception):
fr = filerenamer.FileRenamer(md_test, platform=platform)
@pytest.mark.parametrize("template, move, move_only, platform, expected, exception", file_renames)
def test_rename(template, move, move_only, platform, expected, exception):
fr = filerenamer.FileRenamer(None, platform=platform)
fr.set_metadata(md_test, "cory doctorow #1.cbz")
fr.move = move
fr.move_only = move_only
fr.set_template(template)
with exception:
assert str(pathlib.PureWindowsPath(fr.determine_name(".cbz"))) == str(pathlib.PureWindowsPath(expected))
@pytest.mark.parametrize("inp, result", rfnames)
@pytest.mark.parametrize("inp, result", folder_names)
def test_get_rename_dir(inp, result, cbz):
assert result(cbz) == filerenamer.get_rename_dir(cbz, inp)
assert result() == filerenamer.get_rename_dir(cbz, inp)