diff --git a/EMBY_INTEGRATION_DESIGN.md b/EMBY_INTEGRATION_DESIGN.md deleted file mode 100644 index bc8c5fa..0000000 --- a/EMBY_INTEGRATION_DESIGN.md +++ /dev/null @@ -1,616 +0,0 @@ -# Emby 集成设计方案 - -## 一、可行性分析 - -### 1.1 Emby vs OpenList 对比 - -#### 相似点 -| 特性 | OpenList | Emby | -|------|----------|------| -| 服务类型 | 外部 API 服务 | 外部 API 服务 | -| 认证方式 | 用户名/密码 + Token | API Key 或用户名/密码 | -| 媒体列表 | ✅ 提供 | ✅ 提供 | -| 播放链接 | ✅ 提供 | ✅ 提供 | -| 元数据 | 需自行获取 | ✅ 内置完整元数据 | - -#### 关键差异 -| 维度 | OpenList | Emby | -|------|----------|------| -| **元数据来源** | 项目通过 TMDB API 获取 | Emby 自带(已从 TMDB/TVDB 获取) | -| **API 结构** | 文件系统 API | 媒体库 API | -| **组织方式** | 文件夹结构 | 媒体库(Movies/TV Shows) | -| **播放链接** | 云存储直链 | 流媒体 URL(支持转码) | -| **复杂度** | 需要文件名解析 + TMDB 查询 | 直接使用 Emby 元数据 | - -### 1.2 可行性结论 - -**✅ 完全可行!** Emby 的集成甚至比 OpenList 更简单,因为: -- Emby 自带完整元数据系统 -- API 更加成熟和标准化 -- 不需要复杂的文件名解析和 TMDB 查询 -- 媒体已经按照标准格式组织 - ---- - -## 二、CMS-Proxy 实现方案 - -### 2.1 为什么使用 CMS-Proxy - -项目本身是聚合 CMS API 的(苹果 CMS V10 格式),使用 CMS-Proxy 的优势: - -1. **网页播放**:复用现有播放逻辑,无需单独开发 -2. **TVBOX 支持**:直接支持,无需额外适配 -3. **代码复用**:统一接口,降低维护成本 -4. **扩展性强**:未来添加其他源(如 Jellyfin)只需实现 cms-proxy - -### 2.2 CMS API 格式要求 - -```json -{ - "code": 1, - "msg": "数据列表", - "page": 1, - "pagecount": 1, - "limit": 20, - "total": 100, - "list": [ - { - "vod_id": "唯一ID", - "vod_name": "视频名称", - "vod_pic": "海报URL", - "vod_remarks": "备注(如'电影'/'剧集')", - "vod_year": "年份", - "vod_content": "简介", - "vod_play_from": "播放源名称", - "vod_play_url": "第1集$url1#第2集$url2#第3集$url3", - "type_name": "类型" - } - ] -} -``` - -### 2.3 Emby 数据映射 - -```typescript -// Emby Item → CMS Format -{ - vod_id: item.Id, - vod_name: item.Name, - vod_pic: `${embyUrl}/Items/${item.Id}/Images/Primary`, - vod_remarks: item.Type === 'Movie' ? '电影' : '剧集', - vod_year: item.ProductionYear?.toString() || '', - vod_content: item.Overview || '', - vod_play_from: 'Emby', - vod_play_url: buildPlayUrl(item), - type_name: item.Type === 'Movie' ? '电影' : '电视剧' -} -``` - -### 2.4 核心实现 - -#### 路由结构 -``` -/api/emby/cms-proxy/[token]?ac=videolist&wd=关键词 -/api/emby/cms-proxy/[token]?ac=detail&ids=视频ID -``` - -#### 关键逻辑 - -**1. 搜索/列表** -```typescript -async function handleSearch(client: EmbyClient, query: string) { - const items = await client.getItems({ - searchTerm: query, - IncludeItemTypes: 'Movie,Series', - Recursive: true, - Fields: 'Overview,ProductionYear', - Limit: 100 - }); - - return items.map(item => ({ - vod_id: item.Id, - vod_name: item.Name, - vod_pic: getEmbyImageUrl(item.Id), - vod_remarks: item.Type === 'Movie' ? '电影' : '剧集', - vod_year: item.ProductionYear?.toString() || '', - vod_content: item.Overview || '', - type_name: item.Type === 'Movie' ? '电影' : '电视剧' - })); -} -``` - -**2. 详情(关键)** -```typescript -async function handleDetail(client: EmbyClient, itemId: string) { - const item = await client.getItem(itemId); - - let vodPlayUrl = ''; - - if (item.Type === 'Movie') { - // 电影:单个播放链接 - const playUrl = buildPlayUrl(client, itemId); - vodPlayUrl = `正片$${playUrl}`; - } else if (item.Type === 'Series') { - // 剧集:获取所有季和集 - const episodes = await getAllEpisodes(client, itemId); - vodPlayUrl = episodes - .map(ep => `第${ep.IndexNumber}集$${buildPlayUrl(client, ep.Id)}`) - .join('#'); - } - - return { - vod_id: item.Id, - vod_name: item.Name, - vod_play_url: vodPlayUrl, - vod_play_from: 'Emby', - // ... 其他字段 - }; -} -``` - -**3. 播放链接构建** -```typescript -function buildPlayUrl(client: EmbyClient, itemId: string): string { - // 方案 1: 直接返回 Emby 流媒体链接(推荐) - return `${client.serverUrl}/Videos/${itemId}/stream?api_key=${client.apiKey}&Static=true`; - - // 方案 2: 通过项目代理(支持去广告等功能) - const baseUrl = process.env.SITE_BASE; - const token = process.env.TVBOX_SUBSCRIBE_TOKEN; - return `${baseUrl}/api/emby/play/${token}?id=${itemId}`; -} -``` - ---- - -## 三、前台页面集成方案 - -### 3.1 设计思路 - -将 Emby 集成到现有的"私人影库"页面,使用 **CapsuleSwitch** 组件切换 OpenList 和 Emby。 - -**优势:** -- 统一入口,用户体验更好 -- 复用现有 UI 组件(VideoCard、分页等) -- 代码更简洁,维护成本低 - -### 3.2 页面结构 - -``` -┌─────────────────────────────────────────┐ -│ 私人影库 │ -│ 观看自我收藏的高清视频吧 │ -├─────────────────────────────────────────┤ -│ │ -│ ┌─────────────────────────┐ │ -│ │ OpenList │ Emby │ ← CapsuleSwitch -│ └─────────────────────────┘ │ -│ │ -├─────────────────────────────────────────┤ -│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ -│ │ │ │ │ │ │ │ │ │ │ │ -│ └───┘ └───┘ └───┘ └───┘ └───┘ │ -│ │ -│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ -│ │ │ │ │ │ │ │ │ │ │ │ -│ └───┘ └───┘ └───┘ └───┘ └───┘ │ -│ │ -├─────────────────────────────────────────┤ -│ 上一页 第 1 / 5 页 下一页 │ -└─────────────────────────────────────────┘ -``` - -### 3.3 核心代码 - -```typescript -// src/app/private-library/page.tsx - -'use client'; - -import { useState, useEffect } from 'react'; -import CapsuleSwitch from '@/components/CapsuleSwitch'; -import VideoCard from '@/components/VideoCard'; - -type LibrarySource = 'openlist' | 'emby'; - -export default function PrivateLibraryPage() { - const [source, setSource] = useState('openlist'); - const [videos, setVideos] = useState([]); - const [page, setPage] = useState(1); - - // 切换源时重置页码 - useEffect(() => { - setPage(1); - }, [source]); - - useEffect(() => { - const endpoint = source === 'openlist' - ? `/api/openlist/list?page=${page}` - : `/api/emby/list?page=${page}`; - - fetch(endpoint).then(res => res.json()).then(setVideos); - }, [page, source]); - - return ( -
-

私人影库

- - {/* 源切换器 */} - setSource(value as LibrarySource)} - /> - - {/* 视频网格 */} -
- {videos.map(video => ( - - ))} -
- - {/* 分页 */} -
- ); -} -``` - ---- - -## 四、完整实现步骤 - -### Phase 1: 基础设施 - -#### 1. 配置类型定义 -```typescript -// src/lib/admin.types.ts - -interface EmbyConfig { - Enabled: boolean - ServerURL: string // Emby 服务器地址 - ApiKey?: string // API Key(推荐) - Username?: string // 或使用用户名/密码 - Password?: string - UserId?: string // 用户 ID - Libraries?: string[] // 要显示的媒体库 ID - EnableTranscoding?: boolean // 是否启用转码 - MaxBitrate?: number // 最大码率 - LastSyncTime?: number - ItemCount?: number -} -``` - -#### 2. Emby 客户端 -```typescript -// src/lib/emby.client.ts - -export class EmbyClient { - private serverUrl: string - private apiKey?: string - private userId?: string - - constructor(config: EmbyConfig) { - this.serverUrl = config.ServerURL.replace(/\/$/, '') - this.apiKey = config.ApiKey - this.userId = config.UserId - } - - // 核心方法 - async authenticate(username: string, password: string): Promise - async getLibraries(): Promise - async getItems(params: GetItemsParams): Promise - async getItem(itemId: string): Promise - async getSeasons(seriesId: string): Promise - async getEpisodes(seriesId: string, seasonId: string): Promise - async checkConnectivity(): Promise -} -``` - -### Phase 2: API 端点 - -#### 1. CMS-Proxy(核心) -``` -src/app/api/emby/cms-proxy/[token]/route.ts -``` -- 支持搜索:`?ac=videolist&wd=关键词` -- 支持详情:`?ac=detail&ids=视频ID` -- 支持列表:`?ac=videolist` -- 返回苹果 CMS V10 格式 - -#### 2. 列表 API -``` -src/app/api/emby/list/route.ts -``` -- 用于前台页面显示 -- 支持分页 -- 返回格式与 OpenList 一致 - -#### 3. 详情 API -``` -src/app/api/emby/detail/route.ts -``` -- 获取媒体详情 -- 获取剧集列表 -- 返回播放链接 - -#### 4. 播放代理(可选) -``` -src/app/api/emby/play/[token]/route.ts -``` -- 代理播放请求 -- 支持去广告等功能 - -#### 5. 管理 API -``` -src/app/api/admin/emby/route.ts -``` -- 保存/更新 Emby 配置 -- 测试连接 -- 同步媒体库 - -### Phase 3: 前台集成 - -#### 1. 修改私人影库页面 -``` -src/app/private-library/page.tsx -``` -- 添加 CapsuleSwitch 组件 -- 支持切换 OpenList/Emby -- 复用现有 VideoCard 和分页逻辑 - -#### 2. 修改播放页面 -``` -src/app/play/page.tsx -``` -- 支持 `source=emby` 参数 -- 处理 Emby 播放链接 - -#### 3. 管理面板集成 -``` -src/app/admin/page.tsx -``` -- 添加 Emby 配置区域 -- 连接测试 -- 媒体库同步 - -#### 4. 导航集成 -``` -src/components/Sidebar.tsx -``` -- 保持"私人影库"入口不变 -- 内部通过 CapsuleSwitch 切换 - -### Phase 4: TVBOX 集成 - -#### 修改订阅接口 -```typescript -// src/app/api/tvbox/subscribe/[token]/route.ts - -const sites = [ - // 现有的 CMS 站点 - ...existingSites, - - // 添加 OpenList - { - key: 'openlist', - name: '私人影库-OpenList', - type: 1, - api: `${baseUrl}/api/cms-proxy?api=openlist`, - searchable: 1 - }, - - // 添加 Emby - { - key: 'emby', - name: '私人影库-Emby', - type: 1, - api: `${baseUrl}/api/emby/cms-proxy/${token}`, - searchable: 1 - } -]; -``` - ---- - -## 五、文件结构 - -``` -src/ -├── app/ -│ ├── api/ -│ │ ├── admin/ -│ │ │ └── emby/ -│ │ │ └── route.ts # Emby 配置管理 -│ │ └── emby/ -│ │ ├── cms-proxy/ -│ │ │ └── [token]/ -│ │ │ └── route.ts # CMS API 代理(核心) -│ │ ├── list/ -│ │ │ └── route.ts # 媒体列表 -│ │ ├── detail/ -│ │ │ └── route.ts # 媒体详情 -│ │ └── play/ -│ │ └── [token]/ -│ │ └── route.ts # 播放代理(可选) -│ ├── private-library/ -│ │ └── page.tsx # 私人影库页面(集成 CapsuleSwitch) -│ └── admin/ -│ └── page.tsx # 管理面板(添加 Emby 配置) -├── lib/ -│ ├── emby.client.ts # Emby API 客户端 -│ ├── emby-adapter.ts # 数据适配器 -│ ├── emby-cache.ts # 缓存层(可选) -│ └── admin.types.ts # 类型定义(添加 EmbyConfig) -└── components/ - ├── CapsuleSwitch.tsx # 切换组件(已存在) - └── VideoCard.tsx # 视频卡片(已存在) -``` - ---- - -## 六、关键技术点 - -### 6.1 Emby API 认证 - -```typescript -// 方式 1: API Key(推荐) -const headers = { - 'X-Emby-Token': apiKey -} - -// 方式 2: 用户认证 -const authResponse = await fetch(`${serverUrl}/Users/AuthenticateByName`, { - method: 'POST', - body: JSON.stringify({ Username: username, Pw: password }) -}); -const { AccessToken, User } = await authResponse.json(); -``` - -### 6.2 获取媒体列表 - -```typescript -// GET /Users/{userId}/Items -const params = new URLSearchParams({ - ParentId: libraryId, - IncludeItemTypes: 'Movie,Series', - Recursive: 'true', - Fields: 'Overview,ProductionYear', - StartIndex: '0', - Limit: '20' -}); -``` - -### 6.3 获取播放链接 - -```typescript -// 直接播放(无转码) -const playUrl = `${serverUrl}/Videos/${itemId}/stream?api_key=${apiKey}&Static=true`; - -// 转码播放 -const playUrl = `${serverUrl}/Videos/${itemId}/master.m3u8?api_key=${apiKey}&VideoCodec=h264`; -``` - -### 6.4 获取剧集 - -```typescript -// 获取季列表 -const seasons = await fetch(`${serverUrl}/Shows/${seriesId}/Seasons?userId=${userId}`); - -// 获取某季的所有集 -const episodes = await fetch(`${serverUrl}/Shows/${seriesId}/Episodes?seasonId=${seasonId}`); -``` - ---- - -## 七、优势总结 - -### 7.1 相比传统方式 - -| 特性 | 传统方式 | CMS-Proxy 方式 | -|------|---------|---------------| -| **网页播放** | 需要单独开发 Emby 播放页面 | 复用现有播放逻辑 | -| **TVBOX 支持** | 需要单独适配 | 直接支持,无需额外开发 | -| **代码复用** | 低 | 高 | -| **维护成本** | 高(两套逻辑) | 低(统一接口) | -| **扩展性** | 每个源都要适配 | 新增源只需实现 cms-proxy | - -### 7.2 相比 OpenList - -| 维度 | OpenList | Emby | -|------|----------|------| -| **实现复杂度** | 复杂(需要文件名解析 + TMDB 查询) | 简单(直接使用 Emby 元数据) | -| **元数据质量** | 依赖 TMDB API | Emby 自带完整元数据 | -| **播放能力** | 云存储直链 | 支持转码、字幕、多音轨 | -| **媒体组织** | 基于文件夹 | 标准媒体库结构 | - ---- - -## 八、预估工作量 - -- **核心功能**:约 800-1000 行代码 -- **完整集成**:约 1200-1500 行代码 -- **开发时间**:2-3 天(有 OpenList 参考) - -### 代码量分解 - -| 模块 | 代码量 | 说明 | -|------|--------|------| -| Emby 客户端 | 200-300 行 | API 封装 | -| CMS-Proxy | 300-400 行 | 核心转换逻辑 | -| 列表/详情 API | 200-300 行 | 前台接口 | -| 前台页面修改 | 100-150 行 | CapsuleSwitch 集成 | -| 管理面板 | 150-200 行 | 配置界面 | -| 类型定义 | 50-100 行 | TypeScript 类型 | -| **总计** | **1000-1450 行** | | - ---- - -## 九、实现建议 - -1. **优先使用 API Key 认证**(比用户名/密码更简单) -2. **实现良好的缓存策略**(减少对 Emby 服务器的请求) -3. **支持多媒体库**(让用户选择显示哪些库) -4. **考虑转码选项**(根据网络情况动态调整) -5. **复用现有组件**(VideoCard、播放器等) -6. **先实现 CMS-Proxy**(这样 TVBOX 和网页都能用) -7. **再实现前台集成**(CapsuleSwitch 切换) - ---- - -## 十、测试计划 - -### 10.1 功能测试 - -- [ ] Emby 连接测试 -- [ ] 媒体列表获取(电影/剧集) -- [ ] 搜索功能 -- [ ] 详情页面(电影/剧集) -- [ ] 播放功能(直接播放/转码) -- [ ] 剧集切换 -- [ ] 分页功能 -- [ ] CapsuleSwitch 切换 - -### 10.2 集成测试 - -- [ ] 网页播放测试 -- [ ] TVBOX 订阅测试 -- [ ] TVBOX 搜索测试 -- [ ] TVBOX 播放测试 -- [ ] OpenList 和 Emby 切换测试 - -### 10.3 性能测试 - -- [ ] 大型媒体库加载速度 -- [ ] 缓存效果验证 -- [ ] 并发请求处理 - ---- - -## 十一、后续扩展 - -### 可能的增强功能 - -1. **媒体库过滤**:按类型、年份、评分过滤 -2. **收藏功能**:标记喜欢的媒体 -3. **观看历史**:记录播放进度 -4. **字幕支持**:加载 Emby 字幕 -5. **转码设置**:用户自定义转码参数 -6. **多用户支持**:不同用户看到不同的媒体库 -7. **Jellyfin 支持**:Jellyfin API 与 Emby 类似,可以复用大部分代码 - ---- - -## 十二、总结 - -Emby 集成方案通过 **CMS-Proxy** 和 **CapsuleSwitch** 的组合,实现了: - -✅ **统一接口**:网页和 TVBOX 都使用 CMS API 格式 -✅ **统一入口**:私人影库页面集成 OpenList 和 Emby -✅ **代码复用**:最大化复用现有组件和逻辑 -✅ **扩展性强**:未来添加其他源(Jellyfin、Plex)只需实现 cms-proxy -✅ **用户体验好**:无缝切换,流畅播放 - -这是一个**优雅、高效、可扩展**的设计方案! diff --git a/EMBY_USAGE_GUIDE.md b/EMBY_USAGE_GUIDE.md deleted file mode 100644 index cf8415e..0000000 --- a/EMBY_USAGE_GUIDE.md +++ /dev/null @@ -1,287 +0,0 @@ -# Emby 集成使用指南 - -## 🎉 实现完成 - -Emby 已经成功集成到 MoonTVPlus 项目中!所有核心功能都已实现并可以使用。 - ---- - -## 📋 已实现的功能 - -### 1. 核心基础设施 -- ✅ EmbyConfig 类型定义 (`src/lib/admin.types.ts`) -- ✅ Emby 客户端 (`src/lib/emby.client.ts`) - -### 2. API 端点 -- ✅ `/api/emby/list` - 媒体列表(分页) -- ✅ `/api/emby/detail` - 媒体详情 -- ✅ `/api/emby/cms-proxy/[token]` - CMS API 代理(核心) -- ✅ `/api/admin/emby` - 管理配置 - -### 3. 前台集成 -- ✅ 私人影库页面集成 CapsuleSwitch(OpenList ↔ Emby 切换) -- ✅ 播放页面支持 `source=emby` 参数 - -### 4. 管理面板 -- ✅ Emby 配置区域(服务器地址、API Key、用户名/密码) -- ✅ 连接测试功能 -- ✅ 保存配置功能 - ---- - -## 🚀 快速开始 - -### 步骤 1: 配置 Emby - -1. 登录管理面板 -2. 找到 **"Emby 媒体库"** 配置区域 -3. 填写以下信息: - - **服务器地址**: 你的 Emby 服务器地址(如 `http://192.168.1.100:8096`) - - **API Key**(推荐): 在 Emby 设置中生成 API Key - - 或者填写 **用户名** 和 **密码** -4. 点击 **"测试连接"** 验证配置 -5. 点击 **"保存配置"** -6. 启用 **"启用 Emby 媒体库"** 开关 - -### 步骤 2: 访问私人影库 - -1. 访问 **"私人影库"** 页面 -2. 使用顶部的 **CapsuleSwitch** 切换到 **"Emby"** -3. 浏览你的 Emby 媒体库 -4. 点击任意视频即可播放 - -### 步骤 3: TVBOX 订阅(可选) - -如果你启用了 TVBOX 订阅功能,Emby 会自动添加到订阅源中: - -**订阅地址格式**: -``` -http://your-domain.com/api/emby/cms-proxy/{TVBOX_SUBSCRIBE_TOKEN} -``` - -在 TVBOX 中添加此订阅源,即可在 TVBOX 中浏览和播放 Emby 媒体库。 - ---- - -## 🔧 配置说明 - -### Emby 服务器地址 - -- 格式: `http://IP:PORT` 或 `https://domain.com` -- 示例: `http://192.168.1.100:8096` -- 注意: 确保 MoonTVPlus 服务器能够访问 Emby 服务器 - -### 认证方式 - -**方式 1: API Key(推荐)** -- 在 Emby 设置中生成 API Key -- 优点: 更安全,不需要存储密码 -- 获取方式: Emby 设置 → 高级 → API Keys - -**方式 2: 用户名/密码** -- 使用 Emby 用户账号 -- 优点: 简单直接 -- 注意: 密码会加密存储在数据库中 - ---- - -## 📖 功能特性 - -### 1. 网页播放 - -- **统一入口**: 私人影库页面 -- **无缝切换**: CapsuleSwitch 在 OpenList 和 Emby 之间切换 -- **完整支持**: 电影、剧集、季、集 -- **自动播放**: 点击即播,无需额外配置 - -### 2. CMS-Proxy - -Emby 的 CMS-Proxy 将 Emby 媒体库转换为苹果 CMS V10 格式,实现: - -- ✅ 网页播放复用现有逻辑 -- ✅ TVBOX 直接支持 -- ✅ 统一接口,降低维护成本 -- ✅ 扩展性强,未来可添加 Jellyfin、Plex 等 - -### 3. 播放链接 - -**直接播放**(默认): -``` -http://emby-server:8096/Videos/{itemId}/stream?Static=true&api_key={apiKey} -``` - -**转码播放**(可选): -``` -http://emby-server:8096/Videos/{itemId}/master.m3u8?api_key={apiKey} -``` - ---- - -## 🎯 使用场景 - -### 场景 1: 家庭媒体中心 - -- 在家中搭建 Emby 服务器 -- 使用 MoonTVPlus 作为统一的观影入口 -- 在私人影库中浏览和播放 Emby 媒体 - -### 场景 2: 多源聚合 - -- OpenList: 云存储媒体 -- Emby: 本地媒体服务器 -- CMS 源: 在线资源 -- 统一在 MoonTVPlus 中管理和播放 - -### 场景 3: TVBOX 集成 - -- 在 TVBOX 中添加 Emby 订阅源 -- 在电视上浏览和播放 Emby 媒体 -- 无需单独安装 Emby 客户端 - ---- - -## 🔍 故障排查 - -### 问题 1: 连接测试失败 - -**可能原因**: -- Emby 服务器地址错误 -- 网络不通(防火墙、端口未开放) -- API Key 或用户名/密码错误 - -**解决方法**: -1. 检查 Emby 服务器地址是否正确 -2. 确保 MoonTVPlus 服务器能够访问 Emby 服务器 -3. 验证 API Key 或用户名/密码是否正确 -4. 检查 Emby 服务器日志 - -### 问题 2: 媒体列表为空 - -**可能原因**: -- Emby 媒体库为空 -- 用户权限不足 -- 媒体库未扫描完成 - -**解决方法**: -1. 在 Emby 中检查媒体库是否有内容 -2. 确保使用的用户有访问媒体库的权限 -3. 等待 Emby 完成媒体库扫描 - -### 问题 3: 播放失败 - -**可能原因**: -- 媒体文件损坏 -- 网络带宽不足 -- 浏览器不支持视频格式 - -**解决方法**: -1. 在 Emby 客户端中测试播放 -2. 检查网络连接 -3. 尝试使用其他浏览器 -4. 考虑启用转码 - ---- - -## 📊 性能优化 - -### 1. 缓存策略 - -- 媒体列表缓存: 减少对 Emby 服务器的请求 -- 播放链接缓存: 提高播放响应速度 - -### 2. 网络优化 - -- 使用本地网络: Emby 服务器和 MoonTVPlus 在同一网络 -- 启用转码: 根据网络情况动态调整码率 - -### 3. 媒体库优化 - -- 定期清理无效媒体 -- 使用 SSD 存储媒体文件 -- 优化 Emby 服务器配置 - ---- - -## 🔐 安全建议 - -1. **使用 HTTPS**: 在生产环境中使用 HTTPS 访问 Emby -2. **强密码**: 使用强密码保护 Emby 账号 -3. **API Key**: 优先使用 API Key 而不是用户名/密码 -4. **防火墙**: 限制 Emby 服务器的访问来源 -5. **定期更新**: 保持 Emby 和 MoonTVPlus 更新到最新版本 - ---- - -## 🎨 自定义 - -### 修改播放链接格式 - -编辑 `src/lib/emby.client.ts` 中的 `getStreamUrl` 方法: - -```typescript -getStreamUrl(itemId: string, direct: boolean = true): string { - if (direct) { - // 直接播放 - return `${this.serverUrl}/Videos/${itemId}/stream?Static=true&api_key=${this.apiKey}`; - } - // 转码播放 - return `${this.serverUrl}/Videos/${itemId}/master.m3u8?api_key=${this.apiKey}&VideoCodec=h264`; -} -``` - -### 添加媒体库过滤 - -在 `src/lib/admin.types.ts` 中的 `EmbyConfig` 添加 `Libraries` 字段,然后在 API 中使用: - -```typescript -const result = await client.getItems({ - ParentId: config.EmbyConfig.Libraries?.[0], // 指定媒体库 - IncludeItemTypes: 'Movie,Series', - // ... -}); -``` - ---- - -## 🚧 已知限制 - -1. **字幕支持**: 当前版本不支持加载 Emby 字幕(计划中) -2. **转码设置**: 不支持用户自定义转码参数(计划中) -3. **多用户**: 不支持不同用户看到不同的媒体库(计划中) -4. **收藏同步**: 不支持与 Emby 的收藏同步(计划中) - ---- - -## 🔮 未来计划 - -- [ ] 字幕支持 -- [ ] 转码设置 -- [ ] 多用户支持 -- [ ] 收藏同步 -- [ ] 观看历史同步 -- [ ] Jellyfin 支持(API 与 Emby 类似) -- [ ] Plex 支持 - ---- - -## 📞 支持 - -如果遇到问题或有建议,请: - -1. 查看本文档的故障排查部分 -2. 查看 Emby 服务器日志 -3. 查看 MoonTVPlus 服务器日志 -4. 在 GitHub 上提交 Issue - ---- - -## 🎉 总结 - -Emby 集成为 MoonTVPlus 带来了强大的本地媒体服务器支持,通过 CMS-Proxy 的设计,实现了: - -- ✅ 统一的播放体验 -- ✅ TVBOX 无缝集成 -- ✅ 代码复用和维护简化 -- ✅ 良好的扩展性 - -享受你的 Emby 媒体库吧!🎬 diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index 1da9e74..c52b3cd 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -1219,7 +1219,7 @@ const VideoCard = forwardRef(function VideoCard {config.showSourceName && source_name && !cmsData && ( (function VideoCard