feat:完善soop日志和注释

This commit is contained in:
Joftal committed 2026-03-15 13:23:41 +08:00
1 parent fe9565c54f
commit 87fddfc357
1 file changed
+31 -15
+31 -15
View File
@@ -60,12 +60,16 @@ type Live struct {
// pageMeta 表示从播放页 HTML 中直接提取的最小元信息。
// 这一步不依赖 Soop API,主要用于:
// 1. 在接口异常时提供基础房间信息;
// 2. 从页面脚本中兜底提取 nBroadNo;
// 3. 在页面明确暴露“当前没有直播场次号”时快速返回。
// 2. 区分页面是“明确离线(nBroadNo=null)”还是“字段缺失”;
// 3. 仅在页面字段缺失时,回退使用 URL 路径中的 broadNo 继续尝试后续 API。
//
// 注意:
// 当前 IsLiving 只是基于页面里是否拿到了 nBroadNo 的启发式判断,
// 不能等价理解为“平台最终确认未开播”。
// 字段语义:
// - PathBroadNo: URL 路径里携带的 broadNo(/channel/bno)。
// - PageBroadNo: 页面脚本里解析出的 broadNo,仅当页面给出数字时非空。
// - PageBroadNoFound: 页面是否出现过 window.nBroadNo 字段。
// - PageExplicitlyOffline: 页面是否明确给出 nBroadNo=null。
// - BroadNo: 当前后续 API 实际使用的最终 broadNo。
// - IsLiving: 当前是否存在“可继续请求后续 API 的在线候选”。
type pageMeta struct {
Channel string
BroadNo string
@@ -116,11 +120,11 @@ func (l *Live) GetInfo() (*live.Info, error) {
AudioOnly: l.Options.AudioOnly,
}
// 页面上不存在 nBroadNo 时,当前实现会先按“未解析到有效直播场次号”处理。
// 这通常意味着未开播,但也可能是需要登录、页面结构变化或页面脚本返回受限。
// 当前版本这里不再继续请求播放接口,而是直接返回页面元信息。
// 页面明确离线(nBroadNo=null)或既没有页面 broadNo 也没有路径 broadNo 时,
// 当前请求不会继续访问 Soop 播放信息接口,而是直接返回离线状态。
if !meta.IsLiving {
l.GetLogger().Debugf("Soop GetInfo 完成:页面未解析到有效直播场次号 channel=%s broadNo=%s", meta.Channel, meta.BroadNo)
l.GetLogger().Debugf("Soop GetInfo 完成:页面判定离线 channel=%s pathBroadNo=%s pageBroadNo=%s pageBroadNoFound=%v explicitOffline=%v resolvedBroadNo=%s",
meta.Channel, meta.PathBroadNo, meta.PageBroadNo, meta.PageBroadNoFound, meta.PageExplicitlyOffline, meta.BroadNo)
return info, nil
}
@@ -155,8 +159,9 @@ func (l *Live) GetInfo() (*live.Info, error) {
// 5. 将 view_url 与 aid 组合成最终可录制的 m3u8 地址。
//
// 注意:
// 当前实现仍以页面中的 nBroadNo 作为进入后续 API 链路的前提,
// 因此页面元信息缺失时返回的是“无法确认可录制流”的错误,而不是平台最终业务结论。
// - 页面明确离线(nBroadNo=null)时,这里会直接返回“当前无可录制流”;
// - 页面缺失 nBroadNo 字段但路径里带有 broadNo 时,仍会回退使用路径 broadNo 继续请求 API;
// - 因此这里返回的“无法获取播放流”既可能表示离线,也可能表示登录态不足或页面/API 结构变化。
func (l *Live) GetStreamInfos() ([]*live.StreamUrlInfo, error) {
l.GetLogger().Debugf("Soop GetStreamInfos 开始: url=%s", l.GetRawUrl())
meta, err := l.fetchPageMeta()
@@ -165,6 +170,8 @@ func (l *Live) GetStreamInfos() ([]*live.StreamUrlInfo, error) {
return nil, err
}
if !meta.IsLiving {
l.GetLogger().Debugf("Soop GetStreamInfos 结束:页面判定无有效 broadNo channel=%s pathBroadNo=%s pageBroadNo=%s pageBroadNoFound=%v explicitOffline=%v resolvedBroadNo=%s",
meta.Channel, meta.PathBroadNo, meta.PageBroadNo, meta.PageBroadNoFound, meta.PageExplicitlyOffline, meta.BroadNo)
return nil, fmt.Errorf("未从 Soop 播放页解析到有效直播场次号,可能未开播、需要登录或页面结构已变更,暂时无法获取播放流")
}
@@ -280,7 +287,11 @@ func (l *Live) UpdateLiveOptionsbyConfig(ctx context.Context, room *configs.Live
// fetchPageMeta 从播放页 HTML 中提取频道名、bno、主播名、标题等基础信息。
// 这是当前后续 API 请求的前置步骤,因为 Soop 的很多接口都依赖 channel + bno。
// 如果页面里没有可用的 nBroadNo,后续流程会在当前版本中提前结束。
//
// 解析规则:
// 1. 页面给出有效 nBroadNo 时,优先使用页面值;
// 2. 页面明确给出 nBroadNo=null 时,视为页面确认离线,不再回退到路径 broadNo;
// 3. 只有页面字段缺失时,才允许回退到 URL 路径中的 broadNo。
func (l *Live) fetchPageMeta() (*pageMeta, error) {
l.GetLogger().Debugf("Soop 请求播放页: url=%s", l.GetRawUrl())
resp, err := l.RequestSession.Get(
@@ -321,8 +332,8 @@ func (l *Live) fetchPageMeta() (*pageMeta, error) {
RoomName: roomName,
IsLiving: isLiving,
}
l.GetLogger().Debugf("Soop 页面元信息: channel=%s pathBroadNo=%s pageBroadNo=%s pageBroadNoFound=%v host=%s room=%s living=%v",
channel, pathBroadNo, pageBroadNo, pageBroadNoFound, hostName, roomName, meta.IsLiving)
l.GetLogger().Debugf("Soop 页面元信息: channel=%s pathBroadNo=%s pageBroadNo=%s pageBroadNoFound=%v explicitOffline=%v resolvedBroadNo=%s host=%s room=%s living=%v",
channel, pathBroadNo, pageBroadNo, pageBroadNoFound, pageExplicitlyOffline, broadNo, hostName, roomName, meta.IsLiving)
return meta, nil
}
@@ -762,7 +773,11 @@ func parseBroadNoFromPage(body string) (string, bool) {
return match[1], true
}
// parseWindowString 从页面脚本中的 window.xxx = '...'/ "..." 提取字符串变量。
// resolvePageBroadNo 统一处理页面 broadNo 与路径 broadNo 的优先级。
// 返回值含义:
// 1. resolvedBroadNo: 当前后续 API 应使用的 broadNo;
// 2. isLiving: 当前是否仍存在“可继续请求后续 API 的在线候选”;
// 3. explicitlyOffline: 页面是否明确给出 nBroadNo=null。
func resolvePageBroadNo(pathBroadNo, pageBroadNo string, pageBroadNoFound bool) (string, bool, bool) {
switch {
case pageBroadNoFound && pageBroadNo != "":
@@ -776,6 +791,7 @@ func resolvePageBroadNo(pathBroadNo, pageBroadNo string, pageBroadNoFound bool)
}
}
// parseWindowString 从页面脚本中的 window.xxx = '...'/ "..." 提取字符串变量。
func parseWindowString(body, varName string) string {
doubleQuotePattern := fmt.Sprintf(`window\.%s\s*=\s*"((?:\\.|[^"\\])*)"`, regexp.QuoteMeta(varName))
if matched := utils.Match1(doubleQuotePattern, body); matched != "" {