mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[vlive] Add support for live videos
This commit is contained in:
		| @@ -1,8 +1,11 @@ | ||||
| # coding: utf-8 | ||||
| from __future__ import unicode_literals | ||||
| from __future__ import division, unicode_literals | ||||
|  | ||||
| import re | ||||
| import time | ||||
| from .common import InfoExtractor | ||||
| from ..utils import ( | ||||
|     ExtractorError, | ||||
|     dict_get, | ||||
|     float_or_none, | ||||
|     int_or_none, | ||||
| @@ -31,16 +34,77 @@ class VLiveIE(InfoExtractor): | ||||
|         webpage = self._download_webpage( | ||||
|             'http://www.vlive.tv/video/%s' % video_id, video_id) | ||||
|  | ||||
|         long_video_id = self._search_regex( | ||||
|             r'vlive\.tv\.video\.ajax\.request\.handler\.init\(\s*"[0-9]+"\s*,\s*"[^"]*"\s*,\s*"([^"]+)"', | ||||
|             webpage, 'long video id') | ||||
|         # UTC+x - UTC+9 (KST) | ||||
|         tz = time.altzone if time.localtime().tm_isdst == 1 else time.timezone | ||||
|         tz_offset = -tz // 60 - 9 * 60 | ||||
|         self._set_cookie('vlive.tv', 'timezoneOffset', '%d' % tz_offset) | ||||
|  | ||||
|         key = self._search_regex( | ||||
|             r'vlive\.tv\.video\.ajax\.request\.handler\.init\(\s*"[0-9]+"\s*,\s*"[^"]*"\s*,\s*"[^"]+"\s*,\s*"([^"]+)"', | ||||
|             webpage, 'key') | ||||
|         status_params = self._download_json( | ||||
|             'http://www.vlive.tv/video/status?videoSeq=%s' % video_id, | ||||
|             video_id, 'Downloading JSON status', | ||||
|             headers={'Referer': url}) | ||||
|         status = status_params.get('status') | ||||
|         air_start = status_params.get('onAirStartAt', '') | ||||
|         is_live = status_params.get('isLive') | ||||
|  | ||||
|         video_params = self._search_regex( | ||||
|             r'vlive\.tv\.video\.ajax\.request\.handler\.init\((.+)\)', | ||||
|             webpage, 'video params') | ||||
|         live_params, long_video_id, key = re.split( | ||||
|             r'"\s*,\s*"', video_params)[1:4] | ||||
|  | ||||
|         if status == 'LIVE_ON_AIR' or status == 'BIG_EVENT_ON_AIR': | ||||
|             live_params = self._parse_json('"%s"' % live_params, video_id) | ||||
|             live_params = self._parse_json(live_params, video_id) | ||||
|             return self._live(video_id, webpage, live_params) | ||||
|         elif status == 'VOD_ON_AIR' or status == 'BIG_EVENT_INTRO': | ||||
|             if long_video_id and key: | ||||
|                 return self._replay(video_id, webpage, long_video_id, key) | ||||
|             elif is_live: | ||||
|                 status = 'LIVE_END' | ||||
|             else: | ||||
|                 status = 'COMING_SOON' | ||||
|  | ||||
|         if status == 'LIVE_END': | ||||
|             raise ExtractorError('Uploading for replay. Please wait...', | ||||
|                                  expected=True) | ||||
|         elif status == 'COMING_SOON': | ||||
|             raise ExtractorError('Coming soon! %s' % air_start, expected=True) | ||||
|         elif status == 'CANCELED': | ||||
|             raise ExtractorError('We are sorry, ' | ||||
|                                  'but the live broadcast has been canceled.', | ||||
|                                  expected=True) | ||||
|         else: | ||||
|             raise ExtractorError('Unknown status %s' % status) | ||||
|  | ||||
|     def _get_common_fields(self, webpage): | ||||
|         title = self._og_search_title(webpage) | ||||
|         creator = self._html_search_regex( | ||||
|             r'<div[^>]+class="info_area"[^>]*>\s*<a\s+[^>]*>([^<]+)', | ||||
|             webpage, 'creator', fatal=False) | ||||
|         thumbnail = self._og_search_thumbnail(webpage) | ||||
|         return { | ||||
|             'title': title, | ||||
|             'creator': creator, | ||||
|             'thumbnail': thumbnail, | ||||
|         } | ||||
|  | ||||
|     def _live(self, video_id, webpage, live_params): | ||||
|         formats = [] | ||||
|         for vid in live_params.get('resolutions', []): | ||||
|             formats.extend(self._extract_m3u8_formats( | ||||
|                 vid['cdnUrl'], video_id, 'mp4', | ||||
|                 m3u8_id=vid.get('name'), | ||||
|                 fatal=False, live=True)) | ||||
|         self._sort_formats(formats) | ||||
|  | ||||
|         return dict(self._get_common_fields(webpage), | ||||
|             id=video_id, | ||||
|             formats=formats, | ||||
|             is_live=True, | ||||
|         ) | ||||
|  | ||||
|     def _replay(self, video_id, webpage, long_video_id, key): | ||||
|         playinfo = self._download_json( | ||||
|             'http://global.apis.naver.com/rmcnmv/rmcnmv/vod_play_videoInfo.json?%s' | ||||
|             % compat_urllib_parse_urlencode({ | ||||
| @@ -62,11 +126,6 @@ class VLiveIE(InfoExtractor): | ||||
|         } for vid in playinfo.get('videos', {}).get('list', []) if vid.get('source')] | ||||
|         self._sort_formats(formats) | ||||
|  | ||||
|         thumbnail = self._og_search_thumbnail(webpage) | ||||
|         creator = self._html_search_regex( | ||||
|             r'<div[^>]+class="info_area"[^>]*>\s*<a\s+[^>]*>([^<]+)', | ||||
|             webpage, 'creator', fatal=False) | ||||
|  | ||||
|         view_count = int_or_none(playinfo.get('meta', {}).get('count')) | ||||
|  | ||||
|         subtitles = {} | ||||
| @@ -77,12 +136,9 @@ class VLiveIE(InfoExtractor): | ||||
|                     'ext': 'vtt', | ||||
|                     'url': caption['source']}] | ||||
|  | ||||
|         return { | ||||
|             'id': video_id, | ||||
|             'title': title, | ||||
|             'creator': creator, | ||||
|             'thumbnail': thumbnail, | ||||
|             'view_count': view_count, | ||||
|             'formats': formats, | ||||
|             'subtitles': subtitles, | ||||
|         } | ||||
|         return dict(self._get_common_fields(webpage), | ||||
|             id=video_id, | ||||
|             formats=formats, | ||||
|             view_count=view_count, | ||||
|             subtitles=subtitles, | ||||
|         ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Kagami Hiiragi
					Kagami Hiiragi