|
import logging |
|
import os |
|
import re |
|
import string |
|
from typing import List |
|
|
|
from loguru import logger as log |
|
import streamlit as st |
|
import yt_dlp |
|
from pytube import Search |
|
|
|
logger = logging.getLogger("pytube") |
|
logger.setLevel(logging.ERROR) |
|
|
|
|
|
def _sanitize_filename(filename): |
|
safe_chars = "-_.() %s%s" % ( |
|
re.escape(string.ascii_letters), |
|
re.escape(string.digits), |
|
) |
|
safe_filename = re.sub(f"[^{safe_chars}]", "_", filename) |
|
return safe_filename.strip() |
|
|
|
|
|
@st.cache_data(show_spinner=False) |
|
def download_audio_from_youtube(url, output_path): |
|
if not os.path.exists(output_path): |
|
os.makedirs(output_path) |
|
|
|
with yt_dlp.YoutubeDL({"quiet": True}) as ydl: |
|
info_dict = ydl.extract_info(url, download=False) |
|
if info_dict.get("duration", 0) > 360: |
|
st.error("Song is too long. Please use a song no longer than 6 minutes.") |
|
return |
|
video_title = info_dict.get("title", None) |
|
video_title = _sanitize_filename(video_title) |
|
ydl_opts = { |
|
"format": "bestaudio/best", |
|
"postprocessors": [ |
|
{ |
|
"key": "FFmpegExtractAudio", |
|
"preferredcodec": "mp3", |
|
"preferredquality": "192", |
|
} |
|
], |
|
"outtmpl": os.path.join(output_path, video_title), |
|
"quiet": True, |
|
} |
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
|
ydl.download([url]) |
|
return f"{video_title}.mp3" |
|
|
|
|
|
@st.cache_data(show_spinner=False, max_entries=10) |
|
def query_youtube(query: str) -> Search: |
|
return Search(query) |
|
|
|
|
|
def search_youtube(query: str, limit=5) -> List: |
|
log.info(f"{query}") |
|
if len(query) > 3: |
|
search = query_youtube(query + " lyrics") |
|
st.session_state.search_results = search.results |
|
if "search_results" in st.session_state and st.session_state.search_results is not None: |
|
video_options = [video.title for video in st.session_state.search_results[:limit]] |
|
else: |
|
video_options = [] |
|
else: |
|
video_options = [] |
|
st.session_state.video_options = video_options |
|
return video_options |
|
|
|
|
|
def get_youtube_url(title: str) -> str: |
|
video = st.session_state.search_results[st.session_state.video_options.index(title)] |
|
return video.embed_url |
|
|
|
|
|
def check_if_is_youtube_url(url: str) -> bool: |
|
return url.startswith("http") |
|
|