added loader, added video format check, fix video download
This commit is contained in:
		@@ -2,6 +2,7 @@ import os
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from fastapi import APIRouter, Form, HTTPException
 | 
					from fastapi import APIRouter, Form, HTTPException
 | 
				
			||||||
from starlette.requests import Request
 | 
					from starlette.requests import Request
 | 
				
			||||||
 | 
					from fastapi.responses import JSONResponse
 | 
				
			||||||
from starlette.responses import HTMLResponse, FileResponse
 | 
					from starlette.responses import HTMLResponse, FileResponse
 | 
				
			||||||
from starlette.templating import Jinja2Templates
 | 
					from starlette.templating import Jinja2Templates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,25 +26,22 @@ async def get_url_for_download_video(request: Request, link: str = Form(...)):
 | 
				
			|||||||
    ydl_opts = {
 | 
					    ydl_opts = {
 | 
				
			||||||
                "forceurl": True,
 | 
					                "forceurl": True,
 | 
				
			||||||
                'outtmpl': f'downloads/%(extractor_key)s/{file_name}.%(ext)s'
 | 
					                'outtmpl': f'downloads/%(extractor_key)s/{file_name}.%(ext)s'
 | 
				
			||||||
                # "username": "garick.badalov@yandex.ru",
 | 
					 | 
				
			||||||
                # "password": "garik876.",
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    downloader = VideoDownloader(link=link, ydl_opts=ydl_opts)
 | 
					    downloader = VideoDownloader(link=link, ydl_opts=ydl_opts)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        result = downloader.download()
 | 
					        result = downloader.download()
 | 
				
			||||||
        file_path = str(request.base_url) + f"{file_name}.mp4"
 | 
					        link_to_download_video = str(request.base_url) + f"{file_name}.{result['formats'][-1]['ext']}"
 | 
				
			||||||
    except SiteNotImplementedException as ex:
 | 
					    except SiteNotImplementedException as ex:
 | 
				
			||||||
        raise HTTPException(
 | 
					        raise HTTPException(
 | 
				
			||||||
            status_code=400,
 | 
					            status_code=400,
 | 
				
			||||||
            detail=ex.message
 | 
					            detail=ex.message
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    return templates.TemplateResponse("index.html", {"request": request, "result": file_path})
 | 
					    return JSONResponse({"result": link_to_download_video})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@main_router.get('/{file_path}', response_class=FileResponse)
 | 
					@main_router.get('/{file_path}', response_class=FileResponse)
 | 
				
			||||||
async def download_video(request: Request, file_path):
 | 
					async def download_video(file_path):
 | 
				
			||||||
    base = os.path.dirname(os.path.dirname(os.path.abspath(file_path)))
 | 
					    base = os.path.dirname(os.path.dirname(os.path.abspath(file_path)))
 | 
				
			||||||
    BASE_DOWNLOAD_DIR = os.path.join(base, "src", "downloads")
 | 
					    base_download_dir = os.path.join(base, "src", "downloads")
 | 
				
			||||||
    BASE_YOUTUBE_DIR = os.path.join(BASE_DOWNLOAD_DIR, "Youtube")
 | 
					    youtube_dir = os.path.join(base_download_dir, "Youtube")
 | 
				
			||||||
    return BASE_YOUTUBE_DIR + f'/{file_path}'
 | 
					    return FileResponse(youtube_dir + f'/{file_path}', media_type="multipart/form-data")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ from src.exceptions.download_exceptions import SiteNotImplementedException
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class VideoDownloader:
 | 
					class VideoDownloader:
 | 
				
			||||||
    SUPPORTING_WEBSITES = [
 | 
					    SUPPORTING_WEBSITES = [
 | 
				
			||||||
        "ok.ru", "vk.com", "www.youtube.com"
 | 
					        "ok.ru", "vk.com", "www.youtube.com",
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
					    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
				
			||||||
    BASE_DOWNLOAD_DIR = os.path.join(BASE_DIR, "downloads")
 | 
					    BASE_DOWNLOAD_DIR = os.path.join(BASE_DIR, "downloads")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
import uvicorn
 | 
					import uvicorn
 | 
				
			||||||
from fastapi import FastAPI
 | 
					from fastapi import FastAPI
 | 
				
			||||||
from fastapi.staticfiles import StaticFiles
 | 
					from fastapi.staticfiles import StaticFiles
 | 
				
			||||||
from starlette.templating import Jinja2Templates
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.api.api_v1.endpoints.main import main_router
 | 
					from api.api_v1.endpoints.main import main_router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = FastAPI(
 | 
					app = FastAPI(
 | 
				
			||||||
    title="PythonProject", openapi_url=f"/api/v1/openapi.json"
 | 
					    title="PythonProject", openapi_url=f"/api/v1/openapi.json"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,9 @@
 | 
				
			|||||||
    <title>Video Downloading</title>
 | 
					    <title>Video Downloading</title>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
 | 
					 | 
				
			||||||
    .custom-btn {
 | 
					    .custom-btn {
 | 
				
			||||||
      width: 130px;
 | 
					      width: 145px;
 | 
				
			||||||
      height: 40px;
 | 
					      height: 60px;
 | 
				
			||||||
      color: #fff;
 | 
					      color: #fff;
 | 
				
			||||||
      border-radius: 5px;
 | 
					      border-radius: 5px;
 | 
				
			||||||
      padding: 10px 25px;
 | 
					      padding: 10px 25px;
 | 
				
			||||||
@@ -48,16 +47,69 @@
 | 
				
			|||||||
    font-size: 1.5em; /* Размер шрифта */
 | 
					    font-size: 1.5em; /* Размер шрифта */
 | 
				
			||||||
    word-wrap: break-word; /* Перенос слов */
 | 
					    word-wrap: break-word; /* Перенос слов */
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					   @keyframes spinner-border {
 | 
				
			||||||
 | 
					    100% {
 | 
				
			||||||
 | 
					      transform: rotate(360deg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .submit-spinner {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    width: 1rem;
 | 
				
			||||||
 | 
					    height: 1rem;
 | 
				
			||||||
 | 
					    vertical-align: -0.125em;
 | 
				
			||||||
 | 
					    border: 0.2em solid currentColor;
 | 
				
			||||||
 | 
					    border-right-color: transparent;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    -webkit-animation: .75s linear infinite spinner-border;
 | 
				
			||||||
 | 
					    animation: .75s linear infinite spinner-border;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .submit-spinner_hide {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <form method="post" action="/submit">
 | 
					    <form method="post" action="/submit" id="download">
 | 
				
			||||||
         <input type="text" name="link">
 | 
					         <input type="text" name="link">
 | 
				
			||||||
         <button type="submit" class="custom-btn btn-1">Download</button>
 | 
					         <button type="submit" class="custom-btn btn-1"><span class="submit-spinner submit-spinner_hide"></span> Download</button>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
    <div class="col">
 | 
					    <div class="col">
 | 
				
			||||||
        <p> Ссылка для скачивания:</p>
 | 
					        <p> Ссылка для скачивания:</p>
 | 
				
			||||||
        <br>
 | 
					        <br>
 | 
				
			||||||
        <a href={{result}}>{{result}}</a>
 | 
					        <a id="result" href=""></a>
 | 
				
			||||||
 | 
					        <div class="loader">
 | 
				
			||||||
 | 
					            <div class="loader_inner"></div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					    function sendForm() {
 | 
				
			||||||
 | 
					    const xhr = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    xhr.open('POST', document.forms.download.action);
 | 
				
			||||||
 | 
					    xhr.responseType = 'json';
 | 
				
			||||||
 | 
					    xhr.onload = () => {
 | 
				
			||||||
 | 
					      document.forms.download.querySelector('[type="submit"]').disabled = false;
 | 
				
			||||||
 | 
					      document.forms.download.querySelector('.submit-spinner').classList.add('submit-spinner_hide');
 | 
				
			||||||
 | 
					      if (xhr.status !== 200) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const response = xhr.response;
 | 
				
			||||||
 | 
					      result.innerHTML = xhr.response.result;
 | 
				
			||||||
 | 
					      result.href = xhr.response.result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    xhr.onerror = () => {
 | 
				
			||||||
 | 
					      document.forms.download.querySelector('[type="submit"]').disabled = false;
 | 
				
			||||||
 | 
					      document.forms.download.querySelector('.submit-spinner').classList.add('submit-spinner_hide');
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    document.forms.download.querySelector('[type="submit"]').disabled = true;
 | 
				
			||||||
 | 
					    document.forms.download.querySelector('.submit-spinner').classList.remove('submit-spinner_hide');
 | 
				
			||||||
 | 
					    xhr.send(new FormData(document.forms.download));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // при отправке формы
 | 
				
			||||||
 | 
					  document.forms.download.addEventListener('submit', (e) => {
 | 
				
			||||||
 | 
					    e.preventDefault();
 | 
				
			||||||
 | 
					    sendForm();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user