renames previously downloaded files to a different filename format
This commit is contained in:
@@ -6016,6 +6016,42 @@ Description
|
|||||||
or the |Path|_ to a `.py` file,
|
or the |Path|_ to a `.py` file,
|
||||||
|
|
||||||
|
|
||||||
|
rename.from
|
||||||
|
-----------
|
||||||
|
Type
|
||||||
|
``string``
|
||||||
|
Description
|
||||||
|
The `format string`_ for filenames to rename.
|
||||||
|
|
||||||
|
When no value is given, `extractor.*.filename`_ is used.
|
||||||
|
|
||||||
|
|
||||||
|
rename.to
|
||||||
|
---------
|
||||||
|
Type
|
||||||
|
``string``
|
||||||
|
Description
|
||||||
|
The `format string`_ for target filenames.
|
||||||
|
|
||||||
|
When no value is given, `extractor.*.filename`_ is used.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
With default settings, the potential download to `extractor.*.filename`_
|
||||||
|
still happens, even when using this post processor.
|
||||||
|
Disabling `file downloads <extractor.*.download_>`__
|
||||||
|
when using this option is recommended.
|
||||||
|
|
||||||
|
|
||||||
|
rename.skip
|
||||||
|
-----------
|
||||||
|
Type
|
||||||
|
``bool``
|
||||||
|
Default
|
||||||
|
``true``
|
||||||
|
Description
|
||||||
|
Do not rename a file when another file with the target name already exists.
|
||||||
|
|
||||||
|
|
||||||
ugoira.extension
|
ugoira.extension
|
||||||
----------------
|
----------------
|
||||||
Type
|
Type
|
||||||
@@ -6340,7 +6376,7 @@ Type
|
|||||||
Example
|
Example
|
||||||
``["~/urls.txt", "$HOME/input"]``
|
``["~/urls.txt", "$HOME/input"]``
|
||||||
Description
|
Description
|
||||||
Additional# input files.
|
Additional input files.
|
||||||
|
|
||||||
|
|
||||||
signals-ignore
|
signals-ignore
|
||||||
@@ -6663,11 +6699,12 @@ Description
|
|||||||
Set file modification time according to its metadata
|
Set file modification time according to its metadata
|
||||||
``python``
|
``python``
|
||||||
Call Python functions
|
Call Python functions
|
||||||
|
``rename``
|
||||||
|
Rename previously downloaded files
|
||||||
``ugoira``
|
``ugoira``
|
||||||
Convert Pixiv Ugoira to WebM using |ffmpeg|
|
Convert Pixiv Ugoira to WebM using |ffmpeg|
|
||||||
``zip``
|
``zip``
|
||||||
Store files in a ZIP archive
|
Store files in a ZIP archive
|
||||||
|ytdl|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ modules = [
|
|||||||
"metadata",
|
"metadata",
|
||||||
"mtime",
|
"mtime",
|
||||||
"python",
|
"python",
|
||||||
|
"rename",
|
||||||
"ugoira",
|
"ugoira",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|||||||
66
gallery_dl/postprocessor/rename.py
Normal file
66
gallery_dl/postprocessor/rename.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright 2024 Mike Fährmann
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
|
||||||
|
"""Rename files"""
|
||||||
|
|
||||||
|
from .common import PostProcessor
|
||||||
|
from .. import formatter
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class RenamePP(PostProcessor):
|
||||||
|
|
||||||
|
def __init__(self, job, options):
|
||||||
|
PostProcessor.__init__(self, job)
|
||||||
|
|
||||||
|
self.skip = options.get("skip", True)
|
||||||
|
old = options.get("from")
|
||||||
|
new = options.get("to")
|
||||||
|
|
||||||
|
if old:
|
||||||
|
self._old = self._apply_format(old)
|
||||||
|
self._new = (self._apply_format(new) if new else
|
||||||
|
self._apply_pathfmt)
|
||||||
|
elif new:
|
||||||
|
self._old = self._apply_pathfmt
|
||||||
|
self._new = self._apply_format(new)
|
||||||
|
else:
|
||||||
|
raise ValueError("Option 'from' or 'to' is required")
|
||||||
|
|
||||||
|
job.register_hooks({"prepare": self.run}, options)
|
||||||
|
|
||||||
|
def run(self, pathfmt):
|
||||||
|
old = self._old(pathfmt)
|
||||||
|
path_old = pathfmt.realdirectory + old
|
||||||
|
|
||||||
|
if os.path.exists(path_old):
|
||||||
|
new = self._new(pathfmt)
|
||||||
|
path_new = pathfmt.realdirectory + new
|
||||||
|
|
||||||
|
if self.skip and os.path.exists(path_new):
|
||||||
|
return self.log.warning(
|
||||||
|
"Not renaming '%s' to '%s' since another file with the "
|
||||||
|
"same name exists", old, new)
|
||||||
|
|
||||||
|
self.log.info("'%s' -> '%s'", old, new)
|
||||||
|
os.replace(path_old, path_new)
|
||||||
|
|
||||||
|
def _apply_pathfmt(self, pathfmt):
|
||||||
|
return pathfmt.build_filename(pathfmt.kwdict)
|
||||||
|
|
||||||
|
def _apply_format(self, format_string):
|
||||||
|
fmt = formatter.parse(format_string).format_map
|
||||||
|
|
||||||
|
def apply(pathfmt):
|
||||||
|
return pathfmt.clean_path(pathfmt.clean_segment(fmt(
|
||||||
|
pathfmt.kwdict)))
|
||||||
|
|
||||||
|
return apply
|
||||||
|
|
||||||
|
|
||||||
|
__postprocessor__ = RenamePP
|
||||||
@@ -12,6 +12,7 @@ import sys
|
|||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import Mock, mock_open, patch
|
from unittest.mock import Mock, mock_open, patch
|
||||||
|
|
||||||
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
import zipfile
|
import zipfile
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -691,6 +692,60 @@ def calc(kwdict):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
class RenameTest(BasePostprocessorTest):
|
||||||
|
|
||||||
|
def _prepare(self, filename):
|
||||||
|
path = self.pathfmt.realdirectory
|
||||||
|
shutil.rmtree(path, ignore_errors=True)
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
|
||||||
|
with open(path + filename, "w"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
def test_rename_from(self):
|
||||||
|
self._create({"from": "{id}.{extension}"}, {"id": 12345})
|
||||||
|
path = self._prepare("12345.ext")
|
||||||
|
|
||||||
|
self._trigger()
|
||||||
|
|
||||||
|
self.assertEqual(os.listdir(path), ["file.ext"])
|
||||||
|
|
||||||
|
def test_rename_to(self):
|
||||||
|
self._create({"to": "{id}.{extension}"}, {"id": 12345})
|
||||||
|
path = self._prepare("file.ext")
|
||||||
|
|
||||||
|
self._trigger()
|
||||||
|
|
||||||
|
self.assertEqual(os.listdir(path), ["12345.ext"])
|
||||||
|
|
||||||
|
def test_rename_from_to(self):
|
||||||
|
self._create({"from": "name", "to": "{id}"}, {"id": 12345})
|
||||||
|
path = self._prepare("name")
|
||||||
|
|
||||||
|
self._trigger()
|
||||||
|
|
||||||
|
self.assertEqual(os.listdir(path), ["12345"])
|
||||||
|
|
||||||
|
def test_rename_noopt(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self._create({})
|
||||||
|
|
||||||
|
def test_rename_skip(self):
|
||||||
|
self._create({"from": "{id}.{extension}"}, {"id": 12345})
|
||||||
|
path = self._prepare("12345.ext")
|
||||||
|
with open(path + "file.ext", "w"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertLogs("postprocessor.rename", level="WARNING") as cm:
|
||||||
|
self._trigger()
|
||||||
|
self.assertTrue(cm.output[0].startswith(
|
||||||
|
"WARNING:postprocessor.rename:Not renaming "
|
||||||
|
"'12345.ext' to 'file.ext'"))
|
||||||
|
self.assertEqual(sorted(os.listdir(path)), ["12345.ext", "file.ext"])
|
||||||
|
|
||||||
|
|
||||||
class ZipTest(BasePostprocessorTest):
|
class ZipTest(BasePostprocessorTest):
|
||||||
|
|
||||||
def test_zip_default(self):
|
def test_zip_default(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user