]>
Commit | Line | Data |
---|---|---|
3121b256 NP |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
865b0872 S |
4 | import re |
5 | ||
3121b256 NP |
6 | from .common import InfoExtractor |
7 | from ..utils import ( | |
8 | ExtractorError, | |
865b0872 S |
9 | int_or_none, |
10 | strip_or_none, | |
11 | unescapeHTML, | |
3121b256 NP |
12 | urlencode_postdata, |
13 | ) | |
14 | ||
15 | ||
16 | class RoosterTeethIE(InfoExtractor): | |
17 | _VALID_URL = r'https?://(?:.+?\.)?roosterteeth\.com/episode/(?P<id>[^/?#&]+)' | |
18 | _LOGIN_URL = 'https://roosterteeth.com/login' | |
19 | _NETRC_MACHINE = 'roosterteeth' | |
20 | _TESTS = [{ | |
21 | 'url': 'http://roosterteeth.com/episode/million-dollars-but-season-2-million-dollars-but-the-game-announcement', | |
865b0872 | 22 | 'md5': 'e2bd7764732d785ef797700a2489f212', |
3121b256 NP |
23 | 'info_dict': { |
24 | 'id': '26576', | |
865b0872 | 25 | 'display_id': 'million-dollars-but-season-2-million-dollars-but-the-game-announcement', |
3121b256 | 26 | 'ext': 'mp4', |
865b0872 S |
27 | 'title': 'Million Dollars, But...: Million Dollars, But... The Game Announcement', |
28 | 'description': 'md5:0cc3b21986d54ed815f5faeccd9a9ca5', | |
3121b256 | 29 | 'thumbnail': 're:^https?://.*\.png$', |
3121b256 NP |
30 | 'series': 'Million Dollars, But...', |
31 | 'episode': 'Million Dollars, But... The Game Announcement', | |
865b0872 | 32 | 'comment_count': int, |
3121b256 NP |
33 | }, |
34 | }, { | |
35 | 'url': 'http://achievementhunter.roosterteeth.com/episode/off-topic-the-achievement-hunter-podcast-2016-i-didn-t-think-it-would-pass-31', | |
36 | 'only_matching': True, | |
37 | }, { | |
38 | 'url': 'http://funhaus.roosterteeth.com/episode/funhaus-shorts-2016-austin-sucks-funhaus-shorts', | |
39 | 'only_matching': True, | |
40 | }, { | |
41 | 'url': 'http://screwattack.roosterteeth.com/episode/death-battle-season-3-mewtwo-vs-shadow', | |
42 | 'only_matching': True, | |
43 | }, { | |
44 | 'url': 'http://theknow.roosterteeth.com/episode/the-know-game-news-season-1-boring-steam-sales-are-better', | |
45 | 'only_matching': True, | |
865b0872 S |
46 | }, { |
47 | # only available for FIRST members | |
48 | 'url': 'http://roosterteeth.com/episode/rt-docs-the-world-s-greatest-head-massage-the-world-s-greatest-head-massage-an-asmr-journey-part-one', | |
49 | 'only_matching': True, | |
3121b256 NP |
50 | }] |
51 | ||
52 | def _login(self): | |
53 | (username, password) = self._get_login_info() | |
865b0872 S |
54 | if username is None: |
55 | return | |
3121b256 | 56 | |
865b0872 S |
57 | login_page = self._download_webpage( |
58 | self._LOGIN_URL, None, | |
59 | note='Downloading login page', | |
60 | errnote='Unable to download login page') | |
3121b256 NP |
61 | |
62 | login_form = self._hidden_inputs(login_page) | |
865b0872 | 63 | |
3121b256 NP |
64 | login_form.update({ |
65 | 'username': username, | |
66 | 'password': password, | |
67 | }) | |
3121b256 NP |
68 | |
69 | login_request = self._download_webpage( | |
70 | self._LOGIN_URL, None, | |
71 | note='Logging in as %s' % username, | |
865b0872 S |
72 | data=urlencode_postdata(login_form), |
73 | headers={ | |
74 | 'Referer': self._LOGIN_URL, | |
75 | }) | |
76 | ||
77 | if not any(re.search(p, login_request) for p in ( | |
78 | r'href=["\']https?://(?:www\.)?roosterteeth\.com/logout"', | |
79 | r'>Sign Out<')): | |
80 | error = self._html_search_regex( | |
81 | r'(?s)<div[^>]+class=(["\']).*?\balert-danger\b.*?\1[^>]*>(?:\s*<button[^>]*>.*?</button>)?(?P<error>.+?)</div>', | |
82 | login_request, 'alert', default=None, group='error') | |
83 | if error: | |
84 | raise ExtractorError('Unable to login: %s' % error, expected=True) | |
85 | raise ExtractorError('Unable to log in') | |
3121b256 NP |
86 | |
87 | def _real_initialize(self): | |
88 | self._login() | |
89 | ||
90 | def _real_extract(self, url): | |
865b0872 S |
91 | display_id = self._match_id(url) |
92 | ||
93 | webpage = self._download_webpage(url, display_id) | |
3121b256 | 94 | |
865b0872 S |
95 | episode = strip_or_none(unescapeHTML(self._search_regex( |
96 | (r'videoTitle\s*=\s*(["\'])(?P<title>(?:(?!\1).)+)\1', | |
97 | r'<title>(?P<title>[^<]+)</title>'), webpage, 'title', | |
98 | default=None, group='title'))) | |
3121b256 | 99 | |
865b0872 S |
100 | title = strip_or_none(self._og_search_title( |
101 | webpage, default=None)) or episode | |
3121b256 | 102 | |
865b0872 S |
103 | m3u8_url = self._search_regex( |
104 | r'file\s*:\s*(["\'])(?P<url>http.+?\.m3u8.*?)\1', | |
105 | webpage, 'm3u8 url', default=None, group='url') | |
3121b256 | 106 | |
865b0872 S |
107 | if not m3u8_url: |
108 | if re.search(r'<div[^>]+class=["\']non-sponsor', webpage): | |
109 | self.raise_login_required( | |
110 | '%s is only available for FIRST members' % display_id) | |
3121b256 | 111 | |
865b0872 S |
112 | if re.search(r'<div[^>]+class=["\']golive-gate', webpage): |
113 | self.raise_login_required('%s is not available yet' % display_id) | |
3121b256 | 114 | |
865b0872 S |
115 | raise ExtractorError('Unable to extract m3u8 URL') |
116 | ||
117 | formats = self._extract_m3u8_formats( | |
118 | m3u8_url, display_id, ext='mp4', | |
119 | entry_protocol='m3u8_native', m3u8_id='hls') | |
3121b256 NP |
120 | self._sort_formats(formats) |
121 | ||
865b0872 S |
122 | description = strip_or_none(self._og_search_description(webpage)) |
123 | thumbnail = self._proto_relative_url(self._og_search_thumbnail(webpage)) | |
124 | ||
125 | series = self._search_regex( | |
126 | (r'<h2>More ([^<]+)</h2>', r'<a[^>]+>See All ([^<]+) Videos<'), | |
127 | webpage, 'series', fatal=False) | |
128 | ||
129 | comment_count = int_or_none(self._search_regex( | |
130 | r'>Comments \((\d+)\)<', webpage, | |
131 | 'comment count', fatal=False)) | |
132 | ||
133 | video_id = self._search_regex( | |
134 | (r'containerId\s*=\s*["\']episode-(\d+)\1', | |
135 | r'<div[^<]+id=["\']episode-(\d+)'), webpage, | |
136 | 'video id', default=display_id) | |
137 | ||
3121b256 | 138 | return { |
865b0872 S |
139 | 'id': video_id, |
140 | 'display_id': display_id, | |
3121b256 | 141 | 'title': title, |
3121b256 | 142 | 'description': description, |
865b0872 | 143 | 'thumbnail': thumbnail, |
3121b256 NP |
144 | 'series': series, |
145 | 'episode': episode, | |
865b0872 S |
146 | 'comment_count': comment_count, |
147 | 'formats': formats, | |
3121b256 | 148 | } |