diff --git a/yt_dlp/extractor/nest.py b/yt_dlp/extractor/nest.py index 5ef3c210f0..dd4d1cf5a7 100644 --- a/yt_dlp/extractor/nest.py +++ b/yt_dlp/extractor/nest.py @@ -1,12 +1,11 @@ -import datetime as dt - from .common import InfoExtractor from ..utils import ExtractorError +from ..utils.traversal import traverse_obj class NestIE(InfoExtractor): - _VALID_URL = r'^https?://video\.nest\.com/embedded/live/(?P[A-Za-z0-9]+)' - _EMBED_REGEX = [r']+?src=(["\'])(?P(?:https?:)?//video\.nest\.com/embedded/live/.+)\1'] + _VALID_URL = r'https?://video\.nest\.com/(?:embedded/)?live/(?P\w+)' + _EMBED_REGEX = [rf']+\bsrc=[\'"](?P{_VALID_URL})'] _TESTS = [{ 'url': 'https://video.nest.com/embedded/live/4fvYdSo8AX?autoplay=0', 'info_dict': { @@ -24,6 +23,9 @@ class NestIE(InfoExtractor): # m3u8 download 'skip_download': True, }, + }, { + 'url': 'https://video.nest.com/live/4fvYdSo8AX', + 'only_matching': True, }] _WEBPAGE_TESTS = [{ 'url': 'https://www.pacificblue.biz/noyo-harbor-webcam/', @@ -46,34 +48,25 @@ class NestIE(InfoExtractor): def _real_extract(self, url): video_id = self._match_id(url) - now = dt.datetime.now().strftime('%s') - api = f'https://video.nest.com/api/dropcam/cameras.get_by_public_token?token={video_id}&_={now}' - data = self._download_json(api, video_id) - items = data.get('items') - item = items[0] if items else {} - titles = [item.get('title'), item.get('name'), item.get('where')] - titles = [title for title in titles if title] - title = titles.pop(0) if titles else None - alt_title = titles.pop(0) if titles else None - timezone = item.get('timezone', '') - timezone = timezone.split('/') - timezone = timezone[1] if len(timezone) > 1 else None - timezone = timezone.replace('_', ' ') - location = timezone or item.get('where') + data = self._download_json( + f'https://video.nest.com/api/dropcam/cameras.get_by_public_token?token={video_id}', video_id) + item = traverse_obj(data, ('items', 0, {dict})) uuid = item.get('uuid') domain = item.get('live_stream_host') if not domain or not uuid: raise ExtractorError('Unable to construct playlist URL') m3u8 = f'https://{domain}/nexus_aac/{uuid}/playlist.m3u8?public={video_id}' - domain = item.get('nexus_api_nest_domain_host') - thumb = f'https://{domain}/get_image?uuid={uuid}&width=540&public={video_id}' if domain else None + + thumb_domain = item.get('nexus_api_nest_domain_host') return { 'id': video_id, - 'title': title, - 'alt_title': alt_title, - 'description': item.get('description'), - 'location': location, - 'thumbnail': thumb, + **traverse_obj(item, { + 'description': ('description', {str}), + 'title': (('title', 'name', 'where'), {str}, filter, any), + 'alt_title': ('name', {str}), + 'location': ((('timezone', {lambda x: x.split('/')[1].replace('_', ' ')}), 'where'), {str}, filter, any), + }), + 'thumbnail': f'https://{thumb_domain}/get_image?uuid={uuid}&public={video_id}' if thumb_domain else None, 'availability': 'public' if item.get('is_public') else None, 'formats': self._extract_m3u8_formats(m3u8, video_id, 'mp4', live=True), 'is_live': True,