mirror of
https://github.com/alexta69/metube.git
synced 2026-09-21 21:45:04 +00:00
fix: detect channels addressed without a tab (closes #1024)
__is_channel_extraction keyed on id == channel_id. That holds for a channel
tab - /channel/UC..., and the videos, streams, shorts and playlists tabs of a
/@handle URL - but not for a channel addressed on its own: yt-dlp reports the
id in the form the channel was asked for, so a bare handle URL yields '@handle'
and a legacy /c/ URL yields the vanity name.
Neither matched, so both fell through to OUTPUT_TEMPLATE_PLAYLIST and the
folder came out as the feed's title. That is why e2c7778 fixed the reporter's
tab URLs while a bare channel URL - what you get copying the address bar - went
on ignoring OUTPUT_TEMPLATE.
Both forms match uploader_id, which is the handle either way, so compare
against that as well, without case: a legacy vanity name and the handle it
became need not agree on it. A real playlist carries its owner's channel_id and
uploader_id but keeps an id of its own, so it still reads as a playlist; no
playlist id can collide with a handle, since those are 'PL...', 'OLAK...' and
the like.
Verified against the live extractor for all six channel URL forms and a real
playlist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+24
-4
@@ -1063,13 +1063,33 @@ class DownloadQueue:
|
||||
|
||||
@staticmethod
|
||||
def __is_channel_extraction(entry):
|
||||
"""Return True when yt-dlp reported a channel tab as a playlist.
|
||||
"""Return True when yt-dlp reported a channel as a playlist.
|
||||
|
||||
YouTube channel tabs are extracted with ``_type: 'playlist'`` but set
|
||||
``id`` equal to ``channel_id``; real playlists keep a distinct id.
|
||||
A channel *tab* -- ``/channel/UC...``, ``/@handle/videos``, and the
|
||||
streams, shorts and playlists tabs -- is extracted with ``id`` equal to
|
||||
``channel_id``. A channel addressed without a tab keeps the form it was
|
||||
asked for instead: ``@handle`` for a handle URL and the vanity name for
|
||||
a legacy ``/c/`` URL. Both of those match ``uploader_id``, which is the
|
||||
handle either way, so compare against it as well.
|
||||
|
||||
A real playlist has an id of its own and matches neither, even though
|
||||
it also carries its owner's ``channel_id``.
|
||||
"""
|
||||
channel_id = entry.get('channel_id')
|
||||
return bool(channel_id) and entry.get('id') == channel_id
|
||||
entry_id = entry.get('id')
|
||||
if not channel_id or not entry_id:
|
||||
return False
|
||||
if entry_id == channel_id:
|
||||
return True
|
||||
uploader_id = entry.get('uploader_id')
|
||||
if not uploader_id:
|
||||
return False
|
||||
# Compared without case because a legacy vanity name and the handle it
|
||||
# became need not agree on it. No playlist id can collide here: those
|
||||
# are 'PL...', 'OLAK...' and the like, never a handle.
|
||||
handle = uploader_id.casefold()
|
||||
entry_id = entry_id.casefold()
|
||||
return handle in (entry_id, f'@{entry_id}')
|
||||
|
||||
async def __import_queue(self):
|
||||
for k, v in self.queue.saved_items():
|
||||
|
||||
Reference in New Issue
Block a user