Files
MediaOrganizer/src/lib/integrate/tmdb.sh
T
Shuery 0df07ad0ae refactor: 迁移至 bashly CLI 与功能域模块结构
- CLI 定义迁移至 src/bashly.yml(bashly 1.4 生成参数解析),入口收敛为 src/root_command.sh
- 源码按功能域重组:config/storage/integrate/media/pipeline,消除扁平散落
- 新增零依赖测试框架 tests/(123 用例)与 CI 流水线(lint + test + build + 产物一致性)
- build.sh 支持版本单一来源注入与 --check 产物校验;新增 lint.sh(bash -n + shellcheck 零容忍)
- 删除旧单文件 media_organizer.sh 与旧扁平模块
2026-08-14 22:41:28 +08:00

114 lines
4.2 KiB
Bash
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.
# shellcheck shell=bash
################################################################################
# TMDB API
################################################################################
# 指定语言的 tmdb_api 封装(语言重试链用):局部覆盖 TMDB_LANG 后调用。
# bash 动态作用域:tmdb_api 内读到的 $TMDB_LANG 为本次调用值;
# 缓存 key/路径含语言段(cache_key 拼 lang、id 类路径带 .lang),语言切换天然隔离缓存。
# 参数:lang(如 en-US) + 原 tmdb_api 全部参数。
tmdb_api_lang() {
local lang="$1"
shift
local TMDB_LANG="$lang"
tmdb_api "$@"
}
# 调用 TMDB API 并缓存结果。端点形如 "/search/movie",额外参数以 key=value 传入。
# 先查缓存(命中且未过期直接返回),未命中才请求并写缓存。
# 返回码约定:0=成功(含空结果的有效响应);1=新鲜空哨兵跳过请求;
# 2=请求失败(curl 错误/HTTP 非 2xx,递增重试耗尽)——不写空哨兵(失败≠无结果)。
# 返回原始 JSON 响应到 stdout。
tmdb_api() {
local endpoint="$1"
shift
local key path is_search
key=$(cache_key "$@")
path=$(cache_path "$endpoint" "$key")
is_search=0
[[ "$endpoint" == /search/* ]] && is_search=1
# --update-cache 修饰(整理时强制重取):跳过缓存读与空哨兵,直接请求并覆盖缓存
local cached
if [[ "${UPDATE_CACHE:-false}" != "true" ]] && cached=$(cache_get "$path" "$is_search"); then
echo "$cached"
return 0
fi
# 新鲜空哨兵:上次已确认空结果,CACHE_EMPTY_TTL_DAYS 内跳过请求(避免重复请求无效数据)
if [[ "${UPDATE_CACHE:-false}" != "true" ]] && cache_empty_fresh "$path" "$is_search"; then
[[ "$DEBUG_LEVEL" -ge 2 ]] && _log 调试 "缓存为空哨兵(新鲜),跳过请求: ${endpoint}"
return 1
fi
# 并发去重(识别池多 worker 可能同时 miss 同一查询):
# flock 跨进程互斥(内核锁,进程退出自动释放,无残留)→ 锁内双检缓存。
# 锁文件放 /tmp(复用不删除;不污染缓存目录,干运行零持久化副作用)。
local lockfile
lockfile="/tmp/mo_lock_$(cache_key_hash "$path")"
local locked=false
if [[ "${UPDATE_CACHE:-false}" != "true" ]]; then
exec 9>"$lockfile"
flock 9
locked=true
# 双检:等待者可能在锁期间已写入缓存
if cached=$(cache_get "$path" "$is_search"); then
exec 9>&-
echo "$cached"
return 0
fi
if cache_empty_fresh "$path" "$is_search"; then
exec 9>&-
return 1
fi
fi
local curl_args=(
"--get" "-s"
"--connect-timeout" "${TMDB_CURL_CONNECT_TIMEOUT}"
"--max-time" "${TMDB_CURL_MAX_TIME}" "-fS"
)
if $TMDB_USE_BEARER; then
curl_args+=("--header" "Authorization: Bearer ${TMDB_AUTH_TOKEN}")
fi
curl_args+=("--data-urlencode" "language=${TMDB_LANG}")
if ! $TMDB_USE_BEARER; then
curl_args+=("--data-urlencode" "api_key=${TMDB_AUTH_TOKEN}")
fi
local a
for a in "$@"; do
curl_args+=("--data-urlencode" "$a")
done
local full_url="${TMDB_API_BASE_URL}${endpoint}"
[[ "$DEBUG_LEVEL" -ge 2 ]] && _log 调试 "TMDB 请求: ${full_url}?..."
# 递增重试(2^n 封顶 16s):curl 的 --retry-delay 为固定延迟,这里手写循环
local result=""
local attempt=0 delay=1
while true; do
if result=$(curl "${curl_args[@]}" "$full_url" 2>&1); then
break
fi
attempt=$((attempt + 1))
if ((attempt > TMDB_CURL_RETRY)); then
_log 错误 "TMDB 请求失败(重试 ${TMDB_CURL_RETRY} 次后): ${full_url} 错误: ${result}"
return 2
fi
_log 警告 "TMDB 请求失败,${delay}s 后重试(${attempt}/${TMDB_CURL_RETRY}): ${full_url}"
sleep "$delay"
((delay *= 2))
[[ $delay -gt 16 ]] && delay=16
done
# 搜索空结果 → 写 3 天短 TTL 哨兵(查无此片;新片出现后自动重试);否则正常写缓存
if [[ "$is_search" == "1" ]] && ! echo "$result" | jq -e '.results | length > 0' >/dev/null 2>&1; then
cache_put_empty "$path" "$is_search" "$key"
else
cache_put "$path" "$result" "$is_search" "$key"
fi
if $locked; then
exec 9>&-
fi
echo "$result"
}