Videos near a video file without and upload date are returned as the prev/next videos.

This commit is contained in:
Roland 2023-08-17 19:31:21 -06:00
parent 14017d43bb
commit 9dbd43cfdd
No known key found for this signature in database
GPG key ID: 9D6DBD3ACF11AB93
3 changed files with 95 additions and 37 deletions

View file

@ -59,7 +59,7 @@ export function CaptionTrack({src, ...props}) {
return <track kind="captions" label="Portuguese" src={src} srcLang="pt" {...props}/>
} else if (src.endsWith('.ro.vtt')) {
return <track kind="captions" label="Romanian" src={src} srcLang="ro" {...props}/>
} else if (src.endsWith('.ru.vtt')) {
} else if (src.endsWith('.ru.vtt')) {
return <track kind="captions" label="Russian" src={src} srcLang="ru" {...props}/>
} else if (src.endsWith('.th.vtt')) {
return <track kind="captions" label="Thai" src={src} srcLang="th" {...props}/>
@ -194,6 +194,22 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) {
let videoSource = <source src={videoUrl}/>;
let prevNextVideosSegment = <Segment><p>No related videos found.</p></Segment>;
if (prevFile || nextFile) {
prevNextVideosSegment = <Segment>
<Grid columns={2} stackable>
<Grid.Row>
<Grid.Column textAlign='left'>
{prevFile && <><Header as='h3'>Older</Header><VideoCard file={prevFile}/></>}
</Grid.Column>
<Grid.Column textAlign='left'>
{nextFile && <><Header as='h3'>Newer</Header><VideoCard file={nextFile}/></>}
</Grid.Column>
</Grid.Row>
</Grid>
</Segment>
}
return <>
<Container style={{margin: '1em'}}>
<BackButton/>
@ -245,18 +261,7 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) {
<Tab menu={tabMenu} panes={tabPanes}/>
<Segment>
<Grid columns={2} stackable>
<Grid.Row>
<Grid.Column textAlign='left'>
{prevFile && <><Header as='h3'>Older</Header><VideoCard file={prevFile}/></>}
</Grid.Column>
<Grid.Column textAlign='left'>
{nextFile && <><Header as='h3'>Newer</Header><VideoCard file={nextFile}/></>}
</Grid.Column>
</Grid.Row>
</Grid>
</Segment>
{prevNextVideosSegment}
</Container>
</>
}

View file

@ -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.

View file

@ -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