up
This commit is contained in:
		@@ -15,6 +15,7 @@ from src.parsers.MyMail.my_mail_parser import MyMailParser
 | 
				
			|||||||
from src.parsers.Yappy.yappy_parser import YappyParser
 | 
					from src.parsers.Yappy.yappy_parser import YappyParser
 | 
				
			||||||
from src.parsers.base_parser import BaseParser
 | 
					from src.parsers.base_parser import BaseParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: добавить логгер с временными метками в yt-dlp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MasterService:
 | 
					class MasterService:
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,17 +19,14 @@ class VideoDownloader:
 | 
				
			|||||||
        self.ydl_opts = ydl_opts
 | 
					        self.ydl_opts = ydl_opts
 | 
				
			||||||
        self.username = username
 | 
					        self.username = username
 | 
				
			||||||
        self.password = password
 | 
					        self.password = password
 | 
				
			||||||
 | 
					        self.info = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_info(self):
 | 
					    def get_info(self):
 | 
				
			||||||
        with YoutubeDL(self.ydl_opts if self.ydl_opts else {}) as ydl:
 | 
					        with YoutubeDL(self.ydl_opts if self.ydl_opts else {}) as ydl:
 | 
				
			||||||
            return ydl.extract_info(self.link, download=False)
 | 
					            self.info = ydl.extract_info(self.link, download=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def download(self):
 | 
					    def download(self):
 | 
				
			||||||
        domain = urlparse(self.link).netloc
 | 
					        # TODO: удалить все файлы связанные с текущим видео, которые сейчас остались
 | 
				
			||||||
        # if domain not in self.SUPPORTING_WEBSITES:
 | 
					 | 
				
			||||||
        #     raise SiteNotImplementedException
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        with YoutubeDL(self.ydl_opts if self.ydl_opts else {}) as ydl:
 | 
					        with YoutubeDL(self.ydl_opts if self.ydl_opts else {}) as ydl:
 | 
				
			||||||
            ydl.download([self.link])
 | 
					            ydl.download([self.link])
 | 
				
			||||||
            result = ydl.extract_info(self.link, download=False)
 | 
					            return self.info
 | 
				
			||||||
            return result
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,8 @@ class BaseParser:
 | 
				
			|||||||
            "quiet": True
 | 
					            "quiet": True
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        downloader = VideoDownloader(link=self.params["link"], ydl_opts=ydl_opts)
 | 
					        downloader = VideoDownloader(link=self.params["link"], ydl_opts=ydl_opts)
 | 
				
			||||||
        video_info = downloader.get_info()
 | 
					        downloader.get_info()
 | 
				
			||||||
        path_to_video = f"{video_info['extractor_key']}/{video_info['id']}_{video_info['width']}p.{video_info['ext']}"
 | 
					        path_to_video = f"{downloader.info['extractor_key']}/{downloader.info['id']}_{downloader.info['width']}p.{downloader.info['ext']}"
 | 
				
			||||||
        if os.path.exists(os.path.join(os.getcwd() + "/downloads/" + path_to_video)):
 | 
					        if os.path.exists(os.path.join(os.getcwd() + "/downloads/" + path_to_video)):
 | 
				
			||||||
            raise FileAlreadyExistException(message=path_to_video)
 | 
					            raise FileAlreadyExistException(message=path_to_video)
 | 
				
			||||||
        downloader.ydl_opts["quiet"] = False
 | 
					        downloader.ydl_opts["quiet"] = False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,20 +47,33 @@ async def is_task_already_done_or_exist(redis: RedisClient, link: str):
 | 
				
			|||||||
async def index(request: Request):
 | 
					async def index(request: Request):
 | 
				
			||||||
    return templates.TemplateResponse("index.html", {"request": request})
 | 
					    return templates.TemplateResponse("index.html", {"request": request})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
@app.post('/submit/')
 | 
					@app.post('/submit/')
 | 
				
			||||||
async def get_url_for_download_video(request: Request, data: SubmitIn = Depends()):
 | 
					async def get_url_for_download_video(request: Request, data: SubmitIn = Depends()):
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    TODO:
 | 
				
			||||||
 | 
					    Сабмит должен проверить что задача может быть уже выполненой (отдать ссылку в ответе) 
 | 
				
			||||||
 | 
					        или ещё в работе (сообщить об этом в ответе, можно вывести на форму, что такая ссылка уже скачивается, ожидайте)
 | 
				
			||||||
 | 
					    Если условия выше провалены, то мы делаем новую задачу в очередь с переданными параметрами и сообщаем об этом клиенту с кодом (200 или 201)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Дополнительно, нужен отдельный метод (ури), который позволит получать статус задачи. Опрашиваться примерно раз в 5с, 
 | 
				
			||||||
 | 
					    возможны увелечения тайминга в зависимости от ответа апи (на будущее)
 | 
				
			||||||
 | 
					    Варианты ответа
 | 
				
			||||||
 | 
					    1) такой задачи нет (404)
 | 
				
			||||||
 | 
					    2) такая задача есть и выполняется (200 ли?)
 | 
				
			||||||
 | 
					    3) такая задача есть и завершена (200 и выдать ссылку на загрузку)
 | 
				
			||||||
 | 
					    4) такая задача есть и завершена, но с ошибкой (500 и сообщение о том, что можно попробовать выполнить задачу занов, 
 | 
				
			||||||
 | 
					                                                    попутно удалив задачу из выполненых, с очисткой мусора за ней)
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
    red = RedisClient()
 | 
					    red = RedisClient()
 | 
				
			||||||
    task_done = await is_task_already_done_or_exist(red, data.link)
 | 
					    task_done = await is_task_already_done_or_exist(red, data.link)
 | 
				
			||||||
    if task_done:
 | 
					    if task_done:
 | 
				
			||||||
        link_to_download_video = str(request.base_url) + "get/?file_path=" + task_done["result"]
 | 
					        link_to_download_video = str(request.base_url) + "get/?file_path=" + task_done["result"]
 | 
				
			||||||
        return JSONResponse({"result": link_to_download_video})
 | 
					        return JSONResponse({"result": link_to_download_video})
 | 
				
			||||||
 | 
					    # TODO: учесть, что если делать запрос CURL\urllib3\etc, в теле может быть несколько ссылок -> должно быть создано несколько задач
 | 
				
			||||||
    async with await connect("amqp://guest:guest@localhost/") as connection:
 | 
					    async with await connect("amqp://guest:guest@localhost/") as connection:
 | 
				
			||||||
        # Creating a channel
 | 
					        # Creating a channel
 | 
				
			||||||
        channel = await connection.channel()
 | 
					        channel = await connection.channel()
 | 
				
			||||||
        body = [
 | 
					        body = [
 | 
				
			||||||
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                "link": data.link,
 | 
					                "link": data.link,
 | 
				
			||||||
                "format": f"bestvideo[ext={data.format.value}]+bestaudio[ext={data.format.value}]/best[ext={data.format.value}]/best",
 | 
					                "format": f"bestvideo[ext={data.format.value}]+bestaudio[ext={data.format.value}]/best[ext={data.format.value}]/best",
 | 
				
			||||||
@@ -91,6 +104,7 @@ async def get_url_for_download_video(request: Request, data: SubmitIn = Depends(
 | 
				
			|||||||
                    if literal_eval(message.decode('utf-8'))["link"] == link["link"]
 | 
					                    if literal_eval(message.decode('utf-8'))["link"] == link["link"]
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
                error_tasks = [tasks.pop(tasks.index(error_task)) for error_task in tasks if error_task["status"] == "error"]
 | 
					                error_tasks = [tasks.pop(tasks.index(error_task)) for error_task in tasks if error_task["status"] == "error"]
 | 
				
			||||||
 | 
					                # TODO: если уже была попытка сделать задачу и в редисе она с ошибкой, то переташить её в очередь на выполнение с очисткой состояние об ошибке
 | 
				
			||||||
                if len(error_tasks) > 0:
 | 
					                if len(error_tasks) > 0:
 | 
				
			||||||
                    return JSONResponse({"result": f"STATUS: ERROR {error_tasks[-1]['result']}"})
 | 
					                    return JSONResponse({"result": f"STATUS: ERROR {error_tasks[-1]['result']}"})
 | 
				
			||||||
                if len(tasks) > 0:
 | 
					                if len(tasks) > 0:
 | 
				
			||||||
@@ -103,6 +117,7 @@ async def get_url_for_download_video(request: Request, data: SubmitIn = Depends(
 | 
				
			|||||||
                continue
 | 
					                continue
 | 
				
			||||||
        link_to_download_video = str(request.base_url) + "get/?file_path=" + task["result"]
 | 
					        link_to_download_video = str(request.base_url) + "get/?file_path=" + task["result"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # TODO: возможно возвращать идентификаторы задач aka куски ссылок
 | 
				
			||||||
    return JSONResponse({"result": link_to_download_video})
 | 
					    return JSONResponse({"result": link_to_download_video})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,14 +4,26 @@ from enum import Enum
 | 
				
			|||||||
from fastapi import Form
 | 
					from fastapi import Form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FormatEnum(Enum):
 | 
					'''
 | 
				
			||||||
 | 
					vext: Video Extension (mp4 > mov > webm > flv > other). If --prefer-free-formats is used, webm is preferred.
 | 
				
			||||||
 | 
					aext: Audio Extension (m4a > aac > mp3 > ogg > opus > webm > other). If --prefer-free-formats is used, the order changes to ogg > opus > webm > mp3 > m4a > aac
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VideoFormatEnum(Enum):
 | 
				
			||||||
    format_3gp = "3gp"
 | 
					    format_3gp = "3gp"
 | 
				
			||||||
    format_aac = "aac"
 | 
					 | 
				
			||||||
    format_flv = "flv"
 | 
					    format_flv = "flv"
 | 
				
			||||||
 | 
					    format_mp4 = "mp4"
 | 
				
			||||||
 | 
					    format_mov = "mov"
 | 
				
			||||||
 | 
					    format_webm = "webm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AudioFormatEnum(Enum):
 | 
				
			||||||
 | 
					    format_aac = "aac"
 | 
				
			||||||
    format_m4a = "m4a"
 | 
					    format_m4a = "m4a"
 | 
				
			||||||
    format_mp3 = "mp3"
 | 
					    format_mp3 = "mp3"
 | 
				
			||||||
    format_mp4 = "mp4"
 | 
					 | 
				
			||||||
    format_ogg = "ogg"
 | 
					    format_ogg = "ogg"
 | 
				
			||||||
 | 
					    format_opus = "opus"
 | 
				
			||||||
 | 
					    format_webm = "webm"
 | 
				
			||||||
 | 
					    format_wav = "wav"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MergeOutputFormatEnum(Enum):
 | 
					class MergeOutputFormatEnum(Enum):
 | 
				
			||||||
@@ -25,6 +37,7 @@ class MergeOutputFormatEnum(Enum):
 | 
				
			|||||||
@dataclass
 | 
					@dataclass
 | 
				
			||||||
class SubmitIn:
 | 
					class SubmitIn:
 | 
				
			||||||
    link: str = Form(...)
 | 
					    link: str = Form(...)
 | 
				
			||||||
    format: FormatEnum = Form(...)
 | 
					    video_format: VideoFormatEnum = Form(...)
 | 
				
			||||||
 | 
					    audio_format: AudioFormatEnum = Form(...)
 | 
				
			||||||
    merge_output_format: MergeOutputFormatEnum = Form(...)
 | 
					    merge_output_format: MergeOutputFormatEnum = Form(...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,7 +72,8 @@
 | 
				
			|||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <form method="post" action="/submit" id="download">
 | 
					    <form method="post" action="/submit" id="download">
 | 
				
			||||||
         <input type="text" name="link" placeholder="link">
 | 
					         <input type="text" name="link" placeholder="link">
 | 
				
			||||||
         <input type="text" name="format" placeholder="format">
 | 
					         <input type="text" name="video_format" placeholder="video_format">
 | 
				
			||||||
 | 
					         <input type="text" name="audio_format" placeholder="audio_format">
 | 
				
			||||||
         <input type="text" name="merge_output_format" placeholder="merge_output_format">
 | 
					         <input type="text" name="merge_output_format" placeholder="merge_output_format">
 | 
				
			||||||
         <button type="submit" class="custom-btn btn-1"><span class="submit-spinner submit-spinner_hide"></span> Download</button>
 | 
					         <button type="submit" class="custom-btn btn-1"><span class="submit-spinner submit-spinner_hide"></span> Download</button>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user