@ -1,23 +1,22 @@
# coding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..compat import (
compat_urlparse ,
compat_urllib_parse ,
)
from ..utils import ExtractorError
def _extract_json ( code ) :
return re . sub (
r ' (?s)^VideoPlayer.data \ ( " " , ({.*}) \ );? \ s*?(?://[^ \ n]*)*$ ' , r ' \ 1 ' , code )
from ..utils import (
ExtractorError ,
int_or_none ,
parse_iso8601 ,
qualities ,
)
class PlaytvakIE ( InfoExtractor ) :
_VALID_URL = r ' https?://.*?(playtvak|idnes|lidovky|metro) \ .cz/.* \ ?c=(?P<id>[A-Z][0-9]{6}_[0-9]{6}_.*) '
IE_DESC = ' Playtvak.cz, iDNES.cz and Lidovky.cz '
_VALID_URL = r ' https?://(?:.+? \ .)?(?:playtvak|idnes|lidovky|metro) \ .cz/.* \ ?(?:c|idvideo)=(?P<id>[^&]+) '
_TESTS = [ {
' url ' : ' http://www.playtvak.cz/vyzente-vosy-a-srsne-ze-zahrady-dn5-/hodinovy-manzel.aspx?c=A150730_150323_hodinovy-manzel_kuko ' ,
' md5 ' : ' 4525ae312c324b4be2f4603cc78ceb4a ' ,
@ -25,8 +24,12 @@ class PlaytvakIE(InfoExtractor):
' id ' : ' A150730_150323_hodinovy-manzel_kuko ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Vyžeňte vosy a sršně ze zahrady ' ,
' thumbnail ' : ' http://oidnes.cz/15/074/mobil/KUK5cea00_010hodmanel58154.jpg ' ,
' description ' : ' Málo co kazí atmosféru venkovního posezení tak jako neustálé bzučení kolem hlavy. Vyzkoušejte náš lapač a odpuzovač vos a sršňů. ' ,
' description ' : ' md5:f93d398691044d303bc4a3de62f3e976 ' ,
' thumbnail ' : ' re:(?i)^https?://.* \ .(?:jpg|png)$ ' ,
' duration ' : 279 ,
' timestamp ' : 1438732860 ,
' upload_date ' : ' 20150805 ' ,
' is_live ' : False ,
}
} , { # live video test
' url ' : ' http://slowtv.playtvak.cz/planespotting-0pr-/planespotting.aspx?c=A150624_164934_planespotting_cat ' ,
@ -34,8 +37,8 @@ class PlaytvakIE(InfoExtractor):
' id ' : ' A150624_164934_planespotting_cat ' ,
' ext ' : ' flv ' ,
' title ' : ' re:^Přímý přenos iDNES.cz [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$ ' ,
' thumbnail ' : ' http://data.idnes.cz/soubory/servisni-play-porady/89A150630_ACEK_026_VIDEOPLAYER-STREA.PNG ' ,
' description ' : ' Sledujte provoz na ranveji Letiště Václava Havla v Praze ' ,
' thumbnail ' : ' re:(?i)^https?://.* \ .(?:jpg|png)$ ' ,
' is_live ' : True ,
} ,
' params ' : {
@ -48,8 +51,12 @@ class PlaytvakIE(InfoExtractor):
' id ' : ' A150809_104116_domaci_pku ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Zavřeli jsme mraženou pizzu do auta. Upekla se ' ,
' thumbnail ' : ' http://i.idnes.cz/15/081/vidw/SHA5d1786_pizzaauto.jpg ' ,
' description ' : ' Na sociálních sítích se objevila výzva, aby lidé, kteří v horkých letních dnech uvidí v zaparkovaném autě zavřeného psa, neváhali rozbít okénko. Zastánci tohoto postoje argumentují zdravím zvířete, které v dusnu může zkolabovat. Policie doporučuje nejprve volat tísňovou linku. ' ,
' description ' : ' md5:01e73f02329e2e5760bd5eed4d42e3c2 ' ,
' thumbnail ' : ' re:(?i)^https?://.* \ .(?:jpg|png)$ ' ,
' duration ' : 39 ,
' timestamp ' : 1438969140 ,
' upload_date ' : ' 20150807 ' ,
' is_live ' : False ,
}
} , { # lidovky.cz
' url ' : ' http://www.lidovky.cz/dalsi-demonstrace-v-praze-o-migraci-duq-/video.aspx?c=A150808_214044_ln-video_ELE ' ,
@ -58,70 +65,102 @@ class PlaytvakIE(InfoExtractor):
' id ' : ' A150808_214044_ln-video_ELE ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Táhni! Demonstrace proti imigrantům budila emoce ' ,
' thumbnail ' : ' http://i.idnes.cz/15/081/vidw/PID5d1d52_vandas3.jpg ' ,
' description ' : ' Desítky lidí se sešly v Praze na protest proti imigrantům. Současně probíhala i demonstrace na jejich podporu. Na Staroměstském náměstí vystoupil i předseda dělnické strany Tomáš Vandas a kontroverzní slovenský politik Marian Kotleba. Dalšího slovenského nacionalistu Mariána Magáta odvedla policie. ' ,
' description ' : ' md5:97c81d589a9491fbfa323c9fa3cca72c ' ,
' thumbnail ' : ' re:(?i)^https?://.* \ .(?:jpg|png)$ ' ,
' timestamp ' : 1439052180 ,
' upload_date ' : ' 20150808 ' ,
' is_live ' : False ,
}
} , {
' url ' : ' http://www.playtvak.cz/embed.aspx?idvideo=V150729_141549_play-porad_kuko ' ,
' only_matching ' : True ,
} ]
def _real_extract ( self , url ) :
video_id = self . _match_id ( url )
webpage = self . _download_webpage ( url , video_id )
infourl = self . _html_search_regex ( r ' Misc.videoFLV \ ({ data: " ([^ " ]+) " ' , webpage , ' xmlinfourl ' )
parsedurl = compat_urlparse . urlparse ( infourl )
qs = compat_urlparse . parse_qs ( parsedurl . query )
if ' reklama ' in qs : # Don't ask for ads
qs [ ' reklama ' ] = [ ' 0 ' ]
qs [ ' type ' ] = [ ' js ' ] # Ask for JS-based info file
newquery = compat_urllib_parse . urlencode ( qs , True )
infourl = compat_urlparse . urlunparse ( parsedurl [ : 4 ] + ( newquery , ' ' ) )
jsoninfo = self . _download_json ( infourl , video_id , transform_source = _extract_json )
info_url = self . _html_search_regex (
r ' Misc \ .videoFLV \ ( \ s*{ \ s*data \ s*: \ s* " ([^ " ]+) " ' , webpage , ' info url ' )
parsed_url = compat_urlparse . urlparse ( info_url )
qs = compat_urlparse . parse_qs ( parsed_url . query )
qs . update ( {
' reklama ' : [ ' 0 ' ] ,
' type ' : [ ' js ' ] ,
} )
info_url = compat_urlparse . urlunparse (
parsed_url . _replace ( query = compat_urllib_parse . urlencode ( qs , True ) ) )
json_info = self . _download_json (
info_url , video_id ,
transform_source = lambda s : s [ s . index ( ' { ' ) : s . rindex ( ' } ' ) + 1 ] )
item = None
for i in jsoninfo [ ' items ' ] :
if i [ ' type ' ] == ' video ' or i [ ' type ' ] == ' stream ' :
for i in json_ info [ ' items ' ] :
if i . get ( ' type ' ) == ' video ' or i . get ( ' type ' ) == ' stream ' :
item = i
break
if item is None :
if not item :
raise ExtractorError ( ' No suitable stream found ' )
title = item [ ' title ' ]
thumbnail = item [ ' image ' ]
is_live = item [ ' type ' ] == ' stream '
if is_live :
title = self . _live_title ( title )
quality = qualities ( [ ' low ' , ' middle ' , ' high ' ] )
formats = [ ]
for fmt in item [ ' video ' ] :
format_entry = { ' url ' : fmt [ ' file ' ] ,
' format_id ' : ( " %s _ %s " % ( fmt [ ' format ' ] , fmt [ ' quality ' ] ) ) ,
}
if fmt [ ' quality ' ] == ' middle ' :
format_entry [ ' quality ' ] = - 2
elif fmt [ ' quality ' ] == ' low ' :
format_entry [ ' quality ' ] = - 3
if fmt [ ' format ' ] == ' mp4 ' :
format_entry [ ' ext ' ] = ' mp4 '
elif fmt [ ' format ' ] == ' webm ' :
format_entry [ ' ext ' ] = ' webm '
elif fmt [ ' format ' ] == ' apple ' :
format_entry [ ' ext ' ] = ' mp4 '
format_entry [ ' protocol ' ] = ' m3u8 '
video_url = fmt . get ( ' file ' )
if not video_url :
continue
format_ = fmt [ ' format ' ]
format_id = ' %s _ %s ' % ( format_ , fmt [ ' quality ' ] )
preference = None
if format_ in [ ' mp4 ' , ' webm ' ] :
ext = format_
elif format_ == ' rtmp ' :
ext = ' flv '
elif format_ == ' apple ' :
ext = ' mp4 '
# Some streams have mp3 audio which does not play
# well with ffmpeg filter aac_adtstoasc
format_entry [ ' preference' ] = - 1
elif fmt [ ' format ' ] == ' rtmp ' :
format_entry [ ' ext ' ] = ' flv '
preference = - 1
elif format_ == ' adobe ' : # f4m manifest fails with 404 in 80% of requests
continue
else : # Other formats not supported yet
continue
formats . append ( format_entry )
formats . append ( {
' url ' : video_url ,
' ext ' : ext ,
' format_id ' : format_id ,
' quality ' : quality ( fmt . get ( ' quality ' ) ) ,
' preference ' : preference ,
} )
self . _sort_formats ( formats )
title = item [ ' title ' ]
is_live = item [ ' type ' ] == ' stream '
if is_live :
title = self . _live_title ( title )
timestamp = None
duration = None
if not is_live :
duration = int_or_none ( item . get ( ' length ' ) )
timestamp = item . get ( ' published ' )
if timestamp :
timestamp = parse_iso8601 ( timestamp [ : - 5 ] )
return {
' id ' : video_id ,
' title ' : title ,
' thumbnail ' : thumbnail ,
' description ' : self . _og_search_description ( webpage ) ,
' thumbnail ' : item . get ( ' image ' ) ,
' duration ' : duration ,
' timestamp ' : timestamp ,
' is_live ' : is_live ,
' formats ' : formats ,
}