From 9dbd43cfdd6d5865bd966590a6d73bb216874591 Mon Sep 17 00:00:00 2001 From: Roland Date: Thu, 17 Aug 2023 19:31:21 -0600 Subject: [PATCH] Videos near a video file without and upload date are returned as the prev/next videos. --- app/src/components/VideoPlayer.js | 31 +++++++++------ modules/videos/models.py | 57 +++++++++++++++++---------- modules/videos/video/test/test_api.py | 44 +++++++++++++++++++-- 3 files changed, 95 insertions(+), 37 deletions(-) diff --git a/app/src/components/VideoPlayer.js b/app/src/components/VideoPlayer.js index 8fffba35..7f5215b3 100644 --- a/app/src/components/VideoPlayer.js +++ b/app/src/components/VideoPlayer.js @@ -59,7 +59,7 @@ export function CaptionTrack({src, ...props}) { return } else if (src.endsWith('.ro.vtt')) { return - } else if (src.endsWith('.ru.vtt')) { + } else if (src.endsWith('.ru.vtt')) { return } else if (src.endsWith('.th.vtt')) { return @@ -194,6 +194,22 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) { let videoSource = ; + let prevNextVideosSegment =

No related videos found.

; + if (prevFile || nextFile) { + prevNextVideosSegment = + + + + {prevFile && <>
Older
} +
+ + {nextFile && <>
Newer
} +
+
+
+
+ } + return <> @@ -245,18 +261,7 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) { - - - - - {prevFile && <>
Older
} -
- - {nextFile && <>
Newer
} -
-
-
-
+ {prevNextVideosSegment}
} diff --git a/modules/videos/models.py b/modules/videos/models.py index 111659f1..d0d316dd 100644 --- a/modules/videos/models.py +++ b/modules/videos/models.py @@ -133,13 +133,12 @@ class Video(ModelHelper, Base): def get_surrounding_videos(self): """ - Get the previous and next videos around this video. The videos must be in the same channel. + Get the previous and next videos around this Video. The videos must be in the same Channel. Example: >>> vid1 = Video(id=1, upload_date=10) >>> vid2 = Video(id=2, upload_date=20) >>> vid3 = Video(id=3, upload_date=30) - >>> vid4 = Video(id=4) >>> vid1.get_surrounding_videos() (None, vid2) @@ -147,38 +146,54 @@ class Video(ModelHelper, Base): (vid1, vid3) >>> vid3.get_surrounding_videos() (vid2, None) - Video 4 has no upload date, so we can't place it in order. - >>> vid4.get_surrounding_videos() - (None, None) """ session = Session.object_session(self) - if not self.upload_date: - # We can't place a video that has no upload date. - return None, None - with get_db_curs() as curs: - query = ''' + if self.upload_date: + # Get videos next to this Video's upload date. + stmt = ''' + WITH numbered_videos AS ( + SELECT id, + ROW_NUMBER() OVER (ORDER BY upload_date ASC) AS row_number + FROM video + WHERE + channel_id = %(channel_id)s + AND upload_date IS NOT NULL + ) + SELECT id + FROM numbered_videos + WHERE row_number IN ( + SELECT row_number+i + FROM numbered_videos + CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n + WHERE + id = %(video_id)s + ) + ''' + else: + # No videos near this Video with upload dates, recommend the files next to this Video. + # Only recommend videos in the same Channel (or similarly without a Channel). + channel_where = 'WHERE v.channel_id = %(channel_id)s' if self.channel_id \ + else 'WHERE v.channel_id IS NULL' + stmt = f''' WITH numbered_videos AS ( - SELECT id, - ROW_NUMBER() OVER (ORDER BY upload_date ASC) AS row_number - FROM video - WHERE - channel_id = %(channel_id)s - AND upload_date IS NOT NULL + SELECT v.id, ROW_NUMBER() OVER (ORDER BY fg.primary_path) AS row_number + FROM + video v + LEFT JOIN file_group fg on fg.id = v.file_group_id + {channel_where} ) - SELECT id FROM numbered_videos WHERE row_number IN ( SELECT row_number+i FROM numbered_videos CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n - WHERE - id = %(video_id)s ) - ''' - curs.execute(query, dict(channel_id=self.channel_id, video_id=self.id)) + ''' + curs.execute(stmt, dict(channel_id=self.channel_id, video_id=self.id)) + results = [i[0] for i in curs.fetchall()] # Assign the returned ID's to their respective positions relative to the ID that matches the video_id. diff --git a/modules/videos/video/test/test_api.py b/modules/videos/video/test/test_api.py index 8b32a343..2a012bdd 100644 --- a/modules/videos/video/test/test_api.py +++ b/modules/videos/video/test/test_api.py @@ -8,7 +8,6 @@ import pytest from modules.videos.models import Video from modules.videos.video.lib import get_video_for_app from wrolpi.dates import now -from wrolpi.errors import WROLModeEnabled def test_get_video_prev_next(test_session, channel_factory, video_factory): @@ -41,7 +40,7 @@ def test_get_video_prev_next(test_session, channel_factory, video_factory): (1, (None, 'vid2')), (2, ('vid1', 'vid4')), (4, ('vid2', None)), # 7 has no upload_date, so it doesn't come after 4. - (7, (None, None)), # 7 has no upload_date, so we don't know the order of it. + (7, ('vid4', None)), # 7 has no upload_date, so we get the video next to it's file. # Channel 3 has only one video. (9, (None, None)), # Channel 2 was inserted out of order. @@ -49,7 +48,8 @@ def test_get_video_prev_next(test_session, channel_factory, video_factory): (3, ('vid5', 'vid6')), (8, ('vid6', None)), # Channel 4's videos have no upload date, so we don't know what is previous/next. - (10, (None, None)), + (10, (None, 'vid11')), + (11, ('vid10', None)), ] for id_, (prev_title, next_title) in tests: @@ -70,6 +70,44 @@ def test_get_video_prev_next(test_session, channel_factory, video_factory): raise AssertionError(f'Assert failed for {id_=} {prev_title=} {next_title=}') from e +def test_get_video_prev_next_no_upload_date(test_session, video_factory, channel_factory): + """ + Previous and Next Videos should be those next to a Video file when videos do not have upload dates. + """ + channel1, channel2 = channel_factory(), channel_factory() + vid0, vid1, vid2, vid3, vid4, vid5 = video_factory(channel2.id, title='vid0'), \ + video_factory(channel1.id, title='vid1'), \ + video_factory(channel1.id, title='vid2'), \ + video_factory(channel1.id, title='vid3'), \ + video_factory(title='vid4'), \ + video_factory(title='vid5') + test_session.commit() + + # Channel 2 has only 1 video. + prev, next_ = vid0.get_surrounding_videos() + assert prev is None + assert next_ is None + + # Channel 1 has 3 videos, finally getting surrounding videos. + prev, next_ = vid1.get_surrounding_videos() + assert prev is None + assert next_ == vid2 + prev, next_ = vid2.get_surrounding_videos() + assert prev == vid1 + assert next_ == vid3 + prev, next_ = vid3.get_surrounding_videos() + assert prev == vid2 + assert next_ is None + + # Videos without a channel + prev, next_ = vid4.get_surrounding_videos() + assert prev is None + assert next_ is vid5 + prev, next_ = vid5.get_surrounding_videos() + assert prev == vid4 + assert next_ is None + + def test_get_video_for_app(test_session, simple_channel, simple_video): vid, prev, next_ = get_video_for_app(simple_video.id) assert vid['id'] == simple_video.id