diff --git a/internal/model/movie.go b/internal/model/movie.go index fc3d6ccd..684d4562 100644 --- a/internal/model/movie.go +++ b/internal/model/movie.go @@ -21,6 +21,19 @@ type Movie struct { Children []*Movie `gorm:"foreignKey:ParentID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"` } +func (m *Movie) Clone() *Movie { + return &Movie{ + ID: m.ID, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + Position: m.Position, + RoomID: m.RoomID, + CreatorID: m.CreatorID, + MovieBase: *m.MovieBase.Clone(), + Children: m.Children, + } +} + func (m *Movie) BeforeCreate(tx *gorm.DB) error { if m.ID == "" { m.ID = utils.SortUUID() @@ -45,19 +58,61 @@ func (m *Movie) BeforeSave(tx *gorm.DB) (err error) { return } +type MoreSource struct { + Name string `json:"name"` + Type string `json:"type"` + Url string `json:"url"` +} + type MovieBase struct { - Url string `gorm:"type:varchar(8192)" json:"url"` - MoreSource map[string]string `gorm:"serializer:fastjson;type:text" json:"moreSource,omitempty"` - Name string `gorm:"not null;type:varchar(256)" json:"name"` - Live bool `json:"live"` - Proxy bool `json:"proxy"` - RtmpSource bool `json:"rtmpSource"` - Type string `json:"type"` - Headers map[string]string `gorm:"serializer:fastjson;type:text" json:"headers,omitempty"` - Subtitles map[string]*Subtitle `gorm:"serializer:fastjson;type:text" json:"subtitles,omitempty"` - VendorInfo VendorInfo `gorm:"embedded;embeddedPrefix:vendor_info_" json:"vendorInfo,omitempty"` - IsFolder bool `json:"isFolder"` - ParentID EmptyNullString `gorm:"type:char(32)" json:"parentId"` + Url string `gorm:"type:varchar(8192)" json:"url"` + MoreSources []*MoreSource `gorm:"serializer:fastjson;type:text" json:"moreSources,omitempty"` + Name string `gorm:"not null;type:varchar(256)" json:"name"` + Live bool `json:"live"` + Proxy bool `json:"proxy"` + RtmpSource bool `json:"rtmpSource"` + Type string `json:"type"` + Headers map[string]string `gorm:"serializer:fastjson;type:text" json:"headers,omitempty"` + Subtitles map[string]*Subtitle `gorm:"serializer:fastjson;type:text" json:"subtitles,omitempty"` + VendorInfo VendorInfo `gorm:"embedded;embeddedPrefix:vendor_info_" json:"vendorInfo,omitempty"` + IsFolder bool `json:"isFolder"` + ParentID EmptyNullString `gorm:"type:char(32)" json:"parentId"` +} + +func (m *MovieBase) Clone() *MovieBase { + mss := make([]*MoreSource, len(m.MoreSources)) + for i, ms := range m.MoreSources { + mss[i] = &MoreSource{ + Name: ms.Name, + Type: ms.Type, + Url: ms.Url, + } + } + hds := make(map[string]string, len(m.Headers)) + for k, v := range m.Headers { + hds[k] = v + } + sbs := make(map[string]*Subtitle, len(m.Subtitles)) + for k, v := range m.Subtitles { + sbs[k] = &Subtitle{ + URL: v.URL, + Type: v.Type, + } + } + return &MovieBase{ + Url: m.Url, + MoreSources: mss, + Name: m.Name, + Live: m.Live, + Proxy: m.Proxy, + RtmpSource: m.RtmpSource, + Type: m.Type, + Headers: hds, + Subtitles: sbs, + VendorInfo: m.VendorInfo, + IsFolder: m.IsFolder, + ParentID: m.ParentID, + } } func (m *MovieBase) IsDynamicFolder() bool { diff --git a/internal/op/movie.go b/internal/op/movie.go index 66491841..f5cfeb38 100644 --- a/internal/op/movie.go +++ b/internal/op/movie.go @@ -5,16 +5,17 @@ import ( "errors" "fmt" "hash/crc32" + "net/http" "net/url" "sync/atomic" "time" - "github.com/go-resty/resty/v2" "github.com/synctv-org/synctv/internal/cache" "github.com/synctv-org/synctv/internal/conf" "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/settings" "github.com/synctv-org/synctv/utils" + "github.com/zijiren233/go-uhc" "github.com/zijiren233/livelib/av" "github.com/zijiren233/livelib/container/flv" "github.com/zijiren233/livelib/protocol/hls" @@ -195,20 +196,26 @@ func (m *Movie) initChannel() error { if c.Closed() { return } - r := resty.New().R() + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, m.Movie.MovieBase.Url, nil) + if err != nil { + time.Sleep(time.Second) + continue + } for k, v := range m.Movie.MovieBase.Headers { - r.SetHeader(k, v) + req.Header.Set(k, v) + } + if req.Header.Get("User-Agent") == "" { + req.Header.Set("User-Agent", utils.UA) } - // r.SetHeader("User-Agent", UserAgent) - resp, err := r.Get(m.Movie.MovieBase.Url) + resp, err := uhc.Do(req) if err != nil { time.Sleep(time.Second) continue } - if err := c.PushStart(flv.NewReader(resp.RawBody())); err != nil { + if err := c.PushStart(flv.NewReader(resp.Body)); err != nil { time.Sleep(time.Second) } - resp.RawBody().Close() + resp.Body.Close() } }() default: diff --git a/server/handlers/movie.go b/server/handlers/movie.go index f4a1241d..b44921a3 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -104,22 +104,21 @@ func genMovieInfo( return nil, errors.New("movie is static folder, can't get movie info") } } - var movie = *opMovie.Movie + var movie = opMovie.Movie.Clone() if movie.MovieBase.VendorInfo.Vendor != "" { vendorMovie, err := genVendorMovie(ctx, user, opMovie, userAgent, userToken) if err != nil { return nil, err } - movie = *vendorMovie + movie = vendorMovie } else if movie.MovieBase.RtmpSource || movie.MovieBase.Live && movie.MovieBase.Proxy { - switch movie.MovieBase.Type { - case "m3u8": - movie.MovieBase.Url = fmt.Sprintf("/api/movie/live/hls/list/%s.m3u8?token=%s", movie.ID, userToken) - case "flv": - movie.MovieBase.Url = fmt.Sprintf("/api/movie/live/flv/%s.flv?token=%s", movie.ID, userToken) - default: - return nil, errors.New("not support live movie type") - } + movie.MovieBase.Url = fmt.Sprintf("/api/movie/live/hls/list/%s.m3u8?token=%s", movie.ID, userToken) + movie.MovieBase.Type = "m3u8" + movie.MoreSources = append(movie.MoreSources, &dbModel.MoreSource{ + Name: "flv", + Url: fmt.Sprintf("/api/movie/live/flv/%s.flv?token=%s", movie.ID, userToken), + Type: "flv", + }) movie.MovieBase.Headers = nil } else if movie.MovieBase.Proxy { movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken) @@ -128,6 +127,11 @@ func genMovieInfo( if movie.MovieBase.Type == "" && movie.MovieBase.Url != "" { movie.MovieBase.Type = utils.GetUrlExtension(movie.MovieBase.Url) } + for _, v := range movie.MoreSources { + if v.Type == "" { + v.Type = utils.GetUrlExtension(v.Url) + } + } resp := &model.Movie{ Id: movie.ID, CreatedAt: movie.CreatedAt.UnixMilli(), @@ -1385,8 +1389,12 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA } else { movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken) movie.MovieBase.Type = "mpd" - movie.MovieBase.MoreSource = map[string]string{ - "hevc": fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s&t=hevc", movie.RoomID, movie.ID, userToken), + movie.MovieBase.MoreSources = []*dbModel.MoreSource{ + { + Name: "hevc", + Type: "mpd", + Url: fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s&t=hevc", movie.RoomID, movie.ID, userToken), + }, } } srt, err := bmc.Subtitle.Get(ctx, user.BilibiliCache()) @@ -1505,10 +1513,12 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA } } for _, s := range data.Sources[1:] { - if movie.MovieBase.MoreSource == nil { - movie.MovieBase.MoreSource = make(map[string]string, len(data.Sources)-1) - } - movie.MovieBase.MoreSource[s.Name] = s.URL + movie.MovieBase.MoreSources = append(movie.MovieBase.MoreSources, + &dbModel.MoreSource{ + Name: s.Name, + Url: s.URL, + }, + ) for _, subt := range s.Subtitles { if movie.MovieBase.Subtitles == nil {