ncm search: 历史+单曲/歌单分类+分页+误触修复+不覆写歌单上下文 (§23)

- 搜索历史:进页自动弹键盘;meow_config 持久化 ≤12 去重最新在前;空态=历史列表(点搜/左滑删/清空)
- 结果分类单曲/歌单页签:独立结果集+独立滚动;歌单行进详情(playlist_open_pl);单曲行播放
- 触底分页:offset 累加 limit=30/页 cloudsearch 同参数;每类各记 offset
- 误触抑制:g_press_row + g_press_delta>10(对齐 home/playlist §13.3)
- 结果改独立数组(不写 g_st.songs[]);播放搜索单曲建搜索队列(queue_src=SEARCH),不弄丢歌单窗口
- core cloudsearch 扩展 type/offset/limit/total + 歌单解析
- bench/search_sim.c 离线回归(历史/独立集/翻页 offset/队列上下文);host searchtap 误触自检

验证:mipsel -Wall -Wextra 0 warning;core host/mipsel PASS;search_sim PASS;
宿主离屏 search(单曲)/searchpl(歌单)/searchhist(空态历史)/searchtap(误触) 均正常;0 真实 NCM 请求。
This commit is contained in:
MeowOS committed 2026-09-01 19:21:16 +08:00
1 parent d4928224a5
commit 1e97dbf54a
15 files changed
+1152 -121

No files matched your search

+58 -4
View File
@@ -63,7 +63,20 @@
* 窗口补载粒度;c 数组缓冲 clist[4096] 装 100 首 ≈2KB) */
#define NCM_LYRIC_LINES 600 /* 歌词行上限 */
#define NCM_COVER_MAX 288*1024 /* 封面下载限幅 ~288KB */
#define NCM_SEARCH_MAX 32 /* 搜索结果上限(v1 只显示前 32 条,无大缓冲) */
/* ---- 搜索(REPORT §23:独立结果数组 + 单曲/歌单两类页签 + 历史 + 分页)---- */
#define NCM_SEARCH_PAGE 30 /* cloudsearch limit/页(用户定案;offset 累加) */
#define NCM_SEARCH_SONG_MAX 256 /* 单曲结果累计上限(独立数组 ≈156KB bss,不覆写歌单窗口) */
#define NCM_SEARCH_PL_MAX 60 /* 歌单结果累计上限(≈48KB bss) */
#define NCM_SEARCH_HIST_MAX 12 /* 搜索历史条数(上次在最新,≤12) */
#define NCM_SEARCH_HIST_LEN 128 /* 单条历史长度 */
/* 播放队列来源(§23:搜索单曲起播建立「搜索队列」上下文,不覆写歌单窗口) */
#define NCM_QUEUE_PLAYLIST 0 /* 默认:歌单滑动窗口 */
#define NCM_QUEUE_SEARCH 1 /* 搜索单曲结果队列 */
/* active_playlist 哨兵:搜索歌单详情(复用 playlist_open 链路,读 g_st.search_pl_open) */
#define NCM_PL_SEARCH (-2)
/* ---- 播放/媒体会话状态(play 线程 ↔ UI/IPC 共享,mu 保护)---- */
enum {
@@ -169,11 +182,26 @@ typedef struct ncm_app_state {
int cache_limit_gb;
int player_bg_mode; /* 歌词页背景模式(§22):NCM_BG_DEFAULT / NCM_BG_POWER_SAVE */
/* 搜索(结果复用 g_st.songs[] 浅拷贝区;仅搜索页上下文有效)*/
/* 搜索(REPORT §23:独立结果数组,不覆写歌单窗口;单曲/歌单两类页签各自独立结果集/分页/滚动) */
char search_query[256];
int search_count; /* 当前搜索结果数(含 0=无/未搜) */
volatile int search_loading; /* 1=搜索请求在途 */
int search_err; /* 最近一次搜索错误(0=ok) */
int search_tab; /* 当前页签:0=单曲 1=歌单 */
ncm_song_t search_songs[NCM_SEARCH_SONG_MAX]; /* 单曲结果(独立数组) */
int search_song_count;
int search_song_offset; /* 下次 offset(=已加载条数) */
int search_song_total; /* 服务端总数(-1=未知) */
int search_song_more; /* 1=单曲还有下一页 */
ncm_playlist_t search_pls[NCM_SEARCH_PL_MAX]; /* 歌单结果(独立数组) */
int search_pl_count;
int search_pl_offset;
int search_pl_total;
int search_pl_more;
/* 搜索歌单打开的详情(active_playlist==NCM_PL_SEARCH 时用;复用 playlist_open 链路) */
ncm_playlist_t search_pl_open;
/* 播放队列来源(§23):默认 NCM_QUEUE_PLAYLIST;搜索单曲起播切 NCM_QUEUE_SEARCH */
int queue_src;
} ncm_app_state_t;
extern ncm_app_state_t g_st; /* 全局状态(app.c 定义) */
@@ -246,6 +274,7 @@ void playlist_swipe(int dir, int dist);
void playlist_touch_down(int x, int y);
void playlist_touch_move(int x, int y);
void playlist_open(int idx); /* 打开第 idx 个歌单(下拉进歌单详情) */
void playlist_open_pl(const ncm_playlist_t *pl); /* 打开「搜索来的歌单」详情(§23,复用链路) */
void playlist_refresh(void);
void playlist_tick(uint64_t now);/* UI tick:检查歌单 worker 是否完成并刷新 */
@@ -254,7 +283,8 @@ meow_view *player_view_create(void);
int player_is_active(void);
void player_on_tap(int x, int y);
void player_tick(uint64_t now); /* 播放进度/歌词滚动 */
void player_play_song(int idx); /* 从歌单第 idx 首开始播放 */
void player_play_song(int idx); /* 从歌单窗口第 idx 首开始播放(queue=PLAYLIST) */
void player_play_search_song(int i); /* 从搜索单曲第 i 首开始播放(queue=SEARCH,§23) */
void player_pause_toggle(int on);
void player_next(int dir); /* dir=+1 下一首 / -1 上一首 */
void player_seek(int64_t ms);
@@ -286,6 +316,7 @@ void search_touch_move(int x, int y);
void search_open(void); /* 进搜索页 */
void search_submit(const char *kw); /* 用户确认后发起搜索(风控:仅在确认时发) */
void search_tick(uint64_t now); /* UI tick:检查搜索 worker 完成并刷新 */
int search_swipe_left(void); /* 历史模式左滑删单条:1=已消费(不触返回) */
/* ---- logic ---- */
int appstate_init(void); /* 初始化 ctx/data/cookie/设置;0=成功 */
@@ -314,6 +345,29 @@ int appstate_song_fetch(int gidx, ncm_song_t *out); /* 任意全局下标物化
void appstate_adopt_songs(int n); /* 收编外部已填的 songs[0..n)(搜索结果)为窗口 base=0,
* 同步 song_ids/track_ids_count(播放上下文) */
/* ---- 播放队列来源(§23)---- */
void appstate_set_queue(int src); /* NCM_QUEUE_PLAYLIST / NCM_QUEUE_SEARCH */
int appstate_get_queue(void);
int appstate_queue_count(void); /* 当前播放队列长度(按 queue_src) */
int appstate_queue_song(int idx, ncm_song_t *out); /* 队列第 idx 首;0=ok(按 queue_src) */
/* ---- 搜索结果独立数组(§23;g_search_mu 保护,UI/worker 经此访问)---- */
int appstate_search_count(int tab); /* tab: 0=单曲 1=歌单 */
int appstate_search_offset(int tab); /* 下次 offset(=已加载条数) */
int appstate_search_has_more(int tab); /* tab 是否还有下一页 */
int appstate_search_song(int i, ncm_song_t *out); /* 单曲条 i;0=ok */
int appstate_search_pl(int i, ncm_playlist_t *out); /* 歌单条 i;0=ok */
void appstate_search_clear(int tab); /* 清空某 tab 结果(offset=0, total=-1, more=1) */
void appstate_search_append_songs(int n, const ncm_song_t *s, int64_t total); /* 追加单曲(锁内) */
void appstate_search_append_pls(int n, const ncm_playlist_t *p, int64_t total); /* 追加歌单 */
/* ---- 搜索历史(≤NCM_SEARCH_HIST_MAX,最新在前;meow_config 持久化)---- */
int appstate_search_history_count(void);
int appstate_search_history_get(int i, char *out, size_t sz); /* 1=存在 */
void appstate_search_history_add(const char *kw); /* 去重 + 最新在前 + 截断 ≤12 */
void appstate_search_history_remove(int i); /* 删第 i 条 */
void appstate_search_history_clear(void);
/* account(app/logic/account.c,§20 会员态):account.json 落盘 + 刷新策略
* (登录后/缓存超 1 天/到期后 各查一次,不轮询——风控)。 */
void account_load(void); /* appstate_init 时读 account.json 恢复 vip 态 */