mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-10 15:26:38 +08:00
添加115云端解码功能
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/truewhile/MeBox/internal/model"
|
||||
"github.com/truewhile/MeBox/internal/repository"
|
||||
"github.com/truewhile/MeBox/internal/service/cloud115"
|
||||
)
|
||||
|
||||
func TestCloud115PlaybackInfoTriggersTranscodeOnce(t *testing.T) {
|
||||
var playCalls int32
|
||||
var pushCalls int32
|
||||
var ready int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.URL.Path {
|
||||
case "/open/video/play":
|
||||
atomic.AddInt32(&playCalls, 1)
|
||||
if atomic.LoadInt32(&ready) == 0 {
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"state": false,
|
||||
"code": 0,
|
||||
"message": "转码中",
|
||||
"data": map[string]any{},
|
||||
})
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"state": true,
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"data": map[string]any{
|
||||
"file_name": "test.mkv",
|
||||
"definition_list_new": map[string]string{
|
||||
"4": "1080P",
|
||||
},
|
||||
"video_url": []map[string]any{
|
||||
{
|
||||
"url": "http://cdn.example/master.m3u8",
|
||||
"definition": 4,
|
||||
"definition_n": 4,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"title": "1080P",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
case "/open/video/video_push":
|
||||
atomic.AddInt32(&pushCalls, 1)
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"state": true, "code": 0, "data": []any{}})
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
oldBase := cloud115.ProAPIBase
|
||||
cloud115.ProAPIBase = server.URL
|
||||
defer func() { cloud115.ProAPIBase = oldBase }()
|
||||
|
||||
db := newServiceTestDB(t, &model.StrmAccount{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
strm := NewStrmService(nil, zap.NewNop(), repos, NewCryptoService("test-secret", zap.NewNop()))
|
||||
ctx := context.Background()
|
||||
account, err := strm.CreateStrmAccount(ctx, "115", model.StrmProvider115, map[string]string{
|
||||
"app_id": "100195129",
|
||||
"access_token": "at",
|
||||
"refresh_token": "rt",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create account: %v", err)
|
||||
}
|
||||
media := &model.Media{
|
||||
Base: model.Base{ID: "media-1"},
|
||||
Title: "test",
|
||||
Path: "/media/test.strm",
|
||||
Container: "strm",
|
||||
Height: 1080,
|
||||
STRMURL: "/api/strm/play/cloud115/video.mkv?acct=" + account.ID + "&pickcode=pc",
|
||||
}
|
||||
if err := db.Create(media).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
svc := NewCloud115PlaybackService(nil, zap.NewNop(), repos, strm)
|
||||
|
||||
info, err := svc.PlaybackInfo(ctx, media.ID, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("first playback info: %v", err)
|
||||
}
|
||||
if info.Provider != model.StrmProvider115 || info.DefaultQuality != "4" {
|
||||
t.Fatalf("unexpected playback info: %#v", info)
|
||||
}
|
||||
if info.Transcode.State != "transcoding" {
|
||||
t.Fatalf("transcode state = %q, want transcoding", info.Transcode.State)
|
||||
}
|
||||
if got := atomic.LoadInt32(&pushCalls); got != 1 {
|
||||
t.Fatalf("push calls = %d, want 1", got)
|
||||
}
|
||||
|
||||
if _, err := svc.PlaybackInfo(ctx, media.ID, 0); err != nil {
|
||||
t.Fatalf("second playback info: %v", err)
|
||||
}
|
||||
if got := atomic.LoadInt32(&pushCalls); got != 1 {
|
||||
t.Fatalf("push calls after polling = %d, want 1", got)
|
||||
}
|
||||
|
||||
atomic.StoreInt32(&ready, 1)
|
||||
info, err = svc.PlaybackInfo(ctx, media.ID, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("ready playback info: %v", err)
|
||||
}
|
||||
if info.Transcode.State != "ready" {
|
||||
t.Fatalf("transcode state = %q, want ready", info.Transcode.State)
|
||||
}
|
||||
url, _, err := svc.ResolveCloud115URL(ctx, media.ID, 4)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve cloud url: %v", err)
|
||||
}
|
||||
if url != "http://cdn.example/master.m3u8" {
|
||||
t.Fatalf("url = %q", url)
|
||||
}
|
||||
if got := atomic.LoadInt32(&playCalls); got < 3 {
|
||||
t.Fatalf("play calls = %d, want >= 3", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloud115PlaybackInfoTranscodePendingBeforeReady(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.URL.Path {
|
||||
case "/open/video/play":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"state": false, "code": 0, "message": "转码中", "data": map[string]any{}})
|
||||
case "/open/video/video_push":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"state": true, "code": 0, "data": []any{}})
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
oldBase := cloud115.ProAPIBase
|
||||
cloud115.ProAPIBase = server.URL
|
||||
defer func() { cloud115.ProAPIBase = oldBase }()
|
||||
|
||||
db := newServiceTestDB(t, &model.StrmAccount{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
strm := NewStrmService(nil, zap.NewNop(), repos, NewCryptoService("test-secret", zap.NewNop()))
|
||||
ctx := context.Background()
|
||||
account, err := strm.CreateStrmAccount(ctx, "115", model.StrmProvider115, map[string]string{
|
||||
"app_id": "100195129",
|
||||
"access_token": "at",
|
||||
"refresh_token": "rt",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create account: %v", err)
|
||||
}
|
||||
media := &model.Media{
|
||||
Base: model.Base{ID: "media-2"},
|
||||
Title: "test",
|
||||
Path: "/media/test2.strm",
|
||||
Container: "strm",
|
||||
Height: 1080,
|
||||
STRMURL: "/api/strm/play/cloud115/video.mkv?acct=" + account.ID + "&pickcode=pc2",
|
||||
}
|
||||
if err := db.Create(media).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
svc := NewCloud115PlaybackService(nil, zap.NewNop(), repos, strm)
|
||||
if _, _, err := svc.ResolveCloud115URL(ctx, media.ID, 4); !errors.Is(err, ErrCloud115TranscodePending) {
|
||||
t.Fatalf("resolve pending err = %v, want ErrCloud115TranscodePending", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMediaPlaybackProvider(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{"115", "/api/strm/play/cloud115/video.mkv?acct=1&pickcode=pc", model.StrmProvider115},
|
||||
{"openlist", "/api/strm/play/openlist/video.mkv?acct=1&ref=/a.mkv", model.StrmProviderOpenList},
|
||||
{"local", "/media/local.mkv", model.StrmProviderLocal},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
media := &model.Media{Path: tc.raw}
|
||||
if tc.name != "local" {
|
||||
media.STRMURL = tc.raw
|
||||
}
|
||||
got := MediaPlaybackProvider(media)
|
||||
if got != tc.want {
|
||||
t.Fatalf("provider = %q, want %q", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user