feat(tuku): CBZ 档案册集成——档案页源/书库列册/解压缓存
- logic/reader/archive_source.c:档案册页源实现 M6 mr_book 契约 (mz_open/mz_count/mz_entry_at/mz_read_alloc),条目自然序 + 图片后缀 + 路径安全(`..`/绝对路径/反斜杠/隐藏段/内嵌 NUL)+ 单页尺寸上限过滤; meta 按需解压只读图片头(不落缓存,结果按页记忆);mr_book_open_auto 统一目录册/档案册开册,翻页与条漫两套消费代码零改动。 - logic/reader/page_cache.c/h:解压页落 MeowData/<pkg>/cache,LRU 64 页或 32MiB,启动清 mrpage_* 孤儿,写入 .part + rename;与缩略图缓存同目录、 前缀隔离;互斥量保护,解码/缩略图线程可并发。 - logic/library.c/h:扫描直接子文件里的 .cbz/.zip 成册(行=文件名+页数, 点入直接阅读);档案探测由调用方注入(logic 不依赖 zip 容器),不注入时 与 M7 行为逐字一致;册间衔接兄弟表=含图目录∪含页档案册,同列自然序。 条目构造/副标题/角标/兄弟判据拆成小函数,便于 M13 书库重写拼接。 - ui/library:档案册行 + 封面缩略图(解压档内首图)、扫描注入探测、缓存 目录统一由 page_cache 推导(一份规则)。 - ui/reader:open_book 走 mr_book_open_auto;跨册衔接纳入档案册。 - build_tuku.sh 补 zip/archive/cache 源与 sysroot zlib 头(zip.c include <zlib.h>);run_tests.sh 纳入 zip+cbz 用例;run_webtoon_tests.sh 的宿主 集成构建补新源与 -lz;.gitignore 同步测试产物。 - test/test_cbz.c(267 项断言)+ make_cbz_samples.py 真实 cbz 夹具: 列档/自然序/解压字节 CRC/路径安全/坏档与 zip 炸弹容错/LRU 与 32MiB 上限/ 启动清孤儿/续读角标/封面首图。
This commit is contained in:
1 parent
19620a7957
commit
562cc44931
16 files changed
+2330
-108
No files matched your search
+25
-11
@@ -39,6 +39,7 @@
|
||||
#include "tuku_internal.h"
|
||||
#include "ui/reader/reader.h"
|
||||
#include "logic/reader/page_source.h"
|
||||
#include "logic/reader/page_cache.h"
|
||||
#include "logic/reader/nav.h"
|
||||
|
||||
#include <pthread.h>
|
||||
@@ -74,7 +75,7 @@
|
||||
static mr_page_ctrl g_ctrl;
|
||||
static char g_dir[MR_PATH_MAX];
|
||||
|
||||
static mr_dir_book g_db;
|
||||
static mr_book_handle g_handle; /* 目录册或档案册(M11 统一开册) */
|
||||
static mr_book g_book;
|
||||
static int g_count; /* 0=空册/不可读 */
|
||||
static int g_open_err;
|
||||
@@ -765,7 +766,7 @@ static void reader_draw(meow_view *v, const meow_theme *th, void *ctx)
|
||||
int w = g_vw, h = g_vh;
|
||||
|
||||
if (g_open_err) {
|
||||
meow_ui_text_center(w / 2, h / 2 - 20, "无法打开目录", th->font_title, th->onSurface);
|
||||
meow_ui_text_center(w / 2, h / 2 - 20, "无法打开此册", th->font_title, th->onSurface);
|
||||
meow_ui_text_center(w / 2, h / 2 + 24, g_dir, th->font_body, th->onSurfaceVariant);
|
||||
return;
|
||||
}
|
||||
@@ -1152,8 +1153,7 @@ static void open_book_reset_state(void)
|
||||
mr_strip_free(&g_strip);
|
||||
g_strip_ok = 0;
|
||||
slots_free_all();
|
||||
mr_book_destroy(&g_book);
|
||||
mr_dir_book_free(&g_db);
|
||||
mr_book_close_auto(&g_book, &g_handle);
|
||||
if (g_slider) { meow_widget_free(g_slider); g_slider = NULL; }
|
||||
g_gen++; /* 作废旧册的异步结果 */
|
||||
g_count = 0;
|
||||
@@ -1183,10 +1183,11 @@ static int open_book(const char *dir, int start_page, int mode)
|
||||
g_mode = mr_mode_valid(mode) ? mode : MR_MODE_PAGED;
|
||||
|
||||
int maxdim = g_vw > g_vh ? g_vw : g_vh;
|
||||
int n = mr_dir_book_init(&g_db, g_dir, maxdim,
|
||||
reader_load_page, reader_unload_page, NULL);
|
||||
/* 目录 → 目录册;.cbz/.zip → 档案册(M11)。两者同一个 mr_book 契约,
|
||||
* 下面的翻页/条漫消费代码完全不区分 provider。 */
|
||||
int n = mr_book_open_auto(&g_book, &g_handle, g_dir, maxdim,
|
||||
reader_load_page, reader_unload_page, NULL);
|
||||
if (n < 0) {
|
||||
mr_dir_book_bind(&g_book, NULL);
|
||||
g_open_err = 1;
|
||||
worker_start();
|
||||
update_title();
|
||||
@@ -1195,7 +1196,6 @@ static int open_book(const char *dir, int start_page, int mode)
|
||||
return 0;
|
||||
}
|
||||
g_count = n;
|
||||
mr_dir_book_bind(&g_book, g_count > 0 ? &g_db : NULL);
|
||||
|
||||
int page = start_page < 0 ? g_count - 1 : start_page;
|
||||
page = mr_nav_clamp_page(page, g_count);
|
||||
@@ -1233,12 +1233,20 @@ static int open_book(const char *dir, int start_page, int mode)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 册间衔接的档案册探测(M11):兄弟表 = 含图目录 ∪ 含图片页的 .cbz/.zip。 */
|
||||
static int cbz_pages_probe(const char *path, void *ud)
|
||||
{
|
||||
(void)ud;
|
||||
return mr_zip_count_pages(path);
|
||||
}
|
||||
|
||||
static int book_switch(int delta)
|
||||
{
|
||||
if (delta == 0) return 0;
|
||||
if (g_count <= 0) return 0;
|
||||
char next[MR_PATH_MAX];
|
||||
int r = mr_book_adjacent(g_dir, delta > 0 ? 1 : -1, next, (int)sizeof next);
|
||||
int r = mr_book_adjacent_ex(g_dir, delta > 0 ? 1 : -1, next, (int)sizeof next,
|
||||
cbz_pages_probe, NULL);
|
||||
if (r != 1) {
|
||||
toast(delta > 0 ? "已是最后一册" : "已是第一册");
|
||||
return 0;
|
||||
@@ -1770,6 +1778,13 @@ static void reader_page_enter(meow_view *v, void *ctx)
|
||||
}
|
||||
if (g_tb) meow_widget_set_rect(g_tb, 0, 0, g_vw, MR_TOP_BAR_H);
|
||||
|
||||
/* 档案册解压缓存(M11):MeowData/<pkg>/cache。library 页通常已初始化,
|
||||
* 这里幂等兜底(进程重启后直接进阅读器、或交付环境只剩 reader 入口)。 */
|
||||
{
|
||||
const char *data = meow_config_dir();
|
||||
if (data && data[0]) mr_cache_init(data);
|
||||
}
|
||||
|
||||
/* 打开册:恢复该册上次的模式与页码(无记录 → 翻页模式第 1 页)。 */
|
||||
int mode = mr_cont_get_mode(g_dir, MR_MODE_PAGED);
|
||||
int page = mr_cont_get_page(g_dir, 0);
|
||||
@@ -1801,8 +1816,7 @@ static void reader_page_leave(meow_view *v, void *ctx)
|
||||
mr_strip_free(&g_strip);
|
||||
g_strip_ok = 0;
|
||||
slots_free_all();
|
||||
mr_book_destroy(&g_book);
|
||||
mr_dir_book_free(&g_db);
|
||||
mr_book_close_auto(&g_book, &g_handle);
|
||||
|
||||
if (g_slider) { meow_widget_free(g_slider); g_slider = NULL; }
|
||||
if (g_tb) { meow_widget_free(g_tb); g_tb = NULL; }
|
||||
|
||||
Reference in new issue
Block a user