added m3u8 to playlist function and fixed playlist to m3u8 function

This commit is contained in:
MrDulfin 2024-04-05 02:09:15 -04:00
parent 7da0b1a1db
commit a75081d4fc
3 changed files with 142 additions and 74 deletions

View file

@ -69,10 +69,10 @@ impl ConfigLibraries {
} }
pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> { pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> {
dbg!(&uuid);
for library in &self.libraries { for library in &self.libraries {
// dbg!(&library.uuid, &uuid);
if &library.uuid == uuid { if &library.uuid == uuid {
dbg!(&library.uuid);
return Ok(library.to_owned()) return Ok(library.to_owned())
} }
} }
@ -148,6 +148,13 @@ impl Config {
let config: Config = serde_json::from_str::<Config>(&bun)?; let config: Config = serde_json::from_str::<Config>(&bun)?;
Ok(config) Ok(config)
} }
pub fn push_library(&mut self, lib: ConfigLibrary) {
if self.libraries.libraries.is_empty() {
self.libraries.default_library = lib.uuid;
}
self.libraries.libraries.push(lib);
}
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -165,45 +172,42 @@ pub enum ConfigError {
} }
#[cfg(test)] #[cfg(test)]
mod tests { pub mod tests {
use std::{path::PathBuf, sync::{Arc, RwLock}}; use std::{path::PathBuf, sync::{Arc, RwLock}};
use crate::music_storage::library::MusicLibrary; use crate::music_storage::library::MusicLibrary;
use super::{Config, ConfigLibraries, ConfigLibrary}; use super::{Config, ConfigLibraries, ConfigLibrary};
#[test] pub fn new_config_lib() -> (Config, MusicLibrary) {
fn config_test() { let lib = ConfigLibrary::new(PathBuf::from("test-config/library"), String::from("library"), None);
let lib_a = ConfigLibrary::new(PathBuf::from("test-config/library1"), String::from("library1"), None); let mut config = Config {
let lib_b = ConfigLibrary::new(PathBuf::from("test-config/library2"), String::from("library2"), None);
let lib_c = ConfigLibrary::new(PathBuf::from("test-config/library3"), String::from("library3"), None);
let config = Config {
path: PathBuf::from("test-config/config_test.json"), path: PathBuf::from("test-config/config_test.json"),
libraries: ConfigLibraries {
libraries: vec![
lib_a.clone(),
lib_b.clone(),
lib_c.clone(),
],
..Default::default()
},
..Default::default() ..Default::default()
}; };
config.write_file();
let arc = Arc::new(RwLock::from(config));
MusicLibrary::init(arc.clone(), lib_a.uuid).unwrap();
MusicLibrary::init(arc.clone(), lib_b.uuid).unwrap();
MusicLibrary::init(arc.clone(), lib_c.uuid).unwrap();
} config.push_library(lib);
config.write_file().unwrap();
#[test] let mut lib = MusicLibrary::init(Arc::new(RwLock::from(config.clone())), dbg!(config.libraries.default_library)).unwrap();
fn test2() {
let config = Config::read_file(PathBuf::from("test-config/config_test.json")).unwrap();
let uuid = config.libraries.get_default().unwrap().uuid;
let mut lib = MusicLibrary::init(Arc::new(RwLock::from(config.clone())), uuid).unwrap();
lib.scan_folder("test-config/music/").unwrap(); lib.scan_folder("test-config/music/").unwrap();
lib.save(config.clone()).unwrap(); lib.save(config.clone()).unwrap();
dbg!(&lib);
dbg!(&config); (config, lib)
}
pub fn read_config_lib() -> (Config, MusicLibrary) {
let config = Config::read_file(PathBuf::from("test-config/config_test.json")).unwrap();
// dbg!(&config);
let mut lib = MusicLibrary::init(Arc::new(RwLock::from(config.clone())), config.libraries.get_default().unwrap().uuid).unwrap();
lib.scan_folder("test-config/music/").unwrap();
lib.save(config.clone()).unwrap();
(config, lib)
} }
#[test] #[test]

View file

@ -686,6 +686,7 @@ impl MusicLibrary {
false => { false => {
// If the library does not exist, re-create it // If the library does not exist, re-create it
let lib = MusicLibrary::new(String::new(), uuid); let lib = MusicLibrary::new(String::new(), uuid);
write_file(&lib, path)?; write_file(&lib, path)?;
lib lib
} }

View file

@ -1,8 +1,9 @@
use std::{fs::File, io::{Read, Error}}; use std::{fs::File, io::Read, path:: PathBuf, sync::{Arc, RwLock}};
use std::error::Error;
use chrono::Duration; use chrono::Duration;
use uuid::Uuid; use uuid::Uuid;
use super::library::{AlbumArt, Song, Tag}; use super::library::{AlbumArt, MusicLibrary, Song, Tag, URI};
use m3u8_rs::{MediaPlaylist, MediaPlaylistType, MediaSegment, Playlist as List2}; use m3u8_rs::{MediaPlaylist, MediaPlaylistType, MediaSegment, Playlist as List2};
@ -34,16 +35,14 @@ impl Playlist {
pub fn set_tracks(&mut self, tracks: Vec<Uuid>) { pub fn set_tracks(&mut self, tracks: Vec<Uuid>) {
self.tracks = tracks; self.tracks = tracks;
} }
pub fn add_track(&mut self, track: Uuid) -> Result<(), Error> { pub fn add_track(&mut self, track: Uuid) {
self.tracks.push(track); self.tracks.push(track);
Ok(())
} }
pub fn remove_track(&mut self, index: i32) -> Result<(), Error> { pub fn remove_track(&mut self, index: i32) {
let index = index as usize; let index = index as usize;
if (self.tracks.len() - 1) >= index { if (self.tracks.len() - 1) >= index {
self.tracks.remove(index); self.tracks.remove(index);
} }
Ok(())
} }
// pub fn get_index(&self, song_name: &str) -> Option<usize> { // pub fn get_index(&self, song_name: &str) -> Option<usize> {
// let mut index = 0; // let mut index = 0;
@ -58,26 +57,41 @@ impl Playlist {
// } // }
// None // None
// } // }
pub fn contains_value(&self, tag: &Tag, value: &str) -> bool { pub fn contains_value(&self, tag: &Tag, value: &String, lib: Arc<RwLock<MusicLibrary>>) -> bool {
&self.tracks.iter().for_each(|track| { let lib = lib.read().unwrap();
let items = match lib.query_tracks(value, &vec![tag.to_owned()], &vec![tag.to_owned()]) {
Some(e) => e,
None => return false
};
for item in items {
for uuid in &self.tracks {
if uuid == &item.uuid {
return true;
}
}
}
});
false false
} }
pub fn to_m3u8(&mut self, tracks: Vec<Song>) {
let seg = tracks
.iter()
.map({
|track| {
MediaSegment { pub fn to_m3u8(&mut self, lib: Arc<RwLock<MusicLibrary>>, location: &str) -> Result<(), Box<dyn Error>> {
uri: track.location.to_string().into(), let lib = lib.read().unwrap();
let seg = self.tracks
.iter()
.filter_map( |uuid| {
if let Some((track, _)) = lib.query_uuid(uuid) {
if let URI::Local(_) = track.location {
Some(MediaSegment {
uri: track.location.to_string(),
duration: track.duration.as_millis() as f32, duration: track.duration.as_millis() as f32,
title: Some(track.tags.get_key_value(&Tag::Title).unwrap().1.into()), title: track.tags.get_key_value(&Tag::Title).map(|tag| tag.1.into()),
..Default::default() ..Default::default()
}
}
}) })
}else { None }
}else { None }
}
)
.collect::<Vec<MediaSegment>>(); .collect::<Vec<MediaSegment>>();
let m3u8 = MediaPlaylist { let m3u8 = MediaPlaylist {
@ -90,19 +104,21 @@ impl Playlist {
segments: seg.clone(), segments: seg.clone(),
..Default::default() ..Default::default()
}; };
//TODO: change this to put in a real file path
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.read(true) .read(true)
.create(true) .create(true)
.truncate(true)
.write(true) .write(true)
.open("F:\\Dango Music Player\\playlist.m3u8") .open(location)?;
.unwrap(); m3u8.write_to(&mut file)?;
m3u8.write_to(&mut file).unwrap(); Ok(())
} }
pub fn from_m3u8(path: &str) -> Result<Playlist, Error> {
pub fn from_m3u8(path: &str, lib: Arc<RwLock<MusicLibrary>>) -> Result<Playlist, Box<dyn Error>> {
let mut file = match File::open(path) { let mut file = match File::open(path) {
Ok(file) => file, Ok(file) => file,
Err(e) => return Err(e), Err(e) => return Err(e.into()),
}; };
let mut bytes = Vec::new(); let mut bytes = Vec::new();
file.read_to_end(&mut bytes).unwrap(); file.read_to_end(&mut bytes).unwrap();
@ -110,18 +126,53 @@ impl Playlist {
let parsed = m3u8_rs::parse_playlist(&bytes); let parsed = m3u8_rs::parse_playlist(&bytes);
let playlist = match parsed { let playlist = match parsed {
Result::Ok((i, playlist)) => playlist, Result::Ok((_, playlist)) => playlist,
Result::Err(e) => panic!("Parsing error: \n{}", e), Result::Err(e) => panic!("Parsing error: \n{}", e),
}; };
match playlist { match playlist {
List2::MasterPlaylist(_) => panic!(), List2::MasterPlaylist(_) => Err("This is a Master Playlist!\nPlase input a Media Playlist".into()),
List2::MediaPlaylist(pl) => { List2::MediaPlaylist(playlist_) => {
let values = pl.segments.iter().map(|seg| seg.uri.to_owned() ).collect::<Vec<String>>(); let mut uuids = Vec::new();
for seg in playlist_.segments {
let path_ = PathBuf::from(seg.uri.to_owned());
let mut lib = lib.write().unwrap();
let uuid = if let Some((song, _)) = lib.query_uri(&URI::Local(path_.clone())) {
song.uuid
}else {
let song_ = Song::from_file(&path_)?;
let uuid = song_.uuid.to_owned();
lib.add_song(song_)?;
uuid
};
uuids.push(uuid);
} }
let mut playlist = Playlist::new();
#[cfg(target_family = "windows")]
{
playlist.title = path.split("\\")
.last()
.unwrap_or_default()
.strip_suffix(".m3u8")
.unwrap_or_default()
.to_string();
}
#[cfg(target_family = "unix")]
{
playlist.title = path.split("/")
.last()
.unwrap_or_default()
.strip_suffix(".m3u8")
.unwrap_or_default()
.to_string();
} }
todo!() playlist.set_tracks(uuids);
Ok(playlist)
}
}
} }
fn title(&self) -> &String { fn title(&self) -> &String {
&self.title &self.title
@ -153,14 +204,26 @@ impl Default for Playlist {
} }
} }
// #[test] #[cfg(test)]
// fn list_to_m3u8() { mod test_super {
// let lib = ITunesLibrary::from_file(Path::new( use super::*;
// "F:\\Music\\Mp3\\Music Main\\iTunes Music Library.xml", use crate::config::config::tests::read_config_lib;
// ));
// let mut a = Playlist::new(); #[test]
// let c = lib.to_songs(); fn list_to_m3u8() {
// let mut b = c.iter().map(|song| song.to_owned()).collect::<Vec<Song>>(); let (_, lib) = read_config_lib();
// a.tracks.append(&mut b); let mut playlist = Playlist::new();
// a.to_m3u8() let tracks = lib.library.iter().map(|track| track.uuid ).collect();
// } playlist.set_tracks(tracks);
_ = playlist.to_m3u8(Arc::new(RwLock::from(lib)), ".\\test-config\\playlists\\playlist.m3u8");
}
#[test]
fn m3u8_to_list() {
let (_, lib) = read_config_lib();
let arc = Arc::new(RwLock::from(lib));
let playlist = Playlist::from_m3u8(".\\test-config\\playlists\\playlist.m3u8", arc).unwrap();
dbg!(playlist);
}
}