Files
JKVideo/CLAUDE.md

227 lines
12 KiB
Markdown
Raw Normal View History

2026-03-10 17:25:18 +08:00
# reactBilibiliApp — 项目架构与技术要点
## 项目概述
2026-03-19 16:34:56 +08:00
仿 B 站 React Native 客户端,使用 Expo SDK 55 + expo-router调用 Bilibili 官方 Web API 获取热门视频、直播、视频详情、弹幕、评论、搜索及扫码登录。
2026-03-10 17:25:18 +08:00
## 技术栈
| 层 | 技术 |
|---|---|
| 框架 | React Native 0.83 + Expo SDK 55 |
2026-03-19 16:34:56 +08:00
| 路由 | expo-router v4文件系统路由Stack 导航) |
2026-03-10 17:25:18 +08:00
| 状态管理 | Zustand |
| 网络请求 | Axios |
| 本地存储 | @react-native-async-storage/async-storage |
2026-03-19 16:34:56 +08:00
| 视频播放(详情页/直播) | react-native-videoDASH/HLS/MP4|
| 视频播放(首页 BigCard | react-native-videoDASH MPD内联自动播放 |
| 视频播放WebView 降级) | react-native-webviewNativeVideoPlayer |
| 页面滑动 | react-native-pager-view首页热门/直播 Tab |
2026-03-10 17:25:18 +08:00
| 图标 | @expo/vector-iconsIonicons |
## 目录结构
```
app/
2026-03-19 16:34:56 +08:00
_layout.tsx # 根布局Stack 导航 + 启动时恢复登录态/下载列表/设置
# 全局挂载 <MiniPlayer />
index.tsx # 首页PagerView 切换热门/直播;绝对定位悬浮导航栏
2026-03-10 17:25:18 +08:00
video/
_layout.tsx # Stack 导航(无头部)
2026-03-19 16:34:56 +08:00
[bvid].tsx # 视频详情页(播放 + 简介/评论/弹幕 三 Tab + 推荐视频 + 下载)
live/
_layout.tsx # Stack 导航(无头部)
[roomId].tsx # 直播详情页HLS/FLV 播放 + 简介/弹幕 Tab
search.tsx # 搜索页(关键词搜索视频)
downloads.tsx # 下载管理页(已下载视频列表)
settings.tsx # 设置页(封面图清晰度 + 退出登录)
2026-03-10 17:25:18 +08:00
components/
2026-03-19 16:34:56 +08:00
VideoCard.tsx # 双列视频卡片封面、标题、UP主、播放量读 settingsStore 决定图片质量
BigVideoCard.tsx # 全宽视频卡片(首页热门精选),内联 react-native-video 自动播放,
# 支持静音/取消静音、水平滑动快进、进度条/缓冲条
LiveCard.tsx # 直播房间卡片(封面、主播、在线人数、直播状态脉冲点)
LivePulse.tsx # 直播红点动画组件
VideoPlayer.tsx # 视频播放器入口web → <video>native → react-native-video (DASH/MP4)
# 支持多清晰度切换
NativeVideoPlayer.tsx# WebView 内嵌 HTML5 videoJS 注入 src降级方案
LivePlayer.tsx # 直播播放器react-native-video HLS多画质切换
DanmakuList.tsx # 弹幕列表面板(视频/直播通用);支持逐行逐帧 drip 渲染、
# 舰长标记、礼物计数、实时直播弹幕追加
DanmakuOverlay.tsx # 悬浮弹幕层(飘屏弹幕,用于视频播放器覆盖层)
MiniPlayer.tsx # 全局迷你播放器(底部悬浮,切页后继续播放)
2026-03-10 17:25:18 +08:00
CommentItem.tsx # 评论条目
LoginModal.tsx # 扫码登录 Modal底部弹出
2026-03-19 16:34:56 +08:00
DownloadSheet.tsx # 下载选择面板(选清晰度后触发下载)
DownloadProgressBtn.tsx # 导航栏下载进度按钮(显示正在下载数量)
2026-03-10 17:25:18 +08:00
hooks/
2026-03-19 16:34:56 +08:00
useVideoList.ts # 热门视频 + 首页直播轮播分页加载(下拉刷新、上拉加载更多)
useLiveList.ts # 直播列表分页加载(按分区过滤)
useVideoDetail.ts # 视频详情 + 获取播放流 URL支持多清晰度 DASH/MP4
useLiveDetail.ts # 直播间详情 + HLS/FLV 流地址(支持画质切换)
useLiveDanmaku.ts # 直播弹幕 WebSocket 实时接收
useComments.ts # 评论分页加载(热评/最新排序)
useRelatedVideos.ts # 推荐视频流(视频详情页简介 Tab 下方)
useSearch.ts # 搜索钩子(分页加载搜索结果)
useDownload.ts # 下载任务管理
2026-03-10 17:25:18 +08:00
services/
bilibili.ts # 所有 API 请求axios 实例 + Cookie 拦截器)
types.ts # 数据类型定义
2026-03-19 16:34:56 +08:00
2026-03-10 17:25:18 +08:00
store/
2026-03-19 16:34:56 +08:00
authStore.ts # Zustand 登录状态sessdata/uid/username/face + 持久化)
downloadStore.ts # Zustand 下载任务列表(持久化)
settingsStore.ts # Zustand 用户设置coverQuality: 'hd'|'normal' + 持久化)
videoStore.ts # Zustand 当前播放视频状态(供 MiniPlayer 使用)
2026-03-10 17:25:18 +08:00
utils/
format.ts # formatCount / formatDuration / formatTime
2026-03-19 16:34:56 +08:00
imageUrl.ts # proxyImageUrlWeb 代理绕防盗链)/ coverImageUrl清晰度参数
dash.ts # buildDashMpdUri将 B 站 DASH 接口数据转换为 MPD 文件 URI
danmaku.ts # danmakuColorToCss弹幕颜色转换
2026-03-10 17:25:18 +08:00
```
## 路由结构
2026-03-19 16:34:56 +08:00
- `/` → 首页Stack 根页面PagerView 热门/直播 Tab
- `/video/[bvid]` → 视频详情Stack pushslide_from_right 动画)
- `/live/[roomId]` → 直播详情Stack pushslide_from_right 动画)
- `/search` → 搜索页Stack push
- `/downloads` → 下载管理Stack push
- `/settings` → 设置Stack push已登录时从头像按钮进入
## 首页结构index.tsx
- **PagerView** 容纳热门列表page 0和直播列表page 1`scrollEnabled: false`
- **绝对定位悬浮导航栏**Header头像/搜索框/下载按钮)+ Tab 行(热门/直播),随内容滚动收起
- **热门列表**`toListRows()` 将视频分为 `big`(全宽 BigVideoCard`live`(直播推荐)、`pair`(双列 VideoCard三种行类型
- **直播列表**:横向分区过滤 ScrollView + 双列 LiveCard 网格,支持按分区 ID 切换
- 点击已激活 Tab 会滚动到顶并刷新数据
## BigVideoCard 内联视频components/BigVideoCard.tsx
- 使用 `react-native-video` 直接播放 DASHfnval=16buildDashMpdUri 转 MPD
- 可见时自动播放(静音),不可见时暂停并恢复封面
- 水平滑动手势PanResponder实现快进/快退,显示时间标签
- 进度条 + 缓冲条;静音/取消静音按钮
- 封面图质量受 `settingsStore.coverQuality` 控制
2026-03-10 17:25:18 +08:00
## Bilibili API 关键点
### axios 实例services/bilibili.ts
- 统一携带 `Referer: https://www.bilibili.com``User-Agent`(模拟 Chrome
- 请求拦截器自动注入 Cookie`buvid3`(随机生成并持久化)+ `SESSDATA`(登录后)
### 主要接口
| 函数 | 接口 | 说明 |
|---|---|---|
| `getPopularVideos(pn)` | `/x/web-interface/popular` | 热门视频,每页 20 条 |
2026-03-19 16:34:56 +08:00
| `getVideoDetail(bvid)` | `/x/web-interface/view` | 视频详情(含 ugc_season 合集) |
| `getPlayUrl(bvid, cid, fnval)` | `/x/player/playurl` | 获取播放流fnval=16 DASHfnval=0 MP4 |
| `getRecommendFeed(idx)` | `/x/web-interface/index/top/rcmd` | 推荐视频流(详情页下方) |
| `getComments(aid, pn, sort)` | `/x/v2/reply` | 评论列表sort=2 热评sort=0 最新) |
| `getDanmaku(cid)` | `/x/v1/dm/list.so` | 弹幕列表XML 格式,返回 DanmakuItem[] |
| `getLiveRoomList(areaId, page)` | live 域名 | 直播列表(按分区) |
| `getLiveDetail(roomId)` | live 域名 | 直播间详情 + 主播信息 |
| `getLiveStream(roomId, qn)` | live 域名 | HLS/FLV 直播流地址 |
| `searchVideos(keyword, pn)` | `/x/web-interface/search/all/v2` | 视频搜索 |
2026-03-10 17:25:18 +08:00
| `generateQRCode()` | passport 域名 | 生成登录二维码 |
| `pollQRCode(key)` | passport 域名 | 轮询扫码状态2s 间隔) |
### 播放流参数(重要)
```ts
2026-03-19 16:34:56 +08:00
// DASHreact-native-videodev build / 生产包)
params: { bvid, cid, qn: 112, fnval: 16, platform: 'pc' }
// → 返回 dash 字段,需 buildDashMpdUri 转为本地 MPD
// MP4WebView 降级 / Expo Go
2026-03-10 17:25:18 +08:00
params: { bvid, cid, qn: 64, fnval: 0, platform: 'html5' }
2026-03-19 16:34:56 +08:00
// → 返回 durl[0].url (MP4)
2026-03-10 17:25:18 +08:00
```
2026-03-19 16:34:56 +08:00
- `fnval: 16` → DASH`dash.video[]` + `dash.audio[]`,由 `buildDashMpdUri` 生成 MPD
- `fnval: 0` + `platform: 'html5'` → MP4`durl[0].url`
- `fnval: 1` → FLV不可用HTML5/WebView 不支持)
- `qn: 112` = 1080P+`qn: 80` = 1080P`qn: 64` = 720P未登录时 B 站可能降级
2026-03-10 17:25:18 +08:00
## 视频播放架构
2026-03-19 16:34:56 +08:00
### 视频详情页VideoPlayer
2026-03-10 17:25:18 +08:00
```
VideoPlayer
├── web (Platform.OS === 'web') → 原生 <video> 标签
2026-03-19 16:34:56 +08:00
└── native → react-native-video (DASH MPD / MP4)
支持多清晰度切换、弹幕覆盖层DanmakuOverlay
降级NativeVideoPlayer (WebView + JS 注入)
```
### 首页 BigVideoCard
2026-03-10 17:25:18 +08:00
```
2026-03-19 16:34:56 +08:00
BigVideoCard
└── react-native-videoDASH MPD静音自动播放
+ PanResponder 手势快进
+ 封面 Animated.View 淡出过渡
```
### 直播LivePlayer
```
LivePlayer
└── react-native-videoHLS m3u8 流)
支持画质切换(触发重新获取流地址)
```
## 弹幕系统
- **视频弹幕**`getDanmaku(cid)` 获取全量弹幕,按时间戳 drip 渲染到 `DanmakuList`
- **直播弹幕**`useLiveDanmaku(roomId)` 通过 WebSocket 实时接收支持礼物计数giftCounts
- **弹幕覆盖**`DanmakuOverlay` 悬浮于播放器之上,飘屏滚动
- DanmakuList 支持 `isLive` 模式(实时追加新弹幕,保留最近 500 条)
2026-03-10 17:25:18 +08:00
2026-03-19 16:34:56 +08:00
## 下载功能
- `DownloadSheet`:选择清晰度后调用 `useDownload` 触发后台下载
- `downloadStore`:持久化下载任务列表(进度、状态、本地路径)
- `DownloadProgressBtn`:导航栏图标,显示正在下载的任务数量
- `downloads.tsx`:下载管理页,列出已完成/进行中任务,支持播放和删除
2026-03-10 17:25:18 +08:00
## 登录流程
2026-03-19 16:34:56 +08:00
1. 未登录时右上角头像图标 → 弹出 `LoginModal`;已登录时跳转 `/settings`
2026-03-10 17:25:18 +08:00
2. 调用 `generateQRCode()` 获取 `qrcode_key` + 二维码 URL
3.`https://api.qrserver.com` 渲染二维码图片(第三方服务)
4. 每 2s 轮询 `pollQRCode``code === 0` 时从响应 Header `set-cookie` 提取 `SESSDATA`
5. `useAuthStore.login()``SESSDATA` 写入 AsyncStorage 并更新 Zustand 状态
2026-03-19 16:34:56 +08:00
6. 启动时 `_layout.tsx` 调用 `restore()` 恢复登录态、下载列表、设置
## 设置settings.tsx / settingsStore
- `coverQuality: 'hd' | 'normal'`:控制封面图清晰度
- `hd`:原始 URL不加参数
- `normal`:追加 `@320w_180h_1c.webp` 缩略图参数,节省流量
- VideoCard 和 BigVideoCard 均从 `settingsStore` 读取此值
- 退出登录功能(调用 `authStore.logout()`
## imageUrl 工具
```ts
proxyImageUrl(url) // Web 端转本地代理 localhost:3001/bilibili-img/...(绕防盗链)
// Native 端将 http:// 强制改为 https://
coverImageUrl(url, quality) // 在 proxyImageUrl 基础上附加清晰度参数
```
2026-03-10 17:25:18 +08:00
## 主题色
- 主色:`#00AEEC`B 站蓝)
- 文字主色:`#212121`
- 次要文字:`#999`
- 背景:`#f4f4f4`(列表)/ `#fff`(卡片)
2026-03-19 16:34:56 +08:00
- 危险色(退出登录等):`#ff4757`
2026-03-10 17:25:18 +08:00
## 开发注意事项
### 运行方式
2026-03-19 16:34:56 +08:00
- Dev Build推荐`expo run:android`,支持 react-native-videoDASH/HLS
- Expo Go`expo start` 扫码react-native-video 可用但部分编解码受限,降级用 WebView 方案
2026-03-10 17:25:18 +08:00
### 常见问题
2026-03-19 16:34:56 +08:00
- **视频无法播放**:检查 `fnval`DASH 需确认 `buildDashMpdUri` 生成的 MPD 合法
2026-03-10 17:25:18 +08:00
- **API 403**`buvid3` Cookie 或 `SESSDATA` 失效,清除 AsyncStorage 重试
- **评论为空**B 站部分视频评论区关闭,`replies` 字段为 null 属正常
- **二维码过期**`pollQRCode` 返回 `code === 86038`,关闭 Modal 重新打开即可
2026-03-19 16:34:56 +08:00
- **直播无法播放**:确认 HLS URL 有效;部分直播间仅提供 FLV需选 FLV 流
- **封面加载慢**:在设置中切换为「普通」清晰度可减小图片体积
2026-03-10 17:25:18 +08:00
### 扩展方向
- 动态流:需更高权限 Cookie`bili_jct` CSRF Token
2026-03-19 16:34:56 +08:00
- 投稿/点赞/收藏:需登录态 + CSRF
- 离线弹幕导出DanmakuItem 已有完整数据结构