manifest refractor
This commit is contained in:
		
							parent
							
								
									3cad0b0651
								
							
						
					
					
						commit
						9fef257bfc
					
				
							
								
								
									
										1276
									
								
								manifest.json
									
									
									
									
									
								
							
							
						
						
									
										1276
									
								
								manifest.json
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,145 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
    "format": "m4a",
 | 
			
		||||
    "genres": {
 | 
			
		||||
        "pop": [
 | 
			
		||||
            {"name": "Green Day - Basket Case", "url": "https://www.youtube.com/watch?v=wZ8eZRxFA-0"},
 | 
			
		||||
            {"name": "Icona Pop - I Love It", "url": "https://www.youtube.com/watch?v=UxxajLWwzqY"}
 | 
			
		||||
        ],
 | 
			
		||||
        "hip-hop": [
 | 
			
		||||
            {"name": "Afroman - Because I Got High", "url": "https://www.youtube.com/watch?v=WeYsTmIzjkw"}
 | 
			
		||||
        ],
 | 
			
		||||
        "rave": [
 | 
			
		||||
            {"name": "EVERYTHING WHAT", "url": "https://www.youtube.com/watch?v=Gjdsq4kc5cA"},
 | 
			
		||||
            {"name": "Tricky Disco", "url": "https://www.youtube.com/watch?v=t78qVdbAiXw"},
 | 
			
		||||
            {"name": "DR. VODKA - Tricky Disco", "url": "https://www.youtube.com/watch?v=IknAUhl3i2o"}
 | 
			
		||||
        ],
 | 
			
		||||
        "techno": [
 | 
			
		||||
            {"name": "Dance For Me", "url": "https://www.youtube.com/watch?v=5DTSvGO_944"},
 | 
			
		||||
            {"name": "Give It To Me", "url": "https://www.youtube.com/watch?v=upQe8EeSyZU"},
 | 
			
		||||
            {"name": "Empire Of The Sun, southstar - We Are The People", "url": "https://www.youtube.com/watch?v=qguEGR5BK2k"},
 | 
			
		||||
            {"name": "Beggin' (Techno)", "url": "https://www.youtube.com/watch?v=tXPs1FwW6lk"},
 | 
			
		||||
            {"name": "Lily Allen - Not Fair", "url": "https://www.youtube.com/watch?v=WON_YIbeLis"},
 | 
			
		||||
            {"name": "I WAS MADE FOR LOVIN' YOU (TECHNO)", "url": "https://www.youtube.com/watch?v=asVznhccYao"},
 | 
			
		||||
            {"name": "Nicolas Julian - Applause", "url": "https://www.youtube.com/watch?v=-pXlrWVICAE"},
 | 
			
		||||
            {"name": "08 Blumchen - Blaue Augen", "url": "https://www.youtube.com/watch?v=mE4PZcUfiwE"},
 | 
			
		||||
            {"name": "MUTA - Party maker", "url": "https://www.youtube.com/watch?v=LT9VNK1aCXY"}
 | 
			
		||||
        ],
 | 
			
		||||
        "electronic": [
 | 
			
		||||
            {"name": "Zombie Nation - Kernkraft 400", "url": "https://www.youtube.com/watch?v=z5LW07FTJbI"},
 | 
			
		||||
            {"name": "Benny Benassi - Satisfaction", "url": "https://www.youtube.com/watch?v=a0fkNdPiIL4"}
 | 
			
		||||
            
 | 
			
		||||
        ],
 | 
			
		||||
        "rock": [
 | 
			
		||||
            {"name": "Black Sabbath", "url": "https://www.youtube.com/watch?v=BOTIIw76qiE"}
 | 
			
		||||
        ],
 | 
			
		||||
        "house": [
 | 
			
		||||
            {"name": "Ralph Castelli - Morning Sex (Mochakk Remix)", "url": "https://www.youtube.com/watch?v=6bCwJ_TIDG4"},
 | 
			
		||||
            {"name": "Billie Eilish - Bossa Nova (Lewii Edit)", "url": "https://www.youtube.com/watch?v=gNawHj2NCxA"},
 | 
			
		||||
            {"name": "Fidde - I Only See Things I Dont Have", "url": "https://www.youtube.com/watch?v=vX_Ye_ZzI-Y"},
 | 
			
		||||
            {"name": "Bauhouse - After Marvins Dance (Marvin Gaye's 'After The Dance' Edit)", "url": "https://www.youtube.com/watch?v=J-cgyYiExh8"},
 | 
			
		||||
            {"name": "Men I Trust - Tailwhip (Lewii Edit)", "url": "https://www.youtube.com/watch?v=XhyM-JUWwWQ"},
 | 
			
		||||
            {"name": "Sweely - Le Son Dancefloor", "url": "https://www.youtube.com/watch?v=5uEvZgmoG6Y"},
 | 
			
		||||
            {"name": "THEOS - Rhodes Trip", "url": "https://www.youtube.com/watch?v=m7guRO0Uz_c"},
 | 
			
		||||
            {"name": "Baltra - Tears Drop", "url": "https://www.youtube.com/watch?v=EXXMtKPfuzY"},
 | 
			
		||||
            {"name": "Fidde - If Theres A Heaven I Wanna See It", "url": "https://www.youtube.com/watch?v=l2Nw7cIh7qg"},
 | 
			
		||||
            {"name": "Unknown Artist - Kcik 23", "url": "https://www.youtube.com/watch?v=SnnqDdZJpzA"}
 | 
			
		||||
        ],
 | 
			
		||||
        "lietuviskos": [
 | 
			
		||||
            {"name": "Adomas Vysniauskas - As Judu", "url": "https://www.youtube.com/watch?v=dMm16TzZrjg"},
 | 
			
		||||
            {"name": "RADVIS - KINO FILMAI", "url": "https://www.youtube.com/watch?v=vhAEkC3xNMo"},
 | 
			
		||||
            {"name": "16Hz - Autostrada Vilnius - Kaunas", "url": "https://www.youtube.com/watch?v=ANS2TSegr40"},
 | 
			
		||||
            {"name": "Zas - Zalias Pasas", "url": "https://www.youtube.com/watch?v=SZA7IjlCfyI"},
 | 
			
		||||
            {"name": "Dzordana Butkute - Nebenoriu Laukt", "url": "https://www.youtube.com/watch?v=_AozFrAqNMk"},
 | 
			
		||||
            {"name": "Juodas Garvezys (Remix)", "url": "https://www.youtube.com/watch?v=D-7qQbXHSAw"},
 | 
			
		||||
            {"name": "morre - Kaip Diena", "url": "https://www.youtube.com/watch?v=6LDgLWCQSSM"},
 | 
			
		||||
            {"name": "MC ENDRAY - AUDI", "url": "https://www.youtube.com/watch?v=oIjNoMGEuRg"},
 | 
			
		||||
            {"name": "Mercy Dance - I Pajuri", "url": "https://www.youtube.com/watch?v=RPpkMh47l9w"},
 | 
			
		||||
            {"name": "NL - Pasitusinam", "url": "https://www.youtube.com/watch?v=WhSFudvloog"},
 | 
			
		||||
            {"name": "SixthBoi - Nevaidink", "url": "https://www.youtube.com/watch?v=nOTNnnrqTII"},
 | 
			
		||||
            {"name": "Mr.Bullet - UZ MUS IR JUS", "url": "https://www.youtube.com/watch?v=85q_7jXEgH8"},
 | 
			
		||||
            {"name": "Jovani, Karaliska Erdve - Is Leto Leidziasi Saule", "url": "https://www.youtube.com/watch?v=VqSu8iG1_DE"},
 | 
			
		||||
            {"name": "Rondo - Margarita", "url": "https://www.youtube.com/watch?v=rF4w-Rxsiv4"},
 | 
			
		||||
            {"name": "Radvis - TU ESI MELAGIS (Techno Extended)", "url": "https://www.youtube.com/watch?v=kmvvP7GW_bw"},
 | 
			
		||||
            {"name": "Zas - Myliu kina", "url": "https://www.youtube.com/watch?v=ImFrfmi-qT8"},
 | 
			
		||||
            {"name": "Zilvinas Zvagulis - Amerikonas grizo sunus", "url": "https://www.youtube.com/watch?v=UvzJEz5ADY8"},
 | 
			
		||||
            {"name": "Raketa - I Kluba", "url": "https://www.youtube.com/watch?v=FkSjtpYN3EI"},
 | 
			
		||||
            {"name": "Karaliska Erdve - Vakareja", "url": "https://www.youtube.com/watch?v=g0HmrlJ7fhE"},
 | 
			
		||||
            {"name": "Tnn - Parukom", "url": "https://www.youtube.com/watch?v=v9pBZK2RIPI"},
 | 
			
		||||
            {"name": "DJ Dalgis - Kauniete", "url": "https://www.youtube.com/watch?v=b3xPE9Iyuzc"},
 | 
			
		||||
            {"name": "Andzikas - I gamta", "url": "https://www.youtube.com/watch?v=UyLdjC-hihM"},
 | 
			
		||||
            {"name": "nemuno krantai - rytmecio rasos", "url": "https://www.youtube.com/watch?v=2-fGbsrofv4"},
 | 
			
		||||
            {"name": "Tipo grupe - Lovoj Vezi", "url": "https://www.youtube.com/watch?v=M3zVMzWCy_c"},
 | 
			
		||||
            {"name": "Kastanenda - Sombrero", "url": "https://www.youtube.com/watch?v=3Z3_4TknCfQ"},
 | 
			
		||||
            {"name": "Elektra - Juda Tavo rankos", "url": "https://www.youtube.com/watch?v=k2RuDoudnOE"},
 | 
			
		||||
            {"name": "Vilija ir Marijonas mikutavicius - Dabar Geriausi Musu Vakarai", "url": "https://www.youtube.com/watch?v=MPnZkEscWo0"},
 | 
			
		||||
            {"name": "Parnesk alaus OG", "url": "https://www.youtube.com/watch?v=e7cB1JIlZ2k"},
 | 
			
		||||
            {"name": "Eugenijus Ostapenko - Dviratukas", "url": "https://www.youtube.com/watch?v=ILFHZQK33Mw"},
 | 
			
		||||
            {"name": "Ciulpuoneliai - Jau Nutilo Sirgaliai", "url": "https://www.youtube.com/watch?v=s8qIVA1U0C0"},
 | 
			
		||||
            {"name": "Tweaxx - Mersas", "url": "https://www.youtube.com/watch?v=7ljAzgALPdA"},
 | 
			
		||||
            {"name": "Dove - Naktinis Tusas", "url": "https://www.youtube.com/watch?v=pz-HEAwFEnk"},
 | 
			
		||||
            {"name": "MAMA MANE RODYS PER FARUS", "url": "https://www.youtube.com/watch?v=F5HqXYRDZaE"},
 | 
			
		||||
            {"name": "Kastaneda - Kelyje", "url": "https://www.youtube.com/watch?v=JVE6NQqKPL4"},
 | 
			
		||||
            {"name": "NL - Juodas Golfas", "url": "https://www.youtube.com/watch?v=f2-ZmElSvPc"},
 | 
			
		||||
            {"name": "DJ Dalgis - Zalia Siera", "url": "https://www.youtube.com/watch?v=nfentq_pez4"},
 | 
			
		||||
            {"name": "L1GHT CASH - Whiskey Cola Lietuviskai (sultys degtinele) remix", "url": "https://www.youtube.com/watch?v=YVaqDaf1KXU"},
 | 
			
		||||
            {"name": "Tipo grupe ir Kastaneda - Po stikliuka", "url": "https://www.youtube.com/watch?v=EtmE60nE7fI"},
 | 
			
		||||
            {"name": "MG INTERNATIONAL - JUODA ORCHIDEJA", "url": "https://www.youtube.com/watch?v=HQvceFRBq9M"},
 | 
			
		||||
            {"name": "Ganja - Truputi", "url": "https://www.youtube.com/watch?v=Pxve7CwiCHM"},
 | 
			
		||||
            {"name": "Riaukenzo - Trys Trys Trys", "url": "https://www.youtube.com/watch?v=qJv6GRQCnCk"},
 | 
			
		||||
            {"name": "Grupiokai - Degtine", "url": "https://www.youtube.com/watch?v=8SqbG2VmEFw"},
 | 
			
		||||
            {"name": "Robertas Kupstas - Cia Mano Rojus", "url": "https://www.youtube.com/watch?v=xij_YeEInr8"},
 | 
			
		||||
            {"name": "NIERKA - PENKTADIENIS", "url": "https://www.youtube.com/watch?v=h3TuZj_OAf0"},
 | 
			
		||||
            {"name": "VAIKAI PO LELIJOM (REMIX)", "url": "https://www.youtube.com/watch?v=k1amBbsAZuo"},
 | 
			
		||||
            {"name": "Vitalija Katunskyte - Robinzonas", "url": "https://www.youtube.com/watch?v=erDHG-QpbPY"},
 | 
			
		||||
            {"name": "Rycka klipas", "url": "https://www.youtube.com/watch?v=nuTUDSQ3BBI"},
 | 
			
		||||
            {"name": "Nezinau, Kodel...", "url": "https://www.youtube.com/watch?v=A-i2CkCnPoc"},
 | 
			
		||||
            {"name": "NL - R1", "url": "https://www.youtube.com/watch?v=hSgav4fYnZ8"},
 | 
			
		||||
            {"name": "DJ Dalgis - Negeriau", "url": "https://www.youtube.com/watch?v=c89YvG3MCcs"},
 | 
			
		||||
            {"name": "Tipo Grupe - tipo daina", "url": "https://www.youtube.com/watch?v=PTIOaSjEgIU"},
 | 
			
		||||
            {"name": "Depresinis feat. Deivas - 0,7", "url": "https://www.youtube.com/watch?v=rjwFjBgTzAA"},
 | 
			
		||||
            {"name": "Depresinis & MERAKI2004 - VASARA ZJBS", "url": "https://www.youtube.com/watch?v=BD-pBjRy-5A"},
 | 
			
		||||
            {"name": "Depresinis feat. Deivas - LEDUKAI", "url": "https://www.youtube.com/watch?v=R2-MtpkKgGI"},
 | 
			
		||||
            {"name": "Depresinis feat. Deivas - Pavasaris", "url": "https://www.youtube.com/watch?v=yWWAucfQdN4"},
 | 
			
		||||
            {"name": "Depresinis - LEDINE", "url": "https://www.youtube.com/watch?v=qugvChkXMLk"},
 | 
			
		||||
            {"name": "Depresinis, Jypas - O Mazuti", "url": "https://www.youtube.com/watch?v=4t_DPbe2r3M"},
 | 
			
		||||
            {"name": "AVA - Eik Tu NA", "url": "https://www.youtube.com/watch?v=yRf3ijaIgOg"},
 | 
			
		||||
            {"name": "Judam Lietuvoj", "url": "https://www.youtube.com/watch?v=WDzWSEgSy5U"},
 | 
			
		||||
            {"name": "16Hz - Baliavojam", "url": "https://www.youtube.com/watch?v=Ia-qERX8WLs"},
 | 
			
		||||
            {"name": "Deivas - Klaipeda On Top", "url": "https://www.youtube.com/watch?v=g_h2M3e2OYU"},
 | 
			
		||||
            {"name": "Depresinis - Volkswagina", "url": "https://www.youtube.com/watch?v=1lZR1VKsQHo"},
 | 
			
		||||
            {"name": "SADBOY - Kaifuok", "url": "https://www.youtube.com/watch?v=vclryWgfy8I"},
 | 
			
		||||
            {"name": "SADBOY - Blizgantys Naikai", "url": "https://www.youtube.com/watch?v=p5KsYJGcfOM"},
 | 
			
		||||
            {"name": "SADBOY - 1001 Naktis", "url": "https://www.youtube.com/watch?v=mLJIjGvWmKI"},
 | 
			
		||||
            {"name": "SADBOY - Deginam", "url": "https://www.youtube.com/watch?v=w3R0Aq1EGXg"},
 | 
			
		||||
            {"name": "Wenona Waves - Topine Panele", "url": "https://www.youtube.com/watch?v=MPHuhmUomfE"},
 | 
			
		||||
            {"name": "Andzikas - Virs debesu", "url": "https://www.youtube.com/watch?v=PHJcVGhxra8"},
 | 
			
		||||
            {"name": "Grupe MX - 1.9 TDI", "url": "https://www.youtube.com/watch?v=8FBr5GQXsI8"},
 | 
			
		||||
            {"name": "Patruliai - Kur Tu", "url": "https://www.youtube.com/watch?v=OPWhiu3cvj0"},
 | 
			
		||||
            {"name": "Ka Tu Ka Vakare", "url": "https://www.youtube.com/watch?v=6SOS4ljHbJY"}
 | 
			
		||||
        ],
 | 
			
		||||
        "lietuviskos/rave": [
 | 
			
		||||
            {"name": "VainHouse - Malunas Prie Kelio", "url": "https://www.youtube.com/watch?v=bbwuNjDXCiM"},
 | 
			
		||||
            {"name": "Sokoledas - Mano Skonis Sokolado (Matuze & Arnisxd Remix)", "url": "https://www.youtube.com/watch?v=hb41bfQxiM0"}
 | 
			
		||||
        ],
 | 
			
		||||
        "rusiskos": [
 | 
			
		||||
            {"name": "Topolini puh", "url": "https://www.youtube.com/watch?v=UUryvYF8tUs"},
 | 
			
		||||
            {"name": "Raim & Artur feat. Zhenis - Diskoteka is 90 hit", "url": "https://www.youtube.com/watch?v=GfBhxlNhrn0"},
 | 
			
		||||
            {"name": "Pimp Schwab - vse shto nas ne Ubivaet", "url": "https://www.youtube.com/watch?v=NTEXFyUE9Ww"},
 | 
			
		||||
            {"name": "Dzaro and hansa - Visky Kola karaleva trans pola", "url": "https://www.youtube.com/watch?v=fflrMvZ2HtA"}
 | 
			
		||||
        ],
 | 
			
		||||
        "noclue": [
 | 
			
		||||
            {"name": "Bad Boys", "url": "https://www.youtube.com/watch?v=NTC7RD8xzCY"},
 | 
			
		||||
            {"name": "DR. VODKA - DZIEWCZYNO Z TIKTOKA", "url": "https://www.youtube.com/watch?v=HLbw1WQt64o"},
 | 
			
		||||
            {"name": "Maco Mamuko - Whiskey, Cola i Tequila", "url": "https://www.youtube.com/watch?v=aBrN0k0Phtc"}
 | 
			
		||||
    
 | 
			
		||||
        ],
 | 
			
		||||
        "reggea": [
 | 
			
		||||
            {"name": "Shaggy - It Wasn't Me", "url": "https://www.youtube.com/watch?v=ssVj50ombaM"}
 | 
			
		||||
        ],
 | 
			
		||||
        "alt": [
 | 
			
		||||
            {"name": "ROMANCEPLANET - FALL FROM THE SKY", "url": "https://www.youtube.com/watch?v=HMhzxzXBisw"},
 | 
			
		||||
            {"name": "ROMANCEPLANET - PLAIN WHITE TEE", "url": "https://www.youtube.com/watch?v=tdVQbNwjGac"},
 | 
			
		||||
            {"name": "ROMANCEPLANET - DANCE", "url": "https://www.youtube.com/watch?v=ircOfMb4gEw"}
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
use std::str::FromStr;
 | 
			
		||||
 | 
			
		||||
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::{Manifest, ManifestSong}, util::is_supported_host};
 | 
			
		||||
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::{song::Song, Manifest}, util::is_supported_host};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ pub async fn add(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut
 | 
			
		|||
    log::debug!("url: {url:?}");
 | 
			
		||||
    log::debug!("name: {name:?}");
 | 
			
		||||
 | 
			
		||||
    let mut genres = manifest.genres.keys().map(|f| f.clone()).collect::<Vec<String>>();
 | 
			
		||||
    let mut genres = manifest.get_genres().keys().map(|f| f.clone()).collect::<Vec<String>>();
 | 
			
		||||
 | 
			
		||||
    genres.sort();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,18 +35,14 @@ pub async fn add(cfg: &ConfigWrapper, manifest: &mut Manifest, downloader: &mut
 | 
			
		|||
        crate::prompt::simple_prompt("Enter song name with like this: {Author} - {Song name}")
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    manifest.add_song(genre.clone(), name.clone(), url.clone())?;
 | 
			
		||||
    manifest.save()?;
 | 
			
		||||
    let song = Song::from_url_str(url)?;
 | 
			
		||||
    manifest.add_song(genre.clone(), name.clone(), song.clone());
 | 
			
		||||
    manifest.save(None)?;
 | 
			
		||||
 | 
			
		||||
    let should_download = crate::prompt::prompt_bool("Download song now?", Some(false));
 | 
			
		||||
 | 
			
		||||
    if should_download {
 | 
			
		||||
        let song = &ManifestSong {
 | 
			
		||||
            name,
 | 
			
		||||
            url,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        downloader.download_song(cfg, song, &genre, &manifest.format()?).await?;
 | 
			
		||||
        downloader.download_song(cfg, &name, &song, &genre, manifest.get_format()).await?;
 | 
			
		||||
        downloader.wait_for_procs(0).await?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,11 @@ pub async fn command_run(cfg: &ConfigWrapper, manifest: &mut Manifest) -> anyhow
 | 
			
		|||
        Some(c) => {
 | 
			
		||||
            match c {
 | 
			
		||||
                CliCommand::Download => unreachable!(),
 | 
			
		||||
                CliCommand::Add { url, name, genre  } => add::add(cfg, manifest, &mut downloader, url, name, genre).await?,
 | 
			
		||||
                CliCommand::Add { url, name, genre  } => {
 | 
			
		||||
                    if let Err(e) = add::add(cfg, manifest, &mut downloader, url, name, genre).await {
 | 
			
		||||
                        log::error!("Failed to run 'add' command: {e}");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
use std::{collections::HashMap, path::PathBuf, process::Stdio, str::FromStr};
 | 
			
		||||
use std::{collections::HashMap, path::PathBuf, process::Stdio};
 | 
			
		||||
 | 
			
		||||
use lazy_static::lazy_static;
 | 
			
		||||
use log::Level;
 | 
			
		||||
use tokio::sync::{Mutex, RwLock};
 | 
			
		||||
 | 
			
		||||
use crate::{config::ConfigWrapper, manifest::{Manifest, ManifestSong}};
 | 
			
		||||
use crate::{config::ConfigWrapper, manifest::{song::{Song, SongType}, Format, Manifest}};
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
| 
						 | 
				
			
			@ -32,11 +32,11 @@ impl Downloader {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn download_all(&mut self, manifest: &Manifest, cfg: &ConfigWrapper) -> anyhow::Result<usize> {
 | 
			
		||||
        let format = manifest.format()?;
 | 
			
		||||
        let format = manifest.get_format();
 | 
			
		||||
 | 
			
		||||
        for (genre, songs) in &manifest.genres {
 | 
			
		||||
            for song in songs {
 | 
			
		||||
                self.download_song(cfg, song, &genre, &format).await?;
 | 
			
		||||
        for (genre, songs) in manifest.get_genres() {
 | 
			
		||||
            for (song_name, song) in songs {
 | 
			
		||||
                self.download_song(cfg, song_name, song, &genre, format).await?;
 | 
			
		||||
                self.wait_for_procs(10).await?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -44,26 +44,20 @@ impl Downloader {
 | 
			
		|||
        Ok(self.count)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    pub async fn download_song(&mut self, cfg: &ConfigWrapper, song: &ManifestSong, genre: &String, format: &String) -> anyhow::Result<()> {
 | 
			
		||||
        let dl_dir = format!("{}/{genre}/", cfg.cli.output);
 | 
			
		||||
        let dl_file = format!("{dl_dir}/{}.{}", song.name, &format);
 | 
			
		||||
    pub async fn download_song(&mut self, cfg: &ConfigWrapper, name: &String, song: &Song, genre: &String, format: &Format) -> anyhow::Result<()> {
 | 
			
		||||
        let dl_dir = format!("{}/{genre}", cfg.cli.output);
 | 
			
		||||
        let dl_file = format!("{dl_dir}/{}.{}", name, &format);
 | 
			
		||||
 | 
			
		||||
        if PathBuf::from(&dl_file).exists() {
 | 
			
		||||
            log::debug!("File {dl_file} exists, skipping");
 | 
			
		||||
            return Ok(())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let url = url::Url::from_str(&song.url)?;
 | 
			
		||||
        let Some(url_host) = url.host() else {
 | 
			
		||||
            log::error!("Url {} doesnt have a valid host name", &song.url);
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        };
 | 
			
		||||
        log::debug!("File {dl_file} doesnt exist, downloading");
 | 
			
		||||
        let mut cmd = match url_host.to_string().as_str() {
 | 
			
		||||
        let mut cmd = match song.get_type() {
 | 
			
		||||
 | 
			
		||||
            "youtube.com" |
 | 
			
		||||
            "youtu.be" => {
 | 
			
		||||
                log::debug!("Song {} is from yotube", song.url);
 | 
			
		||||
            &SongType::Youtube => {
 | 
			
		||||
                log::debug!("Song {} is from yotube", song.get_url_str());
 | 
			
		||||
                let mut cmd = tokio::process::Command::new(&cfg.cfg.ytdlp.path);
 | 
			
		||||
                cmd.args([
 | 
			
		||||
                        "-x",
 | 
			
		||||
| 
						 | 
				
			
			@ -71,11 +65,11 @@ impl Downloader {
 | 
			
		|||
                        &format.to_string(),
 | 
			
		||||
                        "-o",
 | 
			
		||||
                        dl_file.as_str(),
 | 
			
		||||
                        song.url.as_str()
 | 
			
		||||
                        song.get_url_str().as_str()
 | 
			
		||||
                    ]);
 | 
			
		||||
                cmd
 | 
			
		||||
            }
 | 
			
		||||
            "open.spotify.com" => {
 | 
			
		||||
            SongType::Spotify => {
 | 
			
		||||
 | 
			
		||||
                let mut cmd = tokio::process::Command::new(&cfg.cfg.spotdl.path);
 | 
			
		||||
                cmd.args([
 | 
			
		||||
| 
						 | 
				
			
			@ -83,12 +77,12 @@ impl Downloader {
 | 
			
		|||
                    &format.to_string(),
 | 
			
		||||
                    "--output",
 | 
			
		||||
                    dl_dir.as_str(),
 | 
			
		||||
                    song.url.as_str()
 | 
			
		||||
                    song.get_url_str().as_str()
 | 
			
		||||
                ]);
 | 
			
		||||
                cmd
 | 
			
		||||
            }
 | 
			
		||||
            url => {
 | 
			
		||||
                log::error!("Unknown or unsupported hostname '{}'", url);
 | 
			
		||||
                log::error!("Unknown or unsupported hostname '{:?}'", url);
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +103,7 @@ impl Downloader {
 | 
			
		|||
        
 | 
			
		||||
        log::info!("Downloading {dl_file}");
 | 
			
		||||
        PROCESSES.lock().await.write().await.insert(id, Proc {
 | 
			
		||||
            url: song.url.clone(),
 | 
			
		||||
            url: song.get_url_str().clone(),
 | 
			
		||||
            path: dl_file,
 | 
			
		||||
            finished: false,
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +135,7 @@ impl Downloader {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        #[allow(unreachable_code)] //? rust_analizer not smart enough for this
 | 
			
		||||
        #[allow(unreachable_code)] //? rust_analyzer not smart enough for this
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ async fn main() {
 | 
			
		|||
        return;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut manifest = match manifest::Manifest::from_path(&cfg.cli.manifest.as_std_path()) {
 | 
			
		||||
    let mut manifest = match manifest::Manifest::load_new(&cfg.cli.manifest.clone().into_std_path_buf()) {
 | 
			
		||||
        Ok(m) => m,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to parse manifest file {}: {e}", cfg.cli.manifest);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,165 +1,120 @@
 | 
			
		|||
// pub mod v1;
 | 
			
		||||
 | 
			
		||||
use std::{collections::HashMap, fmt::{Debug, Display}, path::{Path, PathBuf}, str::FromStr};
 | 
			
		||||
pub mod song;
 | 
			
		||||
use song::Song;
 | 
			
		||||
 | 
			
		||||
use std::{collections::HashMap, fmt::{Debug, Display}, path::PathBuf};
 | 
			
		||||
 | 
			
		||||
use anyhow::{bail, Result};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
const ALLOWED_FORMATS: &[&'static str] = &["m4a", "aac", "flac", "mp3", "vaw"];
 | 
			
		||||
pub type GenreName = String;
 | 
			
		||||
pub type SongName = String;
 | 
			
		||||
pub type Genre = HashMap<SongName, song::Song>;
 | 
			
		||||
 | 
			
		||||
#[allow(non_camel_case_types)]
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
 | 
			
		||||
pub enum Format {
 | 
			
		||||
    #[default]
 | 
			
		||||
    m4a,
 | 
			
		||||
    aac,
 | 
			
		||||
    flac,
 | 
			
		||||
    mp3,
 | 
			
		||||
    vaw,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Genre = String;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
 | 
			
		||||
pub struct Manifest {
 | 
			
		||||
    #[serde(skip)]
 | 
			
		||||
    path: PathBuf,
 | 
			
		||||
    format: String,
 | 
			
		||||
    pub genres: HashMap<Genre, Vec<ManifestSong>>
 | 
			
		||||
    format: Format,
 | 
			
		||||
    genres: HashMap<GenreName, Genre>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
impl Manifest {
 | 
			
		||||
    pub fn format(&self) -> anyhow::Result<String> {
 | 
			
		||||
        if !ALLOWED_FORMATS.contains(&self.format.as_str()) {
 | 
			
		||||
            log::error!("Unknown format, allowed formats: {}", ALLOWED_FORMATS.join(", "));
 | 
			
		||||
            bail!("")
 | 
			
		||||
        }
 | 
			
		||||
        Ok(self.format.clone())
 | 
			
		||||
    pub fn get_format(&self) -> &Format {
 | 
			
		||||
        &self.format
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct ManifestSong {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub url: String
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl Manifest {
 | 
			
		||||
    fn from_string(s: String) -> anyhow::Result<Self> {
 | 
			
		||||
        let s = serde_json::from_str(&s)?;
 | 
			
		||||
        Ok(s)
 | 
			
		||||
    pub fn add_song(&mut self, genre: GenreName, name: SongName, song: Song) -> Option<Song> {
 | 
			
		||||
        self.get_genre_mut(genre)?.insert(name, song)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_path(p: &Path) -> anyhow::Result<Self> {
 | 
			
		||||
        let data = std::fs::read_to_string(p)?;
 | 
			
		||||
        let mut s = Self::from_string(data)?;
 | 
			
		||||
        s.path = p.to_path_buf();
 | 
			
		||||
        Ok(s)
 | 
			
		||||
    pub fn get_song(&self, genre: GenreName, name: &SongName) -> Option<&Song> {
 | 
			
		||||
        self.get_genre(genre)?.get(name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_song_mut(&mut self, genre: GenreName, name: &SongName) -> Option<&mut Song> {
 | 
			
		||||
        self.get_genre_mut(genre)?.get_mut(name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn add_genre(&mut self, name: GenreName) {
 | 
			
		||||
        self.genres.insert(name, Default::default());
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_genre(&self, name: GenreName) -> Option<&Genre> {
 | 
			
		||||
        self.genres.get(&name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_genre_mut(&mut self, name: GenreName) -> Option<&mut Genre> {
 | 
			
		||||
        self.genres.get_mut(&name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_genres(&self) -> &HashMap<GenreName, Genre> {
 | 
			
		||||
        &self.genres
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_genres_mut(&mut self) -> &mut HashMap<GenreName, Genre> {
 | 
			
		||||
        &mut self.genres
 | 
			
		||||
    }
 | 
			
		||||
    pub fn load(&mut self, p: Option<&PathBuf>) -> Result<()> {
 | 
			
		||||
        let path = p.unwrap_or(&self.path);
 | 
			
		||||
        log::debug!("Path: {path:?}");
 | 
			
		||||
        let data = std::fs::read_to_string(path)?;
 | 
			
		||||
 | 
			
		||||
    pub fn add_song(&mut self, genre: String, name: String, url: String) -> anyhow::Result<()> {
 | 
			
		||||
 | 
			
		||||
        if !self.genres.contains_key(&genre) {
 | 
			
		||||
            self.genres.insert(genre.clone(), Vec::new());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let Some(genre_ref) = self.genres.get_mut(&genre) else {
 | 
			
		||||
            log::error!("Invalid genre '{}'", genre);
 | 
			
		||||
            bail!("Invalid genre")
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        genre_ref.push(ManifestSong {
 | 
			
		||||
            name,
 | 
			
		||||
            url,
 | 
			
		||||
        });
 | 
			
		||||
        let s: Self = serde_json::from_str(data.as_str())?;
 | 
			
		||||
        self.genres = s.genres;
 | 
			
		||||
        self.format = s.format;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn save(&self) -> anyhow::Result<()> {
 | 
			
		||||
    pub fn save(&self, p: Option<&PathBuf>) -> Result<()> {
 | 
			
		||||
        let path = p.unwrap_or(&self.path);
 | 
			
		||||
        log::debug!("Path: {path:?}");
 | 
			
		||||
        let data = serde_json::to_string_pretty(self)?;
 | 
			
		||||
        std::fs::write(&self.path, data)?;
 | 
			
		||||
        std::fs::write(path, data)?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    pub fn load_new(p: &PathBuf) -> Result<Self> {
 | 
			
		||||
        let mut s = Self::default();
 | 
			
		||||
        log::debug!("Path: {p:?}");
 | 
			
		||||
        s.path = p.clone();
 | 
			
		||||
        s.load(Some(p))?;
 | 
			
		||||
        Ok(s)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl TryFrom<String> for Format {
 | 
			
		||||
    type Error = anyhow::Error;
 | 
			
		||||
    fn try_from(value: String) -> std::prelude::v1::Result<Self, Self::Error> {
 | 
			
		||||
        match value.as_str() {
 | 
			
		||||
            "m4a" => Ok(Self::m4a),
 | 
			
		||||
            "aac" => Ok(Self::aac),
 | 
			
		||||
            "flac" => Ok(Self::flac),
 | 
			
		||||
            "mp3" => Ok(Self::mp3),
 | 
			
		||||
            "vaw" => Ok(Self::vaw),
 | 
			
		||||
            v => bail!("Unknown format {v}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for Format {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Format::m4a => write!(f, "m4a")?,
 | 
			
		||||
            Format::aac => write!(f, "aac")?,
 | 
			
		||||
            Format::flac => write!(f, "flac")?,
 | 
			
		||||
            Format::mp3 => write!(f, "mp3")?,
 | 
			
		||||
            Format::vaw => write!(f, "vaw")?,
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// pub type GenreName = String;
 | 
			
		||||
// pub type SongName = String;
 | 
			
		||||
// pub type Genre = HashMap<SongName, Box<dyn Song>>;
 | 
			
		||||
 | 
			
		||||
// #[derive(Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
// pub enum SongType {
 | 
			
		||||
//     Youtube,
 | 
			
		||||
//     Spotify,
 | 
			
		||||
//     Soundcloud,
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// impl TryFrom<url::Url> for SongType {
 | 
			
		||||
//     type Error = anyhow::Error;
 | 
			
		||||
 | 
			
		||||
//     fn try_from(url: url::Url) -> std::prelude::v1::Result<Self, Self::Error> {
 | 
			
		||||
//         let Some(host) = url.host_str() else {
 | 
			
		||||
//             bail!("{url} does not have a host");
 | 
			
		||||
//         };
 | 
			
		||||
 | 
			
		||||
//         match host {
 | 
			
		||||
//             "youtube.com" | "youtu.be"  => Ok(Self::Youtube),
 | 
			
		||||
//             "open.spotify.com"  => Ok(Self::Spotify),
 | 
			
		||||
//             "SOUNDCLOUD" => Ok(Self::Soundcloud), // TODO: Fix this
 | 
			
		||||
//             _ => bail!("Unknwon host {url}")
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// #[allow(non_camel_case_types)]
 | 
			
		||||
// #[derive(Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
// pub enum Format {
 | 
			
		||||
//     m4a,
 | 
			
		||||
//     aac,
 | 
			
		||||
//     flac,
 | 
			
		||||
//     mp3,
 | 
			
		||||
//     vaw,
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// impl TryFrom<String> for Format {
 | 
			
		||||
//     type Error = anyhow::Error;
 | 
			
		||||
//     fn try_from(value: String) -> std::prelude::v1::Result<Self, Self::Error> {
 | 
			
		||||
//         match value.as_str() {
 | 
			
		||||
//             "m4a" => Ok(Self::m4a),
 | 
			
		||||
//             "aac" => Ok(Self::aac),
 | 
			
		||||
//             "flac" => Ok(Self::flac),
 | 
			
		||||
//             "mp3" => Ok(Self::mp3),
 | 
			
		||||
//             "vaw" => Ok(Self::vaw),
 | 
			
		||||
//             v => bail!("Unknown format {v}")
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
    
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// impl Display for Format {
 | 
			
		||||
//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
//         match self {
 | 
			
		||||
//             Format::m4a => write!(f, "m4a")?,
 | 
			
		||||
//             Format::aac => write!(f, "aac")?,
 | 
			
		||||
//             Format::flac => write!(f, "flac")?,
 | 
			
		||||
//             Format::mp3 => write!(f, "mp3")?,
 | 
			
		||||
//             Format::vaw => write!(f, "vaw")?,
 | 
			
		||||
//         }
 | 
			
		||||
//         Ok(())
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
// pub trait Song: Debug +  serde_traitobject::Serialize + serde_traitobject::Deserialize{
 | 
			
		||||
//     fn get_url(&self) -> Result<url::Url>;
 | 
			
		||||
//     fn get_url_str(&self) -> &String;
 | 
			
		||||
//     fn get_url_str_mut(&mut self) -> &mut String;
 | 
			
		||||
//     fn get_type(&self) -> &SongType;
 | 
			
		||||
//     fn get_type_mut(&mut self) -> &mut SongType;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// pub trait Manifest: Debug + Clone + serde_traitobject::Serialize + serde_traitobject::Deserialize{
 | 
			
		||||
//     fn get_format(&self) -> Result<Format>;
 | 
			
		||||
//     fn add_song(&mut self, genre: GenreName, name: SongName, song: &dyn Song) -> Option<Box<dyn Song>>;
 | 
			
		||||
//     fn get_song(&self, genre: GenreName, name: SongName) -> Option<&Box<dyn Song>>;
 | 
			
		||||
//     fn get_song_mut(&mut self, genre: GenreName, name: SongName) -> Option<&mut Box<dyn Song>>;
 | 
			
		||||
//     fn add_genre(&mut self, genre: GenreName);
 | 
			
		||||
//     fn get_genre(&self, genre: GenreName) -> Option<&Genre>;
 | 
			
		||||
//     fn get_genre_mut(&mut self, genre: GenreName) -> Option<&mut Genre>;
 | 
			
		||||
//     fn get_genres(&self) -> &HashMap<GenreName, Genre>;
 | 
			
		||||
//     fn get_genres_mut(&mut self) -> &mut HashMap<GenreName, Genre>;
 | 
			
		||||
//     fn load(&mut self, p: PathBuf);
 | 
			
		||||
//     fn save(&self, p: Option<&PathBuf>);
 | 
			
		||||
// }
 | 
			
		||||
							
								
								
									
										66
									
								
								music_mgr/src/manifest/song.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								music_mgr/src/manifest/song.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
use std::str::FromStr;
 | 
			
		||||
 | 
			
		||||
use anyhow::{bail, Result};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
pub enum SongType {
 | 
			
		||||
    Youtube,
 | 
			
		||||
    Spotify,
 | 
			
		||||
    Soundcloud,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
pub struct Song {
 | 
			
		||||
    url: String,
 | 
			
		||||
    typ: SongType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
impl Song {
 | 
			
		||||
    pub fn from_url_str(url: String) -> Result<Self> {
 | 
			
		||||
        Self::from_url(url::Url::from_str(url.as_str())?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_url(url: url::Url) -> Result<Self> {
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            url: url.to_string(),
 | 
			
		||||
            typ: url.try_into()?,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_url(&self) -> Result<url::Url> {
 | 
			
		||||
        Ok(url::Url::from_str(&self.url)?)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_url_str(&self) -> &String {
 | 
			
		||||
        &self.url
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_url_str_mut(&mut self) -> &mut String {
 | 
			
		||||
        &mut self.url
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_type(&self) -> &SongType {
 | 
			
		||||
        &self.typ
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_type_mut(&mut self) -> &mut SongType {
 | 
			
		||||
        &mut self.typ
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl TryFrom<url::Url> for SongType {
 | 
			
		||||
    type Error = anyhow::Error;
 | 
			
		||||
 | 
			
		||||
    fn try_from(url: url::Url) -> std::prelude::v1::Result<Self, Self::Error> {
 | 
			
		||||
        let Some(host) = url.host_str() else {
 | 
			
		||||
            bail!("{url} does not have a host");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        match host {
 | 
			
		||||
            "youtube.com" | "youtu.be" | "www.youtube.com" => Ok(Self::Youtube),
 | 
			
		||||
            "open.spotify.com"  => Ok(Self::Spotify),
 | 
			
		||||
            "SOUNDCLOUD" => Ok(Self::Soundcloud), // TODO: Fix this
 | 
			
		||||
            _ => bail!("Unknwon host {url}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,72 +0,0 @@
 | 
			
		|||
pub mod song;
 | 
			
		||||
 | 
			
		||||
use std::{collections::HashMap, path::PathBuf, str::FromStr};
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use self::song::SongV1;
 | 
			
		||||
 | 
			
		||||
use super::{Format, Genre, GenreName, Manifest, Song, SongName};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct ManifestV1 {
 | 
			
		||||
    version: usize,
 | 
			
		||||
    format: String,
 | 
			
		||||
    genres: HashMap<GenreName, HashMap<SongName, Box<SongV1>>>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl Manifest for ManifestV1 {
 | 
			
		||||
    fn get_format(&self) -> Result<super::Format> {
 | 
			
		||||
        Ok(Format::try_from(self.format.clone())?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_song(&mut self, genre: GenreName, name: SongName, song: &dyn Song) -> Option<Box<dyn Song>> {
 | 
			
		||||
        let song: SongV1 = song.into();
 | 
			
		||||
        self.get_genre_mut(genre)?
 | 
			
		||||
            .insert(name, Box::new(song))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_song(&self, genre: GenreName, name: SongName) -> Option<&Box<dyn Song>> {
 | 
			
		||||
        self.get_genre(genre)?.get(&name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_song_mut(&mut self, genre: GenreName, name: SongName) -> Option<&mut Box<dyn Song>> {
 | 
			
		||||
        self.get_genre_mut(genre)?.get_mut(&name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_genre(&mut self, name: GenreName) {
 | 
			
		||||
        self.genres.insert(name, Default::default());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_genre(&self, genre: GenreName) -> Option<&super::Genre> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            std::mem::transmute(self.genres.get(&genre))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_genre_mut(&mut self, genre: GenreName) -> Option<&mut super::Genre> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            std::mem::transmute(self.genres.get_mut(&genre))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_genres(&self) -> &HashMap<GenreName, super::Genre> {
 | 
			
		||||
        &self.genres
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_genres_mut(&mut self) -> &mut HashMap<GenreName, super::Genre> {
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn load(&mut self, p: PathBuf) {
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn save(&self, p: Option<&PathBuf>) {
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,57 +0,0 @@
 | 
			
		|||
use std::str::FromStr;
 | 
			
		||||
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use crate::manifest::{Song, SongType};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct SongV1 {
 | 
			
		||||
    url: String,
 | 
			
		||||
    typ: SongType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SongV1 {
 | 
			
		||||
    pub fn from_str(url: String) -> Result<Self> {
 | 
			
		||||
        Self::from_url(url::Url::from_str(&url)?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_url(url: url::Url) -> Result<Self> {
 | 
			
		||||
        let typ = SongType::try_from(url.clone())?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            url: url.to_string(),
 | 
			
		||||
            typ,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&dyn Song> for SongV1 {
 | 
			
		||||
    fn from(value: &dyn Song) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            url: value.get_url_str().clone(),
 | 
			
		||||
            typ: value.get_type().clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Song for SongV1 {
 | 
			
		||||
    fn get_url(&self) -> anyhow::Result<url::Url> {
 | 
			
		||||
        Ok(url::Url::from_str(&self.url)?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_url_str(&self) -> &String {
 | 
			
		||||
        &self.url
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_url_str_mut(&mut self) -> &mut String {
 | 
			
		||||
        &mut self.url
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_type(&self) -> &crate::manifest::SongType {
 | 
			
		||||
        &self.typ
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_type_mut(&mut self) -> &mut crate::manifest::SongType {
 | 
			
		||||
        &mut self.typ
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,12 +2,6 @@ use std::path::PathBuf;
 | 
			
		|||
 | 
			
		||||
use crate::constants;
 | 
			
		||||
 | 
			
		||||
pub(crate) fn escape_song_name(s: String) -> String {
 | 
			
		||||
    s
 | 
			
		||||
        .replace(".", "")
 | 
			
		||||
        .replace("'", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn is_supported_host(url: url::Url) -> bool {
 | 
			
		||||
    let host = url.host_str();
 | 
			
		||||
    if host.is_none() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user