[youtube] Fix extraction.
[youtube-dl] / youtube_dl / extractor / kakao.py
index 0caa41e9e275a6377c35f59a496de09cd14f2e52..32935bb283bfda6273c3eccf0f98fc6fb02f3e84 100644 (file)
@@ -3,16 +3,18 @@
 from __future__ import unicode_literals
 
 from .common import InfoExtractor
+from ..compat import compat_str
 from ..utils import (
     int_or_none,
-    compat_str,
+    strip_or_none,
     unified_timestamp,
+    update_url_query,
 )
 
 
 class KakaoIE(InfoExtractor):
-    _VALID_URL = r'https?://tv.kakao.com/channel/(?P<channel>\d+)/cliplink/(?P<id>\d+)'
-    IE_NAME = 'kakao.com'
+    _VALID_URL = r'https?://(?:play-)?tv\.kakao\.com/(?:channel/\d+|embed/player)/cliplink/(?P<id>\d+|[^?#&]+@my)'
+    _API_BASE_TMPL = 'http://tv.kakao.com/api/v1/ft/cliplinks/%s/'
 
     _TESTS = [{
         'url': 'http://tv.kakao.com/channel/2671005/cliplink/301965083',
@@ -35,7 +37,7 @@ class KakaoIE(InfoExtractor):
             'description': '러블리즈 - Destiny (나의 지구) (Lovelyz - Destiny)\r\n\r\n[쇼! 음악중심] 20160611, 507회',
             'title': '러블리즈 - Destiny (나의 지구) (Lovelyz - Destiny)',
             'uploader_id': 2653210,
-            'uploader': '쇼 음악중심',
+            'uploader': '쇼! 음악중심',
             'timestamp': 1485684628,
             'upload_date': '20170129',
         }
@@ -43,67 +45,59 @@ class KakaoIE(InfoExtractor):
 
     def _real_extract(self, url):
         video_id = self._match_id(url)
+        display_id = video_id.rstrip('@my')
+        api_base = self._API_BASE_TMPL % video_id
+
+        player_header = {
+            'Referer': update_url_query(
+                'http://tv.kakao.com/embed/player/cliplink/%s' % video_id, {
+                    'service': 'kakao_tv',
+                    'autoplay': '1',
+                    'profile': 'HIGH',
+                    'wmode': 'transparent',
+                })
+        }
 
-        player_url = 'http://tv.kakao.com/embed/player/cliplink/' + video_id + \
-            '?service=kakao_tv&autoplay=1&profile=HIGH&wmode=transparent'
-        player_header = {'Referer': player_url}
+        query = {
+            'player': 'monet_html5',
+            'referer': url,
+            'uuid': '',
+            'service': 'kakao_tv',
+            'section': '',
+            'dteType': 'PC',
+            'fields': ','.join([
+                '-*', 'tid', 'clipLink', 'displayTitle', 'clip', 'title',
+                'description', 'channelId', 'createTime', 'duration', 'playCount',
+                'likeCount', 'commentCount', 'tagList', 'channel', 'name',
+                'clipChapterThumbnailList', 'thumbnailUrl', 'timeInSec', 'isDefault',
+                'videoOutputList', 'width', 'height', 'kbps', 'profile', 'label'])
+        }
 
         impress = self._download_json(
-            'http://tv.kakao.com/api/v1/ft/cliplinks/%s/impress' % video_id,
-            video_id, 'Downloading video info',
-            query={
-                'player': 'monet_html5',
-                'referer': url,
-                'uuid': '',
-                'service': 'kakao_tv',
-                'section': '',
-                'dteType': 'PC',
-                'fields': 'clipLink,clip,channel,hasPlusFriend,-service,-tagList'
-            }, headers=player_header)
-
-        clipLink = impress['clipLink']
-        clip = clipLink['clip']
-
-        video_info = {
-            'id': video_id,
-            'title': clip['title'],
-            'description': clip.get('description'),
-            'uploader': clipLink.get('channel', {}).get('name'),
-            'uploader_id': clipLink.get('channelId'),
-            'duration': int_or_none(clip.get('duration')),
-            'view_count': int_or_none(clip.get('playCount')),
-            'like_count': int_or_none(clip.get('likeCount')),
-            'comment_count': int_or_none(clip.get('commentCount')),
-        }
+            api_base + 'impress', display_id, 'Downloading video info',
+            query=query, headers=player_header)
+
+        clip_link = impress['clipLink']
+        clip = clip_link['clip']
 
-        tid = impress.get('tid', '')
-        raw = self._download_json(
-            'http://tv.kakao.com/api/v1/ft/cliplinks/%s/raw' % video_id,
-            video_id, 'Downloading video formats info',
-            query={
-                'player': 'monet_html5',
-                'referer': url,
-                'uuid': '',
-                'service': 'kakao_tv',
-                'section': '',
-                'tid': tid,
-                'profile': 'HIGH',
-                'dteType': 'PC',
-            }, headers=player_header, fatal=False)
+        title = clip.get('title') or clip_link.get('displayTitle')
+
+        query['tid'] = impress.get('tid', '')
 
         formats = []
-        for fmt in raw.get('outputList', []):
+        for fmt in clip.get('videoOutputList', []):
             try:
                 profile_name = fmt['profile']
+                if profile_name == 'AUDIO':
+                    continue
+                query.update({
+                    'profile': profile_name,
+                    'fields': '-*,url',
+                })
                 fmt_url_json = self._download_json(
-                    'http://tv.kakao.com/api/v1/ft/cliplinks/%s/raw/videolocation' % video_id,
-                    video_id, 'Downloading video URL for profile %s' % profile_name,
-                    query={
-                        'service': 'kakao_tv',
-                        'section': '',
-                        'tid': tid,
-                        'profile': profile_name
-                    }, headers=player_header, fatal=False)
+                    api_base + 'raw/videolocation', display_id,
+                    'Downloading video URL for profile %s' % profile_name,
+                    query=query, headers=player_header, fatal=False)
 
                 if fmt_url_json is None:
                     continue
@@ -115,15 +109,13 @@ class KakaoIE(InfoExtractor):
                     'width': int_or_none(fmt.get('width')),
                     'height': int_or_none(fmt.get('height')),
                     'format_note': fmt.get('label'),
-                    'filesize': int_or_none(fmt.get('filesize'))
+                    'filesize': int_or_none(fmt.get('filesize')),
+                    'tbr': int_or_none(fmt.get('kbps')),
                 })
             except KeyError:
                 pass
-
         self._sort_formats(formats)
-        video_info['formats'] = formats
 
-        top_thumbnail = clip.get('thumbnailUrl')
         thumbs = []
         for thumb in clip.get('clipChapterThumbnailList', []):
             thumbs.append({
@@ -131,10 +123,25 @@ class KakaoIE(InfoExtractor):
                 'id': compat_str(thumb.get('timeInSec')),
                 'preference': -1 if thumb.get('isDefault') else 0
             })
-        video_info['thumbnail'] = top_thumbnail
-        video_info['thumbnails'] = thumbs
-
-        upload_date = unified_timestamp(clipLink.get('createTime'))
-        video_info['timestamp'] = upload_date
+        top_thumbnail = clip.get('thumbnailUrl')
+        if top_thumbnail:
+            thumbs.append({
+                'url': top_thumbnail,
+                'preference': 10,
+            })
 
-        return video_info
+        return {
+            'id': display_id,
+            'title': title,
+            'description': strip_or_none(clip.get('description')),
+            'uploader': clip_link.get('channel', {}).get('name'),
+            'uploader_id': clip_link.get('channelId'),
+            'thumbnails': thumbs,
+            'timestamp': unified_timestamp(clip_link.get('createTime')),
+            'duration': int_or_none(clip.get('duration')),
+            'view_count': int_or_none(clip.get('playCount')),
+            'like_count': int_or_none(clip.get('likeCount')),
+            'comment_count': int_or_none(clip.get('commentCount')),
+            'formats': formats,
+            'tags': clip.get('tagList'),
+        }