# DASH 1080P Playback Implementation Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 在 Android 上解锁 1080P+ 画质,通过切换至 DASH 格式并生成合法 MPD data URI 传给 ExoPlayer。 **Architecture:** `getPlayUrl` 按平台分叉——Android 使用 `fnval=16` 获取 DASH JSON(含分离的 video/audio 流及 segmentBase 范围);iOS/Web 保持 `fnval=0,platform=html5`(720P MP4)。DASH 数据在 `utils/dash.ts` 中组装成标准 MPD XML,经 `btoa` 编码为 `data:` URI,传给 `react-native-video` 的 ExoPlayer 播放。 **Tech Stack:** React Native 0.83, Expo SDK 55, react-native-video 6.x (ExoPlayer on Android), TypeScript --- ## File Map | 文件 | 操作 | 说明 | |---|---|---| | `services/types.ts` | Modify | 扩展 dash video/audio 条目类型,加 segmentBase/width/height/mimeType/frameRate | | `services/bilibili.ts` | Modify | `getPlayUrl` 按 Platform.OS 分叉 fnval | | `utils/dash.ts` | **Create** | `buildDashDataUri(playData, qn): string` | | `components/NativeVideoPlayer.tsx` | Modify | 有 dash 时用 data URI + `type="mpd"`,否则走原 durl 路径 | --- ## Task 1: 扩展 PlayUrlResponse 类型 **Files:** - Modify: `services/types.ts` - [ ] **Step 1: 更新 dash video/audio 条目类型,加入 B 站实际返回字段** ```typescript // services/types.ts — 替换现有 PlayUrlResponse export interface DashSegmentBase { Initialization: string; // e.g. "0-938" indexRange: string; // e.g. "939-2694" } export interface DashVideoItem { id: number; baseUrl: string; bandwidth: number; mimeType: string; // "video/mp4" codecs: string; // "avc1.640028" width: number; height: number; frameRate: string; // "25" or "25000/1000" segmentBase: DashSegmentBase; } export interface DashAudioItem { id: number; baseUrl: string; bandwidth: number; mimeType: string; // "audio/mp4" codecs: string; // "mp4a.40.2" segmentBase: DashSegmentBase; } export interface PlayUrlResponse { durl?: Array<{ url: string; length: number; size: number; }>; dash?: { duration: number; video: DashVideoItem[]; audio: DashAudioItem[]; }; quality: number; accept_quality: number[]; accept_description: string[]; } ``` - [ ] **Step 2: 验证 TypeScript 无报错** ```bash cd C:/claude-code-studly/reactBilibiliApp && npx tsc --noEmit 2>&1 | head -30 ``` - [ ] **Step 3: Commit** ```bash git add services/types.ts git commit -m "feat: extend PlayUrlResponse types for DASH segmentBase fields" ``` --- ## Task 2: getPlayUrl 按平台分叉 **Files:** - Modify: `services/bilibili.ts` (line 97–102) - [ ] **Step 1: 修改 `getPlayUrl` 函数** 将现有函数替换为: ```typescript export async function getPlayUrl(bvid: string, cid: number, qn = 64): Promise { const isAndroid = Platform.OS === 'android'; const params = isAndroid ? { bvid, cid, qn, fnval: 16, fourk: 1 } : { bvid, cid, qn, fnval: 0, platform: 'html5', fourk: 1 }; const res = await api.get('/x/player/playurl', { params }); return res.data.data as PlayUrlResponse; } ``` 注:`Platform` 已在文件顶部从 `react-native` 导入(第 3 行),无需新增 import。 - [ ] **Step 2: 验证 TypeScript 无报错** ```bash cd C:/claude-code-studly/reactBilibiliApp && npx tsc --noEmit 2>&1 | head -30 ``` - [ ] **Step 3: Commit** ```bash git add services/bilibili.ts git commit -m "feat: use DASH (fnval=16) on Android for getPlayUrl" ``` --- ## Task 3: 新建 utils/dash.ts **Files:** - Create: `utils/dash.ts` - [ ] **Step 1: 创建文件,实现 `buildDashDataUri`** ```typescript // utils/dash.ts import type { PlayUrlResponse } from '../services/types'; /** * 从 Bilibili DASH 响应生成 MPD data URI。 * 选取 id === qn 的视频流(找不到则取第一条),带宽最高的音频流。 * 返回 "data:application/dash+xml;base64,..." 供 react-native-video 使用。 */ export function buildDashDataUri(playData: PlayUrlResponse, qn: number): string { const dash = playData.dash!; const video = dash.video.find(v => v.id === qn) ?? dash.video[0]; const audio = dash.audio.reduce((best, a) => a.bandwidth > best.bandwidth ? a : best ); const dur = dash.duration; const xml = ` ${escapeXml(video.baseUrl)} ${escapeXml(audio.baseUrl)} `; // btoa is available in React Native's Hermes JS engine return `data:application/dash+xml;base64,${btoa(xml)}`; } function escapeXml(s: string): string { return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } ``` - [ ] **Step 2: 验证 TypeScript 无报错** ```bash cd C:/claude-code-studly/reactBilibiliApp && npx tsc --noEmit 2>&1 | head -30 ``` - [ ] **Step 3: Commit** ```bash git add utils/dash.ts git commit -m "feat: add buildDashDataUri utility for DASH MPD generation" ``` --- ## Task 4: 更新 NativeVideoPlayer 使用 DASH data URI **Files:** - Modify: `components/NativeVideoPlayer.tsx` - [ ] **Step 1: 导入 `buildDashDataUri`,更新 url 选取逻辑** 在文件顶部 import 区域添加: ```typescript import { buildDashDataUri } from '../utils/dash'; ``` 将第 34 行的 url 计算替换为(在组件函数体内): ```typescript // 优先使用 DASH data URI(Android),降级使用 durl MP4(iOS) const url = playData?.dash ? buildDashDataUri(playData, currentQn) : playData?.durl?.[0]?.url; ``` 将 `