2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:15:35 +08:00
2026-02-26 22:19:55 +08:00

低端影视 (DDYS Client)

原生 SwiftUI 客户端,用于浏览 ddys.io 影视资源,支持 macOS / iPadOS / iOS。

功能

  • 首页推荐 — 热门推荐横向滚动 + 最新更新网格展示
  • 分类浏览 — 电影、电视剧、综艺、动漫四大板块,支持排序 / 类型 / 地区 / 年份筛选
  • 全局搜索 — 首页搜索栏,回车触发,支持分页加载更多
  • 详情页 — 海报、评分、年份、地区、类型标签、剧情简介、导演、主演
  • 在线播放 — HLS (m3u8) 原生播放,多播放源切换,剧集选择
  • 播放器 — macOS 独立窗口可调整大小、全屏iOS 全屏播放,支持倍速、画中画
  • 观看进度 — 自动保存 / 恢复播放进度
  • 图片缓存 — 双层缓存NSCache 内存 + URLCache 磁盘),切换页面秒加载
  • 数据缓存 — Tab 切换保留数据5 分钟 TTL 自动刷新
  • 认证支持 — WebView 登录 或 手动 Cookie 输入

技术栈

项目 选型
UI 框架 SwiftUI (iOS 17+ / macOS 14+)
HTML 解析 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-cardh3 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 命令行工具)

命令行构建

# Debug
swift build

# Release
swift build -c release

打包为 .app

# 构建 Release
swift build -c release

# 复制到 app bundle
cp "$(swift build -c release --show-bin-path)/DDYSClient" /path/to/DDYSClient.app/Contents/MacOS/DDYSClient

安装

cp -R DDYSClient.app /Applications/低端影视.app

使用说明

  1. 启动应用后首页自动加载热门推荐和最新更新
  2. 通过左侧边栏切换 电影 / 电视剧 / 综艺 / 动漫
  3. 使用顶部筛选栏按 排序 / 类型 / 地区 / 年份 过滤内容
  4. 首页搜索栏输入关键词,按回车搜索
  5. 点击卡片进入详情页,点击「立即播放」打开播放器窗口
  6. 如需登录,在 设置 → 认证 中通过 WebView 或手动输入 Cookie

依赖

License

MIT

Description
低端影视客户端
Readme 99 KiB
Languages
Swift 100%