|
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, need to restart the player)", |
|
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<br>You will see the video with lyrics below ⬇️<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} - {sess.delay}s delay") |
|
|
|
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, |
|
) |
|
radio_selection = st.empty() |
|
if not sess.get("karaoke", False): |
|
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: |
|
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): |
|
reset_karaoke() |
|
sess.last_dir, sess.url = get_random_song() |
|
log.info(f"Random song - {sess.last_dir}") |
|
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", |
|
) |
|
|
|
|
|
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!" |
|
): |
|
log.info(f"Separating vocals from {sess.selected_value}") |
|
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" |
|
): |
|
log.info(f"Cancel separation of vocals from {filename}") |
|
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() |
|
log.info(f"Separating Done - {sess.selected_value}") |
|
|
|
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) |
|
|