8d57b21ac2e7a1a8b71c85df171753c773da1643
- Author
- TheEdgeOfRage <git@theedgeofrage.com>
- Committer
- TheEdgeOfRage <git@theedgeofrage.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/db/db.go b/db/db.go
2index 05f27bb5e79cb87596b380ff165254fea23a52cb..27ae92b78cfac55e853fffd348fc788c44b90325 100644
3--- a/db/db.go
4+++ b/db/db.go
5@@ -52,6 +52,10 @@ type DB interface {
6 SetVideoDownloadFailed(ctx context.Context, videoID string, errorMsg string) error
7 // GetVideosForCleanup returns videos that were downloaded and watched older than the given duration
8 GetVideosForCleanup(ctx context.Context, olderThan time.Duration) ([]models.Video, error)
9+ // GetLiveVideos returns unwatched videos that are currently live
10+ GetLiveVideos(ctx context.Context) ([]models.Video, error)
11+ // UpdateVideoLiveStatus updates the live status and duration of a video
12+ UpdateVideoLiveStatus(ctx context.Context, videoID string, isLive bool, duration int) error
13 // DeleteVideoFile clears the download fields for a video
14 DeleteVideoFile(ctx context.Context, videoID string) error
15
16diff --git a/db/videos.go b/db/videos.go
17index 04a3c733966ef274402def8ad22ea62898e82bd4..fbf1015d63ea3f57984cd2da270bcd3e424af49d 100644
18--- a/db/videos.go
19+++ b/db/videos.go
20@@ -382,6 +382,40 @@ func (db *postgresDB) GetVideosForCleanup(ctx context.Context, olderThan time.Du
21 return videos, nil
22 }
23
24+func (db *postgresDB) GetLiveVideos(ctx context.Context) ([]models.Video, error) {
25+ query := `SELECT id FROM videos WHERE is_live = true AND watch_timestamp IS NULL`
26+
27+ rows, err := db.db.Query(ctx, query)
28+ if err != nil {
29+ db.l.Error("Failed to query live videos", "error", err)
30+ return nil, err
31+ }
32+ defer rows.Close()
33+
34+ videos := make([]models.Video, 0)
35+ for rows.Next() {
36+ var video models.Video
37+ err = rows.Scan(&video.ID)
38+ if err != nil {
39+ db.l.Error("Failed to scan live video", "error", err)
40+ return nil, err
41+ }
42+ videos = append(videos, video)
43+ }
44+
45+ return videos, nil
46+}
47+
48+func (db *postgresDB) UpdateVideoLiveStatus(ctx context.Context, videoID string, isLive bool, duration int) error {
49+ query := `UPDATE videos SET is_live = $1, duration = $2 WHERE id = $3`
50+ _, err := db.db.Exec(ctx, query, isLive, duration, videoID)
51+ if err != nil {
52+ db.l.Error("Failed to update video live status", "error", err)
53+ return err
54+ }
55+ return nil
56+}
57+
58 func (db *postgresDB) DeleteVideoFile(ctx context.Context, videoID string) error {
59 query := `
60 UPDATE videos
61diff --git a/handler/videos.go b/handler/videos.go
62index a9db2a25fe44977717a6af2c090a135cf6f351d4..4758b0fe364dd7cb45cae813f5a9453e9ce75d62 100644
63--- a/handler/videos.go
64+++ b/handler/videos.go
65@@ -120,9 +120,43 @@ func (h *handler) FetchVideos(ctx context.Context) error {
66 h.addVideosForChannel(ctx, result.channel, result.enableShorts)
67 }
68
69+ h.recheckLiveVideos(ctx)
70+
71 return nil
72 }
73
74+func (h *handler) recheckLiveVideos(ctx context.Context) {
75+ liveVideos, err := h.db.GetLiveVideos(ctx)
76+ if err != nil {
77+ h.log.Error("Failed to get live videos", "error", err)
78+ return
79+ }
80+ if len(liveVideos) == 0 {
81+ return
82+ }
83+
84+ videos := make(map[string]*models.Video, len(liveVideos))
85+ for i := range liveVideos {
86+ videos[liveVideos[i].ID] = &liveVideos[i]
87+ }
88+
89+ err = h.youTubeClient.GetVideoDurations(ctx, videos)
90+ if err != nil {
91+ h.log.Error("Failed to recheck live video durations", "error", err)
92+ return
93+ }
94+
95+ for _, video := range videos {
96+ if video.IsLive {
97+ continue
98+ }
99+ err = h.db.UpdateVideoLiveStatus(ctx, video.ID, false, video.DurationSeconds)
100+ if err != nil {
101+ h.log.Error("Failed to update video live status", "videoID", video.ID, "error", err)
102+ }
103+ }
104+}
105+
106 func (h *handler) MarkVideoAsWatched(ctx context.Context, videoID string) error {
107 watchTime := time.Now()
108 return h.db.SetVideoWatchTime(ctx, videoID, &watchTime)
109diff --git a/mocks/db/db.go b/mocks/db/db.go
110index 3a075ebfb5fd8aa9ee7da3f006376dc98b60d477..ac0791cf365290d4a0b877b11c6dec38096c0d49 100644
111--- a/mocks/db/db.go
112+++ b/mocks/db/db.go
113@@ -36,6 +36,9 @@ var _ db.DB = &DBMock{}
114 // GetChannelByIDFunc: func(ctx context.Context, channelID string) (*models.Channel, error) {
115 // panic("mock out the GetChannelByID method")
116 // },
117+// GetLiveVideosFunc: func(ctx context.Context) ([]models.Video, error) {
118+// panic("mock out the GetLiveVideos method")
119+// },
120 // GetNewVideosFunc: func(ctx context.Context, sortDesc bool) ([]models.Video, error) {
121 // panic("mock out the GetNewVideos method")
122 // },
123@@ -78,6 +81,9 @@ var _ db.DB = &DBMock{}
124 // UnsubscribeFromChannelFunc: func(ctx context.Context, channelID string) error {
125 // panic("mock out the UnsubscribeFromChannel method")
126 // },
127+// UpdateVideoLiveStatusFunc: func(ctx context.Context, videoID string, isLive bool, duration int) error {
128+// panic("mock out the UpdateVideoLiveStatus method")
129+// },
130 // }
131 //
132 // // use mockedDB in code that requires db.DB
133@@ -100,6 +106,9 @@ type DBMock struct {
134 // GetChannelByIDFunc mocks the GetChannelByID method.
135 GetChannelByIDFunc func(ctx context.Context, channelID string) (*models.Channel, error)
136
137+ // GetLiveVideosFunc mocks the GetLiveVideos method.
138+ GetLiveVideosFunc func(ctx context.Context) ([]models.Video, error)
139+
140 // GetNewVideosFunc mocks the GetNewVideos method.
141 GetNewVideosFunc func(ctx context.Context, sortDesc bool) ([]models.Video, error)
142
143@@ -142,6 +151,9 @@ type DBMock struct {
144 // UnsubscribeFromChannelFunc mocks the UnsubscribeFromChannel method.
145 UnsubscribeFromChannelFunc func(ctx context.Context, channelID string) error
146
147+ // UpdateVideoLiveStatusFunc mocks the UpdateVideoLiveStatus method.
148+ UpdateVideoLiveStatusFunc func(ctx context.Context, videoID string, isLive bool, duration int) error
149+
150 // calls tracks calls to the methods.
151 calls struct {
152 // AddVideo holds details about calls to the AddVideo method.
153@@ -179,6 +191,11 @@ type DBMock struct {
154 // ChannelID is the channelID argument value.
155 ChannelID string
156 }
157+ // GetLiveVideos holds details about calls to the GetLiveVideos method.
158+ GetLiveVideos []struct {
159+ // Ctx is the ctx argument value.
160+ Ctx context.Context
161+ }
162 // GetNewVideos holds details about calls to the GetNewVideos method.
163 GetNewVideos []struct {
164 // Ctx is the ctx argument value.
165@@ -291,12 +308,24 @@ type DBMock struct {
166 // ChannelID is the channelID argument value.
167 ChannelID string
168 }
169+ // UpdateVideoLiveStatus holds details about calls to the UpdateVideoLiveStatus method.
170+ UpdateVideoLiveStatus []struct {
171+ // Ctx is the ctx argument value.
172+ Ctx context.Context
173+ // VideoID is the videoID argument value.
174+ VideoID string
175+ // IsLive is the isLive argument value.
176+ IsLive bool
177+ // Duration is the duration argument value.
178+ Duration int
179+ }
180 }
181 lockAddVideo sync.RWMutex
182 lockClose sync.RWMutex
183 lockDeleteVideoFile sync.RWMutex
184 lockDiscardVideo sync.RWMutex
185 lockGetChannelByID sync.RWMutex
186+ lockGetLiveVideos sync.RWMutex
187 lockGetNewVideos sync.RWMutex
188 lockGetVideo sync.RWMutex
189 lockGetVideosForCleanup sync.RWMutex
190@@ -311,6 +340,7 @@ type DBMock struct {
191 lockSubscribeToChannel sync.RWMutex
192 lockToggleChannelShorts sync.RWMutex
193 lockUnsubscribeFromChannel sync.RWMutex
194+ lockUpdateVideoLiveStatus sync.RWMutex
195 }
196
197 // AddVideo calls AddVideoFunc.
198@@ -492,6 +522,38 @@ func (mock *DBMock) GetChannelByIDCalls() []struct {
199 return calls
200 }
201
202+// GetLiveVideos calls GetLiveVideosFunc.
203+func (mock *DBMock) GetLiveVideos(ctx context.Context) ([]models.Video, error) {
204+ if mock.GetLiveVideosFunc == nil {
205+ panic("DBMock.GetLiveVideosFunc: method is nil but DB.GetLiveVideos was just called")
206+ }
207+ callInfo := struct {
208+ Ctx context.Context
209+ }{
210+ Ctx: ctx,
211+ }
212+ mock.lockGetLiveVideos.Lock()