mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 04:26:38 +08:00
处理bug
处理bug
This commit is contained in:
@@ -85,7 +85,14 @@ func (p *openAPI115Provider) ResolveWithUA(ctx context.Context, fileRef, ua stri
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DirectLink{URL: url, Proxy: false}, nil
|
||||
// 115 CDN 防盗链白名单:直链绑定换取时的 User-Agent(调用方 UA 或
|
||||
// DefaultUA),后续请求必须携带同一 UA,否则 403。302 播放由客户端
|
||||
// 自带 UA 天然满足;服务端直连(弹幕 hash 等)依赖这里的 Headers。
|
||||
bound := strings.TrimSpace(ua)
|
||||
if bound == "" {
|
||||
bound = cloud115.DefaultUA
|
||||
}
|
||||
return &DirectLink{URL: url, Proxy: false, Headers: map[string]string{"User-Agent": bound}}, nil
|
||||
}
|
||||
|
||||
// OpenClient 暴露底层客户端(token 刷新用)。
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/service/cloud"
|
||||
)
|
||||
|
||||
// overrideDanmakuOfficialBase points the "official" endpoint (match + fallback)
|
||||
@@ -178,14 +179,21 @@ func TestDanmakuFetchHashMissFallsBackToFileNameSearch(t *testing.T) {
|
||||
}
|
||||
|
||||
// strm:通过解析出的直链 Range 拉 16MB 前缀算 hash → match → 拉弹幕。
|
||||
// range server 模拟 115 CDN 防盗链:UA 不匹配直接 403(真实部署中
|
||||
// 直链绑定换取时的 UA,不带绑定 UA 拉取会失败,见 pan115_openapi.go)。
|
||||
func TestDanmakuFetchStrmHashViaDirectLink(t *testing.T) {
|
||||
content := bytes.Repeat([]byte("strm-video-bytes-0123456789"), 400)
|
||||
sum := md5.Sum(content)
|
||||
wantHash := hex.EncodeToString(sum[:])
|
||||
|
||||
var gotRange string
|
||||
var gotRange, gotUA string
|
||||
rangeSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotRange = r.Header.Get("Range")
|
||||
gotUA = r.Header.Get("User-Agent")
|
||||
if gotUA != "bound-ua-115" {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
_, _ = w.Write(content)
|
||||
}))
|
||||
@@ -202,7 +210,11 @@ func TestDanmakuFetchStrmHashViaDirectLink(t *testing.T) {
|
||||
var gotProvider string
|
||||
svc.SetStrmResolver(func(_ context.Context, provider string, _ url.Values) (*StrmPlayResult, error) {
|
||||
gotProvider = provider
|
||||
return &StrmPlayResult{RedirectURL: rangeSrv.URL}, nil
|
||||
// 播放链路 302 直链 + 绑定的 UA 头(防服务端直连 403)。
|
||||
return &StrmPlayResult{
|
||||
RedirectURL: rangeSrv.URL,
|
||||
Link: &cloud.DirectLink{URL: rangeSrv.URL, Headers: map[string]string{"User-Agent": "bound-ua-115"}},
|
||||
}, nil
|
||||
})
|
||||
ctx := context.Background()
|
||||
strmPath := filepath.Join(t.TempDir(), "远程动画.第01话.strm")
|
||||
@@ -220,6 +232,7 @@ func TestDanmakuFetchStrmHashViaDirectLink(t *testing.T) {
|
||||
require.Contains(t, res.Raw, "弹幕Strm命中")
|
||||
require.Equal(t, "115", gotProvider)
|
||||
require.Contains(t, gotRange, "bytes=0-")
|
||||
require.Equal(t, "bound-ua-115", gotUA) // 防盗链 UA 必须透传
|
||||
require.Contains(t, seen, `"fileHash":"`+wantHash+`"`)
|
||||
require.Contains(t, seen, `"fileName":"`+url.QueryEscape("远程动画.第01话")+`"`)
|
||||
// strm 的 SizeBytes 是文本大小,不参与 match。
|
||||
|
||||
@@ -545,6 +545,8 @@ func (s *DanmakuService) hashStrmTarget(ctx context.Context, raw string) (string
|
||||
}
|
||||
src, err = s.strmResolve(ctx, segs[0], u.Query())
|
||||
if err != nil || src == nil {
|
||||
s.log.Warn("danmaku strm resolve failed, hash layer skipped",
|
||||
zap.String("provider", segs[0]), zap.Error(err))
|
||||
return "", false
|
||||
}
|
||||
case u.Scheme == "http" || u.Scheme == "https":
|
||||
@@ -557,13 +559,20 @@ func (s *DanmakuService) hashStrmTarget(ctx context.Context, raw string) (string
|
||||
case src.LocalPath != "":
|
||||
return s.hashLocalFile(src.LocalPath)
|
||||
case src.RedirectURL != "":
|
||||
body, err = s.openRangeBody(ctx, src.RedirectURL, nil)
|
||||
var headers map[string]string
|
||||
if src.Link != nil {
|
||||
headers = src.Link.Headers // 115 直链防盗链要求携带绑定 UA
|
||||
}
|
||||
body, err = s.openRangeBody(ctx, src.RedirectURL, headers)
|
||||
case src.Link != nil && src.Link.URL != "":
|
||||
body, err = s.openRangeBody(ctx, src.Link.URL, src.Link.Headers)
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
if err != nil || body == nil {
|
||||
if err != nil {
|
||||
s.log.Warn("danmaku hash prefix fetch failed, hash layer skipped", zap.String("target", raw), zap.Error(err))
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
@@ -84,7 +84,9 @@ func (s *StrmService) resolveCloudPlay(ctx context.Context, provider string, q u
|
||||
if link.Proxy {
|
||||
return &StrmPlayResult{Link: link, Proxy: true}, nil
|
||||
}
|
||||
return &StrmPlayResult{RedirectURL: link.URL}, nil
|
||||
// Link 一并保留:302 处理器只认 RedirectURL,但服务端直连(弹幕 hash
|
||||
// 拉取)需要 link.Headers 才能通过直链防盗链校验。
|
||||
return &StrmPlayResult{RedirectURL: link.URL, Link: link}, nil
|
||||
}
|
||||
|
||||
// resolveLocalPlay 本地源:校验路径位于某个本地同步目录的源目录内。
|
||||
|
||||
Reference in New Issue
Block a user