commit b95395bd04289616e9ebe4d066d34967bd2287ff Author: ronny abraham Date: Mon May 12 02:50:58 2025 +0300 update diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce66825 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Created by https://www.toptal.com/developers/gitignore/api/vim +# Edit at https://www.toptal.com/developers/gitignore?templates=vim + +# Sphinx build output +/docs/build/ + +# Optional extras +docs/source/_build/ +docs/source/*.mo + + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# End of https://www.toptal.com/developers/gitignore/api/vim diff --git a/convert_dir.sh b/convert_dir.sh new file mode 100644 index 0000000..de01278 --- /dev/null +++ b/convert_dir.sh @@ -0,0 +1,167 @@ +#!/bin/bash + +debug() { echo "๐Ÿ› ๏ธ DEBUG: $*" >&2; } + +# Convert .avi and .mkv files to .mp4 +# Supports --dry-run to simulate actions +# --source is required; --archive is optional + +set -euo pipefail + +# --- Defaults --- +DRY_RUN=false +DEBUG=false +SRC_DIR="" +ARCHIVE_DIR="" +LOG_FILE="log.convert" +QUALITY="23" + +SRC_TYPES=() + +# --- Help Message --- +show_help() { + echo "Usage: $0 --source [--archive ] [--quality ] [--dry-run] [--debug]" + echo + echo " --source Directory to scan for .avi and .mkv files" + echo " --archive Directory to move originals after conversion (optional)" + echo " If omitted, originals will be deleted" + echo " --quality Quality of the video 18-28 (18 is high quality, 23 is default, 28 is low)" + echo " --dry-run Show actions without performing them" + echo " --debug Output debug statements" + echo + exit 1 +} + +# --- Parse Arguments --- +while [[ $# -gt 0 ]]; do + case "$1" in + --source) + SRC_DIR="$(realpath "$2")" + shift 2 + ;; + --archive) + ARCHIVE_DIR="$(realpath "$2")" + shift 2 + ;; + --dry-run) + DRY_RUN=true + shift + ;; + --debug) + DEBUG=true + shift + ;; + --src-type) + SRC_TYPES+=("${2,,}") # normalize to lowercase + shift -2 + ;; + --help|-h) + show_help + ;; + --quality) + QUALITY="$2" + if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || ((QUALITY < 18 || QUALITY > 28)); then + echo "โŒ Error: --quality must be an integer between 18 and 28." >&2 + exit 1 + fi + shift 2 + ;; + *) + echo "Unknown option: $1" + show_help + ;; + esac +done + +if [[ "${#SRC_TYPES[@]}" -eq 0 ]]; then + SRC_TYPES=("avi" "mkv") # default id none specified +fi + +# --- Validate Source Directory --- +if [[ -z "$SRC_DIR" ]]; then + echo "โŒ Error: --source is required." >&2 + show_help +fi + +if [[ ! -d "$SRC_DIR" ]]; then + echo "โŒ Error: Source directory does not exist: $SRC_DIR" >&2 + exit 1 +fi + +echo "๐Ÿ” Scanning: $SRC_DIR" +$DRY_RUN && echo "๐Ÿงช Dry-run mode enabled" + +# --- Gather file list once --- +mapfile -d '' FILE_LIST < <(find "$SRC_DIR" \( -iname '*.avi' -o -iname '*.mkv' \) -print0) + +# --- Preview list if in debug mode --- +if [[ "${DEBUG:-false}" == "true" ]]; then + echo "๐Ÿ—‚๏ธ DEBUG: File list to process:" + for file in "${FILE_LIST[@]}"; do + echo " - $file" + done +fi + + +# --- Find and Process Files --- +# Using process substitution instead of a pipe, so the while loop runs in the current shell +for src_file in "${FILE_LIST[@]}"; do + # abs_src_file="$(realpath "$src_file")" + # rel_path="${abs_src_file#$SRC_DIR/}" + + # Use absolute path If the source file path is not absolute + # (doesn't start with '/'), prepend the source directory to + # make it an absolute path. + [[ "$src_file" != /* ]] && src_file="$SRC_DIR/$src_file" + + rel_path="${src_file#$SRC_DIR/}" + + base_name="${rel_path%.*}" + dst_file="$SRC_DIR/$base_name.mp4" + + echo "โ–ถ๏ธ Converting: $rel_path" + + if $DRY_RUN; then + echo " [dry-run] Would convert to: $dst_file" + [[ -n "$ARCHIVE_DIR" ]] && echo " [dry-run] Would move original to: $ARCHIVE_DIR/$rel_path" || echo " [dry-run] Would delete original" + continue + fi + + # Create output directory if needed + mkdir -p "$(dirname "$dst_file")" + + if [[ "${DEBUG:-false}" == "true" ]]; then + debug "dirname dst_file: $(dirname "$dst_file")" + debug "src_file: $src_file" + # debug "abs_src_file: $abs_src_file" + debug "rel_path: $rel_path" + debug "base_name: $base_name" + debug "dst_file: $dst_file" + debug "" + debug "command:" + debug "ffmpeg -i \"$src_file\" -c:v libx264 -preset slow -crf $QUALITY -c:a aac -b:a 128k -movflags +faststart \"$dst_file\" -y >> $LOG_FILE 2>&1" + fi + + # Convert video with ffmpeg and log output + ffmpeg \ + -i "$src_file" \ + -c:v libx264 \ + -preset slow \ + -crf "$QUALITY" \ + -c:a aac \ + -b:a 128k \ + -movflags +faststart \ + "$dst_file" \ + -y >> "$LOG_FILE" 2>&1 + + # Archive or delete original + if [[ -n "$ARCHIVE_DIR" ]]; then + archive_file="$ARCHIVE_DIR/$rel_path" + mkdir -p "$(dirname "$archive_file")" + mv "$src_file" "$archive_file" + else + rm "$src_file" + fi +done + +echo "โœ… Done." diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..747ffb7 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..3f2e482 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,28 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'convert-dirs' +copyright = '2025, Ronny Abraham' +author = 'Ronny Abraham' +release = '1.0.0' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [] + +templates_path = ['_templates'] +exclude_patterns = [] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'alabaster' +html_static_path = ['_static'] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..2141c0e --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,25 @@ +.. convert-dirs documentation master file, created by + sphinx-quickstart on Mon May 12 02:16:34 2025. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to convert-dirs's documentation! +======================================== + +A Bash script to batch convert `.avi`, `.mkv`, etc. to `.mp4` using ffmpeg. + +Contents: + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + usage + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 0000000..4c8a27b --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,26 @@ +Usage Guide +=========== + +Example: + +.. code-block:: bash + + ./convert-dirs.sh --source ./tv \ + --src-type avi \ + --src-type mkv \ + --quality 23 \ + --dry-run + +Options: + +- ``--source``: Directory to scan (required) +- ``--archive``: Where to move originals +- ``--src-type``: File extension to include (repeatable) +- ``--quality``: CRF value for ffmpeg (18 = high, 28 = low) +- ``--dry-run``: Simulate actions +- ``--debug``: Show extra output + +Requirements + +- bash +- ffmpeg