2013-09-08 15:55:11 -04:00
from . common import InfoExtractor
2023-12-06 10:10:11 -05:00
from . dailymotion import DailymotionIE
2014-12-13 06:24:42 -05:00
from . . utils import (
ExtractorError ,
2023-12-06 10:10:11 -05:00
determine_ext ,
2021-10-09 17:50:17 -04:00
format_field ,
2023-12-06 10:10:11 -05:00
int_or_none ,
join_nonempty ,
2021-10-09 17:50:17 -04:00
parse_iso8601 ,
2021-08-22 15:02:00 -04:00
parse_qs ,
2013-09-08 15:55:11 -04:00
)
2013-09-10 09:50:34 -04:00
class FranceTVBaseInfoExtractor ( InfoExtractor ) :
2018-02-11 09:40:38 -05:00
def _make_url_result ( self , video_or_full_id , catalog = None ) :
full_id = ' francetv: %s ' % video_or_full_id
if ' @ ' not in video_or_full_id and catalog :
2018-02-11 09:14:05 -05:00
full_id + = ' @ %s ' % catalog
return self . url_result (
2018-02-11 09:40:38 -05:00
full_id , ie = FranceTVIE . ie_key ( ) ,
video_id = video_or_full_id . split ( ' @ ' ) [ 0 ] )
2018-02-11 09:14:05 -05:00
class FranceTVIE ( InfoExtractor ) :
_VALID_URL = r ''' (?x)
( ? :
https ? : / /
sivideo \. webservices \. francetelevisions \. fr / tools / getInfosOeuvre / v2 / \?
. * ? \bidDiffusion = [ ^ & ] + |
( ? :
https ? : / / videos \. francetv \. fr / video / |
francetv :
)
( ? P < id > [ ^ @ ] + ) ( ? : @ ( ? P < catalog > . + ) ) ?
)
'''
2022-07-31 21:23:25 -04:00
_EMBED_REGEX = [ r ' <iframe[^>]+?src=([ " \' ])(?P<url>(?:https?://)?embed \ .francetv \ .fr/ \ ?ue=.+?) \ 1 ' ]
2018-02-11 09:14:05 -05:00
_TESTS = [ {
# without catalog
' url ' : ' https://sivideo.webservices.francetelevisions.fr/tools/getInfosOeuvre/v2/?idDiffusion=162311093&callback=_jsonp_loader_callback_request_0 ' ,
' md5 ' : ' c2248a8de38c4e65ea8fae7b5df2d84f ' ,
' info_dict ' : {
' id ' : ' 162311093 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' 13h15, le dimanche... - Les mystères de Jésus ' ,
' description ' : ' md5:75efe8d4c0a8205e5904498ffe1e1a42 ' ,
' timestamp ' : 1502623500 ,
' upload_date ' : ' 20170813 ' ,
} ,
} , {
# with catalog
' url ' : ' https://sivideo.webservices.francetelevisions.fr/tools/getInfosOeuvre/v2/?idDiffusion=NI_1004933&catalogue=Zouzous&callback=_jsonp_loader_callback_request_4 ' ,
' only_matching ' : True ,
} , {
' url ' : ' http://videos.francetv.fr/video/NI_657393@Regions ' ,
' only_matching ' : True ,
} , {
' url ' : ' francetv:162311093 ' ,
' only_matching ' : True ,
} , {
' url ' : ' francetv:NI_1004933@Zouzous ' ,
' only_matching ' : True ,
} , {
' url ' : ' francetv:NI_983319@Info-web ' ,
' only_matching ' : True ,
} , {
' url ' : ' francetv:NI_983319 ' ,
' only_matching ' : True ,
} , {
' url ' : ' francetv:NI_657393@Regions ' ,
' only_matching ' : True ,
2018-02-11 09:58:04 -05:00
} , {
# france-3 live
' url ' : ' francetv:SIM_France3 ' ,
' only_matching ' : True ,
2018-02-11 09:14:05 -05:00
} ]
2017-05-09 12:07:01 -04:00
def _extract_video ( self , video_id , catalogue = None ) :
2018-02-11 09:14:05 -05:00
# Videos are identified by idDiffusion so catalogue part is optional.
# However when provided, some extra formats may be returned so we pass
# it if available.
2018-02-11 09:58:04 -05:00
is_live = None
2020-11-19 14:22:59 -05:00
videos = [ ]
2021-10-09 17:50:17 -04:00
title = None
subtitle = None
2023-12-06 10:10:11 -05:00
episode_number = None
season_number = None
2021-10-09 17:50:17 -04:00
image = None
duration = None
timestamp = None
spritesheets = None
for device_type in ( ' desktop ' , ' mobile ' ) :
dinfo = self . _download_json (
' https://player.webservices.francetelevisions.fr/v1/videos/ %s ' % video_id ,
video_id , ' Downloading %s video JSON ' % device_type , query = {
' device_type ' : device_type ,
' browser ' : ' chrome ' ,
} , fatal = False )
if not dinfo :
2020-11-19 14:22:59 -05:00
continue
2021-10-09 17:50:17 -04:00
video = dinfo . get ( ' video ' )
if video :
videos . append ( video )
if duration is None :
duration = video . get ( ' duration ' )
if is_live is None :
is_live = video . get ( ' is_live ' )
if spritesheets is None :
spritesheets = video . get ( ' spritesheets ' )
meta = dinfo . get ( ' meta ' )
if meta :
if title is None :
title = meta . get ( ' title ' )
2023-12-06 10:10:11 -05:00
# meta['pre_title'] contains season and episode number for series in format "S<ID> E<ID>"
season_number , episode_number = self . _search_regex (
r ' S( \ d+) \ s*E( \ d+) ' , meta . get ( ' pre_title ' ) , ' episode info ' , group = ( 1 , 2 ) , default = ( None , None ) )
2021-10-09 17:50:17 -04:00
if subtitle is None :
subtitle = meta . get ( ' additional_title ' )
if image is None :
image = meta . get ( ' image_url ' )
if timestamp is None :
timestamp = parse_iso8601 ( meta . get ( ' broadcasted_at ' ) )
2020-11-19 14:22:59 -05:00
formats = [ ]
2021-04-18 09:47:49 -04:00
subtitles = { }
2020-11-19 14:22:59 -05:00
for video in videos :
format_id = video . get ( ' format ' )
2021-10-09 17:50:17 -04:00
video_url = None
if video . get ( ' workflow ' ) == ' token-akamai ' :
token_url = video . get ( ' token ' )
if token_url :
token_json = self . _download_json (
token_url , video_id ,
' Downloading signed %s manifest URL ' % format_id )
if token_json :
video_url = token_json . get ( ' url ' )
if not video_url :
video_url = video . get ( ' url ' )
2015-04-04 13:02:04 -04:00
ext = determine_ext ( video_url )
if ext == ' f4m ' :
2018-02-11 08:03:31 -05:00
formats . extend ( self . _extract_f4m_formats (
2021-10-09 17:50:17 -04:00
video_url , video_id , f4m_id = format_id , fatal = False ) )
2015-04-04 13:02:04 -04:00
elif ext == ' m3u8 ' :
2021-10-09 17:50:17 -04:00
fmts , subs = self . _extract_m3u8_formats_and_subtitles (
video_url , video_id , ' mp4 ' ,
2018-02-11 08:03:31 -05:00
entry_protocol = ' m3u8_native ' , m3u8_id = format_id ,
2021-04-18 09:47:49 -04:00
fatal = False )
2021-10-09 17:50:17 -04:00
formats . extend ( fmts )
self . _merge_subtitles ( subs , target = subtitles )
2020-11-19 14:22:59 -05:00
elif ext == ' mpd ' :
2021-10-09 17:50:17 -04:00
fmts , subs = self . _extract_mpd_formats_and_subtitles (
video_url , video_id , mpd_id = format_id , fatal = False )
formats . extend ( fmts )
self . _merge_subtitles ( subs , target = subtitles )
2014-09-16 12:47:59 -04:00
elif video_url . startswith ( ' rtmp ' ) :
formats . append ( {
' url ' : video_url ,
' format_id ' : ' rtmp- %s ' % format_id ,
' ext ' : ' flv ' ,
} )
else :
2016-03-20 03:00:46 -04:00
if self . _is_valid_url ( video_url , video_id , format_id ) :
formats . append ( {
' url ' : video_url ,
' format_id ' : format_id ,
} )
2020-11-19 14:22:59 -05:00
2021-10-09 17:50:17 -04:00
# XXX: what is video['captions']?
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 ' )
if spritesheets :
formats . append ( {
' format_id ' : ' spritesheets ' ,
' format_note ' : ' storyboard ' ,
' acodec ' : ' none ' ,
' vcodec ' : ' none ' ,
' ext ' : ' mhtml ' ,
' protocol ' : ' mhtml ' ,
2021-11-18 19:06:28 -05:00
' url ' : ' about:invalid ' ,
2021-10-09 17:50:17 -04:00
' fragments ' : [ {
2022-03-13 18:03:40 -04:00
' url ' : sheet ,
2021-10-09 17:50:17 -04:00
# XXX: not entirely accurate; each spritesheet seems to be
# a 10× 10 grid of thumbnails corresponding to approximately
# 2 seconds of the video; the last spritesheet may be shorter
' duration ' : 200 ,
} for sheet in spritesheets ]
} )
2014-07-28 08:37:13 -04:00
return {
' id ' : video_id ,
2023-12-06 10:10:11 -05:00
' title ' : join_nonempty ( title , subtitle , delim = ' - ' ) . strip ( ) ,
2021-10-09 17:50:17 -04:00
' thumbnail ' : image ,
' duration ' : duration ,
' timestamp ' : timestamp ,
2018-02-11 09:58:04 -05:00
' is_live ' : is_live ,
2014-07-28 08:37:13 -04:00
' formats ' : formats ,
2015-10-26 10:11:09 -04:00
' subtitles ' : subtitles ,
2023-12-06 10:10:11 -05:00
' episode ' : subtitle if episode_number else None ,
' series ' : title if episode_number else None ,
' episode_number ' : int_or_none ( episode_number ) ,
' season_number ' : int_or_none ( season_number ) ,
2014-07-28 08:37:13 -04:00
}
2013-09-10 09:50:34 -04:00
2018-02-11 09:14:05 -05:00
def _real_extract ( self , url ) :
2021-08-18 21:41:24 -04:00
mobj = self . _match_valid_url ( url )
2018-02-11 09:14:05 -05:00
video_id = mobj . group ( ' id ' )
catalog = mobj . group ( ' catalog ' )
if not video_id :
2021-08-22 15:02:00 -04:00
qs = parse_qs ( url )
2018-02-11 09:14:05 -05:00
video_id = qs . get ( ' idDiffusion ' , [ None ] ) [ 0 ]
catalog = qs . get ( ' catalogue ' , [ None ] ) [ 0 ]
if not video_id :
raise ExtractorError ( ' Invalid URL ' , expected = True )
return self . _extract_video ( video_id , catalog )
2013-09-10 09:50:34 -04:00
2018-02-11 09:14:05 -05:00
class FranceTVSiteIE ( FranceTVBaseInfoExtractor ) :
2017-05-31 13:15:15 -04:00
_VALID_URL = r ' https?://(?:(?:www \ .)?france \ .tv|mobile \ .france \ .tv)/(?:[^/]+/)*(?P<id>[^/]+) \ .html '
2013-09-08 15:55:11 -04:00
2017-05-09 12:07:01 -04:00
_TESTS = [ {
' url ' : ' https://www.france.tv/france-2/13h15-le-dimanche/140921-les-mysteres-de-jesus.html ' ,
' info_dict ' : {
2019-03-08 11:26:59 -05:00
' id ' : ' ec217ecc-0733-48cf-ac06-af1347b849d1 ' ,
2017-05-09 12:07:01 -04:00
' ext ' : ' mp4 ' ,
' title ' : ' 13h15, le dimanche... - Les mystères de Jésus ' ,
2018-02-11 09:14:05 -05:00
' timestamp ' : 1502623500 ,
2023-12-06 10:10:11 -05:00
' duration ' : 2580 ,
' thumbnail ' : r ' re:^https?://.* \ .jpg$ ' ,
2018-02-11 09:14:05 -05:00
' upload_date ' : ' 20170813 ' ,
2017-05-09 12:07:01 -04:00
} ,
' params ' : {
' skip_download ' : True ,
} ,
2018-02-11 09:14:05 -05:00
' add_ie ' : [ FranceTVIE . ie_key ( ) ] ,
2023-12-06 10:10:11 -05:00
} , {
' url ' : ' https://www.france.tv/enfants/six-huit-ans/foot2rue/saison-1/3066387-duel-au-vieux-port.html ' ,
' info_dict ' : {
' id ' : ' a9050959-eedd-4b4a-9b0d-de6eeaa73e44 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Foot2Rue - Duel au vieux port ' ,
' episode ' : ' Duel au vieux port ' ,
' series ' : ' Foot2Rue ' ,
' episode_number ' : 1 ,
' season_number ' : 1 ,
' timestamp ' : 1642761360 ,
' upload_date ' : ' 20220121 ' ,
' season ' : ' Season 1 ' ,
' thumbnail ' : r ' re:^https?://.* \ .jpg$ ' ,
' duration ' : 1441 ,
} ,
2017-05-09 12:07:01 -04:00
} , {
# france3
' url ' : ' https://www.france.tv/france-3/des-chiffres-et-des-lettres/139063-emission-du-mardi-9-mai-2017.html ' ,
' only_matching ' : True ,
} , {
# france4
' url ' : ' https://www.france.tv/france-4/hero-corp/saison-1/134151-apres-le-calme.html ' ,
' only_matching ' : True ,
} , {
# france5
' url ' : ' https://www.france.tv/france-5/c-a-dire/saison-10/137013-c-a-dire.html ' ,
' only_matching ' : True ,
} , {
# 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 ,
} , {
' url ' : ' https://www.france.tv/jeux-et-divertissements/divertissements/133965-le-web-contre-attaque.html ' ,
' only_matching ' : True ,
2017-05-13 10:57:00 -04:00
} , {
' url ' : ' https://mobile.france.tv/france-5/c-dans-l-air/137347-emission-du-vendredi-12-mai-2017.html ' ,
' only_matching ' : True ,
2017-05-31 13:15:15 -04:00
} , {
' url ' : ' https://www.france.tv/142749-rouge-sang.html ' ,
' only_matching ' : True ,
2018-02-11 12:25:42 -05:00
} , {
# france-3 live
' url ' : ' https://www.france.tv/france-3/direct.html ' ,
' only_matching ' : True ,
2017-05-09 12:07:01 -04:00
} ]
2013-09-08 15:55:11 -04:00
def _real_extract ( self , url ) :
2015-10-27 11:43:29 -04:00
display_id = self . _match_id ( url )
webpage = self . _download_webpage ( url , display_id )
2017-05-09 12:07:01 -04:00
catalogue = None
video_id = self . _search_regex (
2019-03-08 11:26:59 -05:00
r ' (?:data-main-video \ s*=|videoId[ " \' ]? \ s*[:=]) \ s*([ " \' ])(?P<id>(?:(?! \ 1).)+) \ 1 ' ,
2017-05-09 12:07:01 -04:00
webpage , ' video id ' , default = None , group = ' id ' )
2015-10-27 11:43:29 -04:00
if not video_id :
2017-05-09 12:07:01 -04:00
video_id , catalogue = self . _html_search_regex (
r ' (?:href=|player \ .setVideo \ ( \ s*) " http://videos? \ .francetv \ .fr/video/([^@]+@[^ " ]+) " ' ,
webpage , ' video ID ' ) . split ( ' @ ' )
2018-02-11 09:14:05 -05:00
return self . _make_url_result ( video_id , catalogue )
2017-05-09 12:07:01 -04:00
class FranceTVInfoIE ( FranceTVBaseInfoExtractor ) :
2014-01-30 00:13:57 -05:00
IE_NAME = ' francetvinfo.fr '
2018-02-11 09:14:05 -05:00
_VALID_URL = r ' https?://(?:www|mobile|france3-regions) \ .francetvinfo \ .fr/(?:[^/]+/)*(?P<id>[^/?#&.]+) '
2013-09-08 15:55:11 -04:00
2014-05-16 09:51:01 -04:00
_TESTS = [ {
2020-08-14 07:11:20 -04:00
' url ' : ' https://www.francetvinfo.fr/replay-jt/france-3/soir-3/jt-grand-soir-3-jeudi-22-aout-2019_3561461.html ' ,
2014-01-30 00:13:57 -05:00
' info_dict ' : {
2020-08-14 07:11:20 -04:00
' id ' : ' d12458ee-5062-48fe-bfdd-a30d6a01b793 ' ,
2016-03-20 03:00:46 -04:00
' ext ' : ' mp4 ' ,
2014-01-30 00:13:57 -05:00
' title ' : ' Soir 3 ' ,
2020-08-14 07:11:20 -04:00
' upload_date ' : ' 20190822 ' ,
' timestamp ' : 1566510900 ,
' description ' : ' md5:72d167097237701d6e8452ff03b83c00 ' ,
2015-10-26 10:35:45 -04:00
' subtitles ' : {
' fr ' : ' mincount:2 ' ,
} ,
2013-09-10 09:50:34 -04:00
} ,
2016-03-20 03:00:46 -04:00
' params ' : {
' skip_download ' : True ,
} ,
2018-02-11 09:14:05 -05:00
' add_ie ' : [ FranceTVIE . ie_key ( ) ] ,
2021-04-22 14:31:09 -04:00
} , {
' note ' : ' Only an image exists in initial webpage instead of the video ' ,
' url ' : ' https://www.francetvinfo.fr/sante/maladie/coronavirus/covid-19-en-inde-une-situation-catastrophique-a-new-dehli_4381095.html ' ,
' info_dict ' : {
' id ' : ' 7d204c9e-a2d3-11eb-9e4c-000d3a23d482 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Covid-19 : une situation catastrophique à New Dehli ' ,
' thumbnail ' : str ,
' duration ' : 76 ,
' timestamp ' : 1619028518 ,
' upload_date ' : ' 20210421 ' ,
} ,
' params ' : {
' skip_download ' : True ,
} ,
' add_ie ' : [ FranceTVIE . ie_key ( ) ] ,
2014-05-16 09:51:01 -04:00
} , {
' url ' : ' http://www.francetvinfo.fr/elections/europeennes/direct-europeennes-regardez-le-debat-entre-les-candidats-a-la-presidence-de-la-commission_600639.html ' ,
2018-02-11 09:14:05 -05:00
' only_matching ' : True ,
2015-06-21 09:31:33 -04:00
} , {
' url ' : ' http://www.francetvinfo.fr/economie/entreprises/les-entreprises-familiales-le-secret-de-la-reussite_933271.html ' ,
2018-02-11 09:14:05 -05:00
' only_matching ' : True ,
2016-03-20 02:44:04 -04:00
} , {
' url ' : ' http://france3-regions.francetvinfo.fr/bretagne/cotes-d-armor/thalassa-echappee-breizh-ce-venredi-dans-les-cotes-d-armor-954961.html ' ,
2018-02-11 09:14:05 -05:00
' only_matching ' : True ,
2016-07-06 11:37:54 -04:00
} , {
# Dailymotion embed
' url ' : ' http://www.francetvinfo.fr/politique/notre-dame-des-landes/video-sur-france-inter-cecile-duflot-denonce-le-regard-meprisant-de-patrick-cohen_1520091.html ' ,
' md5 ' : ' ee7f1828f25a648addc90cb2687b1f12 ' ,
' info_dict ' : {
' id ' : ' x4iiko0 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' NDDL, référendum, Brexit : Cécile Duflot répond à Patrick Cohen ' ,
' description ' : ' Au lendemain de la victoire du " oui " au référendum sur l \' aéroport de Notre-Dame-des-Landes, l \' ancienne ministre écologiste est l \' invitée de Patrick Cohen. Plus d \' info : https://www.franceinter.fr/emissions/le-7-9/le-7-9-27-juin-2016 ' ,
' timestamp ' : 1467011958 ,
' upload_date ' : ' 20160627 ' ,
' uploader ' : ' France Inter ' ,
' uploader_id ' : ' x2q2ez ' ,
} ,
' add_ie ' : [ ' Dailymotion ' ] ,
2016-08-11 10:42:55 -04:00
} , {
' url ' : ' http://france3-regions.francetvinfo.fr/limousin/emissions/jt-1213-limousin ' ,
' only_matching ' : True ,
2021-05-06 12:01:20 -04:00
} , {
# "<figure id=" pattern (#28792)
' url ' : ' https://www.francetvinfo.fr/culture/patrimoine/incendie-de-notre-dame-de-paris/notre-dame-de-paris-de-l-incendie-de-la-cathedrale-a-sa-reconstruction_4372291.html ' ,
' only_matching ' : True ,
2014-05-16 09:51:01 -04:00
} ]
2013-09-10 09:50:34 -04:00
def _real_extract ( self , url ) :
2018-02-11 09:14:05 -05:00
display_id = self . _match_id ( url )
webpage = self . _download_webpage ( url , display_id )
2015-06-21 09:31:33 -04:00
2022-08-06 17:59:19 -04:00
dailymotion_urls = tuple ( DailymotionIE . _extract_embed_urls ( url , webpage ) )
2016-07-06 11:37:54 -04:00
if dailymotion_urls :
return self . playlist_result ( [
self . url_result ( dailymotion_url , DailymotionIE . ie_key ( ) )
for dailymotion_url in dailymotion_urls ] )
2015-06-21 09:31:33 -04:00
2019-05-04 19:26:30 -04:00
video_id = self . _search_regex (
( r ' player \ .load[^;]+src: \ s*[ " \' ]([^ " \' ]+) ' ,
r ' id-video=([^@]+@[^ " ]+) ' ,
2020-08-14 07:11:20 -04:00
r ' <a[^>]+href= " (?:https?:)?//videos \ .francetv \ .fr/video/([^@]+@[^ " ]+) " ' ,
2021-05-06 12:01:20 -04:00
r ' (?:data-id|<figure[^<]+ \ bid)=[ " \' ]([ \ da-f] {8} -[ \ da-f] {4} -[ \ da-f] {4} -[ \ da-f] {4} -[ \ da-f] {12} ) ' ) ,
2019-05-04 19:26:30 -04:00
webpage , ' video id ' )
2018-02-11 09:14:05 -05:00
2019-05-04 19:26:30 -04:00
return self . _make_url_result ( video_id )