#!/usr/bin/env bash
#
# split_videos.sh
#
# 功能：
#   遍历指定文件夹下的视频文件（文件名以 8 位数字 MMDDHHmm 结尾，
#   例如 xxx07091111.mp4），每 110 分钟用 ffmpeg 流复制（-c copy，
#   不重新编码）分割一次，并按“原时间戳 + 110*n 分钟”重新命名分片。
#
#   命名规则示例：
#     原文件: xxx07091111.mp4   (07-09 11:11)
#     第1段:  xxx07091301.mp4   (11:11 + 110min = 13:01)
#     第2段:  xxx07091451.mp4   (13:01 + 110min = 14:51)
#
#   规则细节（已与用户确认）：
#     1. 分割方式：ffmpeg -c copy 流复制，只能在关键帧处切割，
#        时间点可能有几秒误差，不重新编码、不做任何画质/参数处理。
#     2. 分割成功后会删除原始文件。
#     3. 视频总时长本身不足 110 分钟：不分割，文件名保持不变，直接跳过。
#     4. 文件名最后 8 位数字 = MMDDHHmm（月日时分，无年份），
#        前面部分（不管多长、含不含数字）都当作前缀原样保留。
#
# 用法：
#   ./split_videos.sh /path/to/video/folder
#   不传参数则默认处理当前目录
#
# 依赖：ffmpeg, ffprobe
#
set -uo pipefail

SEGMENT_MINUTES=110
SEGMENT_SECONDS=$((SEGMENT_MINUTES * 60))
DUMMY_YEAR=2000   # 仅用于日期加减运算的占位年份（闰年，避免2月29日报错），输出时会被去掉

TARGET_DIR="${1:-.}"

if ! command -v ffmpeg >/dev/null 2>&1; then
    echo "错误: 未找到 ffmpeg，请先安装。" >&2
    exit 1
fi
if ! command -v ffprobe >/dev/null 2>&1; then
    echo "错误: 未找到 ffprobe，请先安装。" >&2
    exit 1
fi

if [[ ! -d "$TARGET_DIR" ]]; then
    echo "错误: 目录不存在: $TARGET_DIR" >&2
    exit 1
fi

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

# 获取视频时长（秒，浮点数）
get_duration() {
    local file="$1"
    ffprobe -v error -show_entries format=duration \
        -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null
}

# 根据原始 MMDDHHmm + 累加分钟数，计算新的 MMDDHHmm 字符串
#
# 注意：这里刻意不用 `date -d "... + N minutes"` 这种“相对时间”写法，
# 因为 busybox date（常见于 OpenWrt / 路由器 / NAS）不支持这种语法，
# 会解析出错乱的结果。改用“先转成 Unix 时间戳，纯数字加减，再转换回去”，
# 兼容 GNU date 和 busybox date。
calc_new_timestamp() {
    local mm="$1" dd="$2" hh="$3" mi="$4" add_minutes="$5"
    local base_epoch new_epoch

    base_epoch="$(date -d "${DUMMY_YEAR}-${mm}-${dd} ${hh}:${mi}:00" +%s 2>/dev/null)"
    if [[ -z "$base_epoch" ]]; then
        return 1
    fi

    new_epoch=$(( base_epoch + add_minutes * 60 ))
    date -d "@${new_epoch}" +"%m%d%H%M" 2>/dev/null
}

shopt -s nullglob

for filepath in "$TARGET_DIR"/*; do
    [[ -f "$filepath" ]] || continue

    filename="$(basename -- "$filepath")"
    ext="${filename##*.}"
    base="${filename%.*}"

    # 需要至少 8 位数字结尾
    if [[ ! "$base" =~ ^(.*)([0-9]{8})$ ]]; then
        continue
    fi

    # 简单判断这是不是视频文件（用ffprobe能读到时长即可，读不到就跳过）
    prefix="${BASH_REMATCH[1]}"
    timestamp="${BASH_REMATCH[2]}"

    mm="${timestamp:0:2}"
    dd="${timestamp:2:2}"
    hh="${timestamp:4:2}"
    mi="${timestamp:6:2}"

    duration="$(get_duration "$filepath")"
    if [[ -z "$duration" ]]; then
        log "跳过（无法读取时长，可能不是视频文件）: $filename"
        continue
    fi

    duration_int="${duration%.*}"

    if (( duration_int <= SEGMENT_SECONDS )); then
        log "跳过（时长不足 ${SEGMENT_MINUTES} 分钟，文件名保持不变）: $filename"
        continue
    fi

    log "开始处理: $filename (时长约 $((duration_int/60)) 分钟)"

    tmpdir="$(mktemp -d)"

    # 用 ffmpeg segment muxer 一次性按时间切割，流复制不重新编码
    if ! ffmpeg -y -v error -i "$filepath" -map 0 -c copy \
        -f segment -segment_time "$SEGMENT_SECONDS" -reset_timestamps 1 \
        "$tmpdir/part_%03d.$ext" </dev/null; then
        log "错误: ffmpeg 分割失败，跳过该文件，原文件保留: $filename"
        rm -rf "$tmpdir"
        continue
    fi

    # 显式排序，确保 part_000, part_001, part_002 ... 严格按顺序处理
    mapfile -t parts < <(printf '%s\n' "$tmpdir"/part_*."$ext" | sort)
    if [[ ${#parts[@]} -eq 0 ]]; then
        log "错误: 未生成任何分片，跳过该文件，原文件保留: $filename"
        rm -rf "$tmpdir"
        continue
    fi

    ok=true
    idx=0
    for part in "${parts[@]}"; do
        if (( idx == 0 )); then
            add_minutes=1
        else
            add_minutes=$(( SEGMENT_MINUTES * idx ))
        fi
        new_ts="$(calc_new_timestamp "$mm" "$dd" "$hh" "$mi" "$add_minutes")"
        if [[ -z "$new_ts" ]]; then
            log "错误: 计算新时间戳失败，终止处理该文件，原文件保留: $filename"
            ok=false
            break
        fi

        new_name="${prefix}${new_ts}.${ext}"
        new_path="$TARGET_DIR/$new_name"
        log "  分片 $((idx+1)): +${add_minutes}分钟 -> $new_name"

        if [[ -e "$new_path" ]]; then
            log "警告: 目标文件已存在，跳过覆盖: $new_name"
            ok=false
            break
        fi

        mv "$part" "$new_path"
        idx=$((idx + 1))
    done

    rm -rf "$tmpdir"

    if [[ "$ok" == true ]]; then
        rm -f "$filepath"
        log "完成，已删除原文件: $filename"
    else
        log "处理未完全成功，原文件保留，请手动检查: $filename"
    fi
done

log "全部处理完成。"
