]>
Commit | Line | Data |
---|---|---|
632e5684 NJ |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | import re | |
5 | ||
6 | from .common import InfoExtractor | |
1cc79574 PH |
7 | from ..compat import ( |
8 | compat_urllib_parse_urlparse, | |
9 | ) | |
632e5684 NJ |
10 | from ..utils import ( |
11 | ExtractorError, | |
12 | int_or_none, | |
13 | remove_end, | |
14 | ) | |
15 | ||
16 | ||
17 | class NFLIE(InfoExtractor): | |
18 | IE_NAME = 'nfl.com' | |
5f4c3188 NJ |
19 | _VALID_URL = r'''(?x)https?:// |
20 | (?P<host>(?:www\.)?(?:nfl\.com|.*?\.clubs\.nfl\.com))/ | |
21 | (?:.+?/)* | |
22 | (?P<id>(?:\d[a-z]{2}\d{13}|\w{8}\-(?:\w{4}\-){3}\w{12}))''' | |
23 | _TESTS = [ | |
24 | { | |
25 | 'url': 'http://www.nfl.com/videos/nfl-game-highlights/0ap3000000398478/Week-3-Redskins-vs-Eagles-highlights', | |
26 | 'md5': '394ef771ddcd1354f665b471d78ec4c6', | |
27 | 'info_dict': { | |
28 | 'id': '0ap3000000398478', | |
29 | 'ext': 'mp4', | |
30 | 'title': 'Week 3: Redskins vs. Eagles highlights', | |
31 | 'description': 'md5:56323bfb0ac4ee5ab24bd05fdf3bf478', | |
32 | 'upload_date': '20140921', | |
33 | 'timestamp': 1411337580, | |
34 | 'thumbnail': 're:^https?://.*\.jpg$', | |
35 | } | |
36 | }, | |
37 | { | |
38 | 'url': 'http://prod.www.steelers.clubs.nfl.com/video-and-audio/videos/LIVE_Post_Game_vs_Browns/9d72f26a-9e2b-4718-84d3-09fb4046c266', | |
39 | 'md5': 'cf85bdb4bc49f6e9d3816d130c78279c', | |
40 | 'info_dict': { | |
41 | 'id': '9d72f26a-9e2b-4718-84d3-09fb4046c266', | |
42 | 'ext': 'mp4', | |
43 | 'title': 'LIVE: Post Game vs. Browns', | |
44 | 'description': 'md5:6a97f7e5ebeb4c0e69a418a89e0636e8', | |
45 | 'upload_date': '20131229', | |
46 | 'timestamp': 1388354455, | |
47 | 'thumbnail': 're:^https?://.*\.jpg$', | |
48 | } | |
49 | } | |
50 | ] | |
51 | ||
52 | @staticmethod | |
53 | def prepend_host(host, url): | |
54 | if not url.startswith('http'): | |
55 | if not url.startswith('/'): | |
56 | url = '/%s' % url | |
57 | url = 'http://{0:}{1:}'.format(host, url) | |
58 | return url | |
59 | ||
60 | @staticmethod | |
61 | def format_from_stream(stream, protocol, host, path_prefix='', | |
62 | preference=0, note=None): | |
63 | url = '{protocol:}://{host:}/{prefix:}{path:}'.format( | |
64 | protocol=protocol, | |
65 | host=host, | |
66 | prefix=path_prefix, | |
67 | path=stream.get('path'), | |
68 | ) | |
69 | return { | |
70 | 'url': url, | |
71 | 'vbr': int_or_none(stream.get('rate', 0), 1000), | |
72 | 'preference': preference, | |
73 | 'format_note': note, | |
632e5684 | 74 | } |
632e5684 NJ |
75 | |
76 | def _real_extract(self, url): | |
77 | mobj = re.match(self._VALID_URL, url) | |
5f4c3188 | 78 | video_id, host = mobj.group('id'), mobj.group('host') |
632e5684 | 79 | |
5f4c3188 | 80 | webpage = self._download_webpage(url, video_id) |
632e5684 | 81 | |
5f4c3188 NJ |
82 | config_url = NFLIE.prepend_host(host, self._search_regex( |
83 | r'(?:config|configURL)\s*:\s*"([^"]+)"', webpage, 'config URL')) | |
84 | config = self._download_json(config_url, video_id, | |
85 | note='Downloading player config') | |
86 | url_template = NFLIE.prepend_host( | |
87 | host, '{contentURLTemplate:}'.format(**config)) | |
88 | video_data = self._download_json( | |
89 | url_template.format(id=video_id), video_id) | |
632e5684 NJ |
90 | |
91 | formats = [] | |
5f4c3188 NJ |
92 | cdn_data = video_data.get('cdnData', {}) |
93 | streams = cdn_data.get('bitrateInfo', []) | |
94 | if cdn_data.get('format') == 'EXTERNAL_HTTP_STREAM': | |
f8fb4a7c | 95 | parts = compat_urllib_parse_urlparse(cdn_data.get('uri')) |
5f4c3188 | 96 | protocol, host = parts.scheme, parts.netloc |
632e5684 | 97 | for stream in streams: |
5f4c3188 NJ |
98 | formats.append( |
99 | NFLIE.format_from_stream(stream, protocol, host)) | |
100 | else: | |
101 | cdns = config.get('cdns') | |
102 | if not cdns: | |
103 | raise ExtractorError('Failed to get CDN data', expected=True) | |
104 | ||
105 | for name, cdn in cdns.items(): | |
106 | # LimeLight streams don't seem to work | |
107 | if cdn.get('name') == 'LIMELIGHT': | |
108 | continue | |
109 | ||
110 | protocol = cdn.get('protocol') | |
111 | host = remove_end(cdn.get('host', ''), '/') | |
112 | if not (protocol and host): | |
632e5684 NJ |
113 | continue |
114 | ||
5f4c3188 NJ |
115 | prefix = cdn.get('pathprefix', '') |
116 | if prefix and not prefix.endswith('/'): | |
117 | prefix = '%s/' % prefix | |
118 | ||
119 | preference = 0 | |
120 | if protocol == 'rtmp': | |
121 | preference = -2 | |
122 | elif 'prog' in name.lower(): | |
123 | preference = 1 | |
124 | ||
125 | for stream in streams: | |
126 | formats.append( | |
127 | NFLIE.format_from_stream(stream, protocol, host, | |
128 | prefix, preference, name)) | |
632e5684 NJ |
129 | |
130 | self._sort_formats(formats) | |
131 | ||
132 | thumbnail = None | |
133 | for q in ('xl', 'l', 'm', 's', 'xs'): | |
134 | thumbnail = video_data.get('imagePaths', {}).get(q) | |
135 | if thumbnail: | |
136 | break | |
137 | ||
138 | return { | |
139 | 'id': video_id, | |
dfee8323 | 140 | 'title': video_data.get('headline'), |
632e5684 NJ |
141 | 'formats': formats, |
142 | 'description': video_data.get('caption'), | |
143 | 'duration': video_data.get('duration'), | |
144 | 'thumbnail': thumbnail, | |
145 | 'timestamp': int_or_none(video_data.get('posted'), 1000), | |
146 | } |