lcjln's picture
Update app.py
63029cb verified
import streamlit as st
import yt_dlp
import os
# Streamlit 제λͺ©
st.title('유튜브 μ˜μƒ λ‹€μš΄λ‘œλ“œ')
st.write("<br>", unsafe_allow_html=True) # 1쀄 띄어쓰기
st.write("μ‚¬μš©λ°©λ²•")
st.write("<br>", unsafe_allow_html=True) # 1쀄 띄어쓰기
st.write("1. λ‹€μš΄λ°›μœΌλ €λŠ” 유튜브 μ˜μƒμ˜ 링크λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”")
st.write("2. 링크λ₯Ό μž…λ ₯ν•˜κ³  ν™•μΈλ²„νŠΌμ„ λˆ„λ₯΄λ©΄ ν•΄λ‹Ή μ˜μƒμ˜ 썸넀일이 λ“±μž₯ν•©λ‹ˆλ‹€")
st.write("3. 썸넀일 λ°‘μ˜ μ„ νƒλž€μ„ 톡해 해상도와 μ˜μƒ μš©λŸ‰μ„ ν™•μΈν•œ ν›„ μ›ν•˜λŠ” 해상도λ₯Ό μ„ νƒν•˜κ³  μΆ”μΆœ λ²„νŠΌμ„ λˆŒλŸ¬μ£Όμ„Έμš”")
st.write("4. μž μ‹œ ν›„ λ‹€μš΄λ°›μœΌλ €λŠ” μ˜μƒμ΄ 밑에 λ“±μž₯ν•˜κ³  μž¬μƒν•˜κ±°λ‚˜ λ‹€μš΄λ‘œλ“œ 받을 수 μžˆμŠ΅λ‹ˆλ‹€ (μ˜μƒμ˜ μš©λŸ‰μ΄ 클수둝 μΆ”μΆœν•˜λŠ”λ° μ‹œκ°„μ΄ 더 κ±Έλ¦½λ‹ˆλ‹€. 20λΆ„ μ˜μƒ μΆ”μΆœν•˜λŠ”λ° 1λΆ„λ‚΄λ‘œ μ†Œμš”)")
# μœ μ €λ‘œλΆ€ν„° 유튜브 링크 μž…λ ₯λ°›κΈ°
col1, col2 = st.columns([4, 1])
with col1:
youtube_url = st.text_input('Enter YouTube video URL')
def fetch_video_info(youtube_url):
ydl_opts = {
'nocheckcertificate': True,
'cookiefile': 'cookies.txt' # μΏ ν‚€ 파일 경둜
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(youtube_url, download=False)
return info_dict
def get_available_formats(info_dict):
formats = {}
for fmt in info_dict['formats']:
if fmt.get('height') and fmt.get('ext') == 'mp4':
filesize = fmt.get('filesize', 0)
if filesize:
filesize_mb = round(filesize / (1024 * 1024), 2)
resolution = f"{fmt['height']}p"
formats[resolution] = {
'id': fmt['format_id'],
'info': f"{resolution} - {filesize_mb} MB"
}
return formats
def reset_session_state():
st.session_state.pop('info_dict', None)
st.session_state.pop('thumbnail_url', None)
st.session_state.pop('formats', None)
st.session_state.pop('youtube_url', None)
st.session_state.pop('confirmed', None)
st.session_state.pop('selected_format_id', None)
def delete_downloaded_video():
if os.path.exists('downloaded_video.mp4'):
os.remove('downloaded_video.mp4')
# "확인" λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ μ²˜λ¦¬ν•  둜직
if st.button('확인'):
if youtube_url:
try:
# κΈ°μ‘΄ λ‹€μš΄λ‘œλ“œλœ μ˜μƒ μ‚­μ œ
delete_downloaded_video()
# μ„Έμ…˜ μƒνƒœ μ΄ˆκΈ°ν™” 및 URL λ³€κ²½ 확인
if 'youtube_url' in st.session_state and st.session_state.youtube_url != youtube_url:
reset_session_state()
st.session_state.youtube_url = youtube_url
info_dict = fetch_video_info(youtube_url)
st.session_state.info_dict = info_dict
st.session_state.thumbnail_url = info_dict.get('thumbnail')
st.session_state.formats = get_available_formats(info_dict)
st.session_state.confirmed = True
except Exception as e:
st.error(f"An error occurred: {e}")
else:
st.warning('Please enter a valid YouTube video URL')
if 'confirmed' in st.session_state and st.session_state.confirmed:
st.image(st.session_state.thumbnail_url, caption='Video Thumbnail', use_column_width=True)
# 해상도 선택
format_options = [value['info'] for value in st.session_state.formats.values()]
format_selection = st.selectbox('Select resolution', format_options)
# μ„ νƒλœ ν•΄μƒλ„μ˜ format_id μ €μž₯
st.session_state.selected_format_id = next(
(value['id'] for key, value in st.session_state.formats.items() if value['info'] == format_selection), None
)
def download_video(youtube_url, format_id):
ydl_opts = {
'format': f"{format_id}+bestaudio/best",
'merge_output_format': 'mp4',
'outtmpl': 'downloaded_video.%(ext)s',
'nocache': True, # μΊμ‹œ λΉ„ν™œμ„±ν™”
'cookiefile': 'cookies.txt' # μΏ ν‚€ 파일 경둜
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([youtube_url])
# "μΆ”μΆœ" λ²„νŠΌ μΆ”κ°€
if st.button('μΆ”μΆœ'):
format_id = st.session_state.selected_format_id
if format_id is None:
st.error('Selected format not found.')
else:
try:
# μ„Έμ…˜ μƒνƒœμ˜ youtube_url μ‚¬μš©
download_video(st.session_state.youtube_url, format_id)
st.success('Video downloaded successfully!')
st.video('downloaded_video.mp4')
# λ‹€μš΄λ‘œλ“œλœ 파일 제곡 (optional)
with open('downloaded_video.mp4', 'rb') as file:
st.download_button(
label="Download Video File",
data=file,
file_name='downloaded_video.mp4',
mime='video/mp4'
)
# μΆ”μΆœλœ μ˜μƒ 정보 좜λ ₯
st.write(f"**제λͺ©:** {st.session_state.info_dict['title']}")
st.write(f"**채널λͺ…:** {st.session_state.info_dict['uploader']}")
st.write(f"**μ—…λ‘œλ“œ λ‚ μ§œ:** {st.session_state.info_dict['upload_date']}")
# λ‹€μš΄λ‘œλ“œ ν›„ μ„Έμ…˜ μƒνƒœ 리셋
reset_session_state()
except Exception as e:
st.error(f"An error occurred during download: {e}")