summaryrefslogtreecommitdiff
path: root/youtube_dl/extractor/beeg.py
blob: b0b7914d89777fcba136a12562f771bf4f2af4d6 (plain)
    1 from __future__ import unicode_literals
    2 
    3 from .common import InfoExtractor
    4 from ..compat import (
    5     compat_chr,
    6     compat_ord,
    7     compat_urllib_parse_unquote,
    8 )
    9 from ..utils import (
   10     int_or_none,
   11     parse_iso8601,
   12 )
   13 
   14 
   15 class BeegIE(InfoExtractor):
   16     _VALID_URL = r'https?://(?:www\.)?beeg\.com/(?P<id>\d+)'
   17     _TEST = {
   18         'url': 'http://beeg.com/5416503',
   19         'md5': '46c384def73b33dbc581262e5ee67cef',
   20         'info_dict': {
   21             'id': '5416503',
   22             'ext': 'mp4',
   23             'title': 'Sultry Striptease',
   24             'description': 'md5:d22219c09da287c14bed3d6c37ce4bc2',
   25             'timestamp': 1391813355,
   26             'upload_date': '20140207',
   27             'duration': 383,
   28             'tags': list,
   29             'age_limit': 18,
   30         }
   31     }
   32 
   33     def _real_extract(self, url):
   34         video_id = self._match_id(url)
   35 
   36         webpage = self._download_webpage(url, video_id)
   37 
   38         cpl_url = self._search_regex(
   39             r'<script[^>]+src=(["\'])(?P<url>(?:https?:)?//static\.beeg\.com/cpl/\d+\.js.*?)\1',
   40             webpage, 'cpl', default=None, group='url')
   41 
   42         beeg_version, beeg_salt = [None] * 2
   43 
   44         if cpl_url:
   45             cpl = self._download_webpage(
   46                 self._proto_relative_url(cpl_url), video_id,
   47                 'Downloading cpl JS', fatal=False)
   48             if cpl:
   49                 beeg_version = int_or_none(self._search_regex(
   50                     r'beeg_version\s*=\s*([^\b]+)', cpl,
   51                     'beeg version', default=None)) or self._search_regex(
   52                     r'/(\d+)\.js', cpl_url, 'beeg version', default=None)
   53                 beeg_salt = self._search_regex(
   54                     r'beeg_salt\s*=\s*(["\'])(?P<beeg_salt>.+?)\1', cpl, 'beeg salt',
   55                     default=None, group='beeg_salt')
   56 
   57         beeg_version = beeg_version or '2000'
   58         beeg_salt = beeg_salt or 'pmweAkq8lAYKdfWcFCUj0yoVgoPlinamH5UE1CB3H'
   59 
   60         video = self._download_json(
   61             'https://api.beeg.com/api/v6/%s/video/%s' % (beeg_version, video_id),
   62             video_id)
   63 
   64         def split(o, e):
   65             def cut(s, x):
   66                 n.append(s[:x])
   67                 return s[x:]
   68             n = []
   69             r = len(o) % e
   70             if r > 0:
   71                 o = cut(o, r)
   72             while len(o) > e:
   73                 o = cut(o, e)
   74             n.append(o)
   75             return n
   76 
   77         def decrypt_key(key):
   78             # Reverse engineered from http://static.beeg.com/cpl/1738.js
   79             a = beeg_salt
   80             e = compat_urllib_parse_unquote(key)
   81             o = ''.join([
   82                 compat_chr(compat_ord(e[n]) - compat_ord(a[n % len(a)]) % 21)
   83                 for n in range(len(e))])
   84             return ''.join(split(o, 3)[::-1])
   85 
   86         def decrypt_url(encrypted_url):
   87             encrypted_url = self._proto_relative_url(
   88                 encrypted_url.replace('{DATA_MARKERS}', ''), 'https:')
   89             key = self._search_regex(
   90                 r'/key=(.*?)%2Cend=', encrypted_url, 'key', default=None)
   91             if not key:
   92                 return encrypted_url
   93             return encrypted_url.replace(key, decrypt_key(key))
   94 
   95         formats = []
   96         for format_id, video_url in video.items():
   97             if not video_url:
   98                 continue
   99             height = self._search_regex(
  100                 r'^(\d+)[pP]$', format_id, 'height', default=None)
  101             if not height:
  102                 continue
  103             formats.append({
  104                 'url': decrypt_url(video_url),
  105                 'format_id': format_id,
  106                 'height': int(height),
  107             })
  108         self._sort_formats(formats)
  109 
  110         title = video['title']
  111         video_id = video.get('id') or video_id
  112         display_id = video.get('code')
  113         description = video.get('desc')
  114 
  115         timestamp = parse_iso8601(video.get('date'), ' ')
  116         duration = int_or_none(video.get('duration'))
  117 
  118         tags = [tag.strip() for tag in video['tags'].split(',')] if video.get('tags') else None
  119 
  120         return {
  121             'id': video_id,
  122             'display_id': display_id,
  123             'title': title,
  124             'description': description,
  125             'timestamp': timestamp,
  126             'duration': duration,
  127             'tags': tags,
  128             'formats': formats,
  129             'age_limit': self._rta_search(webpage),
  130         }

Generated by cgit