video_downloader_service/src/core/master_service.py

78 lines
2.8 KiB
Python
Raw Normal View History

import asyncio
import concurrent.futures as pool
2023-08-24 03:28:55 +03:00
from functools import partial
from fastapi import HTTPException
2023-08-24 16:45:55 +03:00
from src.core.rabbitmq import get_messages
from src.core.result import Result, ResultTypeEnum
from src.core.ydl import VideoDownloader
from src.exceptions.download_exceptions import SiteNotImplementedException
2023-08-24 03:28:55 +03:00
class MasterService:
def __init__(self):
2023-08-24 16:45:55 +03:00
self.loop = asyncio.get_event_loop()
2023-08-24 03:28:55 +03:00
self.MAX_EXECUTOR_WORKERS = 8
2023-08-24 16:45:55 +03:00
self.executor = pool.ProcessPoolExecutor(max_workers=self.MAX_EXECUTOR_WORKERS,
initializer=executor_initializer)
2023-08-24 03:28:55 +03:00
self.queue = asyncio.Queue()
self.rabbit_consumer = get_messages
2023-08-24 16:45:55 +03:00
self.currently_underway = {} # contains currently in progress videos
2023-08-24 03:28:55 +03:00
async def run(self):
2023-08-24 16:45:55 +03:00
# TODO add cleanup procedure for existing exector procs
tasks = [self.loop.create_task(self.create_workers()) for i in range(self.MAX_EXECUTOR_WORKERS + 1)]
2023-08-24 03:28:55 +03:00
await asyncio.gather(self.rabbit_consumer(self.queue), *tasks)
2023-08-24 16:45:55 +03:00
async def create_workers(self):
while True:
video_params = await self.queue.get()
self.currently_underway[video_params['link']] = video_params
# TODO save current copy of self.currently_underway to DB\file\etc
download_task = self.loop.run_in_executor(self.executor, partial(
MasterService.video_processing_executor, video_params=video_params
)
)
if download_task.done():
result = download_task.result()
# process result
self.queue.task_done()
@staticmethod
def video_download(video_params: dict):
ydl_opts = {
"format": video_params["format"],
"merge_output_format": video_params["merge_output_format"],
'outtmpl': video_params["outtmpl"],
}
downloader = VideoDownloader(link=video_params["link"], ydl_opts=ydl_opts)
try:
result = downloader.download()
return result
except SiteNotImplementedException as ex:
raise HTTPException(
status_code=400,
detail=ex.message
)
@staticmethod
def video_processing_executor(video_params: dict):
# TODO check if video exists on server etc. Result(type=ResultType.EXISTS, value=False)
try:
MasterService.video_download(video_params=video_params)
return Result(result_type=ResultTypeEnum.DONE)
except Exception as ex:
return Result(result_type=ResultTypeEnum.EXCEPTION, value=ex)
# TODO upload to server
def executor_initializer():
import setproctitle
setproctitle.setproctitle(f'video_downloader_executor_process')
return True