diff --git a/modules/videos/downloader.py b/modules/videos/downloader.py index 14e0fd1b..1cd6708f 100755 --- a/modules/videos/downloader.py +++ b/modules/videos/downloader.py @@ -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( diff --git a/modules/videos/test/test_downloader.py b/modules/videos/test/test_downloader.py index 834e14b0..cc8438ff 100644 --- a/modules/videos/test/test_downloader.py +++ b/modules/videos/test/test_downloader.py @@ -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."""