You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
9.9 KiB

Switch codebase to use sanitized_Request instead of compat_urllib_request.Request [downloader/dash] Use sanitized_Request [downloader/http] Use sanitized_Request [atresplayer] Use sanitized_Request [bambuser] Use sanitized_Request [bliptv] Use sanitized_Request [brightcove] Use sanitized_Request [cbs] Use sanitized_Request [ceskatelevize] Use sanitized_Request [collegerama] Use sanitized_Request [extractor/common] Use sanitized_Request [crunchyroll] Use sanitized_Request [dailymotion] Use sanitized_Request [dcn] Use sanitized_Request [dramafever] Use sanitized_Request [dumpert] Use sanitized_Request [eitb] Use sanitized_Request [escapist] Use sanitized_Request [everyonesmixtape] Use sanitized_Request [extremetube] Use sanitized_Request [facebook] Use sanitized_Request [fc2] Use sanitized_Request [flickr] Use sanitized_Request [4tube] Use sanitized_Request [gdcvault] Use sanitized_Request [extractor/generic] Use sanitized_Request [hearthisat] Use sanitized_Request [hotnewhiphop] Use sanitized_Request [hypem] Use sanitized_Request [iprima] Use sanitized_Request [ivi] Use sanitized_Request [keezmovies] Use sanitized_Request [letv] Use sanitized_Request [lynda] Use sanitized_Request [metacafe] Use sanitized_Request [minhateca] Use sanitized_Request [miomio] Use sanitized_Request [meovideo] Use sanitized_Request [mofosex] Use sanitized_Request [moniker] Use sanitized_Request [mooshare] Use sanitized_Request [movieclips] Use sanitized_Request [mtv] Use sanitized_Request [myvideo] Use sanitized_Request [neteasemusic] Use sanitized_Request [nfb] Use sanitized_Request [niconico] Use sanitized_Request [noco] Use sanitized_Request [nosvideo] Use sanitized_Request [novamov] Use sanitized_Request [nowness] Use sanitized_Request [nuvid] Use sanitized_Request [played] Use sanitized_Request [pluralsight] Use sanitized_Request [pornhub] Use sanitized_Request [pornotube] Use sanitized_Request [primesharetv] Use sanitized_Request [promptfile] Use sanitized_Request [qqmusic] Use sanitized_Request [rtve] Use sanitized_Request [safari] Use sanitized_Request [sandia] Use sanitized_Request [shared] Use sanitized_Request [sharesix] Use sanitized_Request [sina] Use sanitized_Request [smotri] Use sanitized_Request [sohu] Use sanitized_Request [spankwire] Use sanitized_Request [sportdeutschland] Use sanitized_Request [streamcloud] Use sanitized_Request [streamcz] Use sanitized_Request [tapely] Use sanitized_Request [tube8] Use sanitized_Request [tubitv] Use sanitized_Request [twitch] Use sanitized_Request [twitter] Use sanitized_Request [udemy] Use sanitized_Request [vbox7] Use sanitized_Request [veoh] Use sanitized_Request [vessel] Use sanitized_Request [vevo] Use sanitized_Request [viddler] Use sanitized_Request [videomega] Use sanitized_Request [viewvster] Use sanitized_Request [viki] Use sanitized_Request [vk] Use sanitized_Request [vodlocker] Use sanitized_Request [voicerepublic] Use sanitized_Request [wistia] Use sanitized_Request [xfileshare] Use sanitized_Request [xtube] Use sanitized_Request [xvideos] Use sanitized_Request [yandexmusic] Use sanitized_Request [youku] Use sanitized_Request [youporn] Use sanitized_Request [youtube] Use sanitized_Request [patreon] Use sanitized_Request [extractor/common] Remove unused import [nfb] PEP 8
9 years ago
Switch codebase to use sanitized_Request instead of compat_urllib_request.Request [downloader/dash] Use sanitized_Request [downloader/http] Use sanitized_Request [atresplayer] Use sanitized_Request [bambuser] Use sanitized_Request [bliptv] Use sanitized_Request [brightcove] Use sanitized_Request [cbs] Use sanitized_Request [ceskatelevize] Use sanitized_Request [collegerama] Use sanitized_Request [extractor/common] Use sanitized_Request [crunchyroll] Use sanitized_Request [dailymotion] Use sanitized_Request [dcn] Use sanitized_Request [dramafever] Use sanitized_Request [dumpert] Use sanitized_Request [eitb] Use sanitized_Request [escapist] Use sanitized_Request [everyonesmixtape] Use sanitized_Request [extremetube] Use sanitized_Request [facebook] Use sanitized_Request [fc2] Use sanitized_Request [flickr] Use sanitized_Request [4tube] Use sanitized_Request [gdcvault] Use sanitized_Request [extractor/generic] Use sanitized_Request [hearthisat] Use sanitized_Request [hotnewhiphop] Use sanitized_Request [hypem] Use sanitized_Request [iprima] Use sanitized_Request [ivi] Use sanitized_Request [keezmovies] Use sanitized_Request [letv] Use sanitized_Request [lynda] Use sanitized_Request [metacafe] Use sanitized_Request [minhateca] Use sanitized_Request [miomio] Use sanitized_Request [meovideo] Use sanitized_Request [mofosex] Use sanitized_Request [moniker] Use sanitized_Request [mooshare] Use sanitized_Request [movieclips] Use sanitized_Request [mtv] Use sanitized_Request [myvideo] Use sanitized_Request [neteasemusic] Use sanitized_Request [nfb] Use sanitized_Request [niconico] Use sanitized_Request [noco] Use sanitized_Request [nosvideo] Use sanitized_Request [novamov] Use sanitized_Request [nowness] Use sanitized_Request [nuvid] Use sanitized_Request [played] Use sanitized_Request [pluralsight] Use sanitized_Request [pornhub] Use sanitized_Request [pornotube] Use sanitized_Request [primesharetv] Use sanitized_Request [promptfile] Use sanitized_Request [qqmusic] Use sanitized_Request [rtve] Use sanitized_Request [safari] Use sanitized_Request [sandia] Use sanitized_Request [shared] Use sanitized_Request [sharesix] Use sanitized_Request [sina] Use sanitized_Request [smotri] Use sanitized_Request [sohu] Use sanitized_Request [spankwire] Use sanitized_Request [sportdeutschland] Use sanitized_Request [streamcloud] Use sanitized_Request [streamcz] Use sanitized_Request [tapely] Use sanitized_Request [tube8] Use sanitized_Request [tubitv] Use sanitized_Request [twitch] Use sanitized_Request [twitter] Use sanitized_Request [udemy] Use sanitized_Request [vbox7] Use sanitized_Request [veoh] Use sanitized_Request [vessel] Use sanitized_Request [vevo] Use sanitized_Request [viddler] Use sanitized_Request [videomega] Use sanitized_Request [viewvster] Use sanitized_Request [viki] Use sanitized_Request [vk] Use sanitized_Request [vodlocker] Use sanitized_Request [voicerepublic] Use sanitized_Request [wistia] Use sanitized_Request [xfileshare] Use sanitized_Request [xtube] Use sanitized_Request [xvideos] Use sanitized_Request [yandexmusic] Use sanitized_Request [youku] Use sanitized_Request [youporn] Use sanitized_Request [youtube] Use sanitized_Request [patreon] Use sanitized_Request [extractor/common] Remove unused import [nfb] PEP 8
9 years ago
  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. import json
  5. import datetime
  6. from .common import InfoExtractor
  7. from ..compat import (
  8. compat_urlparse,
  9. )
  10. from ..utils import (
  11. ExtractorError,
  12. int_or_none,
  13. parse_duration,
  14. parse_iso8601,
  15. sanitized_Request,
  16. xpath_text,
  17. determine_ext,
  18. urlencode_postdata,
  19. )
  20. class NiconicoIE(InfoExtractor):
  21. IE_NAME = 'niconico'
  22. IE_DESC = 'ニコニコ動画'
  23. _TESTS = [{
  24. 'url': 'http://www.nicovideo.jp/watch/sm22312215',
  25. 'md5': 'd1a75c0823e2f629128c43e1212760f9',
  26. 'info_dict': {
  27. 'id': 'sm22312215',
  28. 'ext': 'mp4',
  29. 'title': 'Big Buck Bunny',
  30. 'uploader': 'takuya0301',
  31. 'uploader_id': '2698420',
  32. 'upload_date': '20131123',
  33. 'timestamp': 1385182762,
  34. 'description': '(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org',
  35. 'duration': 33,
  36. },
  37. 'skip': 'Requires an account',
  38. }, {
  39. # File downloaded with and without credentials are different, so omit
  40. # the md5 field
  41. 'url': 'http://www.nicovideo.jp/watch/nm14296458',
  42. 'info_dict': {
  43. 'id': 'nm14296458',
  44. 'ext': 'swf',
  45. 'title': '【鏡音リン】Dance on media【オリジナル】take2!',
  46. 'description': 'md5:689f066d74610b3b22e0f1739add0f58',
  47. 'uploader': 'りょうた',
  48. 'uploader_id': '18822557',
  49. 'upload_date': '20110429',
  50. 'timestamp': 1304065916,
  51. 'duration': 209,
  52. },
  53. 'skip': 'Requires an account',
  54. }, {
  55. # 'video exists but is marked as "deleted"
  56. # md5 is unstable
  57. 'url': 'http://www.nicovideo.jp/watch/sm10000',
  58. 'info_dict': {
  59. 'id': 'sm10000',
  60. 'ext': 'unknown_video',
  61. 'description': 'deleted',
  62. 'title': 'ドラえもんエターナル第3話「決戦第3新東京市」<前編>',
  63. 'upload_date': '20071224',
  64. 'timestamp': int, # timestamp field has different value if logged in
  65. 'duration': 304,
  66. },
  67. 'skip': 'Requires an account',
  68. }, {
  69. 'url': 'http://www.nicovideo.jp/watch/so22543406',
  70. 'info_dict': {
  71. 'id': '1388129933',
  72. 'ext': 'mp4',
  73. 'title': '【第1回】RADIOアニメロミックス ラブライブ!~のぞえりRadio Garden~',
  74. 'description': 'md5:b27d224bb0ff53d3c8269e9f8b561cf1',
  75. 'timestamp': 1388851200,
  76. 'upload_date': '20140104',
  77. 'uploader': 'アニメロチャンネル',
  78. 'uploader_id': '312',
  79. },
  80. 'skip': 'The viewing period of the video you were searching for has expired.',
  81. }]
  82. _VALID_URL = r'https?://(?:www\.|secure\.)?nicovideo\.jp/watch/(?P<id>(?:[a-z]{2})?[0-9]+)'
  83. _NETRC_MACHINE = 'niconico'
  84. def _real_initialize(self):
  85. self._login()
  86. def _login(self):
  87. (username, password) = self._get_login_info()
  88. # No authentication to be performed
  89. if not username:
  90. return True
  91. # Log in
  92. login_form_strs = {
  93. 'mail': username,
  94. 'password': password,
  95. }
  96. login_data = urlencode_postdata(login_form_strs)
  97. request = sanitized_Request(
  98. 'https://secure.nicovideo.jp/secure/login', login_data)
  99. login_results = self._download_webpage(
  100. request, None, note='Logging in', errnote='Unable to log in')
  101. if re.search(r'(?i)<h1 class="mb8p4">Log in error</h1>', login_results) is not None:
  102. self._downloader.report_warning('unable to log in: bad username or password')
  103. return False
  104. return True
  105. def _real_extract(self, url):
  106. video_id = self._match_id(url)
  107. # Get video webpage. We are not actually interested in it for normal
  108. # cases, but need the cookies in order to be able to download the
  109. # info webpage
  110. webpage, handle = self._download_webpage_handle(
  111. 'http://www.nicovideo.jp/watch/' + video_id, video_id)
  112. if video_id.startswith('so'):
  113. video_id = self._match_id(handle.geturl())
  114. video_info = self._download_xml(
  115. 'http://ext.nicovideo.jp/api/getthumbinfo/' + video_id, video_id,
  116. note='Downloading video info page')
  117. # Get flv info
  118. flv_info_webpage = self._download_webpage(
  119. 'http://flapi.nicovideo.jp/api/getflv/' + video_id + '?as3=1',
  120. video_id, 'Downloading flv info')
  121. flv_info = compat_urlparse.parse_qs(flv_info_webpage)
  122. if 'url' not in flv_info:
  123. if 'deleted' in flv_info:
  124. raise ExtractorError('The video has been deleted.',
  125. expected=True)
  126. elif 'closed' in flv_info:
  127. raise ExtractorError('Niconico videos now require logging in',
  128. expected=True)
  129. else:
  130. raise ExtractorError('Unable to find video URL')
  131. video_real_url = flv_info['url'][0]
  132. # Start extracting information
  133. title = xpath_text(video_info, './/title')
  134. if not title:
  135. title = self._og_search_title(webpage, default=None)
  136. if not title:
  137. title = self._html_search_regex(
  138. r'<span[^>]+class="videoHeaderTitle"[^>]*>([^<]+)</span>',
  139. webpage, 'video title')
  140. watch_api_data_string = self._html_search_regex(
  141. r'<div[^>]+id="watchAPIDataContainer"[^>]+>([^<]+)</div>',
  142. webpage, 'watch api data', default=None)
  143. watch_api_data = self._parse_json(watch_api_data_string, video_id) if watch_api_data_string else {}
  144. video_detail = watch_api_data.get('videoDetail', {})
  145. extension = xpath_text(video_info, './/movie_type')
  146. if not extension:
  147. extension = determine_ext(video_real_url)
  148. thumbnail = (
  149. xpath_text(video_info, './/thumbnail_url') or
  150. self._html_search_meta('image', webpage, 'thumbnail', default=None) or
  151. video_detail.get('thumbnail'))
  152. description = xpath_text(video_info, './/description')
  153. timestamp = parse_iso8601(xpath_text(video_info, './/first_retrieve'))
  154. if not timestamp:
  155. match = self._html_search_meta('datePublished', webpage, 'date published', default=None)
  156. if match:
  157. timestamp = parse_iso8601(match.replace('+', ':00+'))
  158. if not timestamp and video_detail.get('postedAt'):
  159. timestamp = parse_iso8601(
  160. video_detail['postedAt'].replace('/', '-'),
  161. delimiter=' ', timezone=datetime.timedelta(hours=9))
  162. view_count = int_or_none(xpath_text(video_info, './/view_counter'))
  163. if not view_count:
  164. match = self._html_search_regex(
  165. r'>Views: <strong[^>]*>([^<]+)</strong>',
  166. webpage, 'view count', default=None)
  167. if match:
  168. view_count = int_or_none(match.replace(',', ''))
  169. view_count = view_count or video_detail.get('viewCount')
  170. comment_count = int_or_none(xpath_text(video_info, './/comment_num'))
  171. if not comment_count:
  172. match = self._html_search_regex(
  173. r'>Comments: <strong[^>]*>([^<]+)</strong>',
  174. webpage, 'comment count', default=None)
  175. if match:
  176. comment_count = int_or_none(match.replace(',', ''))
  177. comment_count = comment_count or video_detail.get('commentCount')
  178. duration = (parse_duration(
  179. xpath_text(video_info, './/length') or
  180. self._html_search_meta(
  181. 'video:duration', webpage, 'video duration', default=None)) or
  182. video_detail.get('length'))
  183. webpage_url = xpath_text(video_info, './/watch_url') or url
  184. if video_info.find('.//ch_id') is not None:
  185. uploader_id = video_info.find('.//ch_id').text
  186. uploader = video_info.find('.//ch_name').text
  187. elif video_info.find('.//user_id') is not None:
  188. uploader_id = video_info.find('.//user_id').text
  189. uploader = video_info.find('.//user_nickname').text
  190. else:
  191. uploader_id = uploader = None
  192. return {
  193. 'id': video_id,
  194. 'url': video_real_url,
  195. 'title': title,
  196. 'ext': extension,
  197. 'format_id': 'economy' if video_real_url.endswith('low') else 'normal',
  198. 'thumbnail': thumbnail,
  199. 'description': description,
  200. 'uploader': uploader,
  201. 'timestamp': timestamp,
  202. 'uploader_id': uploader_id,
  203. 'view_count': view_count,
  204. 'comment_count': comment_count,
  205. 'duration': duration,
  206. 'webpage_url': webpage_url,
  207. }
  208. class NiconicoPlaylistIE(InfoExtractor):
  209. _VALID_URL = r'https?://(?:www\.)?nicovideo\.jp/mylist/(?P<id>\d+)'
  210. _TEST = {
  211. 'url': 'http://www.nicovideo.jp/mylist/27411728',
  212. 'info_dict': {
  213. 'id': '27411728',
  214. 'title': 'AKB48のオールナイトニッポン',
  215. },
  216. 'playlist_mincount': 225,
  217. }
  218. def _real_extract(self, url):
  219. list_id = self._match_id(url)
  220. webpage = self._download_webpage(url, list_id)
  221. entries_json = self._search_regex(r'Mylist\.preload\(\d+, (\[.*\])\);',
  222. webpage, 'entries')
  223. entries = json.loads(entries_json)
  224. entries = [{
  225. '_type': 'url',
  226. 'ie_key': NiconicoIE.ie_key(),
  227. 'url': ('http://www.nicovideo.jp/watch/%s' %
  228. entry['item_data']['video_id']),
  229. } for entry in entries]
  230. return {
  231. '_type': 'playlist',
  232. 'title': self._search_regex(r'\s+name: "(.*?)"', webpage, 'title'),
  233. 'id': list_id,
  234. 'entries': entries,
  235. }