feat(ncm): 三期第一批 — 歌单真分页(取消256截断)+专辑封面ncm_cache+歌词后台加载补锁
[agent-239] 仅改 patch_v2/ncm_app/。 1. 歌单分页(REPORT §14.1): track/all 全 404(§13.1) 弃用, 回 detail(n=1)全量 trackIds + song_detail 分批(≤NCM_SONG_BATCH=100) 触底逐页加载。appstate_load_playlist_songs_page offset=0 重建 song_ids[]/track_ids_count 载第0页, offset>0 追加(失败保留已载); playlist.c g_pl_more=(song_count<track_ids_count && <NCM_SONG_MAX), 触底 g_ploffset=song_count 起下一页(保留滚动), 首屏失败整页空态+点按重试, 追加失败 snack+保留已载。NCM_SONG_MAX 256→1000(单页渲染上限, bss +~1MB), NCM_SONG_BATCH 64→100, 删 NCM_PLAYLIST_PAGE(track/all 遗留)。 2. 专辑封面(§14.2): cover.c 封面改走 ncm_cache(LRU, 键=djb2(url)→song_cov<h>.jpg 同池), 缓存命中免下载/未命中下载→open/write/commit 落盘, 仍写 cover_current.jpg 供 launcher; 顺带修真 bug: save_cover_raw 在已持 g_cm 临界区内再 lock(非递归死锁)→封面永不刷新, 改调用方持锁。 歌单列表/详情头块封面保持现状。 3. 歌词后台加载(§14.3): lyric_worker 已异步(§11)未改线程模型; 补 lyric.c g_lyric_mu 数据竞争锁, 写侧 lyric_parse 整段持锁(清空用 lyric_clear_nolock 免二次取锁), 读侧 lyric_count/line_at/ line_text/line_tl 逐次取锁, 消除 UI/IPC 与 worker 间数据竞争(原 §10.9 FM4 良性竞态)。 验证(0 真实 NCM 请求): bench/pagination_sim.c 离线 stub 驱动真实 appstate 分页函数全 PASS (130首读全程/5191首封顶1000/空/越界无操作); mipsel build_ncm.sh 0 warning(text 842820/bss 2052068); 宿主 build_ncm_host.sh+MEOW_UI_DUMP home/playlist/player/lands 渲染正常无崩溃; host SDK_SRC 补 meow_pinyin(拼音IME py_predict 漏编致链接断)。ncm md5 b34bc1ed, ncm_host md5 1a2327e0。 未动 sdk/(主会话改 meow_ui_ime.c)/meow_launcherd/meow_amsd/vendor/core; 未 commit 它们。
This commit is contained in:
1 parent
5fac5e380d
commit
ee104f1b18
10 files changed
+471
-87
No files matched your search
@@ -10,6 +10,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static pthread_mutex_t g_cm = PTHREAD_MUTEX_INITIALIZER;
|
||||
static meow_img *g_cover_img;
|
||||
@@ -42,18 +43,39 @@ static meow_img *decode_cover(const char *url, size_t *out_len)
|
||||
return meow_img_load_mem((const void *)resp.body, (int)resp.body_len);
|
||||
}
|
||||
|
||||
/* 封面缓存键:URL 的 djb2 哈希(稳定性由 URL 决定——同一专辑封面 URL 名即可命中)。
|
||||
* 走 ncm_cache(LRU 口径沿用 ncm_cache,见 REPORT §14.2):键进 ncm_cache_path => 文件
|
||||
* `song_cov<hex>.jpg`,与 mp3(song_<id>.mp3)同池,lookup/commit 刷新 mtime(LRU)。 */
|
||||
static void cover_cache_id(const char *url, char *out, size_t out_sz)
|
||||
{
|
||||
unsigned long h = 5381;
|
||||
for (const char *p = url; *p; p++) h = ((h << 5) + h) + (unsigned char)*p;
|
||||
snprintf(out, out_sz, "cov%lx", h);
|
||||
}
|
||||
|
||||
/* 读整文件到 buf(< cap),成功返回 1,写入 *len。 */
|
||||
static int read_file_into_buf(const char *path, unsigned char *buf, size_t cap, size_t *len)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) return 0;
|
||||
size_t n = fread(buf, 1, cap, f);
|
||||
fclose(f);
|
||||
if (n == 0) return 0;
|
||||
if (len) *len = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 写 cover_current.jpg 供 launcher 媒体卡片读(兼容保留)。调用方须已持有 g_cm
|
||||
* (早前版本在此内再 lock g_cm → 非递归锁自锁死——cover worker 永久卡死、封面永不出现)。 */
|
||||
static void save_cover_raw(const char *url, size_t len)
|
||||
{
|
||||
if (!url || len == 0) return;
|
||||
if (g_st.cache_dir[0]) {
|
||||
char path[512];
|
||||
char path[NCM_CACHE_DIR_MAX + 32]; /* >512:宿主 glibc fortify 对 %s 展开宽证明可放 */
|
||||
snprintf(path, sizeof path, "%s/cover_current.jpg", g_st.cache_dir);
|
||||
ncm_store_write_file(path, g_buf, len);
|
||||
pthread_mutex_lock(&g_cm);
|
||||
ncm_strlcpy(g_cover_path, path, sizeof g_cover_path);
|
||||
pthread_mutex_unlock(&g_cm);
|
||||
}
|
||||
(void)url;
|
||||
}
|
||||
|
||||
static void *cover_worker(void *arg)
|
||||
@@ -66,9 +88,31 @@ static void *cover_worker(void *arg)
|
||||
ncm_strlcpy(url, g_tgt_url, sizeof url);
|
||||
pthread_mutex_unlock(&g_cm);
|
||||
|
||||
char key[32];
|
||||
cover_cache_id(url, key, sizeof key);
|
||||
size_t blen = 0;
|
||||
meow_img *img = decode_cover(url, &blen);
|
||||
if (!img) { usleep(500 * 1000); continue; }
|
||||
meow_img *img = NULL;
|
||||
|
||||
/* ① 缓存命中直接解码(免下载、离线可看;LRU:lookup 刷新 mtime) */
|
||||
char cpath[512];
|
||||
if (g_st.ctx.cache.dir[0] && ncm_cache_lookup(&g_st.ctx.cache, key, ".jpg",
|
||||
cpath, sizeof cpath) == NCM_OK &&
|
||||
read_file_into_buf(cpath, g_buf, sizeof g_buf, &blen)) {
|
||||
img = meow_img_load_mem(g_buf, (int)blen);
|
||||
}
|
||||
/* ② 未命中 → 下载解码;成功后落进 ncm_cache(LRU 池,超限由 ncm_cache_evict 淘汰) */
|
||||
if (!img) {
|
||||
blen = 0;
|
||||
img = decode_cover(url, &blen);
|
||||
if (!img) { usleep(500 * 1000); continue; }
|
||||
if (g_st.ctx.cache.dir[0]) {
|
||||
ncm_cache_writer_t *w = NULL;
|
||||
if (ncm_cache_open(&g_st.ctx.cache, key, ".jpg", &w) == NCM_OK) {
|
||||
ncm_cache_write(w, g_buf, blen);
|
||||
ncm_cache_commit(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_cm);
|
||||
/* 目标仍是 url 才换入(期间未提交更早) */
|
||||
|
||||
Reference in new issue
Block a user