xiandie/reuse_uid_to_ogg.sh

250 lines
6.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# ============================================================================
# SCRIPT : reuse_uid_to_ogg.sh (v4.0 - 增强版)
# TASK : 将 *.wav.import / *.mp3.import 的 UID 迁移到对应 *.ogg.import
# 并删除源文件中的 UID 行
# USAGE : DEBUG=1 ./reuse_uid_to_ogg.sh # 调试模式
# DRY_RUN=1 ./reuse_uid_to_ogg.sh # 演练
# ./reuse_uid_to_ogg.sh # 实际写入
# ============================================================================
set -Euo pipefail
[[ ${DEBUG:-0} == 1 ]] && set -x
ROOT_DIR="${ROOT_DIR:-asset/audio}"
DRY_RUN="${DRY_RUN:-0}"
VERBOSE="${VERBOSE:-0}"
MODIFIED=0
SKIPPED=0
ERRORS=0
# ---------- 错误处理 ----------
error_handler() {
local line_no=$1
local error_code=$2
printf "❌ 错误发生在第 %s 行,错误代码: %s\n" "$line_no" "$error_code" >&2
printf " 最后处理的文件: %s\n" "${CURRENT_FILE:-未知}" >&2
exit "$error_code"
}
trap 'error_handler ${LINENO} $?' ERR
# ---------- 工具函数 ----------
log() {
[[ $VERBOSE == 1 ]] && echo "[LOG] $*" >&2
}
check_writable() {
local f=$1
if [[ ! -f "$f" ]]; then
printf "❌ 文件不存在:%s\n" "$f" >&2
return 1
fi
if [[ ! -w "$f" ]]; then
printf "❌ 无写权限:%s\n" "$f" >&2
return 1
fi
return 0
}
get_uid() {
local file=$1
local uid=""
if [[ ! -f "$file" ]]; then
log "文件不存在: $file"
return 1
fi
# 提取 UID处理可能的空格和回车
uid=$(awk -F'"' '/^[[:space:]]*uid="uid:\/\// {print $2; exit}' "$file" 2>/dev/null | tr -d '\r\n' || true)
if [[ -n "$uid" ]]; then
echo "$uid"
return 0
else
return 1
fi
}
# ---------- 把 UID 写进 .ogg.import ----------
put_uid() {
local file=$1
local uid=$2
if ! check_writable "$file"; then
((ERRORS++))
return 1
fi
# 统一转义处理
local esc=${uid//\\/\\\\} # 反斜线
esc=${esc//&/\\&} # &
esc=${esc//@/\\@} # @
esc=${esc//\//\\/} # /
if [[ $DRY_RUN == 1 ]]; then
printf " ↪ [演练] 更新 %-30s → %s\n" "$(basename "$file")" "$uid"
return 0
fi
local tmp
if ! tmp=$(mktemp); then
printf "❌ 无法创建临时文件\n" >&2
((ERRORS++))
return 1
fi
# 确保临时文件被清理
trap "rm -f '$tmp'" RETURN
local success=0
if grep -qE '^[[:space:]]*uid="uid://[^"]+"' "$file" 2>/dev/null; then
# 已有 UID → 替换
if sed -E "s@^[[:space:]]*uid=\"uid://[^\"]+\"@uid=\"${esc}\"@" "$file" >"$tmp" 2>/dev/null; then
success=1
fi
else
# 无 UID → 插入
if grep -q '^\[remap\]' "$file" 2>/dev/null; then
if sed -E "/^\[remap\]/a\\
uid=\"${esc}\"
" "$file" >"$tmp" 2>/dev/null; then
success=1
fi
else
if cat "$file" >"$tmp" 2>/dev/null && printf 'uid="%s"\n' "$uid" >>"$tmp" 2>/dev/null; then
success=1
fi
fi
fi
if [[ $success == 1 ]] && mv "$tmp" "$file" 2>/dev/null; then
((MODIFIED++))
log "成功更新 $file"
return 0
else
printf "❌ 更新失败:%s\n" "$file" >&2
((ERRORS++))
return 1
fi
}
# ---------- 删除源文件的 UID 行 ----------
delete_uid_line() {
local file=$1
if ! check_writable "$file"; then
((ERRORS++))
return 1
fi
if [[ $DRY_RUN == 1 ]]; then
printf " ↪ [演练] 删除 %-30s 中的 UID 行\n" "$(basename "$file")"
return 0
fi
local tmp
if ! tmp=$(mktemp); then
printf "❌ 无法创建临时文件\n" >&2
((ERRORS++))
return 1
fi
# 确保临时文件被清理
trap "rm -f '$tmp'" RETURN
if sed -E '/^[[:space:]]*uid="uid:\/\/[^"]+"/d' "$file" >"$tmp" 2>/dev/null && \
mv "$tmp" "$file" 2>/dev/null; then
((MODIFIED++))
log "成功删除 $file 中的 UID"
return 0
else
printf "❌ 删除 UID 失败:%s\n" "$file" >&2
((ERRORS++))
return 1
fi
}
# ---------- 主程序 ----------
main() {
printf "=== 开始 UID 迁移 (DRY_RUN=%s, ROOT_DIR=%s) ===\n" "$DRY_RUN" "$ROOT_DIR"
# 检查根目录
if [[ ! -d "$ROOT_DIR" ]]; then
printf "❌ 目录不存在:%s\n" "$ROOT_DIR" >&2
exit 1
fi
# 使用数组存储文件避免管道子shell问题
local files=()
while IFS= read -r -d '' file; do
files+=("$file")
done < <(find "$ROOT_DIR" -type f \( -name '*.wav.import' -o -name '*.mp3.import' \) -print0 2>/dev/null || true)
if [[ ${#files[@]} -eq 0 ]]; then
printf "未找到任何 .wav.import 或 .mp3.import 文件\n"
exit 0
fi
printf "找到 %d 个源文件\n\n" "${#files[@]}"
# 处理每个文件
for src in "${files[@]}"; do
CURRENT_FILE="$src"
# 获取 UID
local src_uid
if ! src_uid=$(get_uid "$src"); then
printf "🟡 跳过 (无 UID) : %s\n" "$(basename "$src")"
((SKIPPED++))
continue
fi
# 构建对应的 .ogg.import 文件路径
local base="${src%.*.*}"
local ogg="$base.ogg.import"
# 检查 .ogg.import 是否存在
if [[ ! -f "$ogg" ]]; then
printf "🟡 跳过 (无 OGG) : %s\n" "$(basename "$src")"
((SKIPPED++))
continue
fi
# 检查 UID 是否已同步
local ogg_uid
ogg_uid=$(get_uid "$ogg" 2>/dev/null || echo "")
if [[ "$src_uid" == "$ogg_uid" ]]; then
printf "🟢 跳过 (UID 已同步) : %s\n" "$(basename "$src")"
((SKIPPED++))
continue
fi
# 处理文件
printf "🔄 处理 : %s → %s\n" "$(basename "$src")" "$(basename "$ogg")"
if put_uid "$ogg" "$src_uid"; then
delete_uid_line "$src" || true # 即使删除失败也继续
fi
done
# 输出统计
printf "\n=== 处理完毕 ===\n"
if [[ $DRY_RUN == 1 ]]; then
printf "演练模式,未实际修改任何文件。\n"
else
printf "✅ 成功处理: %d 个文件\n" "$((MODIFIED/2))"
printf "🟡 跳过: %d 个文件\n" "$SKIPPED"
if [[ $ERRORS -gt 0 ]]; then
printf "❌ 错误: %d 个\n" "$ERRORS"
fi
fi
return 0
}
# 运行主程序
main "$@"