mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-02-15 04:14:42 +08:00
12 KiB
12 KiB
MoonTV 到 MyTv 迁移可行性分析与方案
项目概述
MoonTV 项目分析
项目定位: 基于 Next.js 的 Web 端影视聚合播放器
核心技术栈:
- 前端框架: Next.js 14 (App Router)
- UI 库: Tailwind CSS + React
- 语言: TypeScript
- 视频播放器: ArtPlayer + HLS.js
- 状态管理: React Hooks + LocalStorage
- 部署: Docker + Vercel
核心功能:
- 多源影视资源聚合搜索
- 在线视频播放 (支持 HLS 流)
- 影片详情展示 (演员、年份、简介等)
- 收藏功能 (LocalStorage)
- 播放记录 (继续观看)
- 响应式布局 (桌面 + 移动端)
- PWA 支持
项目结构:
MoonTV/
├── src/
│ ├── app/ # Next.js 14 App Router 页面
│ │ ├── (pages)/ # 主要页面路由
│ │ ├── api/ # 后端 API 路由
│ │ │ ├── douban/ # 豆瓣 API 集成
│ │ │ ├── search/ # 多源搜索 API
│ │ │ ├── detail/ # 影片详情 API
│ │ │ └── login/ # 认证 API
│ │ └── globals.css # 全局样式
│ ├── components/ # React 组件
│ │ ├── VideoCard.tsx # 视频卡片组件
│ │ ├── AggregateCard.tsx # 聚合卡片组件
│ │ ├── ScrollableRow.tsx # 横向滚动容器
│ │ └── ...
│ └── lib/ # 工具库
│ ├── types.ts # TypeScript 类型定义
│ ├── db.client.ts # 本地存储操作
│ └── config.ts # 配置管理
├── config.json # 影视资源站点配置
└── package.json # 项目依赖
MyTv 项目分析
项目定位: 基于 React Native TV 的电视端应用
核心技术栈:
- 框架: React Native TV (支持 Apple TV + Android TV)
- 导航: Expo Router (文件系统路由)
- 视频播放: react-native-media-console
- 配置: @react-native-tvos/config-tv
- 语言: TypeScript
核心功能:
- TV 遥控器导航支持
- 焦点管理和高亮显示
- 视频播放 (react-native-video)
- TV 专用 UI 组件
- 跨平台支持 (Apple TV + Android TV)
迁移可行性分析
✅ 高度可行的方面
1. 核心业务逻辑
- 数据结构兼容: MoonTV 的
VideoDetail类型定义可直接复用 - API 接口复用: MoonTV 的搜索、详情 API 可通过网络请求在 TV 端调用
- 业务流程一致: 搜索 → 详情 → 播放的核心流程完全匹配
2. 功能特性映射
| MoonTV 功能 | MyTv 对应功能 | 迁移难度 |
|---|---|---|
| 多源搜索 | 网络 API 调用 | ⭐ 容易 |
| 影片详情 | 详情页面适配 | ⭐⭐ 中等 |
| 视频播放 | react-native-video | ⭐⭐ 中等 |
| 收藏功能 | AsyncStorage | ⭐ 容易 |
| 播放记录 | AsyncStorage | ⭐ 容易 |
3. 技术栈兼容性
- TypeScript: 两个项目都使用 TypeScript,类型定义可复用
- React 生态: 核心 React 概念一致,组件逻辑可借鉴
- 状态管理: 都使用 Hooks,状态逻辑可迁移
⚠️ 需要重点关注的挑战
1. UI/UX 差异
- 交互模式: Web 鼠标/触摸 → TV 遥控器 D-Pad 导航
- 布局设计: 响应式网页布局 → TV 固定尺寸界面
- 焦点管理: Web 无需焦点 → TV 必须精确控制焦点流转
2. 视频播放器差异
- MoonTV: ArtPlayer (Web) + HLS.js
- MyTv: react-native-media-console + react-native-video
- 挑战: 播放控制、进度管理、字幕等功能需要重新实现
3. 存储机制差异
- MoonTV: LocalStorage (同步)
- MyTv: AsyncStorage (异步)
- 影响: 所有本地存储操作需要异步化改造
❌ 不可直接迁移的方面
1. Web 特定功能
- PWA 功能 (离线缓存、安装到桌面)
- 豆瓣 API 的 CORS 处理
- 浏览器特定的媒体 API
2. 部署和分发
- Docker/Vercel 部署 → App Store/Google Play 发布
- Web 更新 → 应用商店审核流程
迁移方案设计
方案 A: 渐进式迁移 (推荐)
阶段 1: 基础架构搭建 (1-2 周)
-
创建 TV 端项目结构
MyTv/ ├── app/ │ ├── (tabs)/ │ │ ├── home.tsx # 首页 - 影片推荐 │ │ ├── search.tsx # 搜索页 │ │ ├── library.tsx # 我的收藏/播放记录 │ │ └── settings.tsx # 设置页 │ ├── detail/ │ │ └── [id].tsx # 影片详情页 │ └── play/ │ └── [id].tsx # 播放页面 ├── components/ │ ├── TVVideoCard.tsx # TV 适配的视频卡片 │ ├── TVSearchInput.tsx # TV 搜索输入 │ ├── TVMediaPlayer.tsx # TV 媒体播放器 │ └── FocusableView.tsx # 可获取焦点的容器 ├── services/ │ ├── api.ts # MoonTV API 调用封装 │ ├── storage.ts # AsyncStorage 封装 │ └── player.ts # 播放器控制逻辑 └── types/ └── index.ts # 从 MoonTV 迁移的类型定义 -
核心服务层迁移
// services/api.ts - 调用 MoonTV 后端 class MoonTVAPI { private baseURL = "https://your-moontv-instance.com/api"; async search(query: string): Promise<SearchResult[]> { const response = await fetch(`${this.baseURL}/search?q=${query}`); return response.json(); } async getDetail(source: string, id: string): Promise<VideoDetail> { const response = await fetch( `${this.baseURL}/detail?source=${source}&id=${id}` ); return response.json(); } } -
存储层适配
// services/storage.ts import AsyncStorage from "@react-native-async-storage/async-storage"; export class TVStorage { static async getFavorites(): Promise<string[]> { const data = await AsyncStorage.getItem("favorites"); return data ? JSON.parse(data) : []; } static async addFavorite(videoId: string): Promise<void> { const favorites = await this.getFavorites(); if (!favorites.includes(videoId)) { favorites.push(videoId); await AsyncStorage.setItem("favorites", JSON.stringify(favorites)); } } }
阶段 2: 核心页面开发 (2-3 周)
-
搜索功能实现
// app/(tabs)/search.tsx export default function SearchScreen() { const [query, setQuery] = useState(""); const [results, setResults] = useState<SearchResult[]>([]); const [focusedIndex, setFocusedIndex] = useState(0); const handleSearch = async (text: string) => { const searchResults = await MoonTVAPI.search(text); setResults(searchResults); }; return ( <TVFocusableView> <TVSearchInput value={query} onChangeText={setQuery} onSubmit={handleSearch} /> <FlatList data={results} renderItem={({ item, index }) => ( <TVVideoCard video={item} focused={index === focusedIndex} onFocus={() => setFocusedIndex(index)} /> )} keyExtractor={(item) => item.id} /> </TVFocusableView> ); } -
详情页面开发
// app/detail/[id].tsx export default function DetailScreen() { const { id, source } = useLocalSearchParams(); const [detail, setDetail] = useState<VideoDetail | null>(null); useEffect(() => { MoonTVAPI.getDetail(source as string, id as string).then(setDetail); }, [source, id]); return ( <ScrollView> <TVDetailHeader video={detail} /> <TVEpisodeList episodes={detail?.episodes} /> <TVActionButtons onPlay={handlePlay} onFavorite={handleFavorite} /> </ScrollView> ); }
阶段 3: 播放功能集成 (1-2 周)
-
播放器组件开发
// components/TVMediaPlayer.tsx import VideoPlayer from "react-native-media-console"; export function TVMediaPlayer({ source, title }: TVMediaPlayerProps) { return ( <VideoPlayer source={{ uri: source }} title={title} disableControls={false} resizeMode="contain" onEnd={handlePlaybackEnd} tapAnywhereToPause={true} /> ); } -
播放页面开发
// app/play/[id].tsx export default function PlayScreen() { const { videoUrl, title } = useLocalSearchParams(); return ( <View style={{ flex: 1, backgroundColor: "black" }}> <TVMediaPlayer source={videoUrl as string} title={title as string} /> </View> ); }
阶段 4: TV 专用优化 (1-2 周)
-
焦点导航优化
// components/FocusableView.tsx export function FocusableView({ children, onFocus, onBlur }: Props) { return ( <Pressable onFocus={onFocus} onBlur={onBlur} style={({ focused }) => [styles.container, focused && styles.focused]} > {children} </Pressable> ); } -
遥控器快捷键支持
// hooks/useRemoteControl.ts export function useRemoteControl() { useEffect(() => { const handleKeyPress = (event: any) => { switch (event.key) { case "ArrowUp": // 遥控器上键 // 处理向上导航 break; case "ArrowDown": // 遥控器下键 // 处理向下导航 break; case "Select": // 遥控器确定键 // 处理选择 break; } }; // 注册事件监听器 }, []); }
方案 B: API 服务复用 (备选)
如果不想完全迁移前端,可以保持 MoonTV 作为 API 服务器,MyTv 作为纯客户端:
// MyTv 通过网络调用 MoonTV 的 API
const MOONTV_API_BASE = "https://your-moontv-instance.com/api";
class MoonTVClient {
async search(query: string) {
return fetch(`${MOONTV_API_BASE}/search?q=${query}`);
}
async getVideoDetail(source: string, id: string) {
return fetch(`${MOONTV_API_BASE}/detail?source=${source}&id=${id}`);
}
}
实施建议
开发优先级
-
高优先级 (核心功能)
- 基础 TV 导航框架
- 视频搜索和播放
- 遥控器支持
-
中优先级 (用户体验)
- 收藏和播放记录
- 详情页面丰富化
- 性能优化
-
低优先级 (增值功能)
- 个性化推荐
- 多用户支持
- 云同步
技术风险与缓解
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| TV 焦点管理复杂 | 开发周期延长 | 早期原型验证,分步实现 |
| 视频播放兼容性 | 功能不稳定 | 多设备测试,备用播放器方案 |
| API 调用延迟 | 用户体验差 | 本地缓存,异步加载 |
| 应用商店审核 | 发布延期 | 提前了解审核规则,合规设计 |
开发资源估算
- 开发时间: 6-8 周 (1-2 人团队)
- 技术栈学习: React Native TV (1-2 周)
- UI/UX 设计: TV 界面设计 (1 周)
- 测试验证: 多设备兼容性 (1 周)
结论
迁移可行性: ⭐⭐⭐⭐☆ (高度可行)
推荐方案: 渐进式迁移,保持 MoonTV 作为后端 API 服务,开发独立的 MyTv 客户端
关键成功因素:
- 合理的架构设计 (分离 API 和 UI)
- TV 交互模式的深度理解
- 充分的设备兼容性测试
- 渐进式开发和验证
通过这个方案,可以充分利用 MoonTV 的成熟后端能力,同时为 TV 平台提供原生的使用体验。