Skip to content

修复追番页获取不全的问题 - #1396

Open
citrusreticulata wants to merge 5 commits into
mirai-mamori:previewfrom
citrusreticulata:fix-bangumi-fetch
Open

修复追番页获取不全的问题#1396
citrusreticulata wants to merge 5 commits into
mirai-mamori:previewfrom
citrusreticulata:fix-bangumi-fetch

Conversation

@citrusreticulata

Copy link
Copy Markdown
Contributor

修复追番页获取不全的问题 #1386

该php脚本会从https://api.bgm.tv/拉取用户的追番列表,以json返回,存储在$collData中。然而,当用户追番数量较多时,这段程序没有正确处理分页参数,导致只能获取第一页的数据。

现在,执行1次API调用后,会拿取第一页数据,并且根据返回的total参数判断是否有其他页的数据需要获取。如果有其他页,则调用若干次API获取全部番剧列表。

修复追番页获取不全的问题
mirai-mamori#1386
增加安全锁,放置调用次数过多;修正注释错误
@bymoye
bymoye requested a review from Copilot May 31, 2026 03:05
@bymoye
bymoye requested a review from Shiroiame-Kusu May 31, 2026 03:06
@bymoye
bymoye changed the base branch from main to preview May 31, 2026 03:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Bangumi collection fetch logic to retrieve paginated anime collection data from the Bangumi API, addressing incomplete display when a user has more than one page of tracked anime.

Changes:

  • Adds subject_type, limit, and offset query parameters for Bangumi API requests.
  • Fetches additional pages based on the API total value and merges results.
  • Caches the merged Bangumi API response shape after fetching.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread inc/classes/bangumi.php
Comment thread inc/classes/bangumi.php Outdated
@citrusreticulata

Copy link
Copy Markdown
Contributor Author

这个功能有个讨论点来着,修复的是追番模板获取不全的的问题。那么现在要获取全就牵扯到获取多少个内容。

我加了个安全锁是,如果这个人追番特别多(超过10页)就只获取前10页不然网页卡爆了,但是copilot自动review就不管这事😰

所以是即使可能会卡爆但依然获取全部,还是为保安全只获取前十页(大概是500条)呢,我倾向于后者。

@Sualiu

Sualiu commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

似乎发现了一些可以改进的地方。

关于 API 参数:实测 api.bgm.tv/v0/users/sai/collections,不传 subject_type 时返回 1591 条全类型收藏(动漫+音乐+游戏+书籍+真人),传 subject_type=2 后只返回 508 条动漫。当前代码不传 subject_type,等于拉了 3 倍冗余数据再客户端过滤。虽然 PR 里加了 subject_type=2 ,但是客户端过滤那里还在检查 subject_type == 2,服务端已经保证了,应该可以去掉。

关于同步拉取:最多 10 次串行请求,缓存过期的时候用户得等全部拉完才能看到页面,最坏情况可能需要十几秒。主题里 Bilibili 收藏夹的做法是用 BilibiliFavListCron + wp_schedule_event 后台定时拉取数据写 transient,用户请求时只读缓存,完全不会阻塞。感觉 Bangumi 也可以参考这个模式。

几个小问题

  • http_get_contents 没设 timeout,Bangumi API 偶尔响应很慢,建议加上 timeout => 15,跟 Bilibili 模块保持一致
  • 中间页请求失败时数据被静默跳过了,没有 error_log 也没有重试,用户看到不完整的列表可能不会意识到数据缺失
  • $collData['limit'] = $total 这个覆盖有点危险,limit 原本是每页大小(50)的意思,改成总数的话如果后续有代码依赖原始语义会出问题
  • 分页判断用 do-while + count($dataList) >= $total 可能比 ceil($total / $pageLimit) 算页数再 for 循环更直观一些
  • API 错误时返回格式是 {"title":"Not Found","description":"user doesn't exist..."},没有 data 字段,当前 isset($collData['data']) 虽然检查可以正确处理,但是否缓存写入条件也加上 !isset($collData['error']),避免缓存错误响应

想法:如果没有问题的话,WP-Cron 后台预取的改动比较大,我可以单独提一个 PR 来做,对标 BilibiliFavListCron 的模式。

fetchCollections

if ($collData === null) {
    $dataList = [];
    $offset = 0;
    $pageLimit = 50;
    $maxPages = 10;
    $total = 0;

    do {
        $url = $this->collectionApi
            . '?subject_type=2&limit=' . $pageLimit
            . '&offset=' . $offset;
        $response = $this->http_get_contents($url);
        $pageData = json_decode($response, true);

        if (!isset($pageData['data']) || !is_array($pageData['data'])) {
            error_log('BangumiAPI: fetchCollections failed at offset=' . $offset);
            break;
        }

        $dataList = array_merge($dataList, $pageData['data']);
        $total = $pageData['total'] ?? count($dataList);
        $offset += $pageLimit;

        if (count($dataList) >= $total || count($pageData['data']) < $pageLimit) {
            break;
        }
    } while (--$maxPages > 0);

    if ($bangumi_cache && !empty($dataList)) {
        auto_update_cache($cache_key, json_encode([
            'data' => $dataList,
            'total' => $total,
        ]));
    }

    return array_filter($dataList, function ($item) {
        return in_array($item['type'], [2, 3]);
    });
}

http_get_contentstimeout

$response = wp_remote_get($url, [
    'user-agent' => 'mirai-mamori/Sakurairo(...):WordPressTheme',
    'timeout' => 15,
]);

@Sualiu

Sualiu commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

补充一个问题:关键 API 接口,api.bgm.tv 目前在中国大陆可能无法直接访问。

似乎最近几天开始,Bangumi 的几个域名(bgm.tv、bangumi.tv、chii.in)在中国大陆出现大面积连接故障,监测数据显示符合 GFW/运营商 DNS 污染的典型特征。这意味着部署在国内服务器上的 WordPress 站点,wp_remote_get('https://api.bgm.tv/...') 大概率会超时失败。

这不是本 PR 需要解决的问题,但建议在官方决定并修复问题时在代码或文档中加一条提示,告知国内用户可能需要自行配置代理或通过其他方式确保服务器能访问 api.bgm.tv

一些可以了解的信息来源:https://news.17173.com/content/05302026/145056389.shtml

https://bgm.tv/group/forum

强化了数据返回的判断逻辑;
删掉了防御性的'subject_type'判断;
延长了超时时间。
@citrusreticulata

Copy link
Copy Markdown
Contributor Author

非常感谢review意见@Sualiu ,已经进行了一些修改。
首先是对review的逐条回复:

  1. 关于API参数的问题,subject_type == 2检查是原有的,旧代码在拉取时没有约定参数导致了浪费。我原本加上了请求参数但保留了校验,这部分防御性的检查去掉似乎大概应该也没问题,已经去掉。
  2. 关于同步拉取。这部分我不太熟悉,但我读代码时发现bgm这部分的拉取逻辑是:“(1)全量拉取缓存;(2)只渲染缓存的前一小部分部分;(3)用户下拉再渲染后续部分”时我还是大为震撼。但我不太确定这部分应该怎么写合适,所以没有做出改动。我觉得合适的应该是用户下拉页面后再请求,这才有分页的意义,奈何我对这部分代码其实并不熟悉。
  3. http_get_contents 新增了15秒超时限制,和bilibili保持一致;
  4. “中间页请求失败时数据被静默跳过了”,这个确实是这样。结合另一条所说api近期访问异常的情况,我觉得获取不到数据可能会比较频发。这里的解决方案我觉得不需要特别处理,毕竟网络不通应该是整页都无数据。
  5. $collData['limit'] = $total 这个覆盖,主要是考虑到可能根据limit来获取当前“分片”的数据大小。如果不覆盖则无法直接获取当前数据条目数而需要重新计数。这里的覆盖相当于伪造了api的请求忽略了limit的上限。
  6. 个人习惯用for一点,哈哈。因为计次非常直观,不容易出现条件判断失误造成的死循环。
  7. 缓存写入条件已经有 !isset($collData['error']) 了。不知道你指的是不是最终的返回值检查?这里我新增了error 判断。
  8. WP-Cron 后台预取,这个就在新PR解决吧。
  9. API无法直接访问的问题,这个和wp头像无法直接访问的问题类似。感觉应该从其他角度(例如文档中说明)来解决或提示。

@Sualiu

Sualiu commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

这样理解了,

非常感谢review意见@Sualiu ,已经进行了一些修改。 首先是对review的逐条回复:

  1. 关于API参数的问题,subject_type == 2检查是原有的,旧代码在拉取时没有约定参数导致了浪费。我原本加上了请求参数但保留了校验,这部分防御性的检查去掉似乎大概应该也没问题,已经去掉。
  2. 关于同步拉取。这部分我不太熟悉,但我读代码时发现bgm这部分的拉取逻辑是:“(1)全量拉取缓存;(2)只渲染缓存的前一小部分部分;(3)用户下拉再渲染后续部分”时我还是大为震撼。但我不太确定这部分应该怎么写合适,所以没有做出改动。我觉得合适的应该是用户下拉页面后再请求,这才有分页的意义,奈何我对这部分代码其实并不熟悉。
  3. http_get_contents 新增了15秒超时限制,和bilibili保持一致;
  4. “中间页请求失败时数据被静默跳过了”,这个确实是这样。结合另一条所说api近期访问异常的情况,我觉得获取不到数据可能会比较频发。这里的解决方案我觉得不需要特别处理,毕竟网络不通应该是整页都无数据。
  5. $collData['limit'] = $total 这个覆盖,主要是考虑到可能根据limit来获取当前“分片”的数据大小。如果不覆盖则无法直接获取当前数据条目数而需要重新计数。这里的覆盖相当于伪造了api的请求忽略了limit的上限。
  6. 个人习惯用for一点,哈哈。因为计次非常直观,不容易出现条件判断失误造成的死循环。
  7. 缓存写入条件已经有 !isset($collData['error']) 了。不知道你指的是不是最终的返回值检查?这里我新增了error 判断。
  8. WP-Cron 后台预取,这个就在新PR解决吧。
  9. API无法直接访问的问题,这个和wp头像无法直接访问的问题类似。感觉应该从其他角度(例如文档中说明)来解决或提示。

这样这样,知道了,谢谢。
第7点,补充说明一下我原本担心的场景:!isset($collData['error']) 只能捕获第一页请求失败的情况(因为 $collData 是第一页的响应)。如果第一页正常返回,但后续页失败,$collData 里不会有 error 字段,合并后的不完整数据仍然会被缓存。不过就像你说的,网络不通通常是整页都拿不到,所以这个边界情况实际发生的概率很低,保持现状就好。

@Sualiu

Sualiu commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

另外,同步拉取应该只要在实现了WP-Cron后就好了。不过WP-Cron的PR应该需要在项目维护者的肯定后再实施,避免做无用功。

  • WP-Cron 后台预取全量数据写缓存 → 解决阻塞
  • REST API 读缓存切片返回 → 翻页时零延迟,不需要再请求 Bangumi API
  • 用户翻页体验和"下拉再请求"一样,只是数据源从 Bangumi API 变成了本地缓存

应该会比每次翻页都请求 Bangumi API 更可靠

另外,你似乎没有使用AI辅助分析,有些佩服。因为手写真的特别费时间。再次感谢你的认真回复。

@citrusreticulata

Copy link
Copy Markdown
Contributor Author

好哎,我也感觉后台定期更新、读取缓存切片会更可靠一些,而且用户体验会比较好。不过我试了一下,和之前提到的一样,bangumi的api目前不能直接访问。唉,这种网络问题就比较难办了

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

这个 PR 已经 45 天没有任何活动了,将被标记为过时 stale 。 删除 stale 的标签或评论,否则将在 10 天内关闭。

@github-actions github-actions Bot added the Stale label Aug 5, 2026
@citrusreticulata

Copy link
Copy Markdown
Contributor Author

所以还合吗?

@github-actions github-actions Bot removed the Stale label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants