]>
Commit | Line | Data |
---|---|---|
38e0f16a RA |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from .common import InfoExtractor | |
5 | from ..compat import compat_str | |
6 | from ..utils import ( | |
832f9d52 | 7 | ExtractorError, |
38e0f16a RA |
8 | int_or_none, |
9 | float_or_none, | |
832f9d52 | 10 | smuggle_url, |
03c86279 | 11 | str_or_none, |
12 | try_get, | |
13 | unified_strdate, | |
14 | unified_timestamp, | |
38e0f16a RA |
15 | ) |
16 | ||
17 | ||
18 | class NineNowIE(InfoExtractor): | |
19 | IE_NAME = '9now.com.au' | |
20 | _VALID_URL = r'https?://(?:www\.)?9now\.com\.au/(?:[^/]+/){2}(?P<id>[^/?#]+)' | |
832f9d52 | 21 | _GEO_COUNTRIES = ['AU'] |
38e0f16a RA |
22 | _TESTS = [{ |
23 | # clip | |
24 | 'url': 'https://www.9now.com.au/afl-footy-show/2016/clip-ciql02091000g0hp5oktrnytc', | |
25 | 'md5': '17cf47d63ec9323e562c9957a968b565', | |
26 | 'info_dict': { | |
27 | 'id': '16801', | |
28 | 'ext': 'mp4', | |
29 | 'title': 'St. Kilda\'s Joey Montagna on the potential for a player\'s strike', | |
30 | 'description': 'Is a boycott of the NAB Cup "on the table"?', | |
31 | 'uploader_id': '4460760524001', | |
32 | 'upload_date': '20160713', | |
33 | 'timestamp': 1468421266, | |
34 | }, | |
35 | 'skip': 'Only available in Australia', | |
36 | }, { | |
37 | # episode | |
38 | 'url': 'https://www.9now.com.au/afl-footy-show/2016/episode-19', | |
39 | 'only_matching': True, | |
40 | }, { | |
41 | # DRM protected | |
342f0c36 | 42 | 'url': 'https://www.9now.com.au/andrew-marrs-history-of-the-world/season-1/episode-1', |
38e0f16a | 43 | 'only_matching': True, |
03c86279 | 44 | }, { |
45 | # episode of series | |
46 | 'url': 'https://www.9now.com.au/lego-masters/season-3/episode-3', | |
47 | 'info_dict': { | |
48 | 'id': '6249614030001', | |
49 | 'title': 'Episode 3', | |
50 | 'ext': 'mp4', | |
51 | 'season_number': 3, | |
52 | 'episode_number': 3, | |
53 | 'description': 'In the first elimination of the competition, teams will have 10 hours to build a world inside a snow globe.', | |
54 | 'uploader_id': '4460760524001', | |
55 | 'timestamp': 1619002200, | |
56 | 'upload_date': '20210421', | |
57 | }, | |
58 | 'expected_warnings': ['Ignoring subtitle tracks'], | |
59 | 'params':{ | |
60 | 'skip_download': True, | |
61 | } | |
38e0f16a RA |
62 | }] |
63 | BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/4460760524001/default_default/index.html?videoId=%s' | |
64 | ||
65 | def _real_extract(self, url): | |
66 | display_id = self._match_id(url) | |
67 | webpage = self._download_webpage(url, display_id) | |
68 | page_data = self._parse_json(self._search_regex( | |
69 | r'window\.__data\s*=\s*({.*?});', webpage, | |
6fd26a7d S |
70 | 'page data', default='{}'), display_id, fatal=False) |
71 | if not page_data: | |
72 | page_data = self._parse_json(self._parse_json(self._search_regex( | |
73 | r'window\.__data\s*=\s*JSON\.parse\s*\(\s*(".+?")\s*\)\s*;', | |
74 | webpage, 'page data'), display_id), display_id) | |
56c0ead4 S |
75 | |
76 | for kind in ('episode', 'clip'): | |
77 | current_key = page_data.get(kind, {}).get( | |
78 | 'current%sKey' % kind.capitalize()) | |
79 | if not current_key: | |
80 | continue | |
81 | cache = page_data.get(kind, {}).get('%sCache' % kind, {}) | |
82 | if not cache: | |
83 | continue | |
03c86279 | 84 | common_data = { |
85 | 'episode': (cache.get(current_key) or list(cache.values())[0])[kind], | |
86 | 'season': (cache.get(current_key) or list(cache.values())[0]).get('season', None) | |
87 | } | |
56c0ead4 S |
88 | break |
89 | else: | |
90 | raise ExtractorError('Unable to find video data') | |
91 | ||
03c86279 | 92 | if not self.get_param('allow_unplayable_formats') and try_get(common_data, lambda x: x['episode']['video']['drm'], bool): |
93 | self.report_drm(display_id) | |
94 | brightcove_id = try_get( | |
95 | common_data, lambda x: x['episode']['video']['brightcoveId'], compat_str) or 'ref:%s' % common_data['episode']['video']['referenceId'] | |
96 | video_id = str_or_none(try_get(common_data, lambda x: x['episode']['video']['id'])) or brightcove_id | |
38e0f16a | 97 | |
03c86279 | 98 | title = try_get(common_data, lambda x: x['episode']['name'], compat_str) |
99 | season_number = try_get(common_data, lambda x: x['season']['seasonNumber'], int) | |
100 | episode_number = try_get(common_data, lambda x: x['episode']['episodeNumber'], int) | |
101 | timestamp = unified_timestamp(try_get(common_data, lambda x: x['episode']['airDate'], compat_str)) | |
102 | release_date = unified_strdate(try_get(common_data, lambda x: x['episode']['availability'], compat_str)) | |
103 | thumbnails_data = try_get(common_data, lambda x: x['episode']['image']['sizes'], dict) or {} | |
38e0f16a RA |
104 | thumbnails = [{ |
105 | 'id': thumbnail_id, | |
106 | 'url': thumbnail_url, | |
03c86279 | 107 | 'width': int_or_none(thumbnail_id[1:]), |
108 | } for thumbnail_id, thumbnail_url in thumbnails_data.items()] | |
38e0f16a RA |
109 | |
110 | return { | |
111 | '_type': 'url_transparent', | |
832f9d52 S |
112 | 'url': smuggle_url( |
113 | self.BRIGHTCOVE_URL_TEMPLATE % brightcove_id, | |
114 | {'geo_countries': self._GEO_COUNTRIES}), | |
38e0f16a RA |
115 | 'id': video_id, |
116 | 'title': title, | |
03c86279 | 117 | 'description': try_get(common_data, lambda x: x['episode']['description'], compat_str), |
118 | 'duration': float_or_none(try_get(common_data, lambda x: x['episode']['video']['duration'], float), 1000), | |
38e0f16a RA |
119 | 'thumbnails': thumbnails, |
120 | 'ie_key': 'BrightcoveNew', | |
03c86279 | 121 | 'season_number': season_number, |
122 | 'episode_number': episode_number, | |
123 | 'timestamp': timestamp, | |
124 | 'release_date': release_date, | |
38e0f16a | 125 | } |