rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

うちのTV録画ファイル名に番組名を付加する

2025 Nov. 07.

printNewTvVidepFilename.sh

#!/usr/bin/env bash
# 2025 Nov. 07.
# ^20[0-9]{10} または ^2_20[0-9]{10}なファイル名を対象にファイル名に番組名を付加する。

set -euo pipefail
shopt -s nullglob

# VIDEO_DIR='YOUR/VIDEO/DIR'
VIDEO_DIR='/var/usbhdd01/video/'

# rec-inf テキストファイル一覧を先に取得
mapfile -t RECFILES < <(find "$VIDEO_DIR" -type f -name '*rec*inf*.txt' -print)

# 何も無ければ終了
if [ ${#RECFILES[@]} -eq 0 ]; then
  exit 0
fi

# 番組名JPSTR をファイル名に入れて不適切文字を安全化する関数
sanitize_jpstr() {
  local s
  s="$1"
  s=$(printf '%s' "$s" | tr -d '\000')

  s=$(printf '%s' "$s" |
    sed -e 's#\\#\#g' \
        -e 's#/#/#g' \
        -e 's#:#:#g' \
        -e 's#\*#*#g' \
        -e 's#\?#?#g' \
        -e 's#\"#"#g' \
        -e 's#<#<#g' \
        -e 's#>#>#g' \
        -e 's#|#|#g' \
        -e 's#%#%#g' \
        -e "s#'#'#g" \
        -e "s#‘#'#g" \
        -e "s#’#'#g" \
        -e 's#`#`#g' )
  printf '%s' "$s"
}

# 先頭パターン判定関数(stderr 出力対象か)
# true を返すのはファイル名が ^20[0-9]{10} または ^2_20[0-9]{10} に一致する場合
is_stderr_target() {
  local fname="$1"
  case "$fname" in
    20[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]* ) return 0 ;;
    2_20[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]* ) return 0 ;;
    * ) return 1 ;;
  esac
}

# 再帰検索して処理
find "$VIDEO_DIR" -type f \( -iname '*.m2ts' -o -iname '*.ts' -o -iname '*.mp4' \) -print0 |
while IFS= read -r -d '' file; do
  base=$(basename "$file")

  # タイムスタンプ抽出(先頭が 2_ を含む場合も許容)
  ts=$(printf '%s' "$base" | grep -oE '^(2_)?[0-9]{12}' || true)
  if [ -z "$ts" ]; then
    # タイムスタンプ自体が無ければ stderr 出力の対象か判定して、対象なら出力(要件)
    if is_stderr_target "$base"; then
      printf '%s\n' "$file" >&2
    fi
    continue
  fi
  # タイムスタンプの先頭が 2_ の場合は除去して比較用の純粋な 12 桁にする
  ts=${ts#2_}

  # rec-inf の中からタイムスタンプを含む行を探し、ダブルクォート内の文字列を抽出して日本語を含む最初のものを JPSTR とする
  jpstr=''
  for rf in "${RECFILES[@]}"; do
    if grep -a -q -- "$ts" "$rf"; then
      while IFS= read -r candidate; do
        if printf '%s' "$candidate" | grep -Pq '[\p{Han}\p{Hiragana}\p{Katakana}]'; then
          jpstr="$candidate"
          break 2
        fi
      done < <(grep -a -- "$ts" "$rf" | grep -oP '"\K[^"]+(?=")' || true)
    fi
  done

  if [ -z "$jpstr" ]; then
    # JPSTR が見つからなければ、stderr 出力対象のみ stderr に出力
    if is_stderr_target "$base"; then
      printf '%s\n' "$file" >&2
    fi
    continue
  fi

  # JPSTR の先頭/末尾の ASCII と全角のシングル引用符を削除
  # 対象文字: ' (U+0027), ‘ (U+2018), ’ (U+2019), ' (U+FF07)
  jpstr=$(printf '%s' "$jpstr" | sed -e "s/^[\'‘’']\+//" -e "s/[\'‘’']\+\$//")

  # サニタイズして挿入
  safe_jpstr=$(sanitize_jpstr "$jpstr")

  dir=$(dirname "$file")
  name_noext=${base%.*}
  ext=${base##*.}
  newname="${name_noext}${safe_jpstr}.${ext}"
  printf '%s\n' "$dir/$newname"
done

exit 0