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:
1 parent
d4928224a5
commit
1e97dbf54a
15 files changed
+1152
-121
No files matched your search
@@ -10,6 +10,11 @@
|
||||
/* 滑动窗口互斥(REPORT §17):窗口读写(滑窗/物化/拷贝)全走此锁,见下方窗口节注释。 */
|
||||
static pthread_mutex_t g_song_mu = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* 搜索结果独立数组互斥(§23):g_st.search_songs/search_pls 读写 + queue_src 读。 */
|
||||
static pthread_mutex_t g_search_mu = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void appstate_srch_hist_init(void); /* §23:读入本地搜索历史(appstate_init 首调) */
|
||||
|
||||
int appstate_init(void)
|
||||
{
|
||||
const char *dd = getenv("MEOW_DATA_DIR");
|
||||
@@ -37,6 +42,9 @@ int appstate_init(void)
|
||||
|
||||
account_load(); /* §20:恢复会员态缓存(account.json;无文件则 NCM_VIP_NONE) */
|
||||
|
||||
g_st.queue_src = NCM_QUEUE_PLAYLIST; /* §23:默认播放队列=歌单窗口 */
|
||||
g_st.search_tab = 0;
|
||||
appstate_srch_hist_init(); /* §23:读取本地搜索历史 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -362,10 +370,11 @@ void appstate_adopt_songs(int n)
|
||||
|
||||
int appstate_load_playlist_songs_page(int idx, int offset, int limit)
|
||||
{
|
||||
if (idx < 0 || idx >= g_st.playlist_count) return NCM_ERR_ARG;
|
||||
/* 搜索歌单详情(§23):idx==NCM_PL_SEARCH 时读 g_st.search_pl_open(复用本链路)。 */
|
||||
if (idx != NCM_PL_SEARCH && (idx < 0 || idx >= g_st.playlist_count)) return NCM_ERR_ARG;
|
||||
/* 不在此处写 g_st.active_playlist:调用方(playlist_open/UI)已在 UI 线程设定;
|
||||
* 若后台 worker 在此改写,会覆盖用户已切换到的新歌单,造成“打开 B 却显示 A”。 */
|
||||
const ncm_playlist_t *pl = &g_st.playlists[idx];
|
||||
const ncm_playlist_t *pl = (idx == NCM_PL_SEARCH) ? &g_st.search_pl_open : &g_st.playlists[idx];
|
||||
if (limit <= 0 || limit > NCM_SONG_BATCH) limit = NCM_SONG_BATCH;
|
||||
if (offset < 0) offset = 0;
|
||||
|
||||
@@ -412,6 +421,10 @@ int appstate_load_playlist_songs(int idx)
|
||||
|
||||
void appstate_apply_playlist_cover(int idx)
|
||||
{
|
||||
if (idx == NCM_PL_SEARCH) {
|
||||
ncm_strlcpy(g_st.cover_url, g_st.search_pl_open.cover, sizeof g_st.cover_url);
|
||||
return;
|
||||
}
|
||||
if (idx < 0 || idx >= g_st.playlist_count) return;
|
||||
ncm_strlcpy(g_st.cover_url, g_st.playlists[idx].cover, sizeof g_st.cover_url);
|
||||
}
|
||||
@@ -427,7 +440,9 @@ void appstate_set_playing_song(int idx, const char *cover_url)
|
||||
|
||||
int appstate_current_playing(void)
|
||||
{
|
||||
if (g_st.playing_song < 0 || g_st.playing_song >= g_st.track_ids_count) return -1;
|
||||
if (g_st.playing_song < 0) return -1;
|
||||
int cnt = appstate_queue_count(); /* §23:搜索队列时按搜索条数界(不误判歌单亮点) */
|
||||
if (g_st.playing_song >= cnt) return -1;
|
||||
return g_st.playing_song;
|
||||
}
|
||||
|
||||
@@ -523,3 +538,214 @@ void autoplay_maybe(void)
|
||||
if (pthread_create(&t, NULL, autoplay_worker, sel) == 0) pthread_detach(t);
|
||||
else free(sel);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 搜索(REPORT §23):独立结果数组(不覆写歌单窗口)+ 播放队列来源 + 本地历史。
|
||||
* 结果数组读写经 g_search_mu;queue_src 决定超时/起播读数组还是窗口。
|
||||
* ============================================================ */
|
||||
|
||||
void appstate_set_queue(int src) { g_st.queue_src = src; }
|
||||
int appstate_get_queue(void) { return g_st.queue_src; }
|
||||
|
||||
int appstate_queue_count(void)
|
||||
{
|
||||
int c;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
c = (g_st.queue_src == NCM_QUEUE_SEARCH) ? g_st.search_song_count : g_st.track_ids_count;
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return c < 0 ? 0 : c;
|
||||
}
|
||||
|
||||
int appstate_queue_song(int idx, ncm_song_t *out)
|
||||
{
|
||||
if (!out) return NCM_ERR_ARG;
|
||||
if (g_st.queue_src == NCM_QUEUE_SEARCH) {
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
int ok = (idx >= 0 && idx < g_st.search_song_count);
|
||||
if (ok) *out = g_st.search_songs[idx];
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return ok ? NCM_OK : NCM_ERR_ARG;
|
||||
}
|
||||
if (appstate_song_copy(idx, out) == 0) return NCM_OK;
|
||||
return appstate_song_fetch(idx, out);
|
||||
}
|
||||
|
||||
int appstate_search_count(int tab)
|
||||
{
|
||||
int c;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
c = (tab == 0) ? g_st.search_song_count : g_st.search_pl_count;
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return c;
|
||||
}
|
||||
|
||||
int appstate_search_offset(int tab)
|
||||
{
|
||||
int o;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
o = (tab == 0) ? g_st.search_song_offset : g_st.search_pl_offset;
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return o;
|
||||
}
|
||||
|
||||
int appstate_search_has_more(int tab)
|
||||
{
|
||||
int m;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
m = (tab == 0) ? g_st.search_song_more : g_st.search_pl_more;
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return m;
|
||||
}
|
||||
|
||||
int appstate_search_song(int i, ncm_song_t *out)
|
||||
{
|
||||
if (!out) return NCM_ERR_ARG;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
int ok = (i >= 0 && i < g_st.search_song_count);
|
||||
if (ok) *out = g_st.search_songs[i];
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return ok ? NCM_OK : NCM_ERR_ARG;
|
||||
}
|
||||
|
||||
int appstate_search_pl(int i, ncm_playlist_t *out)
|
||||
{
|
||||
if (!out) return NCM_ERR_ARG;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
int ok = (i >= 0 && i < g_st.search_pl_count);
|
||||
if (ok) *out = g_st.search_pls[i];
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
return ok ? NCM_OK : NCM_ERR_ARG;
|
||||
}
|
||||
|
||||
void appstate_search_clear(int tab)
|
||||
{
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
if (tab == 0) {
|
||||
g_st.search_song_count = 0; g_st.search_song_offset = 0;
|
||||
g_st.search_song_total = -1; g_st.search_song_more = 1;
|
||||
memset(g_st.search_songs, 0, sizeof g_st.search_songs);
|
||||
} else {
|
||||
g_st.search_pl_count = 0; g_st.search_pl_offset = 0;
|
||||
g_st.search_pl_total = -1; g_st.search_pl_more = 1;
|
||||
memset(g_st.search_pls, 0, sizeof g_st.search_pls);
|
||||
}
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
}
|
||||
|
||||
/* 追加单曲结果(worker 锁内):写 g_st.search_songs[count..),回填 offset/total/has_more。 */
|
||||
void appstate_search_append_songs(int n, const ncm_song_t *s, int64_t total)
|
||||
{
|
||||
if (n <= 0 || !s) return;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
int room = NCM_SEARCH_SONG_MAX - g_st.search_song_count;
|
||||
if (n > room) n = room;
|
||||
if (n > 0) memcpy(&g_st.search_songs[g_st.search_song_count], s, (size_t)n * sizeof(ncm_song_t));
|
||||
g_st.search_song_count += n;
|
||||
g_st.search_song_offset = g_st.search_song_count;
|
||||
g_st.search_song_total = (total >= 0) ? (int)total : g_st.search_song_total;
|
||||
int t = g_st.search_song_total;
|
||||
g_st.search_song_more = (t >= 0) ? (g_st.search_song_count < t) : (n >= NCM_SEARCH_PAGE);
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
}
|
||||
|
||||
void appstate_search_append_pls(int n, const ncm_playlist_t *p, int64_t total)
|
||||
{
|
||||
if (n <= 0 || !p) return;
|
||||
pthread_mutex_lock(&g_search_mu);
|
||||
int room = NCM_SEARCH_PL_MAX - g_st.search_pl_count;
|
||||
if (n > room) n = room;
|
||||
if (n > 0) memcpy(&g_st.search_pls[g_st.search_pl_count], p, (size_t)n * sizeof(ncm_playlist_t));
|
||||
g_st.search_pl_count += n;
|
||||
g_st.search_pl_offset = g_st.search_pl_count;
|
||||
g_st.search_pl_total = (total >= 0) ? (int)total : g_st.search_pl_total;
|
||||
int t = g_st.search_pl_total;
|
||||
g_st.search_pl_more = (t >= 0) ? (g_st.search_pl_count < t) : (n >= NCM_SEARCH_PAGE);
|
||||
pthread_mutex_unlock(&g_search_mu);
|
||||
}
|
||||
|
||||
/* ---- 搜索历史(≤NCM_SEARCH_HIST_MAX,最新在前;单键 meow_config 持久化,条目以 \n 连接)---- */
|
||||
#define NCM_SEARCH_HIST_KEY "ncm.search_history"
|
||||
static char g_hist[NCM_SEARCH_HIST_MAX][NCM_SEARCH_HIST_LEN];
|
||||
static int g_hist_count;
|
||||
static int g_hist_loaded;
|
||||
|
||||
static void srch_hist_load(void)
|
||||
{
|
||||
char buf[2048];
|
||||
if (meow_config_get(NCM_SEARCH_HIST_KEY, buf, sizeof buf) != MEOW_CFG_OK) { g_hist_count = 0; return; }
|
||||
g_hist_count = 0;
|
||||
char *p = buf;
|
||||
while (p && *p && g_hist_count < NCM_SEARCH_HIST_MAX) {
|
||||
char *nl = strchr(p, '\n');
|
||||
size_t len = nl ? (size_t)(nl - p) : strlen(p);
|
||||
if (len >= NCM_SEARCH_HIST_LEN) len = NCM_SEARCH_HIST_LEN - 1;
|
||||
if (len > 0) { memcpy(g_hist[g_hist_count], p, len); g_hist[g_hist_count][len] = 0; g_hist_count++; }
|
||||
if (!nl) break;
|
||||
p = nl + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void srch_hist_save(void)
|
||||
{
|
||||
char buf[2048];
|
||||
size_t bl = 0;
|
||||
buf[0] = 0;
|
||||
for (int i = 0; i < g_hist_count; i++) {
|
||||
int n = snprintf(buf + bl, sizeof buf - bl, "%s%s", i ? "\n" : "", g_hist[i]);
|
||||
if (n < 0) break;
|
||||
bl += (size_t)n;
|
||||
if (bl >= sizeof buf - 1) break;
|
||||
}
|
||||
meow_config_set(NCM_SEARCH_HIST_KEY, buf);
|
||||
}
|
||||
|
||||
static void appstate_srch_hist_init(void)
|
||||
{
|
||||
if (!g_hist_loaded) { srch_hist_load(); g_hist_loaded = 1; }
|
||||
}
|
||||
|
||||
int appstate_search_history_count(void)
|
||||
{
|
||||
appstate_srch_hist_init();
|
||||
return g_hist_count;
|
||||
}
|
||||
|
||||
int appstate_search_history_get(int i, char *out, size_t sz)
|
||||
{
|
||||
appstate_srch_hist_init();
|
||||
if (i < 0 || i >= g_hist_count) return 0;
|
||||
ncm_strlcpy(out, g_hist[i], sz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void appstate_search_history_add(const char *kw)
|
||||
{
|
||||
if (!kw || !kw[0]) return;
|
||||
appstate_srch_hist_init();
|
||||
char tmp[NCM_SEARCH_HIST_MAX][NCM_SEARCH_HIST_LEN];
|
||||
int m = 0;
|
||||
ncm_strlcpy(tmp[m], kw, sizeof tmp[m]);
|
||||
m++;
|
||||
for (int i = 0; i < g_hist_count && m < NCM_SEARCH_HIST_MAX; i++)
|
||||
if (strcmp(g_hist[i], kw) != 0) { ncm_strlcpy(tmp[m], g_hist[i], sizeof tmp[m]); m++; }
|
||||
g_hist_count = m;
|
||||
memcpy(g_hist, tmp, sizeof g_hist);
|
||||
srch_hist_save();
|
||||
}
|
||||
|
||||
void appstate_search_history_remove(int i)
|
||||
{
|
||||
appstate_srch_hist_init();
|
||||
if (i < 0 || i >= g_hist_count) return;
|
||||
for (int j = i; j < g_hist_count - 1; j++)
|
||||
ncm_strlcpy(g_hist[j], g_hist[j + 1], sizeof g_hist[j]);
|
||||
g_hist_count--;
|
||||
srch_hist_save();
|
||||
}
|
||||
|
||||
void appstate_search_history_clear(void)
|
||||
{
|
||||
g_hist_count = 0;
|
||||
g_hist_loaded = 1;
|
||||
srch_hist_save();
|
||||
}
|
||||
Reference in new issue
Block a user