/youtube/live 默认 5 分钟缓存会快速耗尽 search.list 的 100 次/日配额
- Dominant language
- TypeScript
- Stars
- 46.2k
- Forks
- 10.2k
- Avg merge
- 8h 48m
- Merged PRs (30d)
- 175
Description
### 路由地址
```routes
/youtube/live/:username/:embed?
```
### 完整路由地址
```fullroutes
/youtube/live/@GawrGura
```
### 相关文档
https://docs.rsshub.app/routes/youtube#youtube-live-username-embed
### 预期是什么?
配置有效的 YOUTUBE_KEY 后,/youtube/live 应当能够在默认缓存配置下持续获取频道的直播状态,而不会因为 RSS 阅读器正常轮询而在一天的大部分时间内耗尽 YouTube search.list 配额。
如果上游配额确实已经耗尽,也希望 RSSHub 能保留并返回明确的 quotaExceeded 错误,方便定位问题,而不是将上游错误转换成后续访问 undefined.data 时产生的 TypeError。
理想情况下,可以避免或显著减少每次缓存过期时对 search.list 的调用;至少也应在文档中说明该路由与 YouTube 默认 Search Queries 配额之间的限制。
### 实际发生了什么?
当前 master 中,/youtube/live 的 getLive() 会在缓存未命中时调用:
https://github.com/DIYgod/RSSHub/blob/dfb39a252a0eb8d26214d59aee2868849ef6ccae/lib/routes/youtube/utils.tsx#L120-L136
该结果使用默认 CACHE_EXPIRE=300,即缓存 5 分钟。
RSSHub 本身并不是每 5 分钟主动执行一次后台任务;但如果 RSS 阅读器持续请求该路由,那么每次缓存过期后的第一个请求都会产生一次新的 search.list 调用。单个频道理论上最多产生:
86400 / 300 = 288 次 search.list / 天
YouTube Data API 从 2026-06-01 起为 search.list 使用独立的 Search Queries 配额。默认额度为 100 次/天,每次 search.list 消耗 1 次 Search
Query:
https://developers.google.com/youtube/v3/docs/search/list
https://developers.google.com/youtube/v3/revision_history#june-01-2026
https://developers.google.com/youtube/v3/determine_quota_cost
因此,在一个频道持续以 5 分钟间隔访问的情况下:
第 100 次调用:约 8 小时 15 分
第 101 次调用:约 8 小时 20 分,开始超过每日配额
这还没有计算多个 /youtube/live 频道共同使用同一个 Google Cloud project 的情况。多个 API key 如果属于同一个 project,也不会增加该 project 的每日额度。
这个问题不要求频道当时真的存在直播,因为 search.list 在返回空结果时同样会消耗配额。配额通常在 Pacific Time 午夜重置。
另外,目前 Google API wrapper 会捕获错误并返回 undefined。因此上游的 HTTP 403 quotaExceeded 可能最终表现为类似下面的错误,而不是明确的配额错误:
Cannot read properties of undefined (reading 'data')
这不是指 2026 年的新配额机制突然降低了原有的可调用次数。旧机制下 search.list 每次消耗 100 个通用 quota units,默认 10,000 units/day 实际上同样大约只能调用 100 次。核心问题是默认 5 分钟刷新周期一直与默认搜索配额不相容;现在独立的 Search Queries 指标使问题更加容易观察。
===========
作为不使用 search.list 的参考,我目前在 asmr-tg-backup 中采用以下方式:
使用 YouTube 官方频道 Atom feed 获取新出现的 video ID:
https://www.youtube.com/feeds/videos.xml?channel_id=
持久化去重,只对新发现或仍处于 active 状态的 ID 做增量 metadata probe,而不是每轮重新搜索整个频道。
dev 分支中的会员直播观察实验会比较 Atom feed、频道 /streams 页面和派生的 UUMO... playlist,并对新 ID 做浅层探测,同时设置退避和冷却:
https://github.com/dreaifekks/asmr-tg-backup/blob/dev/docs/youtube-membership-dev.md#L1-L56
需要说明的是,UUMO... playlist、频道网页和 yt-dlp extractor 都不是 YouTube Data API 的稳定公开契约。这个实验也是默认关闭、匿名、仅元数据的观察器,不使用 cookies 或登录凭据,也不读取或下载会员内容。因此它只能作为“先发现 ID,再增量探测”的设计参考,不能直接作为 RSSHub 的稳定替代实现。
### 部署
自建
### 部署相关信息
OS:Linux, Docker: v28.0.4, Docker Compose: v2.34.0, Node: v24.18.0
### 额外信息
```shell
Google Cloud Console quota:
Queries per day: 10,000
Search Queries per day: 100
Search Queries per minute: 100
Expected upstream error after exhaustion:
HTTP 403
reason: quotaExceeded
```
### 这不是重复的 issue
- [x] 我已经搜索了 [现有 issue](https://github.com/DIYgod/RSSHub/issues),以确保该错误尚未被报告。
Contributor guide
Research direction
Start with lib/routes/youtube/utils.tsx at the getLive() code around lines 120-136, then inspect the cache behavior and Google API wrapper error handling. The work is done when the default polling pattern no longer rapidly exhausts search.list quota, or the limitation is clearly documented, and quotaExceeded remains visible instead of becoming a TypeError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- google-cloud, typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100