初始提交:抖音视频批量采集流水线

App 端免签名接口(设备注册 + detail + CDN 直链),一体化流水线
下载→抽音→传COS→记录→删本地,AI 作品四档判定,四份文档:
README(使用指南)、PROGRESS(批次进度)、RE(逆向全过程)、AI(判定规则)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-29 16:31:10 +08:00
commit 2bb83f3685
39 changed files with 298874 additions and 0 deletions

179
douyin/crypto.py Normal file
View File

@@ -0,0 +1,179 @@
"""a_bogus 依赖的底层密码学原语:SM3、RC4、自定义 Base64。
这三样都是公开算法,与抖音无关,可以独立验证正确性:
- SM3 见 GB/T 32905-2016,本文件底部带官方测试向量自检
- RC4 标准流密码
- 自定义 Base64 只是把标准码表换成抖音自己那套字符顺序
"""
from __future__ import annotations
from typing import Iterable, List, Sequence
# --------------------------------------------------------------------------- #
# SM3
# --------------------------------------------------------------------------- #
_IV = [
0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600,
0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E,
]
_MASK = 0xFFFFFFFF
def _rotl(x: int, n: int) -> int:
n &= 31
return ((x << n) | (x >> (32 - n))) & _MASK
def _ff(j: int, x: int, y: int, z: int) -> int:
return (x ^ y ^ z) if j < 16 else ((x & y) | (x & z) | (y & z))
def _gg(j: int, x: int, y: int, z: int) -> int:
return (x ^ y ^ z) if j < 16 else ((x & y) | ((~x & _MASK) & z))
def _p0(x: int) -> int:
return x ^ _rotl(x, 9) ^ _rotl(x, 17)
def _p1(x: int) -> int:
return x ^ _rotl(x, 15) ^ _rotl(x, 23)
def _cf(v: Sequence[int], block: bytes) -> List[int]:
"""压缩函数 CF(V, B)。"""
w = [int.from_bytes(block[i * 4:i * 4 + 4], "big") for i in range(16)]
for j in range(16, 68):
w.append(
_p1(w[j - 16] ^ w[j - 9] ^ _rotl(w[j - 3], 15))
^ _rotl(w[j - 13], 7)
^ w[j - 6]
)
w1 = [w[j] ^ w[j + 4] for j in range(64)]
a, b, c, d, e, f, g, h = v
for j in range(64):
t = 0x79CC4519 if j < 16 else 0x7A879D8A
ss1 = _rotl((_rotl(a, 12) + e + _rotl(t, j)) & _MASK, 7)
ss2 = ss1 ^ _rotl(a, 12)
tt1 = (_ff(j, a, b, c) + d + ss2 + w1[j]) & _MASK
tt2 = (_gg(j, e, f, g) + h + ss1 + w[j]) & _MASK
d = c
c = _rotl(b, 9)
b = a
a = tt1
h = g
g = _rotl(f, 19)
f = e
e = _p0(tt2)
return [x ^ y for x, y in zip(v, (a, b, c, d, e, f, g, h))]
def sm3(data: bytes) -> bytes:
"""SM3 摘要,返回 32 字节。"""
bit_len = len(data) * 8
padded = data + b"\x80"
padded += b"\x00" * ((56 - len(padded) % 64) % 64)
padded += bit_len.to_bytes(8, "big")
v = list(_IV)
for i in range(0, len(padded), 64):
v = _cf(v, padded[i:i + 64])
return b"".join(x.to_bytes(4, "big") for x in v)
def sm3_to_list(data: bytes | Iterable[int]) -> List[int]:
"""SM3 摘要,返回 32 个 int(a_bogus 内部按字节数组传递)。"""
if not isinstance(data, (bytes, bytearray)):
data = bytes(bytearray(data))
return list(sm3(bytes(data)))
# --------------------------------------------------------------------------- #
# RC4
# --------------------------------------------------------------------------- #
def rc4(key: bytes, data: bytes) -> bytes:
"""标准 RC4。加解密同一函数。"""
s = list(range(256))
j = 0
klen = len(key)
for i in range(256):
j = (j + s[i] + key[i % klen]) & 0xFF
s[i], s[j] = s[j], s[i]
out = bytearray(len(data))
i = j = 0
for n, ch in enumerate(data):
i = (i + 1) & 0xFF
j = (j + s[i]) & 0xFF
s[i], s[j] = s[j], s[i]
out[n] = ch ^ s[(s[i] + s[j]) & 0xFF]
return bytes(out)
# --------------------------------------------------------------------------- #
# 自定义码表 Base64
# --------------------------------------------------------------------------- #
STD_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
def b64_encode(data: bytes, alphabet: str, pad: bool = True) -> str:
"""按给定 64(+1) 字符码表做 Base64 编码。
alphabet 长度为 64 时不补位;为 65 时最后一位作为填充字符。
"""
if len(alphabet) not in (64, 65):
raise ValueError(f"码表长度必须是 64 或 65,收到 {len(alphabet)}")
fill = alphabet[64] if len(alphabet) == 65 else ""
out: List[str] = []
for i in range(0, len(data), 3):
chunk = data[i:i + 3]
n = int.from_bytes(chunk + b"\x00" * (3 - len(chunk)), "big")
quad = [alphabet[(n >> shift) & 0x3F] for shift in (18, 12, 6, 0)]
keep = len(chunk) + 1 # 1字节->2字符, 2字节->3字符, 3字节->4字符
out.extend(quad[:keep])
if pad and fill:
out.extend(fill * (4 - keep))
return "".join(out)
# --------------------------------------------------------------------------- #
# 自检
# --------------------------------------------------------------------------- #
# GB/T 32905-2016 附录 A 给出的两组标准测试向量
_SM3_VECTORS = [
(b"abc",
"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"),
(b"abcd" * 16,
"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732"),
]
def self_test() -> None:
"""跑通即说明 SM3/RC4/Base64 实现无误。"""
for msg, want in _SM3_VECTORS:
got = sm3(msg).hex()
assert got == want, f"SM3({msg[:8]!r}...) = {got}, 期望 {want}"
# RC4 官方测试向量:key="Key", plaintext="Plaintext" -> BBF316E8D940AF0AD3
assert rc4(b"Key", b"Plaintext").hex().upper() == "BBF316E8D940AF0AD3"
# 用标准码表时,自定义 Base64 应与 base64 模块完全一致
import base64
import os
for n in range(1, 40):
raw = os.urandom(n)
assert b64_encode(raw, STD_ALPHABET) == base64.b64encode(raw).decode()
print("crypto self-test OK: SM3 / RC4 / custom-base64 均通过")
if __name__ == "__main__":
self_test()