Added playlist downloading to cli
This commit is contained in:
parent
52a55d8be2
commit
29c7e452b0
1128
manifest.json
1128
manifest.json
File diff suppressed because it is too large
Load Diff
|
@ -1,42 +1,26 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::{song::Song, Manifest}, util::is_supported_host};
|
||||
|
||||
|
||||
|
||||
pub async fn add(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut Downloader, url: &Option<String>, name: &Option<String>, playlist: &Option<String>) -> anyhow::Result<()> {
|
||||
pub async fn add(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut Downloader, url: &String, name: &String, playlist: &String) -> anyhow::Result<()> {
|
||||
|
||||
log::debug!("Playlist: {playlist:?}");
|
||||
log::debug!("url: {url:?}");
|
||||
log::debug!("name: {name:?}");
|
||||
|
||||
let mut playlists = manifest.get_playlists().keys().map(|f| f.clone()).collect::<Vec<String>>();
|
||||
|
||||
playlists.sort();
|
||||
|
||||
let playlist = playlist.clone().unwrap_or_else( || {
|
||||
let g = crate::prompt::prompt_with_list_or_str("Enter song playlist", &playlists);
|
||||
log::info!("Playlist: {g}");
|
||||
g
|
||||
});
|
||||
|
||||
|
||||
let url = url.clone().unwrap_or_else( ||
|
||||
crate::prompt::simple_prompt("Enter song youtube url, make sure its not a playlist, (yt only for now)")
|
||||
);
|
||||
|
||||
if !is_supported_host(url::Url::from_str(&url)?) {
|
||||
log::error!("Invalid or unsupported host name");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
let name = name.clone().unwrap_or_else( ||
|
||||
crate::prompt::simple_prompt("Enter song name with like this: {Author} - {Song name}")
|
||||
);
|
||||
|
||||
let song = Song::from_url_str(url)?;
|
||||
manifest.add_song(playlist.clone(), name.clone(), song.clone());
|
||||
let song = Song::from_url_str(url.clone())?;
|
||||
manifest.add_song(playlist, name.clone(), song.clone());
|
||||
manifest.save(None)?;
|
||||
|
||||
let should_download = crate::prompt::prompt_bool("Download song now?", Some(false));
|
||||
|
@ -48,3 +32,24 @@ pub async fn add(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add_playlist(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut Downloader, url: &String, name: &String) -> anyhow::Result<()> {
|
||||
let songs = downloader.download_playlist_nb(cfg, url, name, manifest.get_format())?;
|
||||
|
||||
if manifest.get_playlist(name).is_some() {
|
||||
log::error!("Playlist {name} already exists");
|
||||
bail!("")
|
||||
}
|
||||
|
||||
manifest.add_playlist(name.clone());
|
||||
|
||||
let playlist = manifest.get_playlist_mut(name).expect("Unreachable");
|
||||
|
||||
for (sname, song) in songs {
|
||||
playlist.add_song(sname, song);
|
||||
}
|
||||
manifest.save(None)?;
|
||||
|
||||
while downloader.download_all_nb_poll(cfg)?.is_some() {};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ impl Gui {
|
|||
|
||||
let (playlist, song_name) = self.song_editor.song.clone();
|
||||
|
||||
let Some(song) = self.manifest.get_song(playlist.clone(), &song_name) else {
|
||||
let Some(song) = self.manifest.get_song(&playlist, &song_name) else {
|
||||
return;
|
||||
};
|
||||
let song = song.clone();
|
||||
|
@ -65,14 +65,14 @@ impl Gui {
|
|||
|
||||
if save {
|
||||
{
|
||||
let Some(song) = self.manifest.get_song_mut(playlist.clone(), &song_name) else {
|
||||
let Some(song) = self.manifest.get_song_mut(&playlist, &song_name) else {
|
||||
return;
|
||||
};
|
||||
|
||||
*song.get_url_str_mut() = self.song_editor.ed_url.clone();
|
||||
}
|
||||
|
||||
let Some(playlist) = self.manifest.get_playlist_mut(playlist.clone()) else {
|
||||
let Some(playlist) = self.manifest.get_playlist_mut(&playlist) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -126,7 +126,7 @@ impl Gui {
|
|||
});
|
||||
|
||||
if save {
|
||||
let Some(playlist) = self.manifest.get_playlist_mut(self.song_editor.ed_playlist.clone().unwrap()) else {
|
||||
let Some(playlist) = self.manifest.get_playlist_mut(&self.song_editor.ed_playlist.clone().unwrap()) else {
|
||||
panic!("couldnt find playlist from a preset playlist list????????????");
|
||||
};
|
||||
|
||||
|
@ -137,7 +137,6 @@ impl Gui {
|
|||
|
||||
|
||||
let _ = self.manifest.save(None);
|
||||
save = false;
|
||||
self.song_editor.is_new_open = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,11 @@ pub async fn command_run(cfg: &ConfigWrapper, manifest: &mut Manifest) -> anyhow
|
|||
(Some(c), _) => {
|
||||
match c {
|
||||
CliCommand::Download => unreachable!(),
|
||||
CliCommand::AddPlaylist { url, name } => {
|
||||
if let Err(e) = add::add_playlist(cfg, manifest, &mut downloader, url, name).await {
|
||||
log::error!("Failed to run 'add-playlist' commmand: {e}");
|
||||
}
|
||||
}
|
||||
CliCommand::Add { url, name, playlist } => {
|
||||
if let Err(e) = add::add(cfg, manifest, &mut downloader, url, name, playlist).await {
|
||||
log::error!("Failed to run 'add' command: {e}");
|
||||
|
|
|
@ -30,11 +30,17 @@ pub enum CliCommand {
|
|||
Download,
|
||||
Add {
|
||||
#[arg(long, short)]
|
||||
url: Option<String>,
|
||||
url: String,
|
||||
#[arg(long, short)]
|
||||
name: Option<String>,
|
||||
name: String,
|
||||
#[arg(long, short)]
|
||||
playlist: Option<String>
|
||||
playlist: String
|
||||
},
|
||||
AddPlaylist {
|
||||
#[arg(long, short)]
|
||||
url: String,
|
||||
#[arg(long, short)]
|
||||
name: String
|
||||
},
|
||||
Gui
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Downloader {
|
|||
self.nb_cache.len()
|
||||
}
|
||||
|
||||
pub fn download_all_nb(&mut self, manifest: &Manifest, cfg: &ConfigWrapper) -> anyhow::Result<usize> {
|
||||
pub fn download_all_nb(&mut self, manifest: &Manifest, cfg: &ConfigWrapper) -> anyhow::Result<Option<usize>> {
|
||||
for (pname, playlist) in manifest.get_playlists() {
|
||||
for (sname, song) in playlist.get_songs() {
|
||||
self.nb_cache.push((pname.clone(), sname.clone(), song.clone(), manifest.get_format().clone()));
|
||||
|
@ -51,14 +51,20 @@ impl Downloader {
|
|||
self.download_all_nb_poll(cfg)
|
||||
}
|
||||
|
||||
pub fn download_all_nb_poll(&mut self, cfg: &ConfigWrapper) -> anyhow::Result<usize> {
|
||||
pub fn download_all_nb_poll(&mut self, cfg: &ConfigWrapper) -> anyhow::Result<Option<usize>> {
|
||||
if !crate::process_manager::is_proc_queue_full(10) {
|
||||
if let Some((pname, sname, song, format)) = self.nb_cache.pop() {
|
||||
self.download_song(cfg, &sname, &song, &pname, &format)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(crate::process_manager::purge_done_procs())
|
||||
if self.nb_cache.is_empty() {
|
||||
self.nb_initial_song_count = 0;
|
||||
}
|
||||
if crate::process_manager::proc_count() == 0 && self.nb_cache.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(crate::process_manager::purge_done_procs()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,6 +82,47 @@ impl Downloader {
|
|||
Ok(self.count)
|
||||
}
|
||||
|
||||
pub fn download_playlist(&mut self, cfg: &ConfigWrapper, url: &String, pname: &String, format: &Format) -> anyhow::Result<usize> {
|
||||
self.download_playlist_nb(cfg, url, pname, format)?;
|
||||
let mut count = 0;
|
||||
while let Some(c) = self.download_all_nb_poll(cfg)? {
|
||||
count += c;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn download_playlist_nb(&mut self, cfg: &ConfigWrapper, url: &String, pname: &String, format: &Format) -> anyhow::Result<HashMap<String, Song>> {
|
||||
log::warn!("This automatically assumes its a youtube link as it is currently the only supported playlist source");
|
||||
let mut cmd = tokio::process::Command::new(&cfg.cfg.ytdlp.path);
|
||||
cmd.args([
|
||||
"--flat-playlist",
|
||||
"--simulate",
|
||||
"-O", "%(url)s|%(title)s",
|
||||
url.as_str()
|
||||
]);
|
||||
cmd
|
||||
.stderr(Stdio::null())
|
||||
.stdout(Stdio::piped());
|
||||
|
||||
let ftr = cmd.output();
|
||||
|
||||
let mut ret = HashMap::new();
|
||||
|
||||
let out = futures::executor::block_on(ftr)?.stdout;
|
||||
let out = String::from_utf8(out)?;
|
||||
for line in out.lines() {
|
||||
let mut split_text = line.split("|").collect::<Vec<&str>>();
|
||||
let url = split_text.swap_remove(0).to_string();
|
||||
let sname = split_text.join("|");
|
||||
let song = Song::from_url_str(url)?.set_type(SongType::Youtube).clone();
|
||||
self.nb_cache.push((pname.clone(), sname.clone(), song.clone(), format.clone()));
|
||||
ret.insert(sname, song.clone());
|
||||
}
|
||||
self.nb_initial_song_count += out.lines().count();
|
||||
self.download_all_nb_poll(cfg)?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn download_song(&mut self, cfg: &ConfigWrapper, name: &String, song: &Song, playlist: &String, format: &Format) -> anyhow::Result<()> {
|
||||
let dl_dir = format!("{}/{playlist}", cfg.cli.output);
|
||||
let dl_file = format!("{dl_dir}/{}.{}", name, &format);
|
||||
|
|
|
@ -43,23 +43,23 @@ impl Manifest {
|
|||
pub fn get_format(&self) -> &Format {
|
||||
&self.format
|
||||
}
|
||||
pub fn add_song(&mut self, playlist_name: String, name: SongName, song: Song) -> Option<Song> {
|
||||
pub fn add_song(&mut self, playlist_name: &String, name: SongName, song: Song) -> Option<Song> {
|
||||
self.get_playlist_mut(playlist_name)?.add_song(name, song)
|
||||
}
|
||||
pub fn get_song(&self, playlist_name: String, name: &String) -> Option<&Song> {
|
||||
pub fn get_song(&self, playlist_name: &String, name: &String) -> Option<&Song> {
|
||||
self.get_playlist(playlist_name)?.get_song(name)
|
||||
}
|
||||
pub fn get_song_mut(&mut self, playlist_name: String, name: &String) -> Option<&mut Song> {
|
||||
pub fn get_song_mut(&mut self, playlist_name: &String, name: &String) -> Option<&mut Song> {
|
||||
self.get_playlist_mut(playlist_name)?.get_song_mut(name)
|
||||
}
|
||||
pub fn add_playlist(&mut self, playlist_name: String) {
|
||||
self.playlists.insert(playlist_name, Default::default());
|
||||
}
|
||||
pub fn get_playlist(&self, playlist_name: String) -> Option<&playlist::Playlist> {
|
||||
self.playlists.get(&playlist_name)
|
||||
pub fn get_playlist(&self, playlist_name: &String) -> Option<&playlist::Playlist> {
|
||||
self.playlists.get(playlist_name)
|
||||
}
|
||||
pub fn get_playlist_mut(&mut self, playlist_name: String) -> Option<&mut playlist::Playlist> {
|
||||
self.playlists.get_mut(&playlist_name)
|
||||
pub fn get_playlist_mut(&mut self, playlist_name: &String) -> Option<&mut playlist::Playlist> {
|
||||
self.playlists.get_mut(playlist_name)
|
||||
}
|
||||
pub fn get_playlists(&self) -> &HashMap<String, playlist::Playlist> {
|
||||
&self.playlists
|
||||
|
|
|
@ -38,6 +38,9 @@ pub fn add_proc(mut cmd: Command, msg: String) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn proc_count() -> usize {
|
||||
PROCESSES.lock().unwrap().read().unwrap().len()
|
||||
}
|
||||
|
||||
pub fn is_proc_queue_full(max: usize) -> bool {
|
||||
let proc_cnt = PROCESSES.lock().unwrap().read().unwrap().len();
|
||||
|
|
Loading…
Reference in New Issue
Block a user