# 低端影视 (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`)。页面内嵌了 `