openhongguo 0.1.0
openhongguo: ^0.1.0 copied to clipboard
红果短剧(Hongguo)的非官方 Flutter SDK:匿名浏览、搜索与播放,基于 Go SDK 编译的原生库。
openhongguo(Flutter) #
本目录包含红果短剧(Hongguo)非官方 SDK 的 Flutter 版。SDK 可以浏览短剧目录、搜索短剧,并取得分集的播放地址。
SDK 用匿名设备发送所有请求。SDK 不需要登录。
原生层是 gomobile 编译的 Go SDK。Dart 代码通过平台通道调用原生层,所以行为与 Go SDK 相同。
免责声明:本仓库的所有内容仅供学习和参考之用,禁止用于商业用途。使用前请阅读完整的免责声明。使用本仓库的内容即表示您同意其所有条款和条件。
术语的含义见根目录 README 的术语表。
快速上手 #
下面的代码搜索一部短剧,然后取得第 1 集的播放地址。
import 'package:openhongguo/openhongguo.dart';
final client = await OpenhongguoClient.create();
final page = await client.search('全球死考');
final episodes = await client.listEpisodes(page.items.first.id);
final result = await client.resolvePlayback(episodes.items.first.id);
for (final s in result.playback.streams) {
print('${s.definition} ${s.url}');
}
第一次请求时,SDK 注册一台匿名设备,并保存设备档案。以后的请求都使用这台匿名设备。
要求 #
| 平台 | 最低版本 |
|---|---|
| Android | 7.0(API 24) |
| iOS | 15 |
最低版本与 Flutter 的要求相同。
注意:这个包不支持 Web 和桌面平台。
构建与安装 #
注意:这个包没有发布到 pub.dev。使用前,从源码构建。
构建需要 Go 1.26 或更高版本和 gomobile。环境要求见 bindings/mobile/README.md。
如果要构建和安装这个包,执行以下步骤:
-
编译 Go core,并把它复制到
android/和ios/:../mobile/build.sh flutter -
在 App 的
pubspec.yaml中用路径引用这个包:dependencies: openhongguo: path: ../openhongguo/bindings/flutter
包的大小主要来自 Go 运行时:
| 平台 | 大小 |
|---|---|
| Android | 每种 CPU 架构约 8 MB |
| iOS | 真机部分约 9 MB |
如果用 flutter build apk --split-per-abi 按架构拆分 APK,每个 APK 只包含一份。
接口 #
方法与其他语言的 SDK 一一对应。所有方法都返回 Future。如果方法失败,它抛出 OpenhongguoException。
发现与搜索 #
| 方法 | 作用 |
|---|---|
discover(options) |
加载书城的一个频道,默认是“推荐” |
discoverAll(options) |
逐页遍历书城的一个频道,并去掉跨页重复的短剧 |
search(query, options) |
搜索短剧,可以按真人剧、漫剧等筛选 |
searchAll(query, options) |
逐页遍历搜索结果,并去掉跨页重复的短剧 |
suggest(prefix) |
返回某个前缀的搜索联想词 |
hotSearch() |
加载搜索页的“猜你想搜”和各个热搜榜 |
searchCues() |
加载搜索框里轮播的提示词 |
newReleases(query) |
加载上新日历的一页 |
短剧与分集 #
| 方法 | 作用 |
|---|---|
getSeries(seriesId) |
加载一部短剧的详情 |
getSeriesBatch(seriesIds) |
加载多部短剧及其分集,按请求顺序返回 |
listEpisodes(seriesId, options) |
加载一部短剧的分集列表 |
seasons(seriesId) |
列出多季短剧的全部季 |
seriesRecommend(seriesId) |
加载一部短剧的相关推荐 |
getAlbum(albumId) |
加载一个合集(多季合集)及其各季 |
榜单与分类 #
| 方法 | 作用 |
|---|---|
shortRank(query) |
加载短剧排行榜的一页,包括演员榜 |
shortFilterPanel(genre) |
加载短剧筛选面板的各个选择行 |
shortFilter(query) |
按条件筛选短剧,一次一页 |
rankRows(cellId, offset) |
加载书城榜单的一页(经典频道的榜单入口) |
rankGroups() |
列出书城榜单的类型(经典频道的各个榜单) |
ranking(activityId, rankListId) |
加载一个活动榜单 |
categories(categoryId) |
加载书籍分类的标签页:全部、男生、女生和默认标签页 |
categoryLanding(categoryId, options) |
加载书籍分类下列表的一页,以及它的筛选面板 |
演员 #
| 方法 | 作用 |
|---|---|
person(userId) |
加载一位演员或一个角色的主页 |
personWorks(userId, cursor) |
加载一位演员参演的短剧,一次一页(主页上的作品 › 剧作) |
播放与设备 #
| 方法 | 作用 |
|---|---|
resolvePlayback(episodeId) |
加载一集的播放模型:各清晰度的地址、编码和码率 |
resetDevice() |
丢弃当前匿名设备,并注册一台新设备 |
release() 释放原生层的客户端。调用 release() 后,其他方法都会失败。
类型 #
返回值的类型由 Go 源码生成。字段说明与 Go SDK 相同。
| 项目 | 规则 |
|---|---|
| 属性名 | JSON 字段名转为驼峰,例如 cover_url 转为 coverUrl。Kotlin SDK 和 Swift SDK 使用相同的规则 |
| 缺省值 | 缺省的字段使用零值(空字符串、0、空列表)。只有 Go 中的指针字段可以为 null,例如 Series.novel |
| 枚举 | ContentType、SeriesStatus 等枚举是包含整数的类。已知的取值是静态常量,例如 ContentType.shortPlay。SDK 保留服务端新增的取值。如果常量名与 Dart 关键字相同,常量名加上 Value 后缀,例如 RankChangeKind.newValue |
| 查询参数 | SearchOptions 等查询参数的字段都可以为空。空字段不发送。用 copyWith 修改部分字段 |
有两个类型使用了不同的名称,以免与 Dart 和 Flutter 的类型同名:
| Go 中的名称 | Dart 中的名称 | 原因 |
|---|---|---|
Page |
PagedResult |
Flutter widgets 有 Page |
Stream |
VideoStream |
dart:core 有 Stream |
翻页 #
discoverAll 和 searchAll 逐部遍历带游标的列表,返回 Stream。服务端会在不同的页中返回同一部短剧。这两个方法删除重复的短剧。
await for (final series in client.searchAll('末世', const SearchOptions(), 3)) {
print('${series.id} ${series.title}');
}
加密分集 #
resolvePlayback 返回播放模型和内容密钥。如果分集是加密的,playback.protected 是 true,contentKey.key 是内容密钥。加密方式是 cenc-aes-ctr。
如果 SDK 不能推导内容密钥,contentKey 是 null。contentKeyError 给出原因。播放模型仍然正常返回。
设置 #
OpenhongguoClient.create 的参数是 ClientOptions。所有设置都是可选的。
| 设置 | 作用 |
|---|---|
profilePath |
设备档案的路径。默认目录不参加系统备份:Android 是 noBackupFilesDir,iOS 是标记为不备份的 Application Support |
apiOrigin、registerOrigin、distributionOrigin |
接口地址。默认值与 App 相同 |
retryAttempts |
可重试的失败的最多尝试次数。默认值是 3 |
device |
新匿名设备的机型。空字段使用默认值(小米 14) |
log |
接收诊断日志的函数。日志中的 URL 已经脱敏 |
错误处理 #
所有错误都是 OpenhongguoException。OpenhongguoException 有三个属性:
| 属性 | 含义 |
|---|---|
code |
错误码,例如 ErrorCode.rateLimited |
retryable |
重试同一请求能否成功 |
retryAfterMs |
服务端建议的等待时间,单位是毫秒。0 表示没有建议 |
try {
await client.getSeries(seriesId);
} on OpenhongguoException catch (e) {
if (e.code == ErrorCode.contentUnavailable) print('这部短剧已下架');
}
下表列出所有错误码。Dart 的常量名是驼峰,例如 RATE_LIMITED 是 ErrorCode.rateLimited。
| 错误码 | 含义 | 可重试 |
|---|---|---|
INVALID_OPTIONS |
客户端的设置或调用参数无效 | 否 |
PROFILE_NOT_FOUND |
还没有保存过设备档案 | 否 |
SIGNER_UNAVAILABLE |
请求需要签名,而客户端没有可用的签名器 | 否 |
AUTHENTICATION_REQUIRED |
内容需要登录才能访问,匿名客户端无法继续 | 否 |
NOT_PROTECTED |
为未加密的播放模型请求了内容密钥 | 否 |
DRM_PROTECTED |
分集是加密的,需要内容密钥才能解密 | 否 |
ANONYMOUS_LIMITED |
服务端给匿名设备返回了空结果 | 否 |
RATE_LIMITED |
请求太频繁,被服务端限流 | 是 |
TRANSPORT |
网络请求失败 | 是 |
SIGNATURE_REJECTED |
服务端拒绝了请求的签名 | 否 |
CONTENT_UNAVAILABLE |
内容已下架、不存在,或当前调用方无权访问 | 否 |
PARAM_INVALID |
服务端认为请求参数无效 | 否 |
CHALLENGE_REQUIRED |
服务端要求验证码或其他验证,匿名客户端无法继续 | 否 |
DEVICE_REJECTED |
匿名设备被拒绝,需要重置设备后重新注册 | 否 |
END_OF_LIST |
列表已经没有更多内容 | 否 |
ALBUM_UNAVAILABLE |
匿名读取不到这个合集,或者这部短剧没有其他季 | 否 |
CANCELLED |
调用被取消 | 否 |
开发 #
注意:不要手工修改
lib/src/types.dart。go run ./bindings/mobile/gen生成这个文件。仓库根目录的go test ./...检查它是否过时。
| 命令 | 作用 |
|---|---|
flutter test |
用模拟的平台通道测试客户端 |
许可证 #
本包使用 Apache License 2.0 许可证,见仓库根目录的 LICENSE。gomobile 生成的代码来自 Go 项目,使用 BSD 许可证。