Skip to content

Commit

Permalink
Added hardlink and copy options
Browse files Browse the repository at this point in the history
  • Loading branch information
Sylvain Willy committed Apr 13, 2020
1 parent a189564 commit 57660c0
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 30 deletions.
6 changes: 6 additions & 0 deletions tvnamer/cliarg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ def getCommandlineParser(defaults):
g.add_option("-m", "--move", action="store_true", dest="move_files_enable", help = "Move files to destination specified in config or with --movedestination argument")
g.add_option("--not-move", action="store_false", dest="move_files_enable", help = "Files will remain in current directory")

g.add_option("-C", "--copy", action="store_true", dest="always_copy", help = "Copy files instead of renaming")
g.add_option("--not-copy", action="store_false", dest="always_copy", help = "Files will not be copied")

g.add_option("-l", "--link", action="store_true", dest="always_hardlink", help = "Hardlink instead of renaming")
g.add_option("--not-link", action="store_false", dest="always_hardlink", help = "Files will not all be hardlink")

g.add_option("--force-move", action="store_true", dest = "overwrite_destination_on_move", help = "Force move and potentially overwrite existing files in destination folder")
g.add_option("--force-rename", action="store_true", dest = "overwrite_destination_on_rename", help = "Force rename source file")

Expand Down
14 changes: 13 additions & 1 deletion tvnamer/config_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
'batch': False,

# Fail if error finding show data (thetvdb.com is down etc)
# Only functions when always_rename is True
# Only functions when always_rename or always_hardlink are True
'skip_file_on_error': True,

# Fail if error finding show data (thetvdb.com is down etc)
Expand Down Expand Up @@ -146,6 +146,18 @@
# Allow user to copy files to specified move location without renaming files.
'move_files_only': False,

# Force the move-files feature to always copy the file.
'always_copy': False,

# If True, instead of copying files to be copied on the same partition,
# a hardlink will be created.
'prefer_hardlink_to_copy': False,

# Forces files to be hard-linked. Will raise an error if it is not possible
# (i.e. different partition, unsuported, etc.).
# This option is incompatible with always_move
'always_hardlink': False,

# Patterns to parse input filenames with
'filename_patterns': [
# [group] Show - 01-02 [crc]
Expand Down
53 changes: 28 additions & 25 deletions tvnamer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def doMoveFile(cnamer, destDir = None, destFilepath = None, getPathPreview = Fal
if (destDir is None and destFilepath is None) or (destDir is not None and destFilepath is not None):
raise ValueError("Specify only destDir or destFilepath")

if not Config['move_files_enable']:
if not (Config['move_files_enable'] or Config['always_copy'] or Config['always_hardlink']):
raise ValueError("move_files feature is disabled but doMoveFile was called")

if Config['move_files_destination'] is None:
Expand All @@ -110,6 +110,8 @@ def doMoveFile(cnamer, destDir = None, destFilepath = None, getPathPreview = Fal
new_path = destDir,
new_fullpath = destFilepath,
always_move = Config['always_move'],
always_copy = Config['always_copy'],
always_hardlink=Config['always_hardlink'],
leave_symlink = Config['leave_symlink'],
getPathPreview = getPathPreview,
force = Config['overwrite_destination_on_move'])
Expand Down Expand Up @@ -224,12 +226,14 @@ def processFile(tvdb_instance, episode):
p("%s will be moved to %s" % (newName, getMoveDestination(episode)))
return
elif Config['always_rename']:
doRenameFile(cnamer, newName)
if Config['move_files_enable']:
if Config['move_files_enable'] or Config['always_copy'] or Config['always_hardlink']:
if Config['move_files_destination_is_filepath']:
doMoveFile(cnamer = cnamer, destFilepath = getMoveDestination(episode))
else:
doMoveFile(cnamer = cnamer, destDir = getMoveDestination(episode))
doRenameFile(cnamer, newName)
else:
doRenameFile(cnamer, newName)
return

ans = confirm("Rename?", options = ['y', 'n', 'a', 'q'], default = 'y')
Expand All @@ -249,31 +253,30 @@ def processFile(tvdb_instance, episode):
else:
p("Invalid input, skipping")

if shouldRename:
doRenameFile(cnamer, newName)
if shouldRename:
if Config['move_files_enable'] or Config['always_copy'] or Config['always_hardlink']:
newPath = getMoveDestination(episode)
if Config['dry_run']:
p("%s will be moved to %s" % (newName, getMoveDestination(episode)))
return

if shouldRename and Config['move_files_enable']:
newPath = getMoveDestination(episode)
if Config['dry_run']:
p("%s will be moved to %s" % (newName, getMoveDestination(episode)))
return
if Config['move_files_destination_is_filepath']:
doMoveFile(cnamer = cnamer, destFilepath = newPath, getPathPreview = True)
else:
doMoveFile(cnamer = cnamer, destDir = newPath, getPathPreview = True)

if Config['move_files_destination_is_filepath']:
doMoveFile(cnamer = cnamer, destFilepath = newPath, getPathPreview = True)
else:
doMoveFile(cnamer = cnamer, destDir = newPath, getPathPreview = True)
if not Config['batch'] and Config['move_files_confirmation']:
ans = confirm("Move file?", options = ['y', 'n', 'q'], default = 'y')
else:
ans = 'y'

if not Config['batch'] and Config['move_files_confirmation']:
ans = confirm("Move file?", options = ['y', 'n', 'q'], default = 'y')
else:
ans = 'y'

if ans == 'y':
p("Moving file")
doMoveFile(cnamer, newPath)
elif ans == 'q':
p("Quitting")
raise UserAbort("user exited with q")
if ans == 'y':
p("Moving file")
doMoveFile(cnamer, newPath)
elif ans == 'q':
p("Quitting")
raise UserAbort("user exited with q")
doRenameFile(cnamer, newName)


def findFiles(paths):
Expand Down
25 changes: 21 additions & 4 deletions tvnamer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,14 +1019,22 @@ def symlink_file(target, name):
os.symlink(target, name)


def hardlink_file(old, new):
"""Creates a hard link from the 'old' file at a 'new' target path with same permissions
"""
p("hardlink %s to %s" % (old, new))
os.link(old, new)
shutil.copystat(old, new)


class Renamer(object):
"""Deals with renaming of files
"""

def __init__(self, filename):
self.filename = os.path.abspath(filename)

def newPath(self, new_path = None, new_fullpath = None, force = False, always_copy = False, always_move = False, leave_symlink = False, create_dirs = True, getPathPreview = False):
def newPath(self, new_path = None, new_fullpath = None, force = False, always_copy = False, always_move = False, always_hardlink = False, leave_symlink = False, create_dirs = True, getPathPreview = False):
"""Moves the file to a new path.
If it is on the same partition, it will be moved (unless always_copy is True)
Expand All @@ -1037,8 +1045,9 @@ def newPath(self, new_path = None, new_fullpath = None, force = False, always_co
pointing to the file's new destination if leave_symlink is True.
"""

if always_copy and always_move:
raise ValueError("Both always_copy and always_move cannot be specified")
if (always_copy, always_move, always_hardlink).count(True) > 1:
raise ValueError("Different incompatible renaming operation cannot be specified: "
"always_copy or always_move or always_hardlink")

if (new_path is None and new_fullpath is None) or (new_path is not None and new_fullpath is not None):
raise ValueError("Specify only new_dir or new_fullpath")
Expand Down Expand Up @@ -1086,7 +1095,15 @@ def newPath(self, new_path = None, new_fullpath = None, force = False, always_co

if always_copy:
# Same partition, but forced to copy
copy_file(self.filename, new_fullpath)
if Config['prefer_hardlink_to_copy']:
try:
hardlink_file(self.filename, new_fullpath)
except OSError:
copy_file(self.filename, new_fullpath)
else:
copy_file(self.filename, new_fullpath)
elif always_hardlink:
hardlink_file(self.filename, new_fullpath)
else:
# Same partition, just rename the file to move it
rename_file(self.filename, new_fullpath)
Expand Down

0 comments on commit 57660c0

Please sign in to comment.