nix/home/program/bash/module/Name.sh

397 lines
8.6 KiB
Bash

# Rename dirs to `snake_case` and files to `PascalCase`. Careful with structured file names like archives!
# Usage: name [FILES]
function name() {
local IFS=$'\n'
local targets=(${@})
[[ ${targets} == "" ]] && targets=($(ls))
process() {
# Skip archive.
if $(_is_archive "${target}"); then
_iterate_skip "File is an archive, skip."
return 0
fi
if [[ -d ${target} ]]; then
local new_name=$(parse_snake ${target})
[[ -e ${new_name} ]] && return 0
mv -- ${target} ${new_name} && echo ${new_name}
else
local ext=".${target##*.}"
local name=${target%.*}
[[ ${ext} == ".${target}" ]] && ext=""
local new_name="$(parse_pascal ${name})${ext}"
[[ -e ${new_name} ]] && return 0
mv -- ${target} ${new_name} && echo ${new_name}
fi
}
_iterate_targets process ${targets[@]}
}
# Rename files with provided parser, i.e. `parse_simple`.
# All files by default.
# Usage: name_parse <PARSER> [FILES]
function name_parse() {
local IFS=$'\n'
local parser=${1}
local targets=(${@:2})
[[ ${targets} == "" ]] && targets=("[^.]*")
if [[ ${parser} == "" ]]; then
help name_parse
return 2
fi
process() {
# Skip archive.
if $(_is_archive "${target}"); then
_iterate_skip "File is an archive, skip."
return 0
fi
# parse new name.
local ext=""
local name="${target}"
# ext only for files.
if [[ -f ${target} ]]; then
ext=".${target##*.}"
name="${target%.*}"
fi
# Files w/o extension support.
[[ ${ext#.} == "${name}" ]] && ext=""
# Get new name.
local new_name=$(${parser} "${name}")${ext,,}
# check if same name.
[[ ${target} == "${new_name}" ]] && return 0
# check if target name already exists.
if [[ -f ${new_name} ]]; then
_error "${new_name}: Already exists!"
return 1
fi
# rename target.
mv -- "${target}" "${new_name}" && echo "${new_name}"
}
_iterate_targets process ${targets[@]}
}
# Rename all files to their hashes while keeping extensions.
# All files by default.
# Usage: name_hash [FILES]
function name_hash() {
local IFS=$'\n'
local targets=(${@})
[[ ${targets} == "" ]] && targets=($(_ls_file))
process() {
# extract extension.
local extension="${target##*.}"
if [[ ${extension} == "${target}" ]]; then
extension=""
else
extension=".${extension}"
fi
# hash the new name.
local hash=$(pv "${target}" | sha1sum | cut -d\ -f1)
new_name="${hash,,}${extension,,}"
# check if same name.
[[ ${target} == "${new_name}" ]] && return 0
# rename target.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Check hashes for previously renamed files.
# All files by default.
# Usage: name_hash_check [FILES]
function name_hash_check() {
local IFS=$'\n'
local targets=(${@})
[[ ${targets} == "" ]] && targets=("[^.]*")
process() {
# extract hashes.
local stored="${target%%.*}"
local actual=$(pv "${target}" | sha1sum | cut -d\ -f1)
# compare hashes.
if [[ ${stored} != "${actual}" ]]; then
_error "Failed."
return 1
fi
}
_iterate_targets process ${targets[@]}
}
# Rename files for Jellyfin shows, i.e. `Episode S01E01.mkv`
# All files by default.
# Usage: name_show [FILES]
function name_show() {
local IFS=$'\n'
local season="$(realpath .)"
season="${season##*\ }"
local episode=0
local targets=(${@})
[[ ${targets} == "" ]] && targets=($(_ls_file))
# Error when no season number specified.
if [[ ${season} == "" ]]; then
_error "Could not determine season number."
return 2
fi
process() {
((episode++))
# extract new name.
local new_name="Episode S${season}E$(printf %02d ${episode}).${target##*.}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# rename target.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Rename files for Kavita manga format.
# All files by default.
# Usage: name_manga <SEASON> [FILES]
function name_manga() {
local IFS=$'\n'
local manga=${PWD##*/}
local season=${1}
local episode=0
local targets=(${@:2})
[[ ${targets} == "" ]] && targets=($(_ls_file))
# Error when no season number specified.
if [[ ${season} == "" ]]; then
help name_manga
return 2
fi
process() {
((episode++))
# Extract new name.
local new_name="${manga} Vol.${season} Ch.${episode}.${target##*.}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# Rename target.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Rename files for ffmpeg_music_meta format.
# All files by default.
# Usage: name_music [FILES]
function name_music() {
local IFS=$'\n'
local targets=(${@})
[[ ${targets} == "" ]] && targets=($(ls))
process() {
# Extract new name.
local ext=${target##*.}
if [[ -d ${target} ]]; then
local new_name="$(parse_startcase $(parse_simple ${target%.*}))"
else
local new_name="$(parse_startcase $(parse_simple ${target%.*})).${ext}"
fi
# Skip on no change.
[[ ${target%/} == "${new_name}" ]] && return 0
# Rename target.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Rename files with new extension.
# All files by default.
# Usage: name_ext <EXTENSION> [FILES]
function name_ext() {
local IFS=$'\n'
local extension=${1}
local targets=(${@:2})
[[ ${targets} == "" ]] && targets=($(_ls_file))
# Error when no new extension specified.
if [[ ${extension} == "" ]]; then
help name_ext
return 2
fi
process() {
# Extract new name.
local new_name="${target%.*}"."${extension}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# Rename target.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Change file name prefix.
# All matching files by default.
# Usage: name_prefix <OLD> <NEW> [FILES]
function name_prefix() {
local IFS=$'\n'
local old=${1}
local new=${2}
local targets=(${@:3})
[[ ${targets} == "" ]] && targets=(${old}*)
process() {
# Create new name.
local new_name="${new}${target#$old}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# Rename.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Change file name postfix.
# All matching files by default.
# Usage: name_postfix <OLD> <NEW> [FILES]
function name_postfix() {
local IFS=$'\n'
local old=${1}
local new=${2}
local targets=(${@:3})
[[ ${targets} == "" ]] && targets=(*${old})
process() {
# Create new name.
local new_name="${target%$old}${new}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# Rename.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Replace part of the name.
# All matching files by default.
# Usage: name_replace <OLD> <NEW> [FILES]
function name_replace() {
local IFS=$'\n'
local old=${1}
local new=${2}
local targets=(${@:3})
[[ ${targets} == "" ]] && targets=(*${old}*)
process() {
# Create new name.
local new_name="${target//$old/$new}"
# Skip on no change.
[[ ${target} == "${new_name}" ]] && return 0
# Rename.
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Fix numbering for numbered files. I.e if there are 10 items and some of them start without zero, then append zero to it. 1..10 -> 01..10.
# Usage: name_fix_numbering [FILES]
function name_fix_numbering() {
local IFS=$'\n'
local highest=0
local power=0
local targets=(${@})
[[ ${targets} == "" ]] && targets=($(ls | grep "^[0-9]"))
# Count leading zeroes.
for target in "${targets[@]}"; do
# Check that starts with a digit.
[[ ${target} =~ ^[0-9] ]] || continue
local digits=($(parse_ints "${target}"))
local digit="${digits[0]}"
digit=$((10#${digit}))
[[ ${digit} -gt ${highest} ]] && highest="${digit}"
done
local i=${highest}
while [[ i -gt 0 ]]; do
((power++))
i=$((i / 10))
done
process() {
# Check that starts with a digit.
if [[ ! ${target} =~ ^[0-9] ]]; then
_error "Does not start with a digit!"
return 1
fi
# Prepare new name.
local digits=($(parse_ints "${target}"))
local digit="${digits[0]}"
digit=$((10#${digit}))
local new_name=$(printf "%0${power}d" "${digit}")"${target#${digits[0]}}"
# Skip if the same name.
[[ ${target} == "${new_name}" ]] && return 0
# Check that file does not exist.
if [[ -e ${new_name} ]]; then
_error "${new_name}: File exists!"
return 1
fi
mv -- ${target} ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
function _comp_name_parse() {
_autocomplete $(find_function | grep ^parse)
}
complete -o filenames -F _comp_name_parse name_parse