moseca / app /pages /Karaoke.py
fabiogra
feat: improve UI and text
5472963
raw
history blame
6.32 kB
from pathlib import Path
import streamlit as st
from streamlit_player import st_player
from streamlit_searchbox import st_searchbox
from service.youtube import (
get_youtube_url,
search_youtube,
download_audio_from_youtube,
)
from helpers import (
get_random_song,
load_audio_segment,
streamlit_player,
local_audio,
delete_old_files,
)
from service.vocal_remover.runner import separate, load_model
from footer import footer
from header import header
from loguru import logger as log
out_path = Path("/tmp")
in_path = Path("/tmp")
sess = st.session_state
def show_karaoke(pathname):
cols = st.columns([1, 1, 3, 1])
with cols[1]:
sess.delay = st.slider(
label="Adjust video start delay in seconds (higher values anticipate lyrics)",
key="delay_slider",
value=2,
min_value=0,
max_value=5,
help="Synchronize youtube player with karaoke audio by adding a delay to the youtube player.",
)
with cols[2]:
events = st_player(
local_audio(pathname),
**{
"progress_interval": 1000,
"playing": False,
"muted": False,
"light": False,
"play_inline": True,
"playback_rate": 1,
"height": 40,
"config": {
"start": 0,
"forceAudio": True,
},
"events": ["onProgress", "onPlay"],
},
key="karaoke_player",
)
st.markdown(
"<center>⬆️ Click on the play button to start karaoke<center>",
unsafe_allow_html=True,
)
with st.columns([1, 4, 1])[1]:
if events.name == "onPlay":
st.session_state.player_restart = True
log.info(f"Play Karaoke - {sess.selected_value}")
elif events.name == "onProgress" and events.data["playedSeconds"] > 0:
if st.session_state.player_restart:
sess.tot_delay = sess.delay + events.data["playedSeconds"]
st.session_state.player_restart = False
st_player(
sess.url + f"&t={sess.tot_delay}s",
**{
"progress_interval": 1000,
"playing": True,
"muted": True,
"light": False,
"play_inline": False,
"playback_rate": 1,
"height": 250,
"events": None,
},
key="yt_muted_player",
)
def body():
st.markdown(
"<h4><center>Play karaoke removing the vocals of your favorite song <center></h4>",
unsafe_allow_html=True,
)
yt_cols = st.columns([1, 3, 2, 1])
with yt_cols[1]:
selected_value = st_searchbox(
search_youtube,
label=None,
placeholder="Search on YouTube by name...",
clear_on_submit=True,
key="yt_searchbox",
)
if selected_value is not None and selected_value in sess.video_options:
sess.random_song = None
if selected_value != sess.selected_value: # New song selected
sess.executed = False
sess.selected_value = selected_value
sess.url = get_youtube_url(selected_value)
with yt_cols[2]:
if st.button("🎲 Random song", use_container_width=True):
sess.last_dir, sess.url = get_random_song()
sess.selected_value = sess.last_dir
sess.random_song = True
sess.video_options = []
sess.executed = False
if sess.url is not None:
player_cols = st.columns([2, 2, 1, 1], gap="medium")
with player_cols[1]:
player = st.empty()
streamlit_player(
player,
sess.url,
height=200,
is_active=False,
muted=False,
start=0,
key="yt_player",
events=["onProgress"],
)
# Separate vocals
cols_before_sep = st.columns([2, 4, 2])
with cols_before_sep[1]:
execute_button = st.empty()
execute = execute_button.button(
"Confirm and remove vocals 🎀 🎢",
type="primary",
use_container_width=True,
)
if execute or sess.executed:
execute_button.empty()
player.empty()
if execute:
sess.executed = False
if sess.random_song is None:
if not sess.executed:
with st.spinner(
"Separating vocals from music, it could take a few minutes... Don't close this page!"
):
sess.filename = download_audio_from_youtube(sess.url, in_path)
if sess.filename is None:
st.stop()
sess.url = None
filename = sess.filename
song = load_audio_segment(in_path / filename, filename.split(".")[-1])
song.export(in_path / filename, format=filename.split(".")[-1])
model, device = load_model(pretrained_model="baseline.pth")
separate(
input=in_path / filename,
model=model,
device=device,
output_dir=out_path,
only_no_vocals=True,
)
selected_value = None
sess.last_dir = ".".join(sess.filename.split(".")[:-1])
sess.executed = True
else:
sess.executed = True
if sess.executed:
show_karaoke(out_path / "vocal_remover" / sess.last_dir / "no_vocals.mp3")
if __name__ == "__main__":
header()
body()
footer()
delete_old_files("/tmp", 60 * 30)