2022-04-17 16:58:28 -04:00
|
|
|
import contextlib
|
2021-06-21 13:23:17 -04:00
|
|
|
import os
|
|
|
|
import signal
|
|
|
|
import threading
|
|
|
|
|
|
|
|
from .common import FileDownloader
|
|
|
|
from .external import FFmpegFD
|
2022-02-04 08:37:02 -05:00
|
|
|
from ..compat import asyncio
|
2022-04-20 15:05:57 -04:00
|
|
|
from ..dependencies import websockets
|
2021-06-21 13:23:17 -04:00
|
|
|
|
|
|
|
|
|
|
|
class FFmpegSinkFD(FileDownloader):
|
|
|
|
""" A sink to ffmpeg for downloading fragments in any form """
|
|
|
|
|
|
|
|
def real_download(self, filename, info_dict):
|
|
|
|
info_copy = info_dict.copy()
|
|
|
|
info_copy['url'] = '-'
|
|
|
|
|
|
|
|
async def call_conn(proc, stdin):
|
|
|
|
try:
|
|
|
|
await self.real_connection(stdin, info_dict)
|
|
|
|
except (BrokenPipeError, OSError):
|
|
|
|
pass
|
|
|
|
finally:
|
2022-04-17 16:58:28 -04:00
|
|
|
with contextlib.suppress(OSError):
|
2021-06-21 13:23:17 -04:00
|
|
|
stdin.flush()
|
|
|
|
stdin.close()
|
|
|
|
os.kill(os.getpid(), signal.SIGINT)
|
|
|
|
|
|
|
|
class FFmpegStdinFD(FFmpegFD):
|
|
|
|
@classmethod
|
|
|
|
def get_basename(cls):
|
|
|
|
return FFmpegFD.get_basename()
|
|
|
|
|
|
|
|
def on_process_started(self, proc, stdin):
|
|
|
|
thread = threading.Thread(target=asyncio.run, daemon=True, args=(call_conn(proc, stdin), ))
|
|
|
|
thread.start()
|
|
|
|
|
|
|
|
return FFmpegStdinFD(self.ydl, self.params or {}).download(filename, info_copy)
|
|
|
|
|
|
|
|
async def real_connection(self, sink, info_dict):
|
|
|
|
""" Override this in subclasses """
|
|
|
|
raise NotImplementedError('This method must be implemented by subclasses')
|
|
|
|
|
|
|
|
|
|
|
|
class WebSocketFragmentFD(FFmpegSinkFD):
|
|
|
|
async def real_connection(self, sink, info_dict):
|
|
|
|
async with websockets.connect(info_dict['url'], extra_headers=info_dict.get('http_headers', {})) as ws:
|
|
|
|
while True:
|
|
|
|
recv = await ws.recv()
|
|
|
|
if isinstance(recv, str):
|
|
|
|
recv = recv.encode('utf8')
|
|
|
|
sink.write(recv)
|