]>
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 | } | |
a57b562c JMF |
49 | }, |
50 | { | |
51 | 'url': 'http://www.nfl.com/news/story/0ap3000000467586/article/patriots-seahawks-involved-in-lategame-skirmish', | |
52 | 'info_dict': { | |
53 | 'id': '0ap3000000467607', | |
54 | 'ext': 'mp4', | |
55 | 'title': 'Frustrations flare on the field', | |
56 | 'description': 'Emotions ran high at the end of the Super Bowl on both sides of the ball after a dramatic finish.', | |
57 | 'timestamp': 1422850320, | |
58 | 'upload_date': '20150202', | |
59 | }, | |
60 | }, | |
5f4c3188 NJ |
61 | ] |
62 | ||
63 | @staticmethod | |
64 | def prepend_host(host, url): | |
65 | if not url.startswith('http'): | |
66 | if not url.startswith('/'): | |
67 | url = '/%s' % url | |
68 | url = 'http://{0:}{1:}'.format(host, url) | |
69 | return url | |
70 | ||
71 | @staticmethod | |
72 | def format_from_stream(stream, protocol, host, path_prefix='', | |
73 | preference=0, note=None): | |
74 | url = '{protocol:}://{host:}/{prefix:}{path:}'.format( | |
75 | protocol=protocol, | |
76 | host=host, | |
77 | prefix=path_prefix, | |
78 | path=stream.get('path'), | |
79 | ) | |
80 | return { | |
81 | 'url': url, | |
82 | 'vbr': int_or_none(stream.get('rate', 0), 1000), | |
83 | 'preference': preference, | |
84 | 'format_note': note, | |
632e5684 | 85 | } |
632e5684 NJ |
86 | |
87 | def _real_extract(self, url): | |
88 | mobj = re.match(self._VALID_URL, url) | |
5f4c3188 | 89 | video_id, host = mobj.group('id'), mobj.group('host') |
632e5684 | 90 | |
5f4c3188 | 91 | webpage = self._download_webpage(url, video_id) |
632e5684 | 92 | |
5f4c3188 | 93 | config_url = NFLIE.prepend_host(host, self._search_regex( |
a57b562c JMF |
94 | r'(?:config|configURL)\s*:\s*"([^"]+)"', webpage, 'config URL', |
95 | default='static/content/static/config/video/config.json')) | |
96 | # For articles, the id in the url is not the video id | |
97 | video_id = self._search_regex( | |
98 | r'contentId\s*:\s*"([^"]+)"', webpage, 'video id', default=video_id) | |
5f4c3188 NJ |
99 | config = self._download_json(config_url, video_id, |
100 | note='Downloading player config') | |
101 | url_template = NFLIE.prepend_host( | |
102 | host, '{contentURLTemplate:}'.format(**config)) | |
103 | video_data = self._download_json( | |
104 | url_template.format(id=video_id), video_id) | |
632e5684 NJ |
105 | |
106 | formats = [] | |
5f4c3188 NJ |
107 | cdn_data = video_data.get('cdnData', {}) |
108 | streams = cdn_data.get('bitrateInfo', []) | |
109 | if cdn_data.get('format') == 'EXTERNAL_HTTP_STREAM': | |
f8fb4a7c | 110 | parts = compat_urllib_parse_urlparse(cdn_data.get('uri')) |
5f4c3188 | 111 | protocol, host = parts.scheme, parts.netloc |
632e5684 | 112 | for stream in streams: |
5f4c3188 NJ |
113 | formats.append( |
114 | NFLIE.format_from_stream(stream, protocol, host)) | |
115 | else: | |
116 | cdns = config.get('cdns') | |
117 | if not cdns: | |
118 | raise ExtractorError('Failed to get CDN data', expected=True) | |
119 | ||
120 | for name, cdn in cdns.items(): | |
121 | # LimeLight streams don't seem to work | |
122 | if cdn.get('name') == 'LIMELIGHT': | |
123 | continue | |
124 | ||
125 | protocol = cdn.get('protocol') | |
126 | host = remove_end(cdn.get('host', ''), '/') | |
127 | if not (protocol and host): | |
632e5684 NJ |
128 | continue |
129 | ||
5f4c3188 NJ |
130 | prefix = cdn.get('pathprefix', '') |
131 | if prefix and not prefix.endswith('/'): | |
132 | prefix = '%s/' % prefix | |
133 | ||
134 | preference = 0 | |
135 | if protocol == 'rtmp': | |
136 | preference = -2 | |
137 | elif 'prog' in name.lower(): | |
138 | preference = 1 | |
139 | ||
140 | for stream in streams: | |
141 | formats.append( | |
142 | NFLIE.format_from_stream(stream, protocol, host, | |
143 | prefix, preference, name)) | |
632e5684 NJ |
144 | |
145 | self._sort_formats(formats) | |
146 | ||
147 | thumbnail = None | |
148 | for q in ('xl', 'l', 'm', 's', 'xs'): | |
149 | thumbnail = video_data.get('imagePaths', {}).get(q) | |
150 | if thumbnail: | |
151 | break | |
152 | ||
153 | return { | |
154 | 'id': video_id, | |
dfee8323 | 155 | 'title': video_data.get('headline'), |
632e5684 NJ |
156 | 'formats': formats, |
157 | 'description': video_data.get('caption'), | |
158 | 'duration': video_data.get('duration'), | |
159 | 'thumbnail': thumbnail, | |
160 | 'timestamp': int_or_none(video_data.get('posted'), 1000), | |
161 | } |