mirror of
https://github.com/l1ving/youtube-dl
synced 2025-03-13 22:07:17 +08:00
187 lines
7.1 KiB
Python
187 lines
7.1 KiB
Python
# coding: utf-8
|
|
from __future__ import unicode_literals
|
|
|
|
import json
|
|
import re
|
|
|
|
from .common import InfoExtractor
|
|
from ..utils import (
|
|
int_or_none,
|
|
ExtractorError,
|
|
)
|
|
|
|
|
|
class StreamMeIE(InfoExtractor):
|
|
IE_NAME = 'StreamMe:video'
|
|
_API_CHANNEL = 'https://www.stream.me/api-user/v1/%s/channel'
|
|
_API_ARCHIVE = 'https://www.stream.me/api-vod/v1/%s/archives'
|
|
_VALID_URL_BASE = r'https?://(video-cdn|www).stream.me'
|
|
_VALID_URL = r'%s/archive\/(?P<channel_id>[^\#/]+)/[^\/]+/(?P<id>[^/]+)' % _VALID_URL_BASE
|
|
_TEST = {
|
|
'url': 'https://www.stream.me/archive/kombatcup/kombat-cup-week-8-sunday-open/pDlXAj6mYb',
|
|
'md5': 'b32af6fad972d0bcf5854a416b5b3b01',
|
|
'info_dict': {
|
|
'id': 'pDlXAj6mYb',
|
|
'ext': 'mp4',
|
|
'title': 'Kombat Cup Week #8 - Sunday Open',
|
|
'uploader': 'KombatCup',
|
|
'uploader_id': 'kombatcup',
|
|
'timestamp': 1481512102000,
|
|
'age_limit': 13,
|
|
}
|
|
}
|
|
|
|
def _real_extract(self, url):
|
|
m = re.match(self._VALID_URL, url)
|
|
video_id = self._match_id(url)
|
|
apiurl = self._API_ARCHIVE % m.group('channel_id')
|
|
|
|
data = self._download_json(apiurl, video_id)
|
|
|
|
for vod in data['_embedded']['vod']:
|
|
vod_info = []
|
|
if vod.get('urlId') == video_id:
|
|
vod_info = vod
|
|
break
|
|
|
|
manifest_json = self._download_json(vod_info['_links']['manifest']['href'],
|
|
video_id, note='Downloading video manifest')
|
|
|
|
formats = self._extract_formats(manifest_json.get('formats'))
|
|
self._sort_formats(formats, 'vbr')
|
|
info = self._extract_info(vod_info)
|
|
info['formats'] = formats
|
|
return info
|
|
|
|
def _extract_info(self, info):
|
|
return {
|
|
'id': info.get('urlId') or info.get('publicId'),
|
|
# 'formats': self.formats,
|
|
'title': info.get('title') or 'Untitled Broadcast',
|
|
'age_limit': int_or_none(info.get('ageRating')),
|
|
'description': info.get('description'),
|
|
'dislike_count': int_or_none(info.get('stats').get('raw').get('dislikes')),
|
|
'display_id': info.get('titleSlug'),
|
|
'duration': int_or_none(info.get('duration')),
|
|
'like_count': int_or_none(info.get('stats').get('raw').get('likes')),
|
|
'thumbnail': info.get('_links').get('thumbnail').get('href'),
|
|
'timestamp': info.get('whenCreated'),
|
|
'uploader': info.get('username'),
|
|
'uploader_id': info.get('userSlug'),
|
|
'view_count': int_or_none(info.get('stats').get('raw').get('views')),
|
|
'is_live': True if info.get('active') else False,
|
|
}
|
|
|
|
def _extract_formats(self, fmts):
|
|
formats = []
|
|
for fmt_tag, d in fmts.items():
|
|
# skip websocket and mjpeg we can't handle them anyway
|
|
if fmt_tag in ('mjpeg-lodef', 'mp4-ws',):
|
|
continue
|
|
for fmt_info in d.get('encodings'):
|
|
formats.append({
|
|
'url': fmt_info.get('location'),
|
|
'width': int_or_none(fmt_info.get('videoWidth')),
|
|
'height': int_or_none(fmt_info.get('videoHeight')),
|
|
'vbr': int_or_none(fmt_info.get('videoKbps')),
|
|
'abr': int_or_none(fmt_info.get('audioKbps')),
|
|
'acodec': d.get('audioCodec'),
|
|
'vcodec': d.get('videoCodec'),
|
|
'format_id': "%s%sp" % (fmt_tag, fmt_info.get('videoHeight')),
|
|
'ext': 'flv' if fmt_tag.split('-')[1] == 'rtmp' else 'mp4',
|
|
# I don't know all the possible protocols yet.
|
|
# 'protocol': 'm3u8_native' if fmt_tag == 'mp4-hls' else 'http'
|
|
})
|
|
if d.get('origin') is not None:
|
|
fmt_tag = d.get('origin').get('location').split(':')[0]
|
|
formats.append({
|
|
'url': d.get('origin').get('location'),
|
|
'acodec': d.get('origin').get('audioCodec'),
|
|
'vcodec': d.get('origin').get('videoCodec'),
|
|
'format_id': 'Source-' + fmt_tag,
|
|
'ext': 'flv' if fmt_tag == 'rtmp' else 'mp4',
|
|
'source_preference': 1,
|
|
})
|
|
return formats
|
|
|
|
|
|
class StreamMeLiveIE(StreamMeIE):
|
|
IE_NAME = 'StreamIE:live'
|
|
_VALID_URL = r'%s\/(?P<id>[^\#\/]+$)' % StreamMeIE._VALID_URL_BASE
|
|
_TEST = {
|
|
'url': 'https://www.stream.me/kombatcup',
|
|
'info_dict': {
|
|
'id': '1246a915-eebe-4ffe-b12e-e4f5332abc4d',
|
|
'ext': 'mp4',
|
|
'title': 'KombatCup\'s Live Stream',
|
|
'age_limit': 13,
|
|
'uploader_id': 'kombatcup',
|
|
'uploader': 'KombatCup',
|
|
'like_count': int,
|
|
'dislike_count': int,
|
|
'is_live': True,
|
|
},
|
|
'params': {
|
|
# m3u8 download
|
|
'skip_download': True,
|
|
},
|
|
}
|
|
|
|
def _real_extract(self, url):
|
|
channel_id = self._match_id(url)
|
|
apiurl = StreamMeIE._API_CHANNEL % channel_id
|
|
|
|
data = json.loads(self._download_webpage(apiurl, channel_id))
|
|
stream_info = []
|
|
# search for a live stream...
|
|
for stream in data.get('_embedded').get('streams'):
|
|
stream_info = stream
|
|
break # TODO: add to a list (multi-streams?)
|
|
|
|
if not stream_info.get('active'):
|
|
raise ExtractorError('%s is offline' % channel_id, expected=True)
|
|
|
|
manifest_json = self._download_json(stream_info['_links']['manifest']['href'],
|
|
channel_id, 'Download video manifest')
|
|
|
|
formats = self._extract_formats(manifest_json.get('formats'))
|
|
self._sort_formats(formats, 'vbr')
|
|
info = self._extract_info(stream_info)
|
|
info['formats'] = formats
|
|
return info
|
|
|
|
|
|
class StreamMeArchiveIE(StreamMeIE):
|
|
IE_NAME = 'StreamMe:archives'
|
|
_VALID_URL = r'%s/(?P<id>[^\#]+)(\#archive)$' % StreamMeIE._VALID_URL_BASE
|
|
_PLAYLIST_TYPE = 'past broadcasts'
|
|
_PLAYLIST_LIMIT = 128
|
|
_TEST = {
|
|
'url': 'https://www.stream.me/kombatcup#archive',
|
|
'info_dict': {
|
|
'id': 'kombatcup',
|
|
'title': 'KombatCup',
|
|
},
|
|
'playlist_mincount': 25,
|
|
'params': {
|
|
'skip_download': True,
|
|
}
|
|
}
|
|
|
|
def _real_extract(self, url):
|
|
channel_id = self._match_id(url).split('#')[0]
|
|
apiurl = StreamMeIE._API_ARCHIVE % channel_id
|
|
# TODO: implement paginated downloading
|
|
data = self._download_json(apiurl, channel_id, query={'limit': self._PLAYLIST_LIMIT, 'offset': 0})
|
|
playlist = []
|
|
|
|
for vod in data['_embedded']['vod']:
|
|
manifest_json = self._download_json(vod['_links']['manifest']['href'], vod.get('urlId'))
|
|
formats = self._extract_formats(manifest_json.get('formats'))
|
|
self._sort_formats(formats, 'vbr')
|
|
info = self._extract_info(vod)
|
|
info['formats'] = formats
|
|
playlist.append(info)
|
|
|
|
return self.playlist_result(playlist, channel_id, info.get('uploader'))
|