mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-03-09 12:50:23 -05:00
Merge 6ec0b6cd61
into 05c8023a27
This commit is contained in:
commit
f320578306
2 changed files with 188 additions and 0 deletions
|
@ -1219,6 +1219,7 @@
|
|||
MxplayerIE,
|
||||
MxplayerShowIE,
|
||||
)
|
||||
from .myfreecams import MyFreeCamsIE
|
||||
from .myspace import (
|
||||
MySpaceAlbumIE,
|
||||
MySpaceIE,
|
||||
|
|
187
yt_dlp/extractor/myfreecams.py
Normal file
187
yt_dlp/extractor/myfreecams.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
import random
|
||||
import re
|
||||
import urllib.parse
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..dependencies import websockets
|
||||
from ..utils import ExtractorError
|
||||
|
||||
|
||||
class MyFreeCamsIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?myfreecams\.com/#(?P<id>[^/?&#]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.myfreecams.com/#Elise_wood',
|
||||
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
|
||||
'info_dict': {
|
||||
'id': 'Elise_wood',
|
||||
'ext': 'mp4',
|
||||
'title': r're:Elise_wood',
|
||||
'description': r're:MyFreeCams',
|
||||
'age_limit': 18,
|
||||
'is_live': True,
|
||||
'live_status': str,
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
'skip': 'Model is currently offline',
|
||||
}]
|
||||
|
||||
JS_SERVER_URL = 'https://www.myfreecams.com/_js/serverconfig.js'
|
||||
|
||||
_dict_re = re.compile(r'''(?P<data>{.*})''')
|
||||
_socket_re = re.compile(r'''(\w+) (\w+) (\w+) (\w+) (\w+)''')
|
||||
|
||||
def _get_servers(self):
|
||||
return self._download_json(
|
||||
self.JS_SERVER_URL, self.video_id,
|
||||
headers={
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Accept': 'application/json',
|
||||
}, fatal=False, impersonate=False) or {}
|
||||
|
||||
def _websocket_data(self, username, chat_servers):
|
||||
try_to_connect = 0
|
||||
xchat = None
|
||||
host = None
|
||||
while try_to_connect < 5:
|
||||
try:
|
||||
xchat = str(random.choice(chat_servers))
|
||||
host = f'wss://{xchat}.myfreecams.com/fcsl'
|
||||
ws = websockets.sync.client.connect(host)
|
||||
ws.send('fcsws_20180422\n\0')
|
||||
ws.send('1 0 0 20071025 0 1/guest:guest\n\0')
|
||||
self.write_debug(f'Websocket server {xchat} connected')
|
||||
self.write_debug(f'Websocket URL: {host}')
|
||||
try_to_connect = 5
|
||||
except websockets.exceptions.WebSocketException:
|
||||
try_to_connect += 1
|
||||
self.report_warning(f'Failed to connect to WS server: {xchat} - try {try_to_connect}')
|
||||
if try_to_connect == 5:
|
||||
error = f'Failed to connect to WS server: {host}'
|
||||
raise ExtractorError(error)
|
||||
|
||||
buff = ''
|
||||
php_message = ''
|
||||
ws_close = 0
|
||||
while ws_close == 0:
|
||||
socket_buffer = ws.recv()
|
||||
socket_buffer = buff + socket_buffer
|
||||
buff = ''
|
||||
while True:
|
||||
ws_answer = self._socket_re.search(socket_buffer)
|
||||
if bool(ws_answer) == 0:
|
||||
break
|
||||
|
||||
FC = ws_answer.group(1)
|
||||
FCTYPE = int(FC[6:])
|
||||
|
||||
message_length = int(FC[0:6])
|
||||
message = socket_buffer[6:6 + message_length]
|
||||
|
||||
if len(message) < message_length:
|
||||
buff = ''.join(socket_buffer)
|
||||
break
|
||||
|
||||
message = urllib.parse.unquote(message)
|
||||
|
||||
if FCTYPE == 1 and username:
|
||||
ws.send(f'10 0 0 20 0 {username}\n')
|
||||
elif FCTYPE == 81:
|
||||
php_message = message
|
||||
if username is None:
|
||||
ws_close = 1
|
||||
elif FCTYPE == 10:
|
||||
ws_close = 1
|
||||
|
||||
socket_buffer = socket_buffer[6 + message_length:]
|
||||
|
||||
if len(socket_buffer) == 0:
|
||||
break
|
||||
|
||||
ws.send('99 0 0 0 0')
|
||||
ws.close()
|
||||
return message, php_message
|
||||
|
||||
def _get_camserver(self, servers, key):
|
||||
server_types = ['h5video_servers', 'wzobs_servers', 'ngvideo_servers']
|
||||
for server_type in server_types:
|
||||
if servers[server_type].get(str(key)):
|
||||
return servers[server_type][str(key)], server_type
|
||||
return None, None
|
||||
|
||||
def _get_streams(self, url):
|
||||
self.video_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, self.video_id)
|
||||
|
||||
servers = self._get_servers()
|
||||
chat_servers = servers['chat_servers']
|
||||
|
||||
message, php_message = self._websocket_data(self.video_id, chat_servers)
|
||||
|
||||
self.write_debug('Attempting to use WebSocket data')
|
||||
data = self._search_json(r'(\w+) (\w+) (\w+) (\w+) (\w+)', message, name='ws_data', video_id=self.video_id)
|
||||
if not data:
|
||||
raise ExtractorError('Could not find data in WebSocket message')
|
||||
|
||||
try:
|
||||
vs = data['vs']
|
||||
ok_vs = [0, 90]
|
||||
if vs not in ok_vs:
|
||||
error_messages = {
|
||||
2: 'Model is currently away',
|
||||
12: 'Model is currently in a private show',
|
||||
13: 'Model is currently in a group show',
|
||||
14: 'Model is currently in a club show',
|
||||
127: 'Model is currently offline',
|
||||
}
|
||||
error = error_messages.get(vs, f'Stream status: {vs}')
|
||||
raise ExtractorError(error, expected=True)
|
||||
|
||||
self.write_debug(f'VS: {vs}')
|
||||
|
||||
nm = data['nm']
|
||||
uid = data['uid']
|
||||
uid_video = uid + 100000000
|
||||
camserver = data['u']['camserv']
|
||||
except KeyError:
|
||||
raise ExtractorError('Could not find required data in WebSocket message')
|
||||
|
||||
server, server_type = self._get_camserver(servers, camserver)
|
||||
|
||||
self.write_debug(f'Username: {nm}')
|
||||
self.write_debug(f'User ID: {uid}')
|
||||
|
||||
if not server:
|
||||
raise ExtractorError('Missing video server')
|
||||
|
||||
self.write_debug(f'Video server: {server}')
|
||||
self.write_debug(f'Video server_type: {server_type}')
|
||||
|
||||
if server_type == 'h5video_servers':
|
||||
# DASH_VIDEO_URL = f'https://{server}.myfreecams.com/NxServer/ngrp:mfc_{uid_video}.f4v_desktop/manifest.mpd'
|
||||
HLS_VIDEO_URL = f'https://{server}.myfreecams.com/NxServer/ngrp:mfc_{uid_video}.f4v_mobile/playlist.m3u8'
|
||||
elif server_type == 'wzobs_servers':
|
||||
# DASH_VIDEO_URL = ''
|
||||
HLS_VIDEO_URL = f'https://{server}.myfreecams.com/NxServer/ngrp:mfc_a_{uid_video}.f4v_mobile/playlist.m3u8'
|
||||
elif server_type == 'ngvideo_servers':
|
||||
raise ExtractorError('ngvideo_servers are not supported.')
|
||||
else:
|
||||
raise ExtractorError('Unknow server type.')
|
||||
|
||||
self.write_debug(f'HLS URL: {HLS_VIDEO_URL}')
|
||||
|
||||
return {
|
||||
'id': self.video_id,
|
||||
'title': self._html_extract_title(html=webpage, default=self.video_id),
|
||||
'description': self._html_search_meta('description', webpage, default=None),
|
||||
'formats': self._extract_m3u8_formats(HLS_VIDEO_URL, self.video_id, ext='mp4', live=True),
|
||||
'age_limit': self._rta_search(webpage),
|
||||
'is_live': True,
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
if not websockets:
|
||||
raise ImportError('This extractor needs websockets installed')
|
||||
self.write_debug(self._get_streams(url=url))
|
||||
return self._get_streams(url=url)
|
Loading…
Reference in a new issue