]>
jfr.im git - yt-dlp.git/blob - youtube_dlc/downloader/youtube_live_chat.py
1 from __future__
import division
, unicode_literals
6 from .fragment
import FragmentFD
7 from ..compat
import compat_urllib_error
8 from ..utils
import try_get
9 from ..extractor
.youtube
import YoutubeBaseInfoExtractor
as YT_BaseIE
12 class YoutubeLiveChatReplayFD(FragmentFD
):
13 """ Downloads YouTube live chat replays fragment by fragment """
15 FD_NAME
= 'youtube_live_chat_replay'
17 def real_download(self
, filename
, info_dict
):
18 video_id
= info_dict
['video_id']
19 self
.to_screen('[%s] Downloading live chat' % self
.FD_NAME
)
21 fragment_retries
= self
.params
.get('fragment_retries', 0)
22 test
= self
.params
.get('test', False)
31 headers
= info_dict
.get('http_headers', {})
32 return self
._download
_fragment
(ctx
, url
, info_dict
, headers
)
34 def parse_yt_initial_data(data
):
36 r
'%s\\s*%s' % (YT_BaseIE
._YT
_INITIAL
_DATA
_RE
, YT_BaseIE
._YT
_INITIAL
_BOUNDARY
_RE
),
37 r
'%s' % YT_BaseIE
._YT
_INITIAL
_DATA
_RE
)
38 data
= data
.decode('utf-8', 'replace')
41 raw_json
= re
.search(patt
, data
).group(1)
42 return json
.loads(raw_json
)
43 except AttributeError:
46 def download_and_parse_fragment(url
, frag_index
):
48 while count
<= fragment_retries
:
50 success
, raw_fragment
= dl_fragment(url
)
52 return False, None, None
53 data
= parse_yt_initial_data(raw_fragment
) or json
.loads(raw_fragment
)['response']
55 live_chat_continuation
= try_get(
57 lambda x
: x
['continuationContents']['liveChatContinuation'], dict) or {}
58 offset
= continuation_id
= None
59 processed_fragment
= bytearray()
60 for action
in live_chat_continuation
.get('actions', []):
61 if 'replayChatItemAction' in action
:
62 replay_chat_item_action
= action
['replayChatItemAction']
63 offset
= int(replay_chat_item_action
['videoOffsetTimeMsec'])
64 processed_fragment
.extend(
65 json
.dumps(action
, ensure_ascii
=False).encode('utf-8') + b
'\n')
66 if offset
is not None:
67 continuation_id
= try_get(
68 live_chat_continuation
,
69 lambda x
: x
['continuations'][0]['liveChatReplayContinuationData']['continuation'])
70 self
._append
_fragment
(ctx
, processed_fragment
)
72 return True, continuation_id
, offset
73 except compat_urllib_error
.HTTPError
as err
:
75 if count
<= fragment_retries
:
76 self
.report_retry_fragment(err
, frag_index
, count
, fragment_retries
)
77 if count
> fragment_retries
:
78 self
.report_error('giving up after %s fragment retries' % fragment_retries
)
79 return False, None, None
81 self
._prepare
_and
_start
_frag
_download
(ctx
)
83 success
, raw_fragment
= dl_fragment(
84 'https://www.youtube.com/watch?v={}'.format(video_id
))
87 data
= parse_yt_initial_data(raw_fragment
)
88 continuation_id
= try_get(
90 lambda x
: x
['contents']['twoColumnWatchNextResults']['conversationBar']['liveChatRenderer']['continuations'][0]['reloadContinuationData']['continuation'])
91 # no data yet but required to call _append_fragment
92 self
._append
_fragment
(ctx
, b
'')
94 frag_index
= offset
= 0
95 while continuation_id
is not None:
98 'https://www.youtube.com/live_chat_replay',
99 '/get_live_chat_replay' if frag_index
> 1 else '',
100 '?continuation=%s' % continuation_id
,
101 '&playerOffsetMs=%d&hidden=false&pbj=1' % max(offset
- 5000, 0) if frag_index
> 1 else ''))
102 success
, continuation_id
, offset
= download_and_parse_fragment(url
, frag_index
)
108 self
._finish
_frag
_download
(ctx
)