[picarto] Add new extractor, Picarto.TV
This commit is contained in:
parent
8a8cc339b6
commit
f2d5dc6bde
1
youtube_dl/extractor/extractors.py
Normal file → Executable file
1
youtube_dl/extractor/extractors.py
Normal file → Executable file
@ -740,6 +740,7 @@ from .periscope import (
|
|||||||
from .philharmoniedeparis import PhilharmonieDeParisIE
|
from .philharmoniedeparis import PhilharmonieDeParisIE
|
||||||
from .phoenix import PhoenixIE
|
from .phoenix import PhoenixIE
|
||||||
from .photobucket import PhotobucketIE
|
from .photobucket import PhotobucketIE
|
||||||
|
from .picarto import PicartoIE
|
||||||
from .piksel import PikselIE
|
from .piksel import PikselIE
|
||||||
from .pinkbike import PinkbikeIE
|
from .pinkbike import PinkbikeIE
|
||||||
from .pladform import PladformIE
|
from .pladform import PladformIE
|
||||||
|
80
youtube_dl/extractor/picarto.py
Executable file
80
youtube_dl/extractor/picarto.py
Executable file
@ -0,0 +1,80 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import ExtractorError
|
||||||
|
from ..compat import compat_str
|
||||||
|
|
||||||
|
|
||||||
|
class PicartoIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?picarto\.tv/(?P<id>[a-zA-Z0-9]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://picarto.tv/setz',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'Setz',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 're:^Setz [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$', # match self._live_title
|
||||||
|
'timestamp': int,
|
||||||
|
'is_live': True
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
# Livestream
|
||||||
|
'skip_download': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_PLACESTREAM_REGEX = r'''(?x)
|
||||||
|
placeStream\(
|
||||||
|
"(?P<channel>[a-zA-Z0-9]+)",
|
||||||
|
(?P<player_id>\d+),
|
||||||
|
(?P<product>\d+),
|
||||||
|
(?P<offline_image>\d+),
|
||||||
|
(?P<online>\d+),
|
||||||
|
"(?P<token>.+?)",
|
||||||
|
"(?P<tech>.+?)",
|
||||||
|
(?P<viewer>\d+)\ *
|
||||||
|
\);
|
||||||
|
'''.replace(r',', r',\ *')
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
url_channel_id = self._match_id(url)
|
||||||
|
stream_page = self._download_webpage('https://picarto.tv/' + url_channel_id, url_channel_id, note="Downloading channel page")
|
||||||
|
|
||||||
|
# Handle nonexistent channels
|
||||||
|
if 'This channel does not exist.' in stream_page:
|
||||||
|
raise ExtractorError("Channel does not exist", expected=True)
|
||||||
|
|
||||||
|
# Grab all relevant stream info
|
||||||
|
placestream_m = re.search(self._PLACESTREAM_REGEX, stream_page)
|
||||||
|
|
||||||
|
if not placestream_m:
|
||||||
|
raise ExtractorError("Unable to fetch channel info")
|
||||||
|
elif int(placestream_m.group('online')) == 0:
|
||||||
|
raise ExtractorError("Stream is offline", expected=True)
|
||||||
|
|
||||||
|
channel_id = placestream_m.group('channel')
|
||||||
|
player_id = placestream_m.group('player_id')
|
||||||
|
token = placestream_m.group('token')
|
||||||
|
|
||||||
|
# Ask for stream host
|
||||||
|
post_body = ('loadbalancinginfo=' + channel_id).encode('utf-8')
|
||||||
|
load_balancing_info = self._download_webpage('https://picarto.tv/process/channel', channel_id, data=post_body, note="Fetching load balancer info")
|
||||||
|
|
||||||
|
if not load_balancing_info or load_balancing_info in ('FULL', 'failedGetIP'):
|
||||||
|
raise ExtractorError("Unable to get stream")
|
||||||
|
|
||||||
|
timestamp = time.time()
|
||||||
|
|
||||||
|
video_url = "https://%s-%s/mp4/%s.mp4?token=%s&ts=%s" % (player_id, load_balancing_info,
|
||||||
|
channel_id, token, compat_str(int(timestamp * 1000)))
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': channel_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': self._live_title(channel_id),
|
||||||
|
'timestamp': int(timestamp),
|
||||||
|
'is_live': True
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user