videos: a collaboration video's channel directory conflict killed the download (#677)
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

* videos: a collaboration video's channel directory conflict killed the download

YouTube collaboration videos appear in every collaborator's feed but their
metadata names only the primary uploader's channel. When that channel's
computed directory already belonged to an existing Channel that no longer
matched by source_id/url/name, channel creation raised
ChannelDirectoryConflict and the download failed unrecoverably. Now the
channel that owns the directory is used instead of creating a conflicting one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* review: trim comments that restated the code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

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

View file

@ -1361,6 +1361,15 @@ def get_or_create_channel(session: Session, source_id: str = None, url: str = No
channel_directory = get_absolute_media_path(destination)
else:
channel_directory = format_videos_destination(name, tag_name, url)
# Reuse the Channel that already owns this directory instead of creating a conflicting one.
try:
channel = get_channel(session, directory=channel_directory, return_dict=False)
channel.dict()
return channel
except UnknownChannel:
pass
if not channel_directory.is_dir():
channel_directory.mkdir(parents=True)
data = ChannelPostRequest(

View file

@ -365,6 +365,29 @@ async def test_get_or_create_channel_destination_nested_conflict(async_client, t
assert result.id == channel.id
@pytest.mark.asyncio
async def test_get_or_create_channel_computed_directory_conflict(async_client, test_session, test_directory):
"""When no existing channel matches by source_id/url/name, but the directory that would be created
already belongs to a channel, that channel should be returned instead of raising.
YouTube collaboration videos report the primary uploader's channel, which may not match any local
channel by name (e.g. the local channel was renamed) even though its directory is already taken."""
from wrolpi.collections import Collection
existing_dir = test_directory / 'videos/Uploader'
existing_dir.mkdir(parents=True)
collection = Collection(name='Uploader (old name)', kind='channel', directory=existing_dir)
test_session.add(collection)
test_session.flush([collection])
channel = Channel(collection_id=collection.id, source_id='UCold', url='https://www.youtube.com/@olduploader')
test_session.add(channel)
test_session.commit()
result = get_or_create_channel(test_session, source_id='UCnew',
url='https://www.youtube.com/channel/UCnew', name='Uploader')
assert result.id == channel.id
@pytest.mark.asyncio
async def test_get_or_create_channel_existing_ignores_destination(async_client, test_session, test_directory):
"""When a channel already exists (matched by source_id), the destination parameter should be ignored."""