logo

youtube-dl

[mirror] Download/Watch videos from video hostersgit clone https://hacktivis.me/git/mirror/youtube-dl.git

videomore.py (11731B)


  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..compat import (
  6. compat_parse_qs,
  7. compat_str,
  8. compat_urllib_parse_urlparse,
  9. )
  10. from ..utils import (
  11. ExtractorError,
  12. int_or_none,
  13. )
  14. class VideomoreBaseIE(InfoExtractor):
  15. _API_BASE_URL = 'https://more.tv/api/v3/web/'
  16. _VALID_URL_BASE = r'https?://(?:videomore\.ru|more\.tv)/'
  17. def _download_page_data(self, display_id):
  18. return self._download_json(
  19. self._API_BASE_URL + 'PageData', display_id, query={
  20. 'url': '/' + display_id,
  21. })['attributes']['response']['data']
  22. def _track_url_result(self, track):
  23. track_vod = track['trackVod']
  24. video_url = track_vod.get('playerLink') or track_vod['link']
  25. return self.url_result(
  26. video_url, VideomoreIE.ie_key(), track_vod.get('hubId'))
  27. class VideomoreIE(InfoExtractor):
  28. IE_NAME = 'videomore'
  29. _VALID_URL = r'''(?x)
  30. videomore:(?P<sid>\d+)$|
  31. https?://
  32. (?:
  33. videomore\.ru/
  34. (?:
  35. embed|
  36. [^/]+/[^/]+
  37. )/|
  38. (?:
  39. (?:player\.)?videomore\.ru|
  40. siren\.more\.tv/player
  41. )/[^/]*\?.*?\btrack_id=|
  42. odysseus\.more.tv/player/(?P<partner_id>\d+)/
  43. )
  44. (?P<id>\d+)
  45. (?:[/?#&]|\.(?:xml|json)|$)
  46. '''
  47. _TESTS = [{
  48. 'url': 'http://videomore.ru/kino_v_detalayah/5_sezon/367617',
  49. 'md5': '44455a346edc0d509ac5b5a5b531dc35',
  50. 'info_dict': {
  51. 'id': '367617',
  52. 'ext': 'flv',
  53. 'title': 'Кино в деталях 5 сезон В гостях Алексей Чумаков и Юлия Ковальчук',
  54. 'series': 'Кино в деталях',
  55. 'episode': 'В гостях Алексей Чумаков и Юлия Ковальчук',
  56. 'thumbnail': r're:^https?://.*\.jpg',
  57. 'duration': 2910,
  58. 'view_count': int,
  59. 'comment_count': int,
  60. 'age_limit': 16,
  61. },
  62. 'skip': 'The video is not available for viewing.',
  63. }, {
  64. 'url': 'http://videomore.ru/embed/259974',
  65. 'info_dict': {
  66. 'id': '259974',
  67. 'ext': 'mp4',
  68. 'title': 'Молодежка 2 сезон 40 серия',
  69. 'series': 'Молодежка',
  70. 'season': '2 сезон',
  71. 'episode': '40 серия',
  72. 'thumbnail': r're:^https?://.*\.jpg',
  73. 'duration': 2789,
  74. 'view_count': int,
  75. 'age_limit': 16,
  76. },
  77. 'params': {
  78. 'skip_download': True,
  79. },
  80. }, {
  81. 'url': 'http://videomore.ru/molodezhka/sezon_promo/341073',
  82. 'info_dict': {
  83. 'id': '341073',
  84. 'ext': 'flv',
  85. 'title': 'Промо Команда проиграла из-за Бакина?',
  86. 'episode': 'Команда проиграла из-за Бакина?',
  87. 'thumbnail': r're:^https?://.*\.jpg',
  88. 'duration': 29,
  89. 'age_limit': 16,
  90. 'view_count': int,
  91. },
  92. 'params': {
  93. 'skip_download': True,
  94. },
  95. 'skip': 'The video is not available for viewing.',
  96. }, {
  97. 'url': 'http://videomore.ru/elki_3?track_id=364623',
  98. 'only_matching': True,
  99. }, {
  100. 'url': 'http://videomore.ru/embed/364623',
  101. 'only_matching': True,
  102. }, {
  103. 'url': 'http://videomore.ru/video/tracks/364623.xml',
  104. 'only_matching': True,
  105. }, {
  106. 'url': 'http://videomore.ru/video/tracks/364623.json',
  107. 'only_matching': True,
  108. }, {
  109. 'url': 'http://videomore.ru/video/tracks/158031/quotes/33248',
  110. 'only_matching': True,
  111. }, {
  112. 'url': 'videomore:367617',
  113. 'only_matching': True,
  114. }, {
  115. 'url': 'https://player.videomore.ru/?partner_id=97&track_id=736234&autoplay=0&userToken=',
  116. 'only_matching': True,
  117. }, {
  118. 'url': 'https://odysseus.more.tv/player/1788/352317',
  119. 'only_matching': True,
  120. }, {
  121. 'url': 'https://siren.more.tv/player/config?track_id=352317&partner_id=1788&user_token=',
  122. 'only_matching': True,
  123. }]
  124. _GEO_BYPASS = False
  125. @staticmethod
  126. def _extract_url(webpage):
  127. mobj = re.search(
  128. r'<object[^>]+data=(["\'])https?://videomore\.ru/player\.swf\?.*config=(?P<url>https?://videomore\.ru/(?:[^/]+/)+\d+\.xml).*\1',
  129. webpage)
  130. if not mobj:
  131. mobj = re.search(
  132. r'<iframe[^>]+src=([\'"])(?P<url>https?://videomore\.ru/embed/\d+)',
  133. webpage)
  134. if mobj:
  135. return mobj.group('url')
  136. def _real_extract(self, url):
  137. mobj = re.match(self._VALID_URL, url)
  138. video_id = mobj.group('sid') or mobj.group('id')
  139. partner_id = mobj.group('partner_id') or compat_parse_qs(compat_urllib_parse_urlparse(url).query).get('partner_id', [None])[0] or '97'
  140. item = self._download_json(
  141. 'https://siren.more.tv/player/config', video_id, query={
  142. 'partner_id': partner_id,
  143. 'track_id': video_id,
  144. })['data']['playlist']['items'][0]
  145. title = item.get('title')
  146. series = item.get('project_name')
  147. season = item.get('season_name')
  148. episode = item.get('episode_name')
  149. if not title:
  150. title = []
  151. for v in (series, season, episode):
  152. if v:
  153. title.append(v)
  154. title = ' '.join(title)
  155. streams = item.get('streams') or []
  156. for protocol in ('DASH', 'HLS'):
  157. stream_url = item.get(protocol.lower() + '_url')
  158. if stream_url:
  159. streams.append({'protocol': protocol, 'url': stream_url})
  160. formats = []
  161. for stream in streams:
  162. stream_url = stream.get('url')
  163. if not stream_url:
  164. continue
  165. protocol = stream.get('protocol')
  166. if protocol == 'DASH':
  167. formats.extend(self._extract_mpd_formats(
  168. stream_url, video_id, mpd_id='dash', fatal=False))
  169. elif protocol == 'HLS':
  170. formats.extend(self._extract_m3u8_formats(
  171. stream_url, video_id, 'mp4', 'm3u8_native',
  172. m3u8_id='hls', fatal=False))
  173. elif protocol == 'MSS':
  174. formats.extend(self._extract_ism_formats(
  175. stream_url, video_id, ism_id='mss', fatal=False))
  176. if not formats:
  177. error = item.get('error')
  178. if error:
  179. if error in ('Данное видео недоступно для просмотра на территории этой страны', 'Данное видео доступно для просмотра только на территории России'):
  180. self.raise_geo_restricted(countries=['RU'])
  181. raise ExtractorError(error, expected=True)
  182. self._sort_formats(formats)
  183. return {
  184. 'id': video_id,
  185. 'title': title,
  186. 'series': series,
  187. 'season': season,
  188. 'episode': episode,
  189. 'thumbnail': item.get('thumbnail_url'),
  190. 'duration': int_or_none(item.get('duration')),
  191. 'view_count': int_or_none(item.get('views')),
  192. 'age_limit': int_or_none(item.get('min_age')),
  193. 'formats': formats,
  194. }
  195. class VideomoreVideoIE(VideomoreBaseIE):
  196. IE_NAME = 'videomore:video'
  197. _VALID_URL = VideomoreBaseIE._VALID_URL_BASE + r'(?P<id>(?:(?:[^/]+/){2})?[^/?#&]+)(?:/*|[?#&].*?)$'
  198. _TESTS = [{
  199. # single video with og:video:iframe
  200. 'url': 'http://videomore.ru/elki_3',
  201. 'info_dict': {
  202. 'id': '364623',
  203. 'ext': 'flv',
  204. 'title': 'Ёлки 3',
  205. 'description': '',
  206. 'thumbnail': r're:^https?://.*\.jpg',
  207. 'duration': 5579,
  208. 'age_limit': 6,
  209. 'view_count': int,
  210. },
  211. 'params': {
  212. 'skip_download': True,
  213. },
  214. 'skip': 'Requires logging in',
  215. }, {
  216. # season single series with og:video:iframe
  217. 'url': 'http://videomore.ru/poslednii_ment/1_sezon/14_seriya',
  218. 'info_dict': {
  219. 'id': '352317',
  220. 'ext': 'mp4',
  221. 'title': 'Последний мент 1 сезон 14 серия',
  222. 'series': 'Последний мент',
  223. 'season': '1 сезон',
  224. 'episode': '14 серия',
  225. 'thumbnail': r're:^https?://.*\.jpg',
  226. 'duration': 2464,
  227. 'age_limit': 16,
  228. 'view_count': int,
  229. },
  230. 'params': {
  231. 'skip_download': True,
  232. },
  233. }, {
  234. 'url': 'http://videomore.ru/sejchas_v_seti/serii_221-240/226_vypusk',
  235. 'only_matching': True,
  236. }, {
  237. # single video without og:video:iframe
  238. 'url': 'http://videomore.ru/marin_i_ego_druzya',
  239. 'info_dict': {
  240. 'id': '359073',
  241. 'ext': 'flv',
  242. 'title': '1 серия. Здравствуй, Аквавилль!',
  243. 'description': 'md5:c6003179538b5d353e7bcd5b1372b2d7',
  244. 'thumbnail': r're:^https?://.*\.jpg',
  245. 'duration': 754,
  246. 'age_limit': 6,
  247. 'view_count': int,
  248. },
  249. 'params': {
  250. 'skip_download': True,
  251. },
  252. 'skip': 'redirects to https://more.tv/'
  253. }, {
  254. 'url': 'https://videomore.ru/molodezhka/6_sezon/29_seriya?utm_so',
  255. 'only_matching': True,
  256. }, {
  257. 'url': 'https://more.tv/poslednii_ment/1_sezon/14_seriya',
  258. 'only_matching': True,
  259. }]
  260. @classmethod
  261. def suitable(cls, url):
  262. return False if VideomoreIE.suitable(url) else super(VideomoreVideoIE, cls).suitable(url)
  263. def _real_extract(self, url):
  264. display_id = self._match_id(url)
  265. return self._track_url_result(self._download_page_data(display_id))
  266. class VideomoreSeasonIE(VideomoreBaseIE):
  267. IE_NAME = 'videomore:season'
  268. _VALID_URL = VideomoreBaseIE._VALID_URL_BASE + r'(?!embed)(?P<id>[^/]+/[^/?#&]+)(?:/*|[?#&].*?)$'
  269. _TESTS = [{
  270. 'url': 'http://videomore.ru/molodezhka/film_o_filme',
  271. 'info_dict': {
  272. 'id': 'molodezhka/film_o_filme',
  273. 'title': 'Фильм о фильме',
  274. },
  275. 'playlist_mincount': 3,
  276. }, {
  277. 'url': 'http://videomore.ru/molodezhka/sezon_promo?utm_so',
  278. 'only_matching': True,
  279. }, {
  280. 'url': 'https://more.tv/molodezhka/film_o_filme',
  281. 'only_matching': True,
  282. }]
  283. @classmethod
  284. def suitable(cls, url):
  285. return (False if (VideomoreIE.suitable(url) or VideomoreVideoIE.suitable(url))
  286. else super(VideomoreSeasonIE, cls).suitable(url))
  287. def _real_extract(self, url):
  288. display_id = self._match_id(url)
  289. season = self._download_page_data(display_id)
  290. season_id = compat_str(season['id'])
  291. tracks = self._download_json(
  292. self._API_BASE_URL + 'seasons/%s/tracks' % season_id,
  293. season_id)['data']
  294. entries = []
  295. for track in tracks:
  296. entries.append(self._track_url_result(track))
  297. return self.playlist_result(entries, display_id, season.get('title'))