[facebook] add support for watchparty pages(closes #27507)
This commit is contained in:
parent
79dd92b1fe
commit
ecaa535cf4
|
@ -1,6 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ from .common import InfoExtractor
|
||||||
from ..compat import (
|
from ..compat import (
|
||||||
compat_etree_fromstring,
|
compat_etree_fromstring,
|
||||||
compat_http_client,
|
compat_http_client,
|
||||||
|
compat_str,
|
||||||
compat_urllib_error,
|
compat_urllib_error,
|
||||||
compat_urllib_parse_unquote,
|
compat_urllib_parse_unquote,
|
||||||
compat_urllib_parse_unquote_plus,
|
compat_urllib_parse_unquote_plus,
|
||||||
|
@ -47,7 +49,8 @@ class FacebookIE(InfoExtractor):
|
||||||
)\?(?:.*?)(?:v|video_id|story_fbid)=|
|
)\?(?:.*?)(?:v|video_id|story_fbid)=|
|
||||||
[^/]+/videos/(?:[^/]+/)?|
|
[^/]+/videos/(?:[^/]+/)?|
|
||||||
[^/]+/posts/|
|
[^/]+/posts/|
|
||||||
groups/[^/]+/permalink/
|
groups/[^/]+/permalink/|
|
||||||
|
watchparty/
|
||||||
)|
|
)|
|
||||||
facebook:
|
facebook:
|
||||||
)
|
)
|
||||||
|
@ -280,8 +283,18 @@ class FacebookIE(InfoExtractor):
|
||||||
# data.video.creation_story.attachments[].media
|
# data.video.creation_story.attachments[].media
|
||||||
'url': 'https://www.facebook.com/watch/live/?v=1823658634322275',
|
'url': 'https://www.facebook.com/watch/live/?v=1823658634322275',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.facebook.com/watchparty/211641140192478',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '211641140192478',
|
||||||
|
},
|
||||||
|
'playlist_count': 1,
|
||||||
|
'skip': 'Requires logging in',
|
||||||
}]
|
}]
|
||||||
_SUPPORTED_PAGLETS_REGEX = r'(?:pagelet_group_mall|permalink_video_pagelet|hyperfeed_story_id_[0-9a-f]+)'
|
_SUPPORTED_PAGLETS_REGEX = r'(?:pagelet_group_mall|permalink_video_pagelet|hyperfeed_story_id_[0-9a-f]+)'
|
||||||
|
_api_config = {
|
||||||
|
'graphURI': '/api/graphql/'
|
||||||
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_urls(webpage):
|
def _extract_urls(webpage):
|
||||||
|
@ -405,6 +418,17 @@ class FacebookIE(InfoExtractor):
|
||||||
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
def extract_relay_data(_filter):
|
||||||
|
return self._parse_json(self._search_regex(
|
||||||
|
r'handleWithCustomApplyEach\([^,]+,\s*({.*?%s.*?})\);' % _filter,
|
||||||
|
webpage, 'replay data', default='{}'), video_id, fatal=False) or {}
|
||||||
|
|
||||||
|
def extract_relay_prefetched_data(_filter):
|
||||||
|
replay_data = extract_relay_data(_filter)
|
||||||
|
for require in (replay_data.get('require') or []):
|
||||||
|
if require[0] == 'RelayPrefetchedStreamCache':
|
||||||
|
return try_get(require, lambda x: x[3][1]['__bbox']['result']['data'], dict) or {}
|
||||||
|
|
||||||
if not video_data:
|
if not video_data:
|
||||||
server_js_data = self._parse_json(self._search_regex([
|
server_js_data = self._parse_json(self._search_regex([
|
||||||
r'bigPipe\.onPageletArrive\(({.+?})\)\s*;\s*}\s*\)\s*,\s*["\']onPageletArrive\s+' + self._SUPPORTED_PAGLETS_REGEX,
|
r'bigPipe\.onPageletArrive\(({.+?})\)\s*;\s*}\s*\)\s*,\s*["\']onPageletArrive\s+' + self._SUPPORTED_PAGLETS_REGEX,
|
||||||
|
@ -413,11 +437,9 @@ class FacebookIE(InfoExtractor):
|
||||||
video_data = extract_from_jsmods_instances(server_js_data)
|
video_data = extract_from_jsmods_instances(server_js_data)
|
||||||
|
|
||||||
if not video_data:
|
if not video_data:
|
||||||
graphql_data = self._parse_json(self._search_regex(
|
data = extract_relay_prefetched_data(
|
||||||
r'handleWithCustomApplyEach\([^,]+,\s*({.*?"(?:dash_manifest|playable_url(?:_quality_hd)?)"\s*:\s*"[^"]+".*?})\);',
|
r'"(?:dash_manifest|playable_url(?:_quality_hd)?)"\s*:\s*"[^"]+"')
|
||||||
webpage, 'graphql data', default='{}'), video_id, fatal=False) or {}
|
if data:
|
||||||
for require in (graphql_data.get('require') or []):
|
|
||||||
if require[0] == 'RelayPrefetchedStreamCache':
|
|
||||||
entries = []
|
entries = []
|
||||||
|
|
||||||
def parse_graphql_video(video):
|
def parse_graphql_video(video):
|
||||||
|
@ -459,8 +481,6 @@ class FacebookIE(InfoExtractor):
|
||||||
if media.get('__typename') == 'Video':
|
if media.get('__typename') == 'Video':
|
||||||
return parse_graphql_video(media)
|
return parse_graphql_video(media)
|
||||||
|
|
||||||
data = try_get(require, lambda x: x[3][1]['__bbox']['result']['data'], dict) or {}
|
|
||||||
|
|
||||||
nodes = data.get('nodes') or []
|
nodes = data.get('nodes') or []
|
||||||
node = data.get('node') or {}
|
node = data.get('node') or {}
|
||||||
if not nodes and node:
|
if not nodes and node:
|
||||||
|
@ -504,6 +524,43 @@ class FacebookIE(InfoExtractor):
|
||||||
elif '>You must log in to continue' in webpage:
|
elif '>You must log in to continue' in webpage:
|
||||||
self.raise_login_required()
|
self.raise_login_required()
|
||||||
|
|
||||||
|
if not video_data and '/watchparty/' in url:
|
||||||
|
post_data = {
|
||||||
|
'doc_id': 3731964053542869,
|
||||||
|
'variables': json.dumps({
|
||||||
|
'livingRoomID': video_id,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
prefetched_data = extract_relay_prefetched_data(r'"login_data"\s*:\s*{')
|
||||||
|
if prefetched_data:
|
||||||
|
lsd = try_get(prefetched_data, lambda x: x['login_data']['lsd'], dict)
|
||||||
|
if lsd:
|
||||||
|
post_data[lsd['name']] = lsd['value']
|
||||||
|
|
||||||
|
relay_data = extract_relay_data(r'\[\s*"RelayAPIConfigDefaults"\s*,')
|
||||||
|
for define in (relay_data.get('define') or []):
|
||||||
|
if define[0] == 'RelayAPIConfigDefaults':
|
||||||
|
self._api_config = define[2]
|
||||||
|
|
||||||
|
living_room = self._download_json(
|
||||||
|
urljoin(url, self._api_config['graphURI']), video_id,
|
||||||
|
data=urlencode_postdata(post_data))['data']['living_room']
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for edge in (try_get(living_room, lambda x: x['recap']['watched_content']['edges']) or []):
|
||||||
|
video = try_get(edge, lambda x: x['node']['video']) or {}
|
||||||
|
v_id = video.get('id')
|
||||||
|
if not v_id:
|
||||||
|
continue
|
||||||
|
v_id = compat_str(v_id)
|
||||||
|
entries.append(self.url_result(
|
||||||
|
self._VIDEO_PAGE_TEMPLATE % v_id,
|
||||||
|
self.ie_key(), v_id, video.get('name')))
|
||||||
|
|
||||||
|
return self.playlist_result(entries, video_id)
|
||||||
|
|
||||||
|
if not video_data:
|
||||||
# Video info not in first request, do a secondary request using
|
# Video info not in first request, do a secondary request using
|
||||||
# tahoe player specific URL
|
# tahoe player specific URL
|
||||||
tahoe_data = self._download_webpage(
|
tahoe_data = self._download_webpage(
|
||||||
|
|
Loading…
Reference in New Issue