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 与旧扁平模块
This commit is contained in:
Shuery committed 2026-08-14 22:41:28 +08:00
1 parent d978a13a83
commit 0df07ad0ae
48 files changed
+5813 -6812

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
# ============================================================================
# 媒体文件名解析模块测试(src/lib/filename.sh)
# ============================================================================
setup() {
TEST_DIR="$(mktemp -d)"
SOURCE_DIR="$TEST_DIR"
SKIP_DIRS_LOWER=(sp sps special specials cd cds bonus bonuses extra extras previews "ps3 special bd" scans fonts 特典 特番 花絮 视频 剧集 动画 合集 电影 音乐 movies series shows anime collections)
SPECIAL_WORDS=("menu" "ncop" "nced" "mini anime" "pv" "cm" "sp" "teaser" "program" "promo" "trailer" "special" "music video" "mv" "opening" "ending" "特典" "特番" "花絮")
VIDEO_EXTS=(mp4 mkv avi mov wmv flv m4v ts m2ts webm)
MAIN_COUNT_CACHE=()
}
teardown() {
rm -rf "$TEST_DIR"
}
# parse_media_filename:标准 S##E## 格式
test_parse_tv_sxxexx() {
assert_eq "tv|Show Name||01|02||" "$(parse_media_filename "$TEST_DIR/Show Name S01E02.mkv")"
}
# parse_media_filename:S##E## + 年份
test_parse_tv_with_year() {
assert_eq "tv|Show|2020|01|01||" "$(parse_media_filename "$TEST_DIR/Show (2020) S01E01.mkv")"
}
# parse_media_filename:多集区间 S01E01-E02
test_parse_tv_episode_range() {
assert_eq "tv|Show||01|01|02|" "$(parse_media_filename "$TEST_DIR/Show S01E01-E02.mkv")"
}
# parse_media_filename:#x## 格式
test_parse_tv_hash_format() {
assert_eq "tv|Show||1|05||" "$(parse_media_filename "$TEST_DIR/Show 1x05.mkv")"
}
# parse_media_filename:Season 2 格式(无集号 → 0)
test_parse_tv_season_format() {
assert_eq "tv|Show||2|0|" "$(parse_media_filename "$TEST_DIR/Show Season 2.mkv")"
}
# parse_media_filename:2nd Season + [NN]
test_parse_tv_ordinal_season() {
assert_eq "tv|Show||2|01|" "$(parse_media_filename "$TEST_DIR/Show 2nd Season [01].mkv")"
}
# parse_media_filename:方括号集号 [NN]
test_parse_tv_bracket_episode() {
assert_eq "tv|Show||1|07||" "$(parse_media_filename "$TEST_DIR/Show [07].mkv")"
}
# parse_media_filename:小数集号 → 特典路径(season=0)
test_parse_tv_decimal_episode_as_special() {
assert_eq "tv|Show||0|||14.5" "$(parse_media_filename "$TEST_DIR/Show [14.5].mkv")"
}
# parse_media_filename:第 0 话 → 特典路径
test_parse_tv_zero_episode_as_special() {
assert_eq "tv|Show||0|||0" "$(parse_media_filename "$TEST_DIR/Show [0].mkv")"
}
# parse_media_filename:电影(年份)
test_parse_movie_with_year() {
assert_eq "movie|Movie|2020||||" "$(parse_media_filename "$TEST_DIR/Movie (2020).mkv")"
}
# parse_media_filename:压制组风格电影
test_parse_movie_group_style() {
assert_eq "movie|Movie|2021||||" "$(parse_media_filename "$TEST_DIR/[Group] Movie (2021) [1080p].mkv")"
}
# detect_special:父目录为特典目录(SPs)
test_detect_special_parent_dir() {
mkdir -p "$TEST_DIR/Show/SPs"
touch "$TEST_DIR/Show/SPs/CM01.mkv"
assert_eq "tv|Show||0|01||CM01" "$(parse_media_filename "$TEST_DIR/Show/SPs/CM01.mkv")"
}
# detect_special:文件名含特典标记 [CM01]
test_detect_special_bracket_mark() {
# Show 目录需 ≥2 个正片(count==1 会被判为电影特典跳过)
mkdir -p "$TEST_DIR/Show"
touch "$TEST_DIR/Show/[CM01].mkv" "$TEST_DIR/Show/EP01.mkv"
assert_eq "tv|Show||0|01||CM01" "$(parse_media_filename "$TEST_DIR/Show/[CM01].mkv")"
}
# find_show_dir_from_path:跳过特典目录找到剧名目录
test_find_show_dir_skips_special_dirs() {
assert_eq "Show" "$(find_show_dir_from_path "$TEST_DIR/Show/SPs/CM01.mkv")"
}
# find_show_dir_from_path:跳过 [数字 CD 子目录
test_find_show_dir_skips_cd_dir() {
assert_eq "Show" "$(find_show_dir_from_path "$TEST_DIR/Show/[200226] Song/01.flac")"
}
# count_main_videos:统计正片、跳过特典子目录
test_count_main_videos_counts_and_skips() {
mkdir -p "$TEST_DIR/Show" "$TEST_DIR/Show/SPs"
touch "$TEST_DIR/Show/EP01.mkv" "$TEST_DIR/Show/EP02.mkv" "$TEST_DIR/Show/SPs/CM01.mkv"
assert_eq "2" "$(count_main_videos "$TEST_DIR/Show")"
}