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
@@ -456,14 +456,11 @@ int ncm_api_lyric(const char *device_id, const char *cookie, const char *id,
|
||||
return NCM_OK;
|
||||
}
|
||||
|
||||
int ncm_api_cloudsearch(const char *device_id, const char *cookie, const char *keyword,
|
||||
ncm_song_t *out, int max, int *out_n) {
|
||||
if (!out_n) return NCM_ERR_ARG;
|
||||
*out_n = 0;
|
||||
if (!keyword || !keyword[0] || !out || max <= 0) return NCM_ERR_ARG;
|
||||
|
||||
/* /api/cloudsearch/pc:s=关键词 type=1(单曲) offset/limit 翻页。v1 只取前 max 条。
|
||||
* 关键词转义(\" 与 \\),防止 IME 输入引号/反斜杠拼出坏 JSON。 */
|
||||
/* /api/cloudsearch/pc 公共 POST(type=单曲/歌单/专辑 共用):s=关键词 type/offset/limit/total。
|
||||
* 关键词转义(\" 与 \\),防止 IME 输入引号/反斜杠拼出坏 JSON。 */
|
||||
static int cloudsearch_post(const char *device_id, const char *cookie, const char *keyword,
|
||||
int type, int offset, int limit, api_json_t *c)
|
||||
{
|
||||
char esc[256], json[512];
|
||||
size_t ei = 0;
|
||||
for (size_t si = 0; keyword[si] && ei < sizeof esc - 3; si++) {
|
||||
@@ -472,20 +469,85 @@ int ncm_api_cloudsearch(const char *device_id, const char *cookie, const char *k
|
||||
esc[ei++] = ch;
|
||||
}
|
||||
esc[ei] = 0;
|
||||
snprintf(json, sizeof json, "{\"s\":\"%s\",\"type\":1,\"offset\":0,\"limit\":%d,\"total\":true}",
|
||||
esc, max);
|
||||
snprintf(json, sizeof json, "{\"s\":\"%s\",\"type\":%d,\"offset\":%d,\"limit\":%d,\"total\":true}",
|
||||
esc, type, offset > 0 ? offset : 0, limit > 0 ? limit : 30);
|
||||
return api_post(device_id, cookie, "/api/cloudsearch/pc", json, NCM_CRYPT_WEAPI,
|
||||
NCM_RESP_MAX, c);
|
||||
}
|
||||
|
||||
/* 解析一处「歌单对象数组」(cloudsearch type=1000)。id 可为数字/字符串(均文本拷贝)。 */
|
||||
static int parse_playlists_array(const ncm_json_t *j, int arr, ncm_playlist_t *out, int max, int *out_n)
|
||||
{
|
||||
*out_n = 0;
|
||||
if (arr < 0 || ncm_json_type(j, arr) != JSMN_ARRAY) return NCM_ERR_NOTFOUND;
|
||||
int cnt = ncm_json_arr_len(j, arr);
|
||||
if (cnt > max) cnt = max;
|
||||
memset(out, 0, sizeof(*out) * (size_t)(cnt > 0 ? cnt : 0));
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
int e = ncm_json_arr_get(j, arr, i);
|
||||
if (e < 0) break;
|
||||
obj_str(j, e, "id", out[i].id, sizeof out[i].id);
|
||||
obj_str(j, e, "name", out[i].name, sizeof out[i].name);
|
||||
obj_str(j, e, "coverImgUrl", out[i].cover, sizeof out[i].cover);
|
||||
out[i].track_count = (int)obj_int(j, e, "trackCount");
|
||||
out[i].is_collected = 0;
|
||||
}
|
||||
*out_n = cnt;
|
||||
return NCM_OK;
|
||||
}
|
||||
|
||||
/* 搜索结果计数(cloudsearch result.songCount / result.playlistCount;缺省 → *out_total=-1 未知)。 */
|
||||
static void cloudsearch_count(const ncm_json_t *j, const char *path, int64_t *out_total)
|
||||
{
|
||||
if (!out_total) return;
|
||||
*out_total = -1;
|
||||
int t = ncm_json_path(j, path);
|
||||
int rc = NCM_ERR_NOTFOUND;
|
||||
int64_t v = ncm_json_get_i64_at(j, t, &rc);
|
||||
if (rc == NCM_OK) *out_total = v;
|
||||
}
|
||||
|
||||
int ncm_api_cloudsearch_song(const char *device_id, const char *cookie, const char *keyword,
|
||||
int offset, int limit, ncm_song_t *out, int max, int *out_n,
|
||||
int64_t *out_total) {
|
||||
if (!out_n) return NCM_ERR_ARG;
|
||||
*out_n = 0;
|
||||
if (out_total) *out_total = -1;
|
||||
if (!keyword || !keyword[0] || !out || max <= 0) return NCM_ERR_ARG;
|
||||
|
||||
api_json_t c; memset(&c, 0, sizeof c);
|
||||
int rc = api_post(device_id, cookie, "/api/cloudsearch/pc", json, NCM_CRYPT_WEAPI,
|
||||
NCM_RESP_MAX, &c);
|
||||
int rc = cloudsearch_post(device_id, cookie, keyword, 1, offset, limit, &c);
|
||||
if (rc != NCM_OK) return rc;
|
||||
|
||||
cloudsearch_count(&c.j, "result.songCount", out_total);
|
||||
int arr = ncm_json_path(&c.j, "result.songs");
|
||||
int rc2 = parse_songs_array(&c.j, arr, out, max, out_n);
|
||||
api_free(&c);
|
||||
return rc2;
|
||||
}
|
||||
|
||||
int ncm_api_cloudsearch_playlist(const char *device_id, const char *cookie, const char *keyword,
|
||||
int offset, int limit, ncm_playlist_t *out, int max, int *out_n,
|
||||
int64_t *out_total) {
|
||||
if (!out_n) return NCM_ERR_ARG;
|
||||
*out_n = 0;
|
||||
if (out_total) *out_total = -1;
|
||||
if (!keyword || !keyword[0] || !out || max <= 0) return NCM_ERR_ARG;
|
||||
|
||||
api_json_t c; memset(&c, 0, sizeof c);
|
||||
int rc = cloudsearch_post(device_id, cookie, keyword, 1000, offset, limit, &c);
|
||||
if (rc != NCM_OK) return rc;
|
||||
cloudsearch_count(&c.j, "result.playlistCount", out_total);
|
||||
int arr = ncm_json_path(&c.j, "result.playlists");
|
||||
int rc2 = parse_playlists_array(&c.j, arr, out, max, out_n);
|
||||
api_free(&c);
|
||||
return rc2;
|
||||
}
|
||||
|
||||
int ncm_api_cloudsearch(const char *device_id, const char *cookie, const char *keyword,
|
||||
ncm_song_t *out, int max, int *out_n) {
|
||||
return ncm_api_cloudsearch_song(device_id, cookie, keyword, 0, max, out, max, out_n, NULL);
|
||||
}
|
||||
|
||||
/* 从一段 track/all 响应 JSON 串解析歌曲数组 + total(离线样本/单元测试用,不打网络)。
|
||||
* 数组取「songs → playlist.tracks → data.songs」首个命中;total 取「total → count →
|
||||
* playlist.trackCount → musicCount」,全缺则 0。 */
|
||||
|
||||
@@ -130,8 +130,16 @@ int ncm_api_parse_vip_info(const char *json, size_t len, int64_t now_ms, ncm_vip
|
||||
int ncm_api_lyric(const char *device_id, const char *cookie, const char *id,
|
||||
char *lrc, size_t lrc_sz, char *tlrc, size_t tlrc_sz);
|
||||
|
||||
/* 搜索(weapi /api/cloudsearch/pc):keyword 搜索歌曲(type=1)。out 填 ncm_song_t。
|
||||
* 仅返回前端可解析字段(name/ar[0]/al/dt/id)。风控:只在用户确认时调用。 */
|
||||
/* 搜索(weapi /api/cloudsearch/pc)。type 映射(BIZ_NOTES §5.1):1=单曲、1000=歌单、(10=专辑留后续)。
|
||||
* offset/limit 分页(limit=30/页,REPORT §23);*out_total=服务端总数(-1=未知)。
|
||||
* 风控:只在用户点「搜索」/翻页时调用。 */
|
||||
int ncm_api_cloudsearch_song(const char *device_id, const char *cookie, const char *keyword,
|
||||
int offset, int limit, ncm_song_t *out, int max, int *out_n,
|
||||
int64_t *out_total);
|
||||
int ncm_api_cloudsearch_playlist(const char *device_id, const char *cookie, const char *keyword,
|
||||
int offset, int limit, ncm_playlist_t *out, int max, int *out_n,
|
||||
int64_t *out_total);
|
||||
/* 兼容旧签名:单曲(type=1, offset=0, limit=max)。 */
|
||||
int ncm_api_cloudsearch(const char *device_id, const char *cookie, const char *keyword,
|
||||
ncm_song_t *out, int max, int *out_n);
|
||||
|
||||
|
||||
Reference in new issue
Block a user