moseca / app /pages /Karaoke.py
Fabio Grasso
feat: replace st_searchbox with text_input and selectbox, limit query youtube (#5)
dc66c98 unverified
raw
history blame
No virus
7.8 kB
from pathlib import Path
import streamlit as st
from streamlit_player import st_player
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):
st.session_state.karaoke = True
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":
sess.player_restart = True
log.info(f"Play Karaoke - {sess.selected_value}")
elif (
events.name == "onProgress"
and events.data["playedSeconds"] > 0
and events.data["played"] < 1
):
if sess.player_restart:
sess.tot_delay = sess.delay + events.data["playedSeconds"]
sess.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 reset_karaoke():
sess.karaoke = False
sess.url = None
sess.executed = False
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])
selected_value = None
with yt_cols[1]:
input_search = st.text_input(
label="Search a song on YouTube",
label_visibility="collapsed",
placeholder="Search on YouTube by name...",
key="yt_input_search",
on_change=reset_karaoke,
)
if not sess.get("karaoke", False):
radio_selection = st.empty()
if input_search != "" and input_search != sess.get("input_search", ""):
sess.input_search = input_search
with st.spinner("Searching on YouTube..."):
sess.options = search_youtube(input_search)
if sess.get("options", []) != []:
selected_value = radio_selection.selectbox(
label="**⬇️ Select a title and see the video preview**",
index=len(sess.options),
options=sess.options + [""],
key="yt_radio",
)
if not sess.get("karaoke", False):
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)
if selected_value is None or 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
radio_selection.empty()
if sess.url is not None and not sess.get("karaoke", False):
player_cols = st.columns([2, 2, 1, 1], gap="medium")
with player_cols[1]:
with st.spinner("Loading video preview..."):
player = st.empty()
streamlit_player(
player,
sess.url,
height=200,
is_active=False,
muted=False,
start=0,
key="yt_player",
)
# 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:
radio_selection.empty()
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()
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")
cancel_button = st.empty()
if cancel_button.button(
"Cancel", use_container_width=True, type="secondary"
):
st.experimental_rerun()
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
cancel_button.empty()
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)