You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
synctv/room/movies.go

348 lines
6.9 KiB
Go

package room
import (
"fmt"
"net/url"
"sync"
"time"
"github.com/zijiren233/gencontainer/dllist"
rtmps "github.com/zijiren233/livelib/server"
)
type FormatErrMovieNotFound uint64
func (e FormatErrMovieNotFound) Error() string {
return fmt.Sprintf("movie id: %v not found", uint64(e))
}
type FormatErrMovieAlreadyExist uint64
func (e FormatErrMovieAlreadyExist) Error() string {
return fmt.Sprintf("movie id: %v already exist", uint64(e))
}
type movies struct {
l *dllist.Dllist[*Movie]
lock *sync.RWMutex
}
// Url will be `PullKey` when Live and Proxy are true
type Movie struct {
BaseMovie
PullKey string `json:"pullKey"`
CreateAt int64 `json:"createAt"`
LastEditAt int64 `json:"lastEditAt"`
id uint64
channel *rtmps.Channel
creator *User
}
type BaseMovie struct {
Url string `json:"url"`
Name string `json:"name"`
Live bool `json:"live"`
Proxy bool `json:"proxy"`
RtmpSource bool `json:"rtmpSource"`
Type string `json:"type"`
Headers map[string][]string `json:"headers"`
}
type MovieConf func(m *Movie)
func WithPullKey(PullKey string) MovieConf {
return func(m *Movie) {
m.PullKey = PullKey
}
}
func WithChannel(channel *rtmps.Channel) MovieConf {
return func(m *Movie) {
m.channel = channel
}
}
func WithCreator(creator *User) MovieConf {
return func(m *Movie) {
m.creator = creator
}
}
func NewMovie(id uint64, url, name, type_ string, live, proxy, rtmpSource bool, headers map[string][]string, conf ...MovieConf) (*Movie, error) {
return NewMovieWithBaseMovie(id, BaseMovie{
Url: url,
Name: name,
Live: live,
Proxy: proxy,
RtmpSource: rtmpSource,
Type: type_,
Headers: headers,
})
}
func NewMovieWithBaseMovie(id uint64, baseMovie BaseMovie, conf ...MovieConf) (*Movie, error) {
now := time.Now().UnixMicro()
m := &Movie{
id: id,
BaseMovie: baseMovie,
CreateAt: now,
LastEditAt: now,
}
m.Init(conf...)
return m, m.Check()
}
func (m *Movie) Check() error {
_, err := url.Parse(m.Url)
if err != nil {
return err
}
return nil
}
func (m *Movie) Id() uint64 {
return m.id
}
func (m *Movie) Init(conf ...MovieConf) {
for _, c := range conf {
c(m)
}
}
func (m *Movie) Creator() *User {
return m.creator
}
func (m *Movie) SetCreator(creator *User) {
m.creator = creator
}
func (m *Movie) Channel() *rtmps.Channel {
return m.channel
}
func (m *Movie) SetChannel(channel *rtmps.Channel) {
m.channel = channel
}
func newMovies() *movies {
return &movies{l: dllist.New[*Movie](), lock: &sync.RWMutex{}}
}
func (m *movies) Range(f func(e *dllist.Element[*Movie]) bool) (interrupt bool) {
m.lock.RLock()
defer m.lock.RUnlock()
interrupt = false
for e := m.l.Front(); !interrupt && e != nil; e = e.Next() {
interrupt = !f(e)
}
return
}
func (m *movies) range_(f func(e *dllist.Element[*Movie]) bool) (interrupt bool) {
interrupt = false
for e := m.l.Front(); !interrupt && e != nil; e = e.Next() {
interrupt = !f(e)
}
return
}
type MovieInfo struct {
Id uint64 `json:"id"`
Url string `json:"url"`
Name string `json:"name"`
Live bool `json:"live"`
Proxy bool `json:"proxy"`
RtmpSource bool `json:"rtmpSource"`
Type string `json:"type"`
Headers map[string][]string `json:"headers"`
PullKey string `json:"pullKey"`
CreateAt int64 `json:"createAt"`
LastEditAt int64 `json:"lastEditAt"`
Creator string `json:"creator"`
}
func (m *movies) MovieList() (movies []MovieInfo) {
m.lock.RLock()
defer m.lock.RUnlock()
movies = make([]MovieInfo, 0, m.l.Len())
m.range_(func(e *dllist.Element[*Movie]) bool {
movies = append(movies, MovieInfo{
Id: e.Value.id,
Url: e.Value.Url,
Name: e.Value.Name,
Live: e.Value.Live,
Proxy: e.Value.Proxy,
RtmpSource: e.Value.RtmpSource,
Type: e.Value.Type,
Headers: e.Value.Headers,
CreateAt: e.Value.CreateAt,
LastEditAt: e.Value.LastEditAt,
Creator: e.Value.Creator().Name(),
})
return true
})
return
}
func (m *movies) Clear() error {
m.lock.Lock()
defer m.lock.Unlock()
m.l.Clear()
return nil
}
func (m *movies) GetAndClear() (movies []*Movie) {
m.lock.Lock()
defer m.lock.Unlock()
movies = make([]*Movie, 0, m.l.Len())
m.range_(func(e *dllist.Element[*Movie]) bool {
movies = append(movies, e.Value)
return true
})
m.l.Clear()
return
}
func (m *movies) HasMovie(id uint64) bool {
m.lock.RLock()
defer m.lock.RUnlock()
return m.hasMovie(id)
}
func (m *movies) hasMovie(id uint64) bool {
return m.range_(func(e *dllist.Element[*Movie]) bool {
return e.Value.id != id
})
}
func (m *movies) GetMovie(id uint64) (movie *Movie, err error) {
m.lock.RLock()
defer m.lock.RUnlock()
e, err := m.getMovie(id)
if err != nil {
return nil, FormatErrMovieNotFound(id)
}
return e.Value, nil
}
func (m *movies) GetMovieWithPullKey(pullKey string) (movie *Movie, err error) {
if pullKey == "" {
return nil, fmt.Errorf("pullKey is empty")
}
m.lock.RLock()
defer m.lock.RUnlock()
m.range_(func(e *dllist.Element[*Movie]) bool {
if e.Value.PullKey == pullKey {
movie = e.Value
return false
}
return true
})
if movie == nil {
return nil, fmt.Errorf("pullKey: %v not found", pullKey)
}
return
}
func (m *movies) GetAndDelMovie(id ...uint64) (movies []*Movie, err error) {
m.lock.Lock()
defer m.lock.Unlock()
es := make([]*dllist.Element[*Movie], 0, len(id))
for _, v := range id {
e, err := m.getMovie(v)
if err != nil {
return nil, FormatErrMovieNotFound(v)
}
es = append(es, e)
}
movies = make([]*Movie, 0, len(es))
for _, e := range es {
movies = append(movies, e.Value)
e.Remove()
}
return movies, nil
}
func (m *movies) getMovie(id uint64) (element *dllist.Element[*Movie], err error) {
err = FormatErrMovieNotFound(id)
m.range_(func(e *dllist.Element[*Movie]) bool {
if e.Value.id == id {
element = e
err = nil
return false
}
return true
})
return
}
func (m *movies) PushBackMovie(movie *Movie) error {
m.lock.Lock()
defer m.lock.Unlock()
if m.hasMovie(movie.id) {
return FormatErrMovieAlreadyExist(movie.id)
}
m.l.PushBack(movie)
return nil
}
func (m *movies) PushFrontMovie(movie *Movie) error {
m.lock.Lock()
defer m.lock.Unlock()
if m.hasMovie(movie.id) {
return FormatErrMovieAlreadyExist(movie.id)
}
m.l.PushFront(movie)
return nil
}
func (m *movies) DelMovie(id uint64) error {
m.lock.Lock()
defer m.lock.Unlock()
e, err := m.getMovie(id)
if err != nil {
return err
}
e.Remove()
return nil
}
func (m *movies) SwapMovie(id1, id2 uint64) error {
m.lock.Lock()
defer m.lock.Unlock()
e1, err := m.getMovie(id1)
if err != nil {
return err
}
e2, err := m.getMovie(id2)
if err != nil {
return err
}
m.l.Swap(e1, e2)
return nil
}