From a70198e54e904af9f69b47277a73ba847dbbbdc1 Mon Sep 17 00:00:00 2001 From: JChris246 Date: Sat, 15 Mar 2025 03:37:59 -0400 Subject: [PATCH 1/2] support xhamster channels and fix creators --- yt_dlp/extractor/xhamster.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/yt_dlp/extractor/xhamster.py b/yt_dlp/extractor/xhamster.py index 3cbe27f61..ec794fdf7 100644 --- a/yt_dlp/extractor/xhamster.py +++ b/yt_dlp/extractor/xhamster.py @@ -423,7 +423,7 @@ def _real_extract(self, url): class XHamsterUserIE(InfoExtractor): - _VALID_URL = rf'https?://(?:[^/?#]+\.)?{XHamsterIE._DOMAINS}/(?:(?Pusers)|creators)/(?P[^/?#&]+)' + _VALID_URL = rf'https?://(?:[^/?#]+\.)?{XHamsterIE._DOMAINS}/(?Pusers|creators|channels)/(?P[^/?#&]+)' _TESTS = [{ # Paginated user profile 'url': 'https://xhamster.com/users/netvideogirls/videos', @@ -437,13 +437,19 @@ class XHamsterUserIE(InfoExtractor): 'info_dict': { 'id': 'firatkaan', }, - 'playlist_mincount': 1, + 'playlist_mincount': 0, }, { 'url': 'https://xhamster.com/creators/squirt-orgasm-69', 'info_dict': { 'id': 'squirt-orgasm-69', }, 'playlist_mincount': 150, + }, { + 'url': 'https://xhamster.com/channels/patreon/', + 'info_dict': { + 'id': 'patreon', + }, + 'playlist_mincount': 500, }, { 'url': 'https://xhday.com/users/mobhunter', 'only_matching': True, @@ -452,9 +458,14 @@ class XHamsterUserIE(InfoExtractor): 'only_matching': True, }] - def _entries(self, user_id, is_user): - prefix, suffix = ('users', 'videos') if is_user else ('creators', 'exclusive') - next_page_url = f'https://xhamster.com/{prefix}/{user_id}/{suffix}/1' + def _entries(self, user_id, collection_type): + collection_prefixes = { + 'users': ('users', 'videos/'), + 'creators': ('creators', 'exclusive/'), + 'channels': ('channels', ''), + } + prefix, suffix = collection_prefixes[collection_type] + next_page_url = f'https://xhamster.com/{prefix}/{user_id}/{suffix}1' for pagenum in itertools.count(1): page = self._download_webpage( next_page_url, user_id, f'Downloading page {pagenum}') @@ -468,7 +479,7 @@ def _entries(self, user_id, is_user): video_id = XHamsterIE._match_id(video_url) yield self.url_result( video_url, ie=XHamsterIE.ie_key(), video_id=video_id) - mobj = re.search(r']+data-page=["\']next[^>]+>', page) + mobj = re.search(r']+(?:data-page=["\']next|rel=["\']next)[^>]+>', page) if not mobj: break next_page = extract_attributes(mobj.group(0)) @@ -477,5 +488,5 @@ def _entries(self, user_id, is_user): break def _real_extract(self, url): - user, user_id = self._match_valid_url(url).group('user', 'id') - return self.playlist_result(self._entries(user_id, bool(user)), user_id) + collection_type, user_id = self._match_valid_url(url).group('collection', 'id') + return self.playlist_result(self._entries(user_id, collection_type), user_id) From a25016a580adb97554fbf3de14f3098f5ab0e515 Mon Sep 17 00:00:00 2001 From: JChris246 Date: Sat, 15 Mar 2025 03:47:54 -0400 Subject: [PATCH 2/2] feat: support user favorites --- yt_dlp/extractor/xhamster.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/yt_dlp/extractor/xhamster.py b/yt_dlp/extractor/xhamster.py index ec794fdf7..f7267ee52 100644 --- a/yt_dlp/extractor/xhamster.py +++ b/yt_dlp/extractor/xhamster.py @@ -423,7 +423,7 @@ def _real_extract(self, url): class XHamsterUserIE(InfoExtractor): - _VALID_URL = rf'https?://(?:[^/?#]+\.)?{XHamsterIE._DOMAINS}/(?Pusers|creators|channels)/(?P[^/?#&]+)' + _VALID_URL = rf'https?://(?:[^/?#]+\.)?{XHamsterIE._DOMAINS}/(?Pusers|creators|channels)/(?P[^/?#&]+)(?P/favorites/videos)?' _TESTS = [{ # Paginated user profile 'url': 'https://xhamster.com/users/netvideogirls/videos', @@ -450,6 +450,12 @@ class XHamsterUserIE(InfoExtractor): 'id': 'patreon', }, 'playlist_mincount': 500, + }, { + 'url': 'https://xhamster.com/users/cubafidel/favorites/videos', + 'info_dict': { + 'id': 'cubafidel', + }, + 'playlist_mincount': 220, }, { 'url': 'https://xhday.com/users/mobhunter', 'only_matching': True, @@ -463,6 +469,7 @@ def _entries(self, user_id, collection_type): 'users': ('users', 'videos/'), 'creators': ('creators', 'exclusive/'), 'channels': ('channels', ''), + 'favorites': ('users', 'favorites/videos/'), } prefix, suffix = collection_prefixes[collection_type] next_page_url = f'https://xhamster.com/{prefix}/{user_id}/{suffix}1' @@ -488,5 +495,6 @@ def _entries(self, user_id, collection_type): break def _real_extract(self, url): - collection_type, user_id = self._match_valid_url(url).group('collection', 'id') + collection_type, user_id, favorites = self._match_valid_url(url).group('collection', 'id', 'favorites') + collection_type = 'favorites' if bool(favorites) else collection_type return self.playlist_result(self._entries(user_id, collection_type), user_id)