]> jfr.im git - yt-dlp.git/blame - yt_dlp/downloader/websocket.py
[compat] Split into sub-modules (#2173)
[yt-dlp.git] / yt_dlp / downloader / websocket.py
CommitLineData
19a03940 1import contextlib
e36d50c5 2import os
3import signal
e36d50c5 4import threading
5
6try:
7 import websockets
1e5d87be 8except (ImportError, SyntaxError):
9 # websockets 3.10 on python 3.6 causes SyntaxError
10 # See https://github.com/yt-dlp/yt-dlp/issues/2633
e36d50c5 11 has_websockets = False
1e5d87be 12else:
13 has_websockets = True
e36d50c5 14
15from .common import FileDownloader
16from .external import FFmpegFD
77f90330 17from ..compat import asyncio
e36d50c5 18
19
20class FFmpegSinkFD(FileDownloader):
21 """ A sink to ffmpeg for downloading fragments in any form """
22
23 def real_download(self, filename, info_dict):
24 info_copy = info_dict.copy()
25 info_copy['url'] = '-'
26
27 async def call_conn(proc, stdin):
28 try:
29 await self.real_connection(stdin, info_dict)
30 except (BrokenPipeError, OSError):
31 pass
32 finally:
19a03940 33 with contextlib.suppress(OSError):
e36d50c5 34 stdin.flush()
35 stdin.close()
e36d50c5 36 os.kill(os.getpid(), signal.SIGINT)
37
38 class FFmpegStdinFD(FFmpegFD):
39 @classmethod
40 def get_basename(cls):
41 return FFmpegFD.get_basename()
42
43 def on_process_started(self, proc, stdin):
44 thread = threading.Thread(target=asyncio.run, daemon=True, args=(call_conn(proc, stdin), ))
45 thread.start()
46
47 return FFmpegStdinFD(self.ydl, self.params or {}).download(filename, info_copy)
48
49 async def real_connection(self, sink, info_dict):
50 """ Override this in subclasses """
51 raise NotImplementedError('This method must be implemented by subclasses')
52
53
54class WebSocketFragmentFD(FFmpegSinkFD):
55 async def real_connection(self, sink, info_dict):
56 async with websockets.connect(info_dict['url'], extra_headers=info_dict.get('http_headers', {})) as ws:
57 while True:
58 recv = await ws.recv()
59 if isinstance(recv, str):
60 recv = recv.encode('utf8')
61 sink.write(recv)