]> jfr.im git - yt-dlp.git/blobdiff - yt_dlp/extractor/francetv.py
[ie/youtube] Suppress "Unavailable videos are hidden" warning (#10159)
[yt-dlp.git] / yt_dlp / extractor / francetv.py
index 47dcfd55cb4d280ad81b760c7761706437df7622..ab08f1c6bf14c8385d566114797321cc6e9e340c 100644 (file)
@@ -5,6 +5,7 @@
 from .dailymotion import DailymotionIE
 from ..networking import HEADRequest
 from ..utils import (
+    clean_html,
     determine_ext,
     filter_dict,
     format_field,
@@ -33,6 +34,7 @@ class FranceTVIE(InfoExtractor):
     _GEO_BYPASS = False
 
     _TESTS = [{
+        # tokenized url is in dinfo['video']['token']
         'url': 'francetv:ec217ecc-0733-48cf-ac06-af1347b849d1',
         'info_dict': {
             'id': 'ec217ecc-0733-48cf-ac06-af1347b849d1',
@@ -44,6 +46,19 @@ class FranceTVIE(InfoExtractor):
             'upload_date': '20170813',
         },
         'params': {'skip_download': 'm3u8'},
+    }, {
+        # tokenized url is in dinfo['video']['token']['akamai']
+        'url': 'francetv:c5bda21d-2c6f-4470-8849-3d8327adb2ba',
+        'info_dict': {
+            'id': 'c5bda21d-2c6f-4470-8849-3d8327adb2ba',
+            'ext': 'mp4',
+            'title': '13h15, le dimanche... - Les mystères de Jésus',
+            'timestamp': 1514118300,
+            'duration': 2880,
+            'thumbnail': r're:^https?://.*\.jpg$',
+            'upload_date': '20171224',
+        },
+        'params': {'skip_download': 'm3u8'},
     }, {
         'url': 'francetv:162311093',
         'only_matching': True,
@@ -68,6 +83,7 @@ class FranceTVIE(InfoExtractor):
     def _extract_video(self, video_id, hostname=None):
         is_live = None
         videos = []
+        drm_formats = False
         title = None
         subtitle = None
         episode_number = None
@@ -85,13 +101,12 @@ def _extract_video(self, video_id, hostname=None):
                     'device_type': device_type,
                     'browser': browser,
                     'domain': hostname,
-                }), fatal=False)
+                }), fatal=False, expected_status=422)  # 422 json gives detailed error code/message
 
             if not dinfo:
                 continue
 
-            video = traverse_obj(dinfo, ('video', {dict}))
-            if video:
+            if video := traverse_obj(dinfo, ('video', {dict})):
                 videos.append(video)
                 if duration is None:
                     duration = video.get('duration')
@@ -99,9 +114,19 @@ def _extract_video(self, video_id, hostname=None):
                     is_live = video.get('is_live')
                 if spritesheets is None:
                     spritesheets = video.get('spritesheets')
+            elif code := traverse_obj(dinfo, ('code', {int})):
+                if code == 2009:
+                    self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
+                elif code in (2015, 2017):
+                    # 2015: L'accès à cette vidéo est impossible. (DRM-only)
+                    # 2017: Cette vidéo n'est pas disponible depuis le site web mobile (b/c DRM)
+                    drm_formats = True
+                    continue
+                self.report_warning(
+                    f'{self.IE_NAME} said: {code} "{clean_html(dinfo.get("message"))}"')
+                continue
 
-            meta = traverse_obj(dinfo, ('meta', {dict}))
-            if meta:
+            if meta := traverse_obj(dinfo, ('meta', {dict})):
                 if title is None:
                     title = meta.get('title')
                 # meta['pre_title'] contains season and episode number for series in format "S<ID> E<ID>"
@@ -114,13 +139,15 @@ def _extract_video(self, video_id, hostname=None):
                 if timestamp is None:
                     timestamp = parse_iso8601(meta.get('broadcasted_at'))
 
+        if not videos and drm_formats:
+            self.report_drm(video_id)
+
         formats, subtitles, video_url = [], {}, None
         for video in traverse_obj(videos, lambda _, v: url_or_none(v['url'])):
             video_url = video['url']
             format_id = video.get('format')
 
-            token_url = url_or_none(video.get('token'))
-            if token_url and video.get('workflow') == 'token-akamai':
+            if token_url := traverse_obj(video, ('token', (None, 'akamai'), {url_or_none}, any)):
                 tokenized_url = traverse_obj(self._download_json(
                     token_url, video_id, f'Downloading signed {format_id} manifest URL',
                     fatal=False, query={
@@ -176,7 +203,7 @@ def _extract_video(self, video_id, hostname=None):
         for f in formats:
             if f.get('acodec') != 'none' and f.get('language') in ('qtz', 'qad'):
                 f['language_preference'] = -10
-                f['format_note'] = 'audio description%s' % format_field(f, 'format_note', ', %s')
+                f['format_note'] = 'audio description{}'.format(format_field(f, 'format_note', ', %s'))
 
         if spritesheets:
             formats.append({
@@ -190,10 +217,10 @@ def _extract_video(self, video_id, hostname=None):
                 'fragments': [{
                     'url': sheet,
                     # XXX: not entirely accurate; each spritesheet seems to be
-                    # a 10×10 grid of thumbnails corresponding to approximately
+                    # a 10x10 grid of thumbnails corresponding to approximately
                     # 2 seconds of the video; the last spritesheet may be shorter
                     'duration': 200,
-                } for sheet in traverse_obj(spritesheets, (..., {url_or_none}))]
+                } for sheet in traverse_obj(spritesheets, (..., {url_or_none}))],
             })
 
         return {
@@ -226,13 +253,13 @@ class FranceTVSiteIE(FranceTVBaseInfoExtractor):
     _TESTS = [{
         'url': 'https://www.france.tv/france-2/13h15-le-dimanche/140921-les-mysteres-de-jesus.html',
         'info_dict': {
-            'id': 'ec217ecc-0733-48cf-ac06-af1347b849d1',
+            'id': 'c5bda21d-2c6f-4470-8849-3d8327adb2ba',
             'ext': 'mp4',
             'title': '13h15, le dimanche... - Les mystères de Jésus',
-            'timestamp': 1502623500,
-            'duration': 2580,
+            'timestamp': 1514118300,
+            'duration': 2880,
             'thumbnail': r're:^https?://.*\.jpg$',
-            'upload_date': '20170813',
+            'upload_date': '20171224',
         },
         'params': {
             'skip_download': True,
@@ -255,6 +282,26 @@ class FranceTVSiteIE(FranceTVBaseInfoExtractor):
             'thumbnail': r're:^https?://.*\.jpg$',
             'duration': 1441,
         },
+    }, {
+        # geo-restricted livestream (workflow == 'token-akamai')
+        'url': 'https://www.france.tv/france-4/direct.html',
+        'info_dict': {
+            'id': '9a6a7670-dde9-4264-adbc-55b89558594b',
+            'ext': 'mp4',
+            'title': r're:France 4 en direct .+',
+            'live_status': 'is_live',
+        },
+        'skip': 'geo-restricted livestream',
+    }, {
+        # livestream (workflow == 'dai')
+        'url': 'https://www.france.tv/france-2/direct.html',
+        'info_dict': {
+            'id': '006194ea-117d-4bcf-94a9-153d999c59ae',
+            'ext': 'mp4',
+            'title': r're:France 2 en direct .+',
+            'live_status': 'is_live',
+        },
+        'params': {'skip_download': 'livestream'},
     }, {
         # france3
         'url': 'https://www.france.tv/france-3/des-chiffres-et-des-lettres/139063-emission-du-mardi-9-mai-2017.html',
@@ -271,10 +318,6 @@ class FranceTVSiteIE(FranceTVBaseInfoExtractor):
         # franceo
         'url': 'https://www.france.tv/france-o/archipels/132249-mon-ancetre-l-esclave.html',
         'only_matching': True,
-    }, {
-        # france2 live
-        'url': 'https://www.france.tv/france-2/direct.html',
-        'only_matching': True,
     }, {
         'url': 'https://www.france.tv/documentaires/histoire/136517-argentine-les-500-bebes-voles-de-la-dictature.html',
         'only_matching': True,