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