diff --git a/src/cmd/bililive/internal/init.go b/src/cmd/bililive/internal/init.go index a0d4c4a7..59309ace 100644 --- a/src/cmd/bililive/internal/init.go +++ b/src/cmd/bililive/internal/init.go @@ -17,6 +17,7 @@ import ( _ "github.com/hr3lxphr6j/bililive-go/src/live/missevan" _ "github.com/hr3lxphr6j/bililive-go/src/live/openrec" _ "github.com/hr3lxphr6j/bililive-go/src/live/qq" + _ "github.com/hr3lxphr6j/bililive-go/src/live/system" _ "github.com/hr3lxphr6j/bililive-go/src/live/twitch" _ "github.com/hr3lxphr6j/bililive-go/src/live/yizhibo" _ "github.com/hr3lxphr6j/bililive-go/src/live/zhanqi" diff --git a/src/listeners/event.go b/src/listeners/event.go index be27c866..35770686 100644 --- a/src/listeners/event.go +++ b/src/listeners/event.go @@ -5,9 +5,10 @@ import ( ) const ( - ListenStart events.EventType = "ListenStart" - ListenStop events.EventType = "ListenStop" - LiveStart events.EventType = "LiveStart" - LiveEnd events.EventType = "LiveEnd" - RoomNameChanged events.EventType = "RoomNameChanged" + ListenStart events.EventType = "ListenStart" + ListenStop events.EventType = "ListenStop" + LiveStart events.EventType = "LiveStart" + LiveEnd events.EventType = "LiveEnd" + RoomNameChanged events.EventType = "RoomNameChanged" + RoomInitializingFinished events.EventType = "RoomInitializingFinished" ) diff --git a/src/listeners/listener.go b/src/listeners/listener.go index 97e82242..24b4c41c 100644 --- a/src/listeners/listener.go +++ b/src/listeners/listener.go @@ -12,6 +12,7 @@ import ( "github.com/hr3lxphr6j/bililive-go/src/instance" "github.com/hr3lxphr6j/bililive-go/src/interfaces" "github.com/hr3lxphr6j/bililive-go/src/live" + "github.com/hr3lxphr6j/bililive-go/src/live/system" "github.com/hr3lxphr6j/bililive-go/src/pkg/events" ) @@ -92,9 +93,10 @@ func (l *listener) refresh() { } ) defer func() { l.status = latestStatus }() + isStatusChanged := true switch l.status.Diff(latestStatus) { case 0: - return + isStatusChanged = false case statusToTrueEvt: l.Live.SetLastStartTime(time.Now()) evtTyp = LiveStart @@ -109,9 +111,22 @@ func (l *listener) refresh() { evtTyp = RoomNameChanged logInfo = "Room name was changed" } + if isStatusChanged { + l.ed.DispatchEvent(events.NewEvent(evtTyp, l.Live)) + l.logger.WithFields(fields).Info(logInfo) + } - l.ed.DispatchEvent(events.NewEvent(evtTyp, l.Live)) - l.logger.WithFields(fields).Info(logInfo) + if info.Initializing { + initializingLive := l.Live.(*live.WrappedLive).Live.(*system.InitializingLive) + info, err = initializingLive.OriginalLive.GetInfo() + if err == nil { + l.ed.DispatchEvent(events.NewEvent(RoomInitializingFinished, live.InitializingFinishedParam{ + InitializingLive: l.Live, + Live: initializingLive.OriginalLive, + Info: info, + })) + } + } } func (l *listener) run() { diff --git a/src/listeners/manager.go b/src/listeners/manager.go index f2355aa5..6515bc0c 100644 --- a/src/listeners/manager.go +++ b/src/listeners/manager.go @@ -7,6 +7,7 @@ import ( "github.com/hr3lxphr6j/bililive-go/src/instance" "github.com/hr3lxphr6j/bililive-go/src/interfaces" "github.com/hr3lxphr6j/bililive-go/src/live" + "github.com/hr3lxphr6j/bililive-go/src/pkg/events" ) // for test @@ -33,11 +34,43 @@ type manager struct { savers map[live.ID]Listener } +func (m *manager) registryListener(ctx context.Context, ed events.Dispatcher) { + ed.AddEventListener(RoomInitializingFinished, events.NewEventListener(func(event *events.Event) { + param := event.Object.(live.InitializingFinishedParam) + initializingLive := param.InitializingLive + live := param.Live + info := param.Info + if info.CustomLiveId != "" { + live.SetLiveIdByString(info.CustomLiveId) + } + inst := instance.GetInstance(ctx) + logger := inst.Logger + inst.Lives[live.GetLiveId()] = live + + room, err := inst.Config.GetLiveRoomByUrl(live.GetRawUrl()) + if err != nil { + logger.WithFields(map[string]interface{}{ + "room": live.GetRawUrl(), + }).Error(err) + panic(err) + } + room.LiveId = live.GetLiveId() + if room.IsListening { + if err := m.replaceListener(ctx, initializingLive, live); err != nil { + logger.WithFields(map[string]interface{}{ + "url": live.GetRawUrl(), + }).Error(err) + } + } + })) +} + func (m *manager) Start(ctx context.Context) error { inst := instance.GetInstance(ctx) if inst.Config.RPC.Enable || len(inst.Lives) > 0 { inst.WaitGroup.Add(1) } + m.registryListener(ctx, inst.EventDispatcher.(events.Dispatcher)) return nil } @@ -76,6 +109,25 @@ func (m *manager) RemoveListener(ctx context.Context, liveId live.ID) error { return nil } +func (m *manager) replaceListener(ctx context.Context, oldLive live.Live, newLive live.Live) error { + m.lock.Lock() + defer m.lock.Unlock() + oldLiveId := oldLive.GetLiveId() + oldListener, ok := m.savers[oldLiveId] + if !ok { + return ErrListenerNotExist + } + oldListener.Close() + newListener := newListener(ctx, newLive) + if oldLiveId == newLive.GetLiveId() { + m.savers[oldLiveId] = newListener + } else { + delete(m.savers, oldLiveId) + m.savers[newLive.GetLiveId()] = newListener + } + return newListener.Start() +} + func (m *manager) GetListener(ctx context.Context, liveId live.ID) (Listener, error) { m.lock.RLock() defer m.lock.RUnlock() diff --git a/src/listeners/manager_test.go b/src/listeners/manager_test.go index 5b5cd104..ebabdff3 100644 --- a/src/listeners/manager_test.go +++ b/src/listeners/manager_test.go @@ -12,6 +12,7 @@ import ( "github.com/hr3lxphr6j/bililive-go/src/instance" "github.com/hr3lxphr6j/bililive-go/src/live" livemock "github.com/hr3lxphr6j/bililive-go/src/live/mock" + evtmock "github.com/hr3lxphr6j/bililive-go/src/pkg/events/mock" ) func TestManagerAddAndRemoveListener(t *testing.T) { @@ -46,7 +47,10 @@ func TestManagerAddAndRemoveListener(t *testing.T) { func TestManagerStartAndClose(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() + ed := evtmock.NewMockDispatcher(ctrl) + ed.EXPECT().AddEventListener(RoomInitializingFinished, gomock.Any()) ctx := context.WithValue(context.Background(), instance.Key, &instance.Instance{ + EventDispatcher: ed, Config: &configs.Config{ RPC: configs.RPC{Enable: true}, }, diff --git a/src/live/info.go b/src/live/info.go index c1375aea..e3b616dd 100644 --- a/src/live/info.go +++ b/src/live/info.go @@ -5,10 +5,12 @@ import ( ) type Info struct { - Live Live - HostName, RoomName string - Status, Listening, Recording bool - CustomLiveId string + Live Live + HostName, RoomName string + Status bool // means isLiving, maybe better to rename it + Listening, Recording bool + Initializing bool + CustomLiveId string } func (i *Info) MarshalJSON() ([]byte, error) { @@ -21,6 +23,7 @@ func (i *Info) MarshalJSON() ([]byte, error) { Status bool `json:"status"` Listening bool `json:"listening"` Recording bool `json:"recording"` + Initializing bool `json:"initializing"` LastStartTime string `json:"last_start_time,omitempty"` LastStartTimeUnix int64 `json:"last_start_time_unix,omitempty"` }{ @@ -32,6 +35,7 @@ func (i *Info) MarshalJSON() ([]byte, error) { Status: i.Status, Listening: i.Listening, Recording: i.Recording, + Initializing: i.Initializing, } if !i.Live.GetLastStartTime().IsZero() { t.LastStartTime = i.Live.GetLastStartTime().Format("2006-01-02 15:04:05") diff --git a/src/live/lives.go b/src/live/lives.go index 64dbde5f..e31aec3e 100755 --- a/src/live/lives.go +++ b/src/live/lives.go @@ -13,7 +13,8 @@ import ( ) var ( - m = make(map[string]Builder) + m = make(map[string]Builder) + InitializingLiveBuilderInstance InitializingLiveBuilder ) func Register(domain string, b Builder) { @@ -29,6 +30,16 @@ type Builder interface { Build(*url.URL, ...Option) (Live, error) } +type InitializingLiveBuilder interface { + Build(Live, *url.URL, ...Option) (Live, error) +} + +type InitializingFinishedParam struct { + InitializingLive Live + Live Live + Info *Info +} + type Options struct { Cookies *cookiejar.Jar Quality int @@ -77,7 +88,7 @@ func WithQuality(quality int) Option { return func(opts *Options) { opts.Quality = quality } -} +} type ID string @@ -92,19 +103,19 @@ type Live interface { SetLastStartTime(time.Time) } -type wrappedLive struct { +type WrappedLive struct { Live cache gcache.Cache } func newWrappedLive(live Live, cache gcache.Cache) Live { - return &wrappedLive{ + return &WrappedLive{ Live: live, cache: cache, } } -func (w *wrappedLive) GetInfo() (*Info, error) { +func (w *WrappedLive) GetInfo() (*Info, error) { i, err := w.Live.GetInfo() if err != nil { return nil, err @@ -135,5 +146,10 @@ func New(url *url.URL, cache gcache.Cache, opts ...Option) (live Live, err error } time.Sleep(1 * time.Second) } - return nil, err + + // when room initializaion is failed + live, err = InitializingLiveBuilderInstance.Build(live, url, opts...) + live = newWrappedLive(live, cache) + live.GetInfo() // dummy call to initialize cache inside wrappedLive + return } diff --git a/src/live/system/initializing_live.go b/src/live/system/initializing_live.go new file mode 100644 index 00000000..fd8def89 --- /dev/null +++ b/src/live/system/initializing_live.go @@ -0,0 +1,48 @@ +package system + +import ( + "net/url" + + "github.com/hr3lxphr6j/bililive-go/src/live" + "github.com/hr3lxphr6j/bililive-go/src/live/internal" +) + +func init() { + live.InitializingLiveBuilderInstance = new(builder) +} + +type builder struct{} + +func (b *builder) Build(live live.Live, url *url.URL, opt ...live.Option) (live.Live, error) { + return &InitializingLive{ + BaseLive: internal.NewBaseLive(url, opt...), + OriginalLive: live, + }, nil +} + +type InitializingLive struct { + internal.BaseLive + OriginalLive live.Live +} + +func (l *InitializingLive) GetInfo() (info *live.Info, err error) { + err = nil + info = &live.Info{ + Live: l, + HostName: "", + RoomName: l.GetRawUrl(), + Status: false, + Initializing: true, + } + return +} + +func (l *InitializingLive) GetStreamUrls() (us []*url.URL, err error) { + us = make([]*url.URL, 0) + err = nil + return +} + +func (l *InitializingLive) GetPlatformCNName() string { + return "" +} diff --git a/src/webapp/src/component/live-list/index.tsx b/src/webapp/src/component/live-list/index.tsx index 4ef6950c..4d7ee138 100644 --- a/src/webapp/src/component/live-list/index.tsx +++ b/src/webapp/src/component/live-list/index.tsx @@ -58,6 +58,9 @@ class LiveList extends React.Component { if (tag === '录制中') { color = 'red'; } + if (tag === '初始化') { + color = 'orange'; + } return ( @@ -234,6 +237,10 @@ class LiveList extends React.Component { tags = ['录制中']; } + if (item.initializing === true) { + tags.push('初始化') + } + return { key: index + 1, name: item.host_name,