videos: parse the published date out of audio file names too (#676)
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Controller Tests / controller-tests (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run

NAME_PARSER's suffix whitelist had no audio suffixes (and no mkv/m4v),
so a correctly-named audio file got no published date and sorted to the
very end of its Channel -- which reads as missing. The whitelist now
carries the media suffixes a Video FileGroup can lead with.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lrnselfreliance 2026-08-24 12:13:52 -06:00 • committed by Roland
parent fdb7258160
commit 340aacb633
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
3 changed files with 38 additions and 2 deletions

View file

@ -1054,7 +1054,11 @@ async def get_statistics():
NAME_PARSER = re.compile(
r'(?:(.*?)_)?((?:\d+?)|(?:NA))_(?:(.{5,25})_)?(.*)'
r'\.(jpg|webp|flv|mp4|part|info\.json|description|webm|..\.srt|..\.vtt)', # the file suffix
# The file suffix. Every media suffix a Video FileGroup can lead with belongs here:
# audio is Channel content too, and a suffix missing from this list leaves the file
# without a published date, sorted to the end of its Channel.
r'\.(jpg|webp|flv|mp4|m4v|mkv|webm|mp3|flac|opus|ogg|m4a|wav|aac|wma'
r'|part|info\.json|description|..\.srt|..\.vtt)',
re.IGNORECASE)

View file

@ -33,6 +33,27 @@ async def test_uploaded_audio_becomes_a_channel_video(async_client, test_session
assert video.channel_id == channel.id, 'the Video must belong to the Channel it was uploaded into'
@pytest.mark.asyncio
async def test_uploaded_audio_gets_published_datetime_from_filename(async_client, test_session,
channel_factory):
"""An uploaded audio file named in WROLPi's format gets its published date from the name.
The Channel page sorts by published date; without one the file sorts to the very end of the
Channel, which reads as missing.
"""
channel = channel_factory(name='The Tech Prepper')
audio_path = channel.directory / 'The Tech Prepper_20260820_WRMI Interview.mp3'
shutil.copy(PROJECT_DIR / 'test/big_buck_bunny.mp3', audio_path)
await upsert_file(audio_path)
file_group = test_session.query(FileGroup).filter_by(primary_path=str(audio_path)).one()
assert file_group.published_datetime is not None, \
'the published date must be parsed from the file name'
assert file_group.published_datetime.strftime('%Y%m%d') == '20260820'
assert file_group.title == 'WRMI Interview'
@pytest.mark.asyncio
async def test_audio_playlist_is_not_a_video(async_client, test_session, test_directory):
"""A playlist with an audio/* mimetype is a text list of URLs, not media.

View file

@ -34,7 +34,18 @@ from wrolpi.vars import PROJECT_DIR
('Learning Self-Reliance_20170529_p_Beekeeping 2017 Part 6 - Merging Hives.mp4',
('Learning Self-Reliance', '20170529', None, 'p_Beekeeping 2017 Part 6 - Merging Hives')),
('Learning Self-Reliance_20240722_clyx8ark92qk70860vtl997n5_Long Source Id File with _.mp4',
('Learning Self-Reliance', '20240722', 'clyx8ark92qk70860vtl997n5', 'Long Source Id File with _'))
('Learning Self-Reliance', '20240722', 'clyx8ark92qk70860vtl997n5', 'Long Source Id File with _')),
# Audio files and other media containers carry the same name format; a suffix missing from
# the parser leaves the file with no published date, sorted to the end of its Channel.
('The Tech Prepper_20260820_WRMI S2 Underground Shortwave Interview.flac',
('The Tech Prepper', '20260820', None, 'WRMI S2 Underground Shortwave Interview')),
('channel_20000101_12345678910_ some title.mp3', ('channel', '20000101', '12345678910', 'some title')),
('channel_20000101_12345678910_ some title.mkv', ('channel', '20000101', '12345678910', 'some title')),
('channel_20000101_some title.opus', ('channel', '20000101', None, 'some title')),
('channel_20000101_some title.ogg', ('channel', '20000101', None, 'some title')),
('channel_20000101_some title.m4a', ('channel', '20000101', None, 'some title')),
('channel_20000101_some title.m4v', ('channel', '20000101', None, 'some title')),
('channel_20000101_some title.wav', ('channel', '20000101', None, 'some title')),
])
def test_parse_video_file_name(file_name, expected):
"""