]>
Commit | Line | Data |
---|---|---|
f670ef1c | 1 | # encoding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
0029071a | 4 | import itertools |
f670ef1c | 5 | |
3793090b | 6 | from .amp import AMPIE |
0029071a S |
7 | from ..compat import ( |
8 | compat_HTTPError, | |
cbcd1a54 S |
9 | compat_urllib_parse, |
10 | compat_urllib_request, | |
0029071a S |
11 | compat_urlparse, |
12 | ) | |
13 | from ..utils import ( | |
14 | ExtractorError, | |
15 | clean_html, | |
16 | determine_ext, | |
17 | int_or_none, | |
18 | parse_iso8601, | |
19 | ) | |
f670ef1c | 20 | |
21 | ||
3793090b | 22 | class DramaFeverBaseIE(AMPIE): |
cbcd1a54 S |
23 | _LOGIN_URL = 'https://www.dramafever.com/accounts/login/' |
24 | _NETRC_MACHINE = 'dramafever' | |
25 | ||
1d1dd597 S |
26 | _CONSUMER_SECRET = 'DA59dtVXYLxajktV' |
27 | ||
28 | _consumer_secret = None | |
29 | ||
30 | def _get_consumer_secret(self): | |
31 | mainjs = self._download_webpage( | |
32 | 'http://www.dramafever.com/static/51afe95/df2014/scripts/main.js', | |
33 | None, 'Downloading main.js', fatal=False) | |
34 | if not mainjs: | |
35 | return self._CONSUMER_SECRET | |
36 | return self._search_regex( | |
37 | r"var\s+cs\s*=\s*'([^']+)'", mainjs, | |
38 | 'consumer secret', default=self._CONSUMER_SECRET) | |
39 | ||
cbcd1a54 S |
40 | def _real_initialize(self): |
41 | self._login() | |
1d1dd597 | 42 | self._consumer_secret = self._get_consumer_secret() |
cbcd1a54 S |
43 | |
44 | def _login(self): | |
45 | (username, password) = self._get_login_info() | |
46 | if username is None: | |
47 | return | |
48 | ||
49 | login_form = { | |
50 | 'username': username, | |
51 | 'password': password, | |
52 | } | |
53 | ||
54 | request = compat_urllib_request.Request( | |
55 | self._LOGIN_URL, compat_urllib_parse.urlencode(login_form).encode('utf-8')) | |
56 | response = self._download_webpage( | |
57 | request, None, 'Logging in as %s' % username) | |
58 | ||
59 | if all(logout_pattern not in response | |
60 | for logout_pattern in ['href="/accounts/logout/"', '>Log out<']): | |
61 | error = self._html_search_regex( | |
62 | r'(?s)class="hidden-xs prompt"[^>]*>(.+?)<', | |
63 | response, 'error message', default=None) | |
64 | if error: | |
65 | raise ExtractorError('Unable to login: %s' % error, expected=True) | |
66 | raise ExtractorError('Unable to log in') | |
67 | ||
68 | ||
69 | class DramaFeverIE(DramaFeverBaseIE): | |
f670ef1c | 70 | IE_NAME = 'dramafever' |
450d89dd | 71 | _VALID_URL = r'https?://(?:www\.)?dramafever\.com/drama/(?P<id>[0-9]+/[0-9]+)(?:/|$)' |
0029071a | 72 | _TEST = { |
f670ef1c | 73 | 'url': 'http://www.dramafever.com/drama/4512/1/Cooking_with_Shin/', |
74 | 'info_dict': { | |
75 | 'id': '4512.1', | |
76 | 'ext': 'flv', | |
77 | 'title': 'Cooking with Shin 4512.1', | |
0029071a S |
78 | 'description': 'md5:a8eec7942e1664a6896fcd5e1287bfd0', |
79 | 'thumbnail': 're:^https?://.*\.jpg', | |
80 | 'timestamp': 1404336058, | |
f670ef1c | 81 | 'upload_date': '20140702', |
0029071a | 82 | 'duration': 343, |
3793090b | 83 | }, |
84 | 'params': { | |
85 | # m3u8 download | |
86 | 'skip_download': True, | |
87 | }, | |
0029071a | 88 | } |
f670ef1c | 89 | |
90 | def _real_extract(self, url): | |
0029071a | 91 | video_id = self._match_id(url).replace('/', '.') |
f670ef1c | 92 | |
0029071a | 93 | try: |
3793090b | 94 | info = self._extract_feed_info('http://www.dramafever.com/amp/episode/feed.json?guid=%s' % video_id) |
0029071a S |
95 | except ExtractorError as e: |
96 | if isinstance(e.cause, compat_HTTPError): | |
97 | raise ExtractorError( | |
98 | 'Currently unavailable in your country.', expected=True) | |
99 | raise | |
f670ef1c | 100 | |
1d1dd597 S |
101 | series_id, episode_number = video_id.split('.') |
102 | episode_info = self._download_json( | |
103 | # We only need a single episode info, so restricting page size to one episode | |
104 | # and dealing with page number as with episode number | |
105 | r'http://www.dramafever.com/api/4/episode/series/?cs=%s&series_id=%s&page_number=%s&page_size=1' | |
106 | % (self._consumer_secret, series_id, episode_number), | |
107 | video_id, 'Downloading episode info JSON', fatal=False) | |
108 | if episode_info: | |
109 | value = episode_info.get('value') | |
110 | if value: | |
111 | subfile = value[0].get('subfile') or value[0].get('new_subfile') | |
112 | if subfile and subfile != 'http://www.dramafever.com/st/': | |
3793090b | 113 | info['subtitiles'].setdefault('English', []).append({ |
1d1dd597 S |
114 | 'ext': 'srt', |
115 | 'url': subfile, | |
116 | }) | |
117 | ||
3793090b | 118 | return info |
f670ef1c | 119 | |
0029071a | 120 | |
cbcd1a54 | 121 | class DramaFeverSeriesIE(DramaFeverBaseIE): |
f670ef1c | 122 | IE_NAME = 'dramafever:series' |
70a20023 | 123 | _VALID_URL = r'https?://(?:www\.)?dramafever\.com/drama/(?P<id>[0-9]+)(?:/(?:(?!\d+(?:/|$)).+)?)?$' |
f670ef1c | 124 | _TESTS = [{ |
125 | 'url': 'http://www.dramafever.com/drama/4512/Cooking_with_Shin/', | |
126 | 'info_dict': { | |
127 | 'id': '4512', | |
128 | 'title': 'Cooking with Shin', | |
0029071a | 129 | 'description': 'md5:84a3f26e3cdc3fb7f500211b3593b5c1', |
f670ef1c | 130 | }, |
131 | 'playlist_count': 4, | |
132 | }, { | |
133 | 'url': 'http://www.dramafever.com/drama/124/IRIS/', | |
134 | 'info_dict': { | |
135 | 'id': '124', | |
136 | 'title': 'IRIS', | |
0029071a | 137 | 'description': 'md5:b3a30e587cf20c59bd1c01ec0ee1b862', |
f670ef1c | 138 | }, |
139 | 'playlist_count': 20, | |
140 | }] | |
141 | ||
463b2e55 | 142 | _PAGE_SIZE = 60 # max is 60 (see http://api.drama9.com/#get--api-4-episode-series-) |
0029071a | 143 | |
f670ef1c | 144 | def _real_extract(self, url): |
145 | series_id = self._match_id(url) | |
0029071a | 146 | |
0029071a S |
147 | series = self._download_json( |
148 | 'http://www.dramafever.com/api/4/series/query/?cs=%s&series_id=%s' | |
1d1dd597 | 149 | % (self._consumer_secret, series_id), |
0029071a | 150 | series_id, 'Downloading series JSON')['series'][series_id] |
f670ef1c | 151 | |
0029071a S |
152 | title = clean_html(series['name']) |
153 | description = clean_html(series.get('description') or series.get('description_short')) | |
f670ef1c | 154 | |
f670ef1c | 155 | entries = [] |
0029071a S |
156 | for page_num in itertools.count(1): |
157 | episodes = self._download_json( | |
158 | 'http://www.dramafever.com/api/4/episode/series/?cs=%s&series_id=%s&page_size=%d&page_number=%d' | |
1d1dd597 | 159 | % (self._consumer_secret, series_id, self._PAGE_SIZE, page_num), |
0029071a S |
160 | series_id, 'Downloading episodes JSON page #%d' % page_num) |
161 | for episode in episodes.get('value', []): | |
10464af5 S |
162 | episode_url = episode.get('episode_url') |
163 | if not episode_url: | |
164 | continue | |
0029071a | 165 | entries.append(self.url_result( |
10464af5 | 166 | compat_urlparse.urljoin(url, episode_url), |
0029071a S |
167 | 'DramaFever', episode.get('guid'))) |
168 | if page_num == episodes['num_pages']: | |
169 | break | |
170 | ||
f670ef1c | 171 | return self.playlist_result(entries, series_id, title, description) |