|
@ -5,14 +5,16 @@ import re |
|
|
import json |
|
|
import json |
|
|
|
|
|
|
|
|
from .common import InfoExtractor |
|
|
from .common import InfoExtractor |
|
|
|
|
|
from ..compat import ( |
|
|
|
|
|
compat_str, |
|
|
|
|
|
) |
|
|
from ..utils import ( |
|
|
from ..utils import ( |
|
|
int_or_none, |
|
|
int_or_none, |
|
|
compat_str, |
|
|
|
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StreamCZIE(InfoExtractor): |
|
|
class StreamCZIE(InfoExtractor): |
|
|
_VALID_URL = r'https?://(?:www\.)?stream\.cz/.+/(?P<videoid>.+)' |
|
|
|
|
|
|
|
|
_VALID_URL = r'https?://(?:www\.)?stream\.cz/.+/(?P<id>[0-9]+)' |
|
|
|
|
|
|
|
|
_TESTS = [{ |
|
|
_TESTS = [{ |
|
|
'url': 'http://www.stream.cz/peklonataliri/765767-ecka-pro-deti', |
|
|
'url': 'http://www.stream.cz/peklonataliri/765767-ecka-pro-deti', |
|
@ -21,61 +23,63 @@ class StreamCZIE(InfoExtractor): |
|
|
'id': '765767', |
|
|
'id': '765767', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': 'Peklo na talíři: Éčka pro děti', |
|
|
'title': 'Peklo na talíři: Éčka pro děti', |
|
|
'description': 'md5:49ace0df986e95e331d0fe239d421519', |
|
|
|
|
|
'thumbnail': 'http://im.stream.cz/episode/52961d7e19d423f8f06f0100', |
|
|
|
|
|
|
|
|
'description': 'Taška s grónskou pomazánkou a další pekelnosti ZDE', |
|
|
|
|
|
'thumbnail': 're:^http://im.stream.cz/episode/52961d7e19d423f8f06f0100', |
|
|
'duration': 256, |
|
|
'duration': 256, |
|
|
}, |
|
|
}, |
|
|
}, { |
|
|
}, { |
|
|
'url': 'http://www.stream.cz/blanik/10002447-tri-roky-pro-mazanka', |
|
|
'url': 'http://www.stream.cz/blanik/10002447-tri-roky-pro-mazanka', |
|
|
'md5': '246272e753e26bbace7fcd9deca0650c', |
|
|
|
|
|
|
|
|
'md5': 'e54a254fb8b871968fd8403255f28589', |
|
|
'info_dict': { |
|
|
'info_dict': { |
|
|
'id': '10002447', |
|
|
'id': '10002447', |
|
|
'ext': 'mp4', |
|
|
'ext': 'mp4', |
|
|
'title': 'Kancelář Blaník: Tři roky pro Mazánka', |
|
|
'title': 'Kancelář Blaník: Tři roky pro Mazánka', |
|
|
'description': 'md5:9177695a8b756a0a8ab160de4043b392', |
|
|
|
|
|
'thumbnail': 'http://im.stream.cz/episode/537f838c50c11f8d21320000', |
|
|
|
|
|
|
|
|
'description': 'md5:3862a00ba7bf0b3e44806b544032c859', |
|
|
|
|
|
'thumbnail': 're:^http://im.stream.cz/episode/537f838c50c11f8d21320000', |
|
|
'duration': 368, |
|
|
'duration': 368, |
|
|
}, |
|
|
}, |
|
|
}] |
|
|
}] |
|
|
|
|
|
|
|
|
def _real_extract(self, url): |
|
|
def _real_extract(self, url): |
|
|
mobj = re.match(self._VALID_URL, url) |
|
|
|
|
|
video_id = mobj.group('videoid') |
|
|
|
|
|
|
|
|
|
|
|
webpage = self._download_webpage(url, video_id) |
|
|
|
|
|
|
|
|
|
|
|
data = self._html_search_regex(r'Stream\.Data\.Episode\((.+?)\);', webpage, 'stream data') |
|
|
|
|
|
|
|
|
|
|
|
jsonData = json.loads(data) |
|
|
|
|
|
|
|
|
video_id = self._match_id(url) |
|
|
|
|
|
data = self._download_json( |
|
|
|
|
|
'http://www.stream.cz/API/episode/%s' % video_id, video_id) |
|
|
|
|
|
|
|
|
formats = [] |
|
|
formats = [] |
|
|
for video in jsonData['instances']: |
|
|
|
|
|
for video_format in video['instances']: |
|
|
|
|
|
format_id = video_format['quality'] |
|
|
|
|
|
|
|
|
|
|
|
if format_id == '240p': |
|
|
|
|
|
quality = 0 |
|
|
|
|
|
elif format_id == '360p': |
|
|
|
|
|
quality = 1 |
|
|
|
|
|
elif format_id == '480p': |
|
|
|
|
|
quality = 2 |
|
|
|
|
|
elif format_id == '720p': |
|
|
|
|
|
quality = 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for quality, video in enumerate(data['video_qualities']): |
|
|
|
|
|
for f in video['formats']: |
|
|
|
|
|
typ = f['type'].partition('/')[2] |
|
|
|
|
|
qlabel = video.get('quality_label') |
|
|
formats.append({ |
|
|
formats.append({ |
|
|
'format_id': '%s-%s' % (video_format['type'].split('/')[1], format_id), |
|
|
|
|
|
'url': video_format['source'], |
|
|
|
|
|
|
|
|
'format_note': '%s-%s' % (qlabel, typ) if qlabel else typ, |
|
|
|
|
|
'format_id': '%s-%s' % (typ, f['quality']), |
|
|
|
|
|
'url': f['source'], |
|
|
|
|
|
'height': int_or_none(f['quality'].rstrip('p')), |
|
|
'quality': quality, |
|
|
'quality': quality, |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
self._sort_formats(formats) |
|
|
self._sort_formats(formats) |
|
|
|
|
|
|
|
|
|
|
|
image = data.get('image') |
|
|
|
|
|
if image: |
|
|
|
|
|
thumbnail = self._proto_relative_url( |
|
|
|
|
|
image.replace('{width}', '1240').replace('{height}', '697'), |
|
|
|
|
|
scheme='http:', |
|
|
|
|
|
) |
|
|
|
|
|
else: |
|
|
|
|
|
thumbnail = None |
|
|
|
|
|
|
|
|
|
|
|
stream = data.get('_embedded', {}).get('stream:show', {}).get('name') |
|
|
|
|
|
if stream: |
|
|
|
|
|
title = '%s: %s' % (stream, data['name']) |
|
|
|
|
|
else: |
|
|
|
|
|
title = data['name'] |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
'id': compat_str(jsonData['episode_id']), |
|
|
|
|
|
'title': self._og_search_title(webpage), |
|
|
|
|
|
'thumbnail': jsonData['episode_image_original_url'].replace('//', 'http://'), |
|
|
|
|
|
|
|
|
'id': video_id, |
|
|
|
|
|
'title': title, |
|
|
|
|
|
'thumbnail': thumbnail, |
|
|
'formats': formats, |
|
|
'formats': formats, |
|
|
'description': self._og_search_description(webpage), |
|
|
|
|
|
'duration': int_or_none(jsonData['duration']), |
|
|
|
|
|
'view_count': int_or_none(jsonData['stats_total']), |
|
|
|
|
|
|
|
|
'description': data.get('web_site_text'), |
|
|
|
|
|
'duration': int_or_none(data.get('duration')), |
|
|
|
|
|
'view_count': int_or_none(data.get('views')), |
|
|
} |
|
|
} |