What to do?
유튜브 다운로더 만들기
구현 내용
- Python 서버를 실행
- terminal에 python app.py 입력
- 브라우져를 열고, localhost:5000 주소로 접속
- 주소를 입력하고 다운로드 버튼을 누름
- 다운로드 버튼disbaled
- 다운로드 완료
- Detail Page에 제목, 조회수, 설명, 썸네일을 보여줌
- 다운로드 버튼 다시 활성화
- 다운로드 완료
- downloaded폴더에 다운로드 됨
프로젝트 구조
- .venv : 가상환경
- downloaded : 다운로드한 파일이 저장되는 경로
- templates : html 파일
- app.py : flask로 만든 서버
가상환경 만들기
- 가상환경 생성 (Window 기준)
가끔 보안오류 때문에 에러가 나는데, 구글링하면 Powershell에서 해결하는 방법 나옴
py -3 -m venv .venv
- 가상환경 활성화
.venv/scripts/activate
- 라이브러리 설치
- pytube
- flask
app.py
import json
from flask import Flask, jsonify, redirect, render_template, request
import logging
from pytube import YouTube
app = Flask(__name__)
@app.route("/")
def index():
return render_template('download.html')
@app.route('/detail')
def detail():
return render_template('detail.html')
@app.route('/download', methods=['POST'])
def download():
# parsing post request
req = json.loads(request.get_data().decode())
link = req.get('link')
option = req.get('option')
# create youtube instance
yt = YouTube(link)
if option.upper() == "AUDIO":
stream = yt.streams.filter(only_audio=True)[0]
elif option.upper() == "VIDEO":
stream = yt.streams.get_highest_resolution()
else:
raise Exception("Option is not valid")
# get meta data
meta_data = {
'title':yt.title,
'length':yt.length,
'thumbnail':yt.thumbnail_url,
'numView':yt.views,
'description':yt.description
}
try:
stream.download("./downloaded")
return {"isSuccess":True, **meta_data}
except:
return {"isSuccess":False}
if __name__=='__main__':
app.debug = True
app.run(host="0.0.0.0")
Templates
detail.html
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Detail Page</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous"></head>
<body>
<div class="container mt-3">
<div class="row mt-3 mb-3">
<h1>Detail Page</h1>
</div>
<hr/>
<div class="row mt-3 mb-3">
<div class="col-md-1">
<span class="input-group-text">제목</span>
</div>
<div class="col">
<p id="title"></p>
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-md-1">
<span class="input-group-text">조회수</span>
</div>
<div class="col">
<p id="numView"></p>
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-md-1">
<span class="input-group-text">설명</span>
</div>
<div class="col">
<p id="description"></p>
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-md-1">
<span class="input-group-text">썸네일</span>
</div>
<div class="col">
<img id="thumbnail"/>
</div>
</div>
</div>
<script>
const titleEl = document.getElementById("title");
const descriptonEl = document.getElementById("description");
const numViewEl = document.getElementById("numView");
const thumbnailEl = document.getElementById("thumbnail");
titleEl.textContent
window.addEventListener('message', (e) => {
titleEl.textContent = e.data.title;
numViewEl.textContent = e.data.numView;
descriptonEl.textContent = e.data.description;
thumbnailEl.src = e.data.thumbnail;
});
</script>
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
</html>
download.html
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>유튜브 다운로더</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous"></head>
<body>
<div class="container mt-3">
<div class="row mt-3 mb-3">
<h1>유튜브 다운로더</h1>
</div>
<div class="row mt-3 mb-3">
<div class="col-md-1">
<span class="input-group-text">링크</span>
</div>
<div class="dropdown col-md-2">
<select class="form-select" id="option">
<option selected value="video">영상</option>
<option value="audio">음성</option>
</select>
</div>
<div class="col-md-6">
<input id="link" type="text" class="form-control" placeholder="link..."/>
</div>
<div class="col-md-2">
<button id="btn-download" type="button" class="btn btn-primary">다운로드</button>
</div>
</div>
<hr/>
<iframe id="detail" src="/detail" style="width:100%;height:500px"></iframe>
</div>
<script>
let link = "";
const linkEl = document.getElementById("link");
linkEl.onchange = (e) => {link=e.target.value};
let option = "video";
const optionEl = document.getElementById("option");
optionEl.onchange= (e) => {option=e.target.value};
const detailEl = document.getElementById("detail");
let isSuccess = true;
const downloadBtn = document.getElementById("btn-download");
downloadBtn.onclick = (e) =>{
e.preventDefault();
downloadBtn.disabled = true;
downloadBtn.textContent = "다운로드 중..."
fetch("/download", {
method:'POST',
body:JSON.stringify({link, option})
}).then((res)=>{
return res.json();
}).then((data)=>{
detailEl.contentWindow.postMessage(data);
isSuccess = data.isSuccess;
if (isSuccess === false){alert("다운로드 실패")}
}).catch((err)=>{
isSuccess = false;
console.log(err);
}).finally(()=>{
downloadBtn.disabled = false;
downloadBtn.textContent = "다운로드"
})
}
</script>
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
</html>
'Python' 카테고리의 다른 글
[Python] 한글문서 편집 자동화하기 #2 (0) | 2023.04.02 |
---|---|
[Python] 한글문서 편집 자동화하기 #1 (0) | 2023.03.15 |
[Python] 코딩테스트 연습 (0) | 2023.02.19 |
[Python] 코딩테스트 연습 (0) | 2023.02.10 |
[Python] Youtube Downloader #2 (0) | 2023.01.28 |