rename folders
This commit is contained in:
1 parent
c192114bcf
commit
d5c82e364d
6 files changed
No files matched your search
Executable
+293
@@ -0,0 +1,293 @@
|
||||
#!/home/lucas/scripts/.venv/bin/python3
|
||||
import os
|
||||
import re
|
||||
import random
|
||||
import datetime
|
||||
import sys
|
||||
from PIL import Image, ExifTags
|
||||
from pillow_heif import open_heif
|
||||
import subprocess
|
||||
import json
|
||||
from serverlibary import safe_rename
|
||||
from pathlib import Path
|
||||
# Folder to scan
|
||||
folder_path = '.'
|
||||
# Supported image and video extensions
|
||||
|
||||
video_extensions = {
|
||||
'.mp4', '.mov', '.avi', '.mkv', '.hevc', '.mov',
|
||||
}
|
||||
img_extensions = {
|
||||
'.jpg', '.jpeg', '.png', '.heic', '.webp',
|
||||
}
|
||||
|
||||
extensions = img_extensions | video_extensions
|
||||
prefixes = { 'IMG', 'VID'}
|
||||
# Build reusable groups for regex
|
||||
ext_group = r'(jpg|jpeg|png|heic|webp|mp4|mov|avi|mkv|hevc)'
|
||||
prefix_group = r'(?:IMG|VID)'
|
||||
# Correct format to keep
|
||||
correct_format_re = re.compile(
|
||||
rf'^{prefix_group}_(\d{{8}}_\d{{6}}).*\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
# Alternate timestamp formats and their patterns
|
||||
alt_patterns = [
|
||||
# PREFIX_YYYY_MM_DD_HH_MM_SS.ext
|
||||
(
|
||||
re.compile(
|
||||
rf'^(?:{prefix_group}_)?(\d{{4}})_(\d{{2}})_(\d{{2}})_(\d{{2}})_(\d{{2}})_(\d{{2}}).*\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
),
|
||||
'%Y_%m_%d_%H_%M_%S'
|
||||
),
|
||||
|
||||
# PREFIX_YYYYMMDD_HHMMSS.ext
|
||||
(
|
||||
re.compile(
|
||||
rf'^(?:{prefix_group}_)?(\d{{8}})_(\d{{6}}).*\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
),
|
||||
'%Y%m%d_%H%M%S'
|
||||
),
|
||||
|
||||
# PREFIX_YYYY.MM.DD-HHMMSS.ext
|
||||
(
|
||||
re.compile(
|
||||
rf'^(?:{prefix_group}_)?(\d{{4}})\.(\d{{2}})\.(\d{{2}})-(\d{{6}}).*\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
),
|
||||
'%Y.%m.%d-%H%M%S'
|
||||
),
|
||||
|
||||
# PREFIX_YYYYMMDD.ext
|
||||
(
|
||||
re.compile(
|
||||
rf'^(?:{prefix_group}_)?(\d{{8}})\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
),
|
||||
'%Y%m%d'
|
||||
),
|
||||
|
||||
# PREFIX_HHMMSS.ext
|
||||
(
|
||||
re.compile(
|
||||
rf'^(?:{prefix_group}_)?(\d{{6}})\.{ext_group}$',
|
||||
re.IGNORECASE
|
||||
),
|
||||
'%H%M%S'
|
||||
),
|
||||
]
|
||||
|
||||
# EXIF tag name for datetime
|
||||
EXIF_DATE_TAGS = ['DateTimeOriginal', 'DateTimeDigitized', 'DateTime']
|
||||
|
||||
|
||||
def local_safe_rename(src_path, new_filename):
|
||||
"""Rename file safely, avoiding overwrites"""
|
||||
directory = os.path.dirname(src_path)
|
||||
base, ext = os.path.splitext(new_filename)
|
||||
counter = 1
|
||||
final_name = new_filename
|
||||
|
||||
while os.path.exists(os.path.join(directory, final_name)):
|
||||
final_name = f"{base}_{counter}{ext}"
|
||||
counter += 1
|
||||
|
||||
os.rename(src_path, os.path.join(directory, final_name))
|
||||
print(f"Renamed: {os.path.basename(src_path)} ➜ {final_name}")
|
||||
|
||||
def get_exif_creation_datetime(filepath):
|
||||
"""Try to extract creation datetime from image EXIF metadata"""
|
||||
try:
|
||||
if filepath.lower().endswith((".mp4", ".mov", ".m4v")):
|
||||
# WhatsApp videos: use filesystem modification time
|
||||
if "WA" in os.path.basename(filepath):
|
||||
return datetime.datetime.fromtimestamp(
|
||||
os.path.getmtime(filepath)
|
||||
)
|
||||
|
||||
tags = ["CreateDate", "MediaCreateDate", "TrackCreateDate"]
|
||||
|
||||
result = subprocess.run(
|
||||
[
|
||||
"exiftool",
|
||||
"-j",
|
||||
"-CreateDate",
|
||||
"-MediaCreateDate",
|
||||
"-TrackCreateDate",
|
||||
filepath,
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
metadata = json.loads(result.stdout)[0]
|
||||
|
||||
for tag in tags:
|
||||
if metadata.get(tag):
|
||||
return datetime.datetime.strptime(
|
||||
metadata[tag],
|
||||
"%Y:%m:%d %H:%M:%S"
|
||||
)
|
||||
|
||||
# Fallback: use filesystem modification time
|
||||
return datetime.datetime.fromtimestamp(
|
||||
os.path.getmtime(filepath)
|
||||
)
|
||||
|
||||
else:
|
||||
with Image.open(filepath) as img:
|
||||
exif = img._getexif()
|
||||
if not exif:
|
||||
print("Exif failed")
|
||||
return None
|
||||
|
||||
tag_label = {
|
||||
ExifTags.TAGS.get(k): v
|
||||
for k, v in exif.items()
|
||||
if k in ExifTags.TAGS
|
||||
}
|
||||
|
||||
for tag in EXIF_DATE_TAGS:
|
||||
print(tag)
|
||||
if tag in tag_label:
|
||||
print(tag)
|
||||
return datetime.datetime.strptime(
|
||||
tag_label[tag],
|
||||
'%Y:%m:%d %H:%M:%S'
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Exif Error {e}")
|
||||
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def get_manufacturer(file_path):
|
||||
# Call exiftool and get JSON output
|
||||
result = subprocess.run(
|
||||
["exiftool", "-j", file_path], # -j outputs JSON
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Parse JSON output
|
||||
metadata = json.loads(result.stdout)[0]
|
||||
# Extract Author tag and remove spaces
|
||||
author = metadata.get("Author", "")
|
||||
if author == "":
|
||||
author = metadata.get("AndroidMake", "")
|
||||
if author == "":
|
||||
author = metadata.get("AndroidManufacturer", "")
|
||||
if author == "":
|
||||
author = metadata.get("Model", "")
|
||||
if author == "":
|
||||
author = "NoAuthor"
|
||||
author_no_spaces = author.replace(" ", "")
|
||||
return author_no_spaces
|
||||
|
||||
def process_images(folder):
|
||||
folder = Path(folder)
|
||||
for fname in os.listdir(folder):
|
||||
fpath = os.path.join(folder, fname)
|
||||
|
||||
if not os.path.isfile(fpath):
|
||||
continue
|
||||
|
||||
_, ext = os.path.splitext(fname)
|
||||
ext = ext.lower()
|
||||
|
||||
if ext not in extensions:
|
||||
continue
|
||||
|
||||
# Step 1: Normalize filename by replacing '-' with '_'
|
||||
normalized_name = fname.replace('-', '_')
|
||||
|
||||
if normalized_name != fname:
|
||||
# Rename the file to the normalized name before continuing
|
||||
new_path = os.path.join(folder, normalized_name)
|
||||
|
||||
safe_rename(fpath, new_path)
|
||||
|
||||
print(f"Normalized: {fname} ➜ {os.path.basename(new_path)}")
|
||||
|
||||
# Update fname and fpath to the new normalized filename
|
||||
fname = os.path.basename(new_path)
|
||||
fpath = new_path
|
||||
|
||||
videoManufacturer = ""
|
||||
file_prefix = "IMG"
|
||||
for extention in video_extensions:
|
||||
if extention in ext:
|
||||
file_prefix = "VID"
|
||||
videoManufacturer = "_" + get_manufacturer(fpath)
|
||||
for extention in img_extensions:
|
||||
if extention in ext:
|
||||
file_prefix = "IMG"
|
||||
|
||||
# Now continue with your existing logic on normalized fname
|
||||
if correct_format_re.match(fname):
|
||||
if videoManufacturer != "" and file_prefix == "VID":
|
||||
if videoManufacturer not in fname:
|
||||
basename, _ = os.path.splitext(fname)
|
||||
new_fname = f"{basename}{videoManufacturer}{ext}"
|
||||
safe_rename(Path(fpath),folder / new_fname)
|
||||
continue
|
||||
|
||||
print(f"[OK] {fname} already correctly named.")
|
||||
continue
|
||||
|
||||
matched = False
|
||||
for pattern, fmt in alt_patterns:
|
||||
m = pattern.match(normalized_name)
|
||||
if m:
|
||||
try:
|
||||
parts = m.groups()
|
||||
timestamp_str = '_'.join(parts[:2]) if len(parts) >= 2 else parts[0]
|
||||
dt = datetime.datetime.strptime(timestamp_str, fmt)
|
||||
new_fname = f"{file_prefix}_{dt.strftime('%Y%m%d_%H%M%S')}{videoManufacturer}{ext}"
|
||||
safe_rename(Path(fpath),folder / new_fname)
|
||||
matched = True
|
||||
break
|
||||
except Exception as e:
|
||||
continue
|
||||
|
||||
if matched:
|
||||
continue
|
||||
|
||||
# 3. Try reading creation date from metadata
|
||||
dt = get_exif_creation_datetime(fpath)
|
||||
if dt:
|
||||
new_fname = f"{file_prefix}_{dt.strftime('%Y%m%d_%H%M%S')}{videoManufacturer}{ext}"
|
||||
safe_rename(Path(fpath),folder / new_fname)
|
||||
continue
|
||||
else:
|
||||
print(f"[Fail] Creation Date for {fpath} not found")
|
||||
# 4. Fallback: keep original name, add _RX_<random> (only if not already added)
|
||||
if '_RX_' in fname:
|
||||
print(f"[SKIP] {fname} already has fallback name.")
|
||||
continue
|
||||
|
||||
basename, _ = os.path.splitext(fname)
|
||||
rand_num = random.randint(100000, 999999)
|
||||
new_fname = f"{basename}_RX_{rand_num}{videoManufacturer}{ext}"
|
||||
safe_rename(Path(fpath),folder / new_fname)
|
||||
|
||||
# ---- Main script entry ----
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python script.py <image_folder_path>")
|
||||
sys.exit(1)
|
||||
|
||||
folder_path = sys.argv[1]
|
||||
|
||||
if not os.path.isdir(folder_path):
|
||||
print(f"Error: '{folder_path}' is not a valid directory.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Processing images in: {os.path.abspath(folder_path)}\n")
|
||||
process_images(folder_path)
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
FOLDER=/data/nextcloud/syncuser/pictures/Camera/
|
||||
|
||||
export PYTHONPATH=/home/lucas/scripts
|
||||
syncNC -c
|
||||
/home/lucas/scripts/file\ processing/rename_camera_folder.py ${FOLDER}
|
||||
|
||||
syncNC -c
|
||||
Executable
+227
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from serverlibary import safe_rename,safe_delete
|
||||
|
||||
VIDEO_EXTENSIONS = {".mpg", ".avi", ".mkv", ".mp4", ".m4v", ".srt"}
|
||||
|
||||
UNWANTED_PATTERNS_POST = [
|
||||
r"\d{2,3}k", r"MULTi", r"TV\ Series", r"[a-z]264", r"10bit", r"\[.*?\]",
|
||||
r"320kbps", r"AC3", r"NF\.WEB", r"bdrip", r"RERIP",
|
||||
r"DUAL-", r"LostFilm", r"readnfo", r"BluRay",
|
||||
r"720p", r"1080p", r"WEB", r"AMZN", r"HDTV",
|
||||
r"DVD", r"BDRip", r"HDRip", r"REPACK", r"XviD", r"ETHEL", f"DL ", f"HEVC"
|
||||
]
|
||||
|
||||
UNWANTED_PATTERNS_PRE = [
|
||||
r"www.UIndex.org", r"\[TorrentCounter\.to\]",
|
||||
r"www.Torrenting.org", r"www.Torrenting.com"
|
||||
]
|
||||
|
||||
GARBAGE_PATTERNS = [
|
||||
r"Downloaded From.*", r"www\.YTS.*", r"YTS.*txt", r"YTS.*jp*g" , r".*\.nfo", r"YTSY.*", r"RARBG.*", r".*YIFY.*\.jpg", f"Torrent Downloaded From.*txt", "Screens"
|
||||
]
|
||||
|
||||
DAMAGE_PATTERNS = [
|
||||
(r"\.\.", "."),
|
||||
(r"__", "_"),
|
||||
(r"\s+", " "),
|
||||
]
|
||||
|
||||
|
||||
def iter_media_files(base: Path):
|
||||
if base.is_file():
|
||||
yield base
|
||||
for path in base.rglob("*"):
|
||||
if path.is_file() and path.suffix.lower() in VIDEO_EXTENSIONS:
|
||||
yield path
|
||||
|
||||
def clean_name(name: Path, search=None, replace=None):
|
||||
if name.is_file():
|
||||
base, ext = os.path.splitext(name.name)
|
||||
else:
|
||||
base = name.name
|
||||
ext = ""
|
||||
#base = base.replace(" ", ".")
|
||||
base = re.sub(r"s(\d{2})e", r"S\1E", base, flags=re.IGNORECASE)
|
||||
|
||||
for pattern in UNWANTED_PATTERNS_PRE:
|
||||
base = re.sub(rf"{pattern}[^a-zA-Z0-9]*", "", base, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
base_new = base
|
||||
for pattern in UNWANTED_PATTERNS_POST:
|
||||
base_new = re.sub(rf"{pattern}.*$", "", base_new, flags=re.IGNORECASE)
|
||||
|
||||
if len(base_new) > 5:
|
||||
base = base_new
|
||||
|
||||
if search and replace:
|
||||
base = re.sub(search, replace, base)
|
||||
|
||||
# Remove all non-word characters at the end of the string
|
||||
base = re.sub(r'[^A-Za-z0-9)]+$', '', base)
|
||||
base = re.sub(r"\.+", ".", base)
|
||||
base = re.sub(r" +", " ", base)
|
||||
#base = re.sub(r" ", ".", base)
|
||||
|
||||
|
||||
base = base.strip(".")
|
||||
return base + ext
|
||||
|
||||
def capitalize_name(name: str):
|
||||
return re.sub(
|
||||
r"(^|[ ._\-])([a-z])",
|
||||
lambda m: m.group(1) + m.group(2).upper(),
|
||||
name.lower()
|
||||
)
|
||||
|
||||
# -----------------------------
|
||||
# Operations
|
||||
# -----------------------------
|
||||
|
||||
def rename_files(base: Path, args):
|
||||
for file in iter_media_files(base):
|
||||
new_name = clean_name(file, args.search, args.replace)
|
||||
|
||||
if args.capitalize:
|
||||
new_name = capitalize_name(new_name)
|
||||
|
||||
new_path = file.with_name(new_name)
|
||||
safe_rename(file, new_path, args.dryrun, args.confirm)
|
||||
|
||||
def rename_directories(base: Path, args):
|
||||
# reverse order → avoid renaming parent first
|
||||
paths = [base] + list(base.rglob("*"))
|
||||
new_base = base
|
||||
if base.is_dir():
|
||||
new_base = clean_name(base, args.search, args.replace)
|
||||
if args.capitalize:
|
||||
new_base = capitalize_name(new_base)
|
||||
new_base = base.with_name(new_base)
|
||||
|
||||
for path in sorted(paths, reverse=True):
|
||||
if not path.is_dir():
|
||||
continue
|
||||
new_name = clean_name(path, args.search, args.replace)
|
||||
|
||||
if args.capitalize:
|
||||
new_name = capitalize_name(new_name)
|
||||
|
||||
new_path = path.with_name(new_name)
|
||||
safe_rename(path, new_path, args.dryrun, args.confirm)
|
||||
return new_base
|
||||
|
||||
def repair_names(base: Path, args):
|
||||
for file in iter_media_files(base):
|
||||
new_name = file.name
|
||||
|
||||
for pattern, repl in DAMAGE_PATTERNS:
|
||||
new_name = re.sub(pattern, repl, new_name)
|
||||
|
||||
new_path = file.with_name(new_name)
|
||||
safe_rename(file, new_path, args.dryrun, args.confirm)
|
||||
|
||||
def delete_garbage(base: Path, args):
|
||||
for path in base.rglob("*"):
|
||||
for pattern in GARBAGE_PATTERNS:
|
||||
if re.match(pattern, path.name, re.IGNORECASE):
|
||||
print(f"Deleting: {path}")
|
||||
if not args.dryrun:
|
||||
safe_delete(path)
|
||||
|
||||
# -----------------------------
|
||||
# CLI
|
||||
# -----------------------------
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Media renamer tool")
|
||||
|
||||
parser.add_argument("-p","--path", default=".", help="Target directory")
|
||||
parser.add_argument("-rep","--repair", action="store_true", help="Fix filenames")
|
||||
parser.add_argument("-d","--delete", dest="delete", action="store_true", help="Delete junk files")
|
||||
parser.add_argument("-cap","--capitalize", dest="capitalize", action="store_true", help="Capitalize names")
|
||||
|
||||
parser.add_argument("-r","--replace", nargs=2, metavar=("SEARCH", "REPLACE"))
|
||||
|
||||
parser.add_argument("-dr","--dryrun", action="store_true", help="Dry run")
|
||||
parser.add_argument("-c","--confirm", action="store_true", help="Confirm each rename")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
if args.replace:
|
||||
args.search = args.replace
|
||||
else:
|
||||
args.search = args.replace = None
|
||||
|
||||
base = Path(args.path).resolve()
|
||||
|
||||
if not base.exists():
|
||||
print("Invalid path")
|
||||
return
|
||||
|
||||
home = Path.home()
|
||||
|
||||
if base == home or home in base.parents:
|
||||
answer = input(
|
||||
f"You are about to run on your home directory:\n"
|
||||
f" {base}\n\n"
|
||||
"This may process many files. Continue? [y/N]: "
|
||||
).strip().lower()
|
||||
|
||||
if answer not in ("y", "yes"):
|
||||
print("Aborted.")
|
||||
sys.exit(1)
|
||||
|
||||
#video_files = []
|
||||
#for file in iter_media_files(base):
|
||||
# print(file)
|
||||
# video_files.append(file)
|
||||
#
|
||||
#if len(video_files) == 0:
|
||||
# print(f"Error: No media files found in {base}")
|
||||
# sys.exit(1)
|
||||
#
|
||||
#for f in video_files:
|
||||
# p = Path(f).resolve()
|
||||
#
|
||||
# # skip files not inside base
|
||||
# try:
|
||||
# rel = p.relative_to(base)
|
||||
# except ValueError:
|
||||
# continue
|
||||
#
|
||||
# # rel.parts includes directories + filename
|
||||
# # depth 0: (file directly in base) -> len(parts) == 1
|
||||
# # depth 1: base/sub/file -> len(parts) == 2
|
||||
# if len(rel.parts) <= 2:
|
||||
# raise ValueError(f"Invalid file location: {p} (inside base or depth 1 subdir)")
|
||||
#
|
||||
# 1. fix broken names first (optional but recommended)
|
||||
if args.repair:
|
||||
print(f"Repair names")
|
||||
repair_names(base, args)
|
||||
|
||||
# 2. rename directories FIRST (important for path stability)
|
||||
print(f"Rename directories: {base}")
|
||||
base = rename_directories(base, args)
|
||||
|
||||
# 3. rename files AFTER
|
||||
print(f"Rename files {base}")
|
||||
rename_files(base, args)
|
||||
|
||||
# 4. cleanup
|
||||
if args.delete:
|
||||
delete_garbage(base, args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+396
@@ -0,0 +1,396 @@
|
||||
#!/bin/bash
|
||||
SR=false
|
||||
CONFIRM=false
|
||||
DRY_RUN=false
|
||||
REPAIR_ONLY=false
|
||||
FILES_ONLY=false
|
||||
DIR_ONLY=false
|
||||
DELETE=false
|
||||
CAPITALIZE=false
|
||||
GOTO_PATH=false
|
||||
FILE_PATH=false
|
||||
FILE=""
|
||||
container=("mpg" "avi" "mkv" "mp4" "m4v" "srt")
|
||||
DAMAGE=("\.\." "-\." "\.-" "\(\." "\.\." "-" "_" "\.\[" "\.\(" " " "\[" " \." "\]" "(" "(\.")
|
||||
unwanted_filename_parts=("TV\ Series" "x264" "Complete" "10bit" "\[.*\]" "320kbps" "WS" "AC3" "iNT" "NF\.WEB" "bdrip" "RERIP" "DUAL-" "(ENG" "\[320\]" "rus.eng" "LostFilm" "readnfo" "800p" "BluRay" "Jasprr" "KORSUB" "576p" "720p" "1080p" "1080P" "720P" "WEB" "AMZN" "internal" "iNTERNAL" "HDTV" "KILLERS" "web" "hdtv" "REAL" "DVD" "dvd" "PDTV" "PROPER" "BDRip" "HDRip" "DvD" "480" "INTERNAL" "REPACK" "\[m00tv\]" "\[VFUA\]" "\[PiXTV\]" "\[GOTHiC\]" "\[RiVER\]" "EXTENDED" "SWESUB" "DVB" "XviD" "\[FoV\]" "repack" "BRRip" "UEE" "BrRip" "brrip" "\[SubRip" "UNRATED" "Directors Cut")
|
||||
KNOWN_SHIT_FILES=("www\.YTS*" "Torrent downloaded*\.txt" "Read Me.txt" "WWW.YTS.RE.jpg" "*\.nfo" "RARBG\.com\.txt" "RARBG\.txt" "RARBG\.COM*" "WWW\.YIFY-TORRENTS\.COM\.jpg" "RARBG_DO_NOT_MIRROR\.exe" "Uploaded\ by*")
|
||||
get_config() {
|
||||
while [[ ${1:0:1} == - ]]; do
|
||||
echo "Param: $1"
|
||||
[[ $1 == -r ]] && {
|
||||
SR=true
|
||||
if [ "$2" == "" ] || [ "$3" == "" ]; then echo "Too few arguments"; usage; exit; fi
|
||||
search="$2"
|
||||
replace="$3"
|
||||
shift 3;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -path ]] && {
|
||||
GOTO_PATH=true
|
||||
if [ "$2" == "" ] ; then echo "Too few arguments"; usage; exit; fi
|
||||
GOTO="$2"
|
||||
if [ ! -d "${GOTO}" ]; then
|
||||
echo "${GOTO} no valid Path"
|
||||
exit 1;
|
||||
fi
|
||||
shift 2;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -file ]] && {
|
||||
FILE_PATH=true
|
||||
if [ "$2" == "" ] ; then echo "Too few arguments"; usage; exit; fi
|
||||
FILE="$2"
|
||||
if [ ! -f "${FILE}" ]; then
|
||||
echo "${FILE} no valid File"
|
||||
exit 1;
|
||||
fi
|
||||
shift 2;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -help ]] && {
|
||||
usage;
|
||||
exit;
|
||||
};
|
||||
[[ $1 == -cap ]] && {
|
||||
CAPITALIZE=true
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -conf ]] && {
|
||||
CONFIRM=true
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -dry ]] && {
|
||||
DRY_RUN=true;
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -dir ]] && {
|
||||
DIR_ONLY=true;
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -files ]] && {
|
||||
FILES_ONLY=true;
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -repair ]] && {
|
||||
REPAIR_ONLY=true;
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
[[ $1 == -l ]] && {
|
||||
find . -name "*${DAM}mkv" -o -name "*${DAM}mp4" -o -name "*${DAM}avi" -o -name "*${DAM}m4v" -o -name "*${DAM}srt"
|
||||
exit 0;
|
||||
};
|
||||
[[ $1 == -del ]] && {
|
||||
DELETE=true;
|
||||
shift 1;
|
||||
continue;
|
||||
};
|
||||
echo "Parameter $1 discarded"
|
||||
usage
|
||||
exit
|
||||
done
|
||||
}
|
||||
usage() {
|
||||
printf "Usage:
|
||||
-r <search> <replace>\tSearch/Replace Phrase
|
||||
-conf\t\tConfirm before moving
|
||||
-dry\t\tOnly perform a Dry Run
|
||||
-files\t\tRename Files in Parh(.)
|
||||
-file <file>\tRename single File
|
||||
-dir\t\tRename Directories
|
||||
-path <path>\tDefine Searchdirectory(Default .)
|
||||
-repair\t\tRepair broken Filenames
|
||||
-del\t\tDelete Garbage Torrent add files
|
||||
-l\t\tList Files
|
||||
-help\t\tDisplay this\n"
|
||||
}
|
||||
capitalize() {
|
||||
|
||||
if [[ "$GOTO_PATH" == "true" ]]; then
|
||||
dir="${PWD##*/}"
|
||||
parent="${PWD%/*}"
|
||||
fi
|
||||
echo $dir
|
||||
echo "Capitalze Files"
|
||||
IFS=$'\n'; set -f
|
||||
FILE_ARR=()
|
||||
if [ "$1" == "" ]; then
|
||||
IFS=$'\n'; set -f
|
||||
for cont in ${container[@]}; do
|
||||
FILE_ARR=("${FILE_ARR[@]}" $(find . -type f -name "*${cont}"))
|
||||
done
|
||||
else
|
||||
FILE_ARR=("$1")
|
||||
fi
|
||||
FILE_ARR+=("$dir")
|
||||
SEP='[ 0123456789/.,\-_:;#$&()]'
|
||||
for f in "${FILE_ARR[@]}"; do
|
||||
dir=$(dirname -- "$f")
|
||||
filename=$(basename -- "$f")
|
||||
|
||||
# ---- function to capitalize a name ----
|
||||
capitalize() {
|
||||
local name="$1"
|
||||
|
||||
# lowercase
|
||||
name=$(echo "$name" | sed 's/[A-Z]/\L&/g')
|
||||
|
||||
# capitalize first letter
|
||||
name=$(echo "$name" | sed -E 's/^([a-z])/\u\1/')
|
||||
|
||||
# capitalize after separators
|
||||
name=$(echo "$name" | sed -E "s@(${SEP})([a-z])@\1\u\2@g")
|
||||
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
# ---- process directories ----
|
||||
new_dir=""
|
||||
IFS='/' read -ra parts <<< "$dir"
|
||||
|
||||
# Preserve absolute paths
|
||||
if [[ "$dir" == /* ]]; then
|
||||
new_dir="/"
|
||||
fi
|
||||
|
||||
for part in "${parts[@]}"; do
|
||||
# Skip empty parts and "."
|
||||
[[ -z "$part" || "$part" == "." ]] && continue
|
||||
|
||||
cap_part=$(capitalize "$part")
|
||||
|
||||
if [[ "$new_dir" == "" || "$new_dir" == "/" ]]; then
|
||||
new_dir="${new_dir}${cap_part}"
|
||||
else
|
||||
new_dir="$new_dir/$cap_part"
|
||||
fi
|
||||
done
|
||||
# ---- process filename ----
|
||||
if [[ "$filename" == *.* ]]; then
|
||||
base="${filename%.*}"
|
||||
ext="${filename##*.}"
|
||||
new_base=$(capitalize "$base")
|
||||
new_filename="$new_base.$ext"
|
||||
else
|
||||
new_filename=$(capitalize "$filename")
|
||||
fi
|
||||
|
||||
# ---- build paths ----
|
||||
old_path="${f#./}"
|
||||
new_path="$new_dir/$new_filename"
|
||||
|
||||
# ---- create directories if needed ----
|
||||
mkdir -p -- "$new_dir"
|
||||
|
||||
# ---- move if different ----
|
||||
if [[ "$old_path" != "$new_path" ]]; then
|
||||
echo "$old_path -> $new_path"
|
||||
if [[ "$old_path" == "${PWD##*/}" ]]; then
|
||||
mv -- "../$old_path" "../$new_path"
|
||||
cd "../$new_path"
|
||||
else
|
||||
mv -- "$old_path" "$new_path"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
repair_damage() {
|
||||
IFS=$'\n'; set -f
|
||||
for DAM in ${DAMAGE[@]}; do
|
||||
echo "Damage: ${DAM}"
|
||||
for file_orig in $(find . -name "*${DAM}mkv" -o -name "*${DAM}mp4" -o -name "*${DAM}avi" -o -name "*${DAM}m4v" -o -name "*${DAM}srt"); do
|
||||
file_path=$(echo ${file_orig} | rev | cut -f2- -d'/' | rev)
|
||||
file="$(echo $file_orig | rev | cut -f1 -d'/' | rev | sed 's/'"${DAM}"'srt/.srt/g' | sed 's/'"${DAM}"'avi/.avi/g'| sed 's/'"${DAM}"'mkv/.mkv/g' | sed 's/'"${DAM}"'mp4/.mp4/g')"
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
mv "${file_orig}" "${file_path}/${file}"
|
||||
done
|
||||
done
|
||||
DAM=(" " "\.\." "__" "\[pseudo\]\.")
|
||||
COR=(" " "\." "_" "")
|
||||
for ((i = 0 ; i < ${#DAM[@]} ; i++)); do
|
||||
echo "Damage: ${DAM[$i]}"
|
||||
for file_orig in $(find . -name "*.mkv" -o -name "*.mp4" -o -name "*.avi" -o -name "*.m4v" -o -name "*.srt" | grep "${DAM[$i]}"); do
|
||||
file_path=$(echo ${file_orig} | rev | cut -f2- -d'/' | rev)
|
||||
file="$(echo ${file_orig} | rev | cut -f1 -d'/' | rev | sed 's/'"${DAM[$i]}"'/'"${COR[$i]}"'/g')"
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
mv "${file_orig}" "${file_path}/${file}"
|
||||
done
|
||||
done
|
||||
for ((i = 0 ; i < ${#DAM[@]} ; i++)); do
|
||||
echo "Damage: ${DAM[$i]}"
|
||||
for file_orig in $(find . -type d | grep "${DAM[$i]}"); do
|
||||
file_path=$(echo ${file_orig} | rev | cut -f2- -d'/' | rev)
|
||||
file="$(echo ${file_orig} | rev | cut -f1 -d'/' | rev | sed 's/'"${DAM[$i]}"'/'"${COR[$i]}"'/g')"
|
||||
if [ "$(find ${file_path}/${file} -name *mkv -o -name *mp4 -o -name *avi)" == "" ]; then
|
||||
echo "${file_path}/${file} is no Media Directory"
|
||||
continue
|
||||
fi
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
mv "${file_orig}" "${file_path}/${file}"
|
||||
done
|
||||
done
|
||||
unset IFS; set +f
|
||||
}
|
||||
rename_files() {
|
||||
echo "Rename Files"
|
||||
IFS=$'\n'; set -f
|
||||
FILE_ARR=()
|
||||
if [ "$1" == "" ]; then
|
||||
IFS=$'\n'; set -f
|
||||
for cont in ${container[@]}; do
|
||||
FILE_ARR=("${FILE_ARR[@]}" $(find . -type f -name "*${cont}"))
|
||||
done
|
||||
else
|
||||
FILE_ARR=("$1")
|
||||
fi
|
||||
# echo ${FILE_ARR[*]}
|
||||
# echo "Rename?"
|
||||
# if [ "$ans" != "y" ]; then
|
||||
# exit
|
||||
# fi
|
||||
|
||||
i=0
|
||||
for file_orig in ${FILE_ARR[@]}; do
|
||||
file=$(echo ${file_orig} | rev | cut -f1 -d'/' | rev)
|
||||
file="$(echo "$file" | sed 's/ /./g')"
|
||||
file="$(echo "$file" | sed 's/s\([0-9]\{2\}\)e/S\1E/g')"
|
||||
file_path=$(echo ${file_orig} | rev | cut -f2- -d'/' | rev)
|
||||
for cont in ${container[@]}; do
|
||||
for part in ${unwanted_filename_parts[@]}; do
|
||||
file_new="$(echo "$file" | sed "s/${part}.*\.${cont}/\.${cont}/g")"
|
||||
if [ ${#file_new} -gt 10 ]; then
|
||||
file=${file_new}
|
||||
else
|
||||
echo "Filename without unwanted part too short: $file, $part"
|
||||
file_new="$(echo "$file" | sed "s/${part}//g")"
|
||||
if [ ${#file_new} -gt 10 ]; then
|
||||
file=${file_new}
|
||||
else
|
||||
echo "Filename without unwanted part too short: $file, $part"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
if [ "${file:0:1}" == '.' ]; then
|
||||
file=${file:1:${#file}}
|
||||
fi
|
||||
if [ "${SR}" == "true" ] && [ "${search}" != "" ] && [ "${replace}" != "" ]; then
|
||||
file="$(echo "$file" | sed "s/${search}/${replace}/g")"
|
||||
fi
|
||||
if [ "${file_orig}" != "${file_path}/${file}" ]; then
|
||||
if [ "${DRY_RUN}" == "false" ]; then
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
if [ "${CONFIRM}" == "true" ]; then
|
||||
read
|
||||
fi
|
||||
mv -i "${file_orig}" "${file_path}/${file}"
|
||||
else
|
||||
echo "Dry rename ${file_orig} ${file_path}/${file}"
|
||||
fi
|
||||
fi
|
||||
((i++))
|
||||
STR="$i/${#FILE_ARR[@]}"
|
||||
printf "%s" "${STR}"
|
||||
echo -en "\033[${#STR}D"
|
||||
done
|
||||
unset IFS; set +f
|
||||
}
|
||||
rename_directories() {
|
||||
echo "Rename Directories"
|
||||
|
||||
IFS=$'\n'; set -f
|
||||
if [ "$1" == "" ]; then
|
||||
FILE_ARR=($(find . -type d))
|
||||
else
|
||||
FILE_ARR=($(find "$1" -type d))
|
||||
fi
|
||||
i=0
|
||||
if [[ "$GOTO_PATH" == "true" ]]; then
|
||||
dir="${PWD/}"
|
||||
FILE_ARR+=("$dir")
|
||||
fi
|
||||
#echo "Rename?"
|
||||
#read -n 10 ans
|
||||
#if [ "$ans" != "y" ]; then
|
||||
# exit
|
||||
#fi
|
||||
for file_orig in ${FILE_ARR[*]}; do
|
||||
if [ "${file_orig}" == '.' ]; then
|
||||
continue
|
||||
fi
|
||||
echo ${file_orig}
|
||||
file="$(echo ${file_orig} | rev | cut -f1 -d'/' | rev)"
|
||||
file="$(echo "$file" | sed 's/\./ /g')"
|
||||
file_path=$(echo ${file_orig} | rev | cut -f2- -d'/' | rev)
|
||||
for part in ${unwanted_filename_parts[@]}; do
|
||||
file="$(echo "$file" | sed "s/${part}//g")"
|
||||
done
|
||||
if [ "${SR}" == "true" ] && [ "${search}" != "" ] && [ "${replace}" != "" ]; then
|
||||
file="$(echo "$file" | sed "s/${search}/${replace}/g")"
|
||||
fi
|
||||
if [[ "${file:${#file}-1:1}" == " " ]] || [[ "${file:${#file}-1:1}" == '.' ]]; then
|
||||
file="${file:0:${#file}-1}"
|
||||
fi
|
||||
if [ "${file:0:1}" == ' ' ]; then
|
||||
file=${file:1:${#file}}
|
||||
fi
|
||||
if [ "${file_orig}" != "${file_path}/${file}" ]; then
|
||||
if [ "${DRY_RUN}" == "false" ]; then
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
if [ "${CONFIRM}" == "true" ]; then
|
||||
read
|
||||
fi
|
||||
mv "${file_orig}" "${file_path}/${file}"
|
||||
if [[ "${file_orig}" == "${PWD}" ]]; then
|
||||
cd "${file_path}/${file}"
|
||||
fi
|
||||
else
|
||||
echo "${file_orig} ${file_path}/${file}"
|
||||
fi
|
||||
fi
|
||||
((i++))
|
||||
STR="$i/${#FILE_ARR[@]}"
|
||||
printf "%s" "${STR}"
|
||||
echo -en "\033[${#STR}D"
|
||||
done
|
||||
unset IFS; set +f
|
||||
}
|
||||
delete_shit() {
|
||||
IFS=$'\n'; set -f
|
||||
for shit in ${KNOWN_SHIT_FILES[@]}; do
|
||||
printf "Shit: %s\n" "${shit}"
|
||||
find . -name "${shit}"
|
||||
find . -name "${shit}" -exec rm {} \;
|
||||
done
|
||||
}
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "At least 1 Argument needed"
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
get_config "$@"
|
||||
if [ "${GOTO_PATH}" == "true" ]; then
|
||||
cd "${GOTO}"
|
||||
fi
|
||||
if [ "${DIR_ONLY}" == "true" ]; then
|
||||
rename_directories "${GOTO}"
|
||||
fi
|
||||
printf "\n"
|
||||
if [ "${FILES_ONLY}" == "true" ]; then
|
||||
rename_files "${FILE}"
|
||||
fi
|
||||
printf "\n"
|
||||
if [ "${REPAIR_ONLY}" == "true" ]; then
|
||||
repair_damage
|
||||
fi
|
||||
if [ "${CAPITALIZE}" == "true" ]; then
|
||||
capitalize
|
||||
fi
|
||||
if [ "${DELETE}" == "true" ]; then
|
||||
delete_shit
|
||||
fi
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
FOLDER=/data/nextcloud/syncuser/Memes
|
||||
|
||||
syncNC -m
|
||||
for IMG_ORIG in ${FOLDER}/*; do
|
||||
if [[ "$(echo ${IMG_ORIG##*/} | grep "-")" != "" ]] || [[ "$(echo ${IMG_ORIG##*/} | grep " ")" != "" ]] ;then
|
||||
mv "${IMG_ORIG}" "$(echo ${IMG_ORIG} | sed 's/-/_/g' | sed 's/ /_/g')"
|
||||
IMG_ORIG="$(echo ${IMG_ORIG} | sed 's/-/_/g' | sed 's/ /_/g')"
|
||||
fi
|
||||
if [[ -f ${IMG_ORIG} ]] ; then
|
||||
IMG_EXT=${IMG_ORIG##*/}
|
||||
IMG=${IMG_EXT%%.*}
|
||||
EXT=${IMG_ORIG##*.}
|
||||
DIR=${IMG_ORIG%/*}
|
||||
if [ "$(echo ${IMG} | grep "MEMES")" == "" ]; then
|
||||
LAST_IDX=$(ls ${FOLDER}/MEMES* | rev | cut -f1 -d'/' | rev | cut -f1 -d'.' | sort | tail -1 | sed 's/MEMES//g')
|
||||
NEW_IDX=$(echo "${LAST_IDX}+1" | bc)
|
||||
mv ${IMG_ORIG} "$(printf "%s/MEMES%04d.%s" ${DIR} ${NEW_IDX} ${EXT})"
|
||||
IMG_ORIG="$(printf "%s/MEMES%04d.%s" ${DIR} ${NEW_IDX} ${EXT})"
|
||||
IMG_EXT=${IMG_ORIG##*/}
|
||||
IMG=${IMG_EXT%%.*}
|
||||
EXT=${IMG_ORIG##*.}
|
||||
fi
|
||||
if [ "$(echo ${EXT} | grep "webp")" != "" ]; then
|
||||
echo Pic: $IMG
|
||||
convert ${IMG_ORIG} $(echo ${IMG_ORIG} | sed 's/webp/jpg/g')
|
||||
rm ${IMG_ORIG}
|
||||
elif [ "$(echo ${EXT} | grep "png")" != "" ]; then
|
||||
echo Pic: $IMG
|
||||
convert ${IMG_ORIG} $(echo ${IMG_ORIG} | sed 's/png/jpg/g')
|
||||
rm ${IMG_ORIG}
|
||||
elif [ "$(echo ${EXT} | grep "webm")" != "" ]; then
|
||||
echo Vid: $IMG
|
||||
ffmpeg -y -i ${IMG_ORIG} $(echo ${IMG_ORIG} | sed 's/webm/mp4/g')
|
||||
rm ${IMG_ORIG}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
syncNC -m
|
||||
echo Fin
|
||||
Reference in new issue
Block a user