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