Files
ddys-client/README.md

140 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 低端影视 (DDYS Client)
原生 SwiftUI 客户端,用于浏览 [ddys.io](https://ddys.io) 影视资源,支持 macOS / iPadOS / iOS。
## 功能
- **首页推荐** — 热门推荐横向滚动 + 最新更新网格展示
- **分类浏览** — 电影、电视剧、综艺、动漫四大板块,支持排序 / 类型 / 地区 / 年份筛选
- **全局搜索** — 首页搜索栏,回车触发,支持分页加载更多
- **详情页** — 海报、评分、年份、地区、类型标签、剧情简介、导演、主演
- **在线播放** — HLS (m3u8) 原生播放,多播放源切换,剧集选择
- **播放器** — macOS 独立窗口可调整大小、全屏iOS 全屏播放,支持倍速、画中画
- **观看进度** — 自动保存 / 恢复播放进度
- **图片缓存** — 双层缓存NSCache 内存 + URLCache 磁盘),切换页面秒加载
- **数据缓存** — Tab 切换保留数据5 分钟 TTL 自动刷新
- **认证支持** — WebView 登录 或 手动 Cookie 输入
## 技术栈
| 项目 | 选型 |
|------|------|
| UI 框架 | SwiftUI (iOS 17+ / macOS 14+) |
| HTML 解析 | [SwiftSoup](https://github.com/scinfu/SwiftSoup) 2.6.1 (本地包,零外部依赖) |
| 视频播放 | AVKit (AVPlayerView / AVPlayerViewController) |
| 网络请求 | URLSession |
| 数据解析 | JSON-LD + SwiftSoup CSS 选择器 |
| 持久化 | UserDefaults |
| 导航 | NavigationSplitView (Mac/iPad) / TabView (iPhone) |
## 项目结构
```
DDYSClient/
├── App/ # 入口 & 根视图
├── Models/ # 数据模型 (ContentItem, Episode, StreamSource...)
├── Services/ # 网络层 & 业务服务
│ ├── APIClient.swift # URLSession 请求封装
│ ├── HTMLParser.swift # SwiftSoup 解析列表/详情/分页
│ ├── CookieManager.swift # Cookie 存储与注入
│ ├── ContentCache.swift # 数据缓存 (5min TTL)
│ └── WatchProgressStore.swift # 观看进度持久化
├── ViewModels/ # MVVM ViewModel (@Observable)
├── Views/
│ ├── Navigation/ # 平台自适应导航
│ ├── Home/ # 首页 + 搜索
│ ├── Browse/ # 分类浏览 + 筛选
│ ├── Detail/ # 详情页 + 剧集列表
│ ├── Player/ # 视频播放器
│ ├── Common/ # 通用组件 (CachedAsyncImage)
│ ├── Auth/ # 认证 (WebView / Cookie 输入)
│ ├── Search/ # 搜索页
│ └── Settings/ # 设置页
└── Utilities/ # 通用扩展
```
## 数据获取原理
ddys.io 是一个服务端渲染 (SSR) 的网站,没有提供公开的 REST API仅有少量内部接口。本客户端通过**模拟浏览器请求网页 + 解析 HTML** 的方式获取数据,整体流程如下:
### 1. 列表页 & 分类浏览
客户端直接以 GET 请求访问网站的 HTML 页面(如 `/movie``/series/page/2`),携带浏览器 User-Agent 和 Referer 头以通过服务端校验。返回的 HTML 经 SwiftSoup 解析,通过 CSS 选择器(如 `.movie-card``h3 a``.badge-top-right`)提取标题、海报、评分、年份等结构化数据。分页信息从页面底部的 `.pagination-active``.pagination-btn` 元素中解析得到。
### 2. 详情页
详情页同样请求对应路径的 HTML`/movie/slug`)。页面内嵌了 `<script type="application/ld+json">` 结构化数据,包含导演、演员、类型、评分、简介等信息,客户端优先从 JSON-LD 提取。对于 JSON-LD 中缺失的字段(如地区、播放源),再 fallback 到 HTML 元素解析。
### 3. 播放源 & 剧集
播放源信息嵌入在详情页 HTML 的 `<button onclick="switchSource(...)">` 属性中,通过正则表达式提取源 ID、视频地址和格式。剧集列表以 `集名$url#集名$url` 的格式编码在 URL 字符串中,按 `#``$` 分隔解析出每集的名称和 m3u8 播放地址。视频播放直接使用 AVKit 原生 HLS 支持。
### 4. 搜索
搜索通过 GET 请求 `/search?q=关键词&type=all` 实现(网站前端使用 POST 表单提交后 302 重定向到此 GET 地址)。返回的 HTML 结构与列表页一致,复用同一套解析逻辑。
### 5. 认证
网站使用 Cloudflare Turnstile 验证码保护,原生客户端无法自动完成验证。因此提供两种方式:通过内嵌 WKWebView 让用户在网页中完成登录后自动提取 Cookie或由用户从浏览器手动复制 Cookie 粘贴到应用中。Cookie 注入到 URLSession 的 HTTPCookieStorage 后,后续所有请求自动携带认证信息。
```
┌─────────┐ GET HTML ┌──────────┐ SwiftSoup ┌──────────┐
│ Client │ ───────────────→ │ ddys.io │ ──────────────→ │ Models │
│ (App) │ ← HTML response │ (SSR) │ CSS解析/正则 │ (Swift) │
└─────────┘ └──────────┘ JSON-LD提取 └──────────┘
│ │
│ m3u8 URL │
└──────────────────────────────────────→ AVPlayer (HLS播放) │
```
## 构建 & 运行
### 环境要求
- macOS 14.0+
- Swift 5.9+
- Xcode 15+ (或 Swift 命令行工具)
### 命令行构建
```bash
# Debug
swift build
# Release
swift build -c release
```
### 打包为 .app
```bash
# 构建 Release
swift build -c release
# 复制到 app bundle
cp "$(swift build -c release --show-bin-path)/DDYSClient" /path/to/DDYSClient.app/Contents/MacOS/DDYSClient
```
### 安装
```bash
cp -R DDYSClient.app /Applications/低端影视.app
```
## 使用说明
1. 启动应用后首页自动加载热门推荐和最新更新
2. 通过左侧边栏切换 电影 / 电视剧 / 综艺 / 动漫
3. 使用顶部筛选栏按 排序 / 类型 / 地区 / 年份 过滤内容
4. 首页搜索栏输入关键词,按回车搜索
5. 点击卡片进入详情页,点击「立即播放」打开播放器窗口
6. 如需登录,在 设置 → 认证 中通过 WebView 或手动输入 Cookie
## 依赖
- [SwiftSoup 2.6.1](https://github.com/scinfu/SwiftSoup/tree/2.6.1) — HTML 解析 (本地包,无网络依赖)
## License
MIT