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