AI代码 小米门铃 m3u8 解密

背景

这是一个困扰了很久的代码,在几年前处理HA通知时,对于门铃视频的处理一直有些小问题,使用了如下访问

  1. ffmpeg 直接解密,预期是正确的,但实际上只有第一段视频正确输出
  2. 使用 VLC 的 cvlc 命令直接播放录制,这个是我一直使用的方案,但实际效果达不到预期,经常出现卡帧,时间异常的问题

M3U8 文件

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:35
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/file-key.bin",IV=0x40B299BCC42D7D578394D579AE2ED67D
#EXTINF:1.3999
https://example.com/file-01.mp4
#EXT-X-DISCONTINUITY
#EXTINF:4.201
https://example.com/file-02.mp4
#EXT-X-DISCONTINUITY
#EXTINF:0.6499
https://example.com/file-03.mp4
#EXT-X-DISCONTINUITY
#EXT-X-ENDLIST

解决

突然看到这个问题,然后丢给AI, 告知其实现步骤,然后就出现了正确的结果。当然实际调试过程也出现了一些这样那样的问题。

#!/bin/bash

# 初始化清理标记
CLEANUP=1

# 检查输入参数
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
    echo "用法: $0 <m3u8文件路径> [--debug]"
    exit 1
fi

# 解析参数
INPUT_M3U8="$1"
if [ $# -eq 2 ]; then
    if [ "$2" == "--debug" ]; then
        CLEANUP=0
        echo "调试模式已启用,临时文件将保留"
    else
        echo "错误: 第二个参数必须是--debug"
        exit 1
    fi
fi

# 验证输入文件
if [ ! -f "$INPUT_M3U8" ]; then
    echo "错误: 指定的m3u8文件不存在"
    exit 2
fi

# 生成路径信息
INPUT_DIR=$(dirname "$INPUT_M3U8")
BASE_NAME=$(basename "${INPUT_M3U8%.*}")
OUTPUT_MP4="${INPUT_DIR}/${BASE_NAME}.mp4"

# 创建临时目录
declare -g TEMP_DIR DECRYPTED_DIR FIXED_DIR  # 用于trap函数访问
TEMP_DIR="${INPUT_DIR}/temp_${BASE_NAME}_downloads"
DECRYPTED_DIR="${INPUT_DIR}/temp_${BASE_NAME}_decrypted"
FIXED_DIR="${INPUT_DIR}/temp_${BASE_NAME}_fixed"
mkdir -p "$TEMP_DIR" "$DECRYPTED_DIR" "$FIXED_DIR"

# 定义清理函数
cleanup() {
    if [ $CLEANUP -eq 1 ]; then
        echo "清理临时文件..."
        rm -rf "$TEMP_DIR" "$DECRYPTED_DIR" "$FIXED_DIR"
    else
        echo "临时文件保留在:"
        [ -d "$TEMP_DIR" ] && echo "  - 加密分片: $(realpath "$TEMP_DIR")"
        [ -d "$DECRYPTED_DIR" ] && echo "  - 解密文件: $(realpath "$DECRYPTED_DIR")"
        [ -d "$FIXED_DIR" ] && echo "  - 修复文件: $(realpath "$FIXED_DIR")"
    fi
}
trap cleanup EXIT

# 1. 提取AES KEY和IV
KEY_URI=$(grep -o 'URI="[^"]*"' "$INPUT_M3U8" | cut -d'"' -f2)
IV_HEX=$(grep -o 'IV=0x[0-9A-Fa-f]*' "$INPUT_M3U8" | cut -d'x' -f2)

# 转换IV为二进制格式
echo -n "$IV_HEX" | xxd -r -p > "${TEMP_DIR}/iv.bin"

# 2. 下载AES KEY
echo "下载加密密钥..."
if ! curl -s -o "${TEMP_DIR}/key.bin" "$KEY_URI"; then
    echo "错误: 密钥下载失败"
    exit 3
fi

# 3. 安全提取分片URL
mapfile -t SEGMENT_URLS < <(grep -E '^https?://' "$INPUT_M3U8")

# 4. 处理分片
for i in "${!SEGMENT_URLS[@]}"; do
    SEG_NUM=$((i+1))
    ENC_FILE="${TEMP_DIR}/${BASE_NAME}_seg${SEG_NUM}.ts"
    DEC_FILE="${DECRYPTED_DIR}/${BASE_NAME}_decrypted_seg${SEG_NUM}.ts"
    FIXED_FILE="${FIXED_DIR}/${BASE_NAME}_fixed_seg${SEG_NUM}.ts"

    # 下载加密分片
    echo "($SEG_NUM/${#SEGMENT_URLS[@]}) 下载分片..."
    if ! curl -fsS -o "$ENC_FILE" "${SEGMENT_URLS[$i]}"; then
        echo "错误: 分片 $SEG_NUM 下载失败"
        exit 4
    fi

    # 解密分片
    echo "($SEG_NUM/${#SEGMENT_URLS[@]}) 解密分片..."
    if ! openssl aes-128-cbc -d \
        -in "$ENC_FILE" \
        -out "$DEC_FILE" \
        -nosalt \
        -iv "$(xxd -p -c16 "${TEMP_DIR}/iv.bin")" \
        -K "$(xxd -p -c16 "${TEMP_DIR}/key.bin")"; then
        echo "错误: 分片 $SEG_NUM 解密失败"
        exit 5
    fi

    # 修复视频分片
    echo "($SEG_NUM/${#SEGMENT_URLS[@]}) 修复分片..."
    if ! ffmpeg -hide_banner -y \
        -i "$DEC_FILE" \
        -c copy \
        -fflags +genpts \
        -avoid_negative_ts make_zero \
        -strict experimental \
        "$FIXED_FILE" 2>/dev/null; then
        echo "错误: 分片 $SEG_NUM 修复失败"
        exit 6
    fi
done

# 5. 合并修复后的文件
echo "合并修复片段..."
cat "${FIXED_DIR}/${BASE_NAME}_fixed_seg"*.ts > "${TEMP_DIR}/${BASE_NAME}_merged.ts"

# 6. 生成最终文件(更新部分)
echo "生成Chrome兼容视频..."
if ! ffmpeg -hide_banner -y \
    -i "${TEMP_DIR}/${BASE_NAME}_merged.ts" \
    -c:v libx264 \
    -preset medium \
    -profile:v high \
    -level 4.0 \
    -pix_fmt yuv420p \
    -crf 23 \
    -c:a aac \
    -b:a 128k \
    -ar 44100 \
    -movflags +faststart \
    -f mp4 \
    "$OUTPUT_MP4" 2>/dev/null; then
    echo "错误: 最终视频生成失败"
    exit 7
fi

echo -e "\n处理成功!输出文件: $(realpath "$OUTPUT_MP4")"

后记

先使用的AI是GROK, 然后他告诉我这个是标准的文件,可以直接使用ffmpeg转换,结果一堆错误还是没卵用,他没有按我预期的实现,可能我使用了 deepsearch 有关。

最后感谢 deepseek R3 解决了问题,耗时1.5小时。

当前还没有任何评论

写下你最简单的想法