2 from __future__ 
import unicode_literals
 
   6 from .common 
import InfoExtractor
 
  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' 
  21         'url': 'http://roosterteeth.com/episode/million-dollars-but-season-2-million-dollars-but-the-game-announcement', 
  22         'md5': 'e2bd7764732d785ef797700a2489f212', 
  25             'display_id': 'million-dollars-but-season-2-million-dollars-but-the-game-announcement', 
  27             'title': 'Million Dollars, But...: Million Dollars, But... The Game Announcement', 
  28             'description': 'md5:0cc3b21986d54ed815f5faeccd9a9ca5', 
  29             'thumbnail': r
're:^https?://.*\.png$', 
  30             'series': 'Million Dollars, But...', 
  31             'episode': 'Million Dollars, But... The Game Announcement', 
  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, 
  38         'url': 'http://funhaus.roosterteeth.com/episode/funhaus-shorts-2016-austin-sucks-funhaus-shorts', 
  39         'only_matching': True, 
  41         'url': 'http://screwattack.roosterteeth.com/episode/death-battle-season-3-mewtwo-vs-shadow', 
  42         'only_matching': True, 
  44         'url': 'http://theknow.roosterteeth.com/episode/the-know-game-news-season-1-boring-steam-sales-are-better', 
  45         'only_matching': True, 
  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, 
  53         (username
, password
) = self
._get
_login
_info
() 
  57         login_page 
= self
._download
_webpage
( 
  58             self
._LOGIN
_URL
, None, 
  59             note
='Downloading login page', 
  60             errnote
='Unable to download login page') 
  62         login_form 
= self
._hidden
_inputs
(login_page
) 
  69         login_request 
= self
._download
_webpage
( 
  70             self
._LOGIN
_URL
, None, 
  71             note
='Logging in as %s' % username
, 
  72             data
=urlencode_postdata(login_form
), 
  74                 'Referer': self
._LOGIN
_URL
, 
  77         if not any(re
.search(p
, login_request
) for p 
in ( 
  78                 r
'href=["\']https?
://(?
:www\
.)?roosterteeth\
.com
/logout
"', 
  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
') 
  84                 raise ExtractorError('Unable to login
: %s' % error, expected=True) 
  85             raise ExtractorError('Unable to log 
in') 
  87     def _real_initialize(self): 
  90     def _real_extract(self, url): 
  91         display_id = self._match_id(url) 
  93         webpage = self._download_webpage(url, display_id) 
  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'))) 
 100         title = strip_or_none(self._og_search_title( 
 101             webpage, default=None)) or episode 
 103         m3u8_url = self._search_regex( 
 104             r'file\s*:\s*(["\'])(?P
<url
>http
.+?\
.m3u8
.*?
)\
1', 
 105             webpage, 'm3u8 url
', default=None, group='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) 
 112             if re.search(r'<div[^>]+class=["\']golive
-gate
', webpage): 
 113                 self.raise_login_required('%s is not available yet
' % display_id) 
 115             raise ExtractorError('Unable to extract m3u8 URL
') 
 117         formats = self._extract_m3u8_formats( 
 118             m3u8_url, display_id, ext='mp4
', 
 119             entry_protocol='m3u8_native
', m3u8_id='hls
') 
 120         self._sort_formats(formats) 
 122         description = strip_or_none(self._og_search_description(webpage)) 
 123         thumbnail = self._proto_relative_url(self._og_search_thumbnail(webpage)) 
 125         series = self._search_regex( 
 126             (r'<h2
>More ([^
<]+)</h2
>', r'<a
[^
>]+>See 
All ([^
<]+) Videos
<'), 
 127             webpage, 'series
', fatal=False) 
 129         comment_count = int_or_none(self._search_regex( 
 130             r'>Comments \
((\d
+)\
)<', webpage, 
 131             'comment count
', fatal=False)) 
 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) 
 140             'display_id
': display_id, 
 142             'description
': description, 
 143             'thumbnail
': thumbnail, 
 146             'comment_count
': comment_count,