This commit is contained in:
MrDulfin 2023-12-11 13:16:59 -05:00
commit 8fda06a846
8 changed files with 102 additions and 84 deletions

View file

@ -6,6 +6,7 @@ pub mod music_storage {
pub mod db_reader { pub mod db_reader {
pub mod foobar { pub mod foobar {
pub mod reader; pub mod reader;
pub mod utils;
} }
pub mod musicbee { pub mod musicbee {
pub mod reader; pub mod reader;

View file

@ -179,7 +179,7 @@ impl Player {
match msg.view() { match msg.view() {
gst::MessageView::Eos(_) => {} gst::MessageView::Eos(_) => {}
gst::MessageView::StreamStart(_) => println!("Stream start"), gst::MessageView::StreamStart(_) => println!("Stream start"),
gst::MessageView::Error(e) => { gst::MessageView::Error(_) => {
playbin_bus_ctrl playbin_bus_ctrl
.write() .write()
.unwrap() .unwrap()
@ -201,7 +201,7 @@ impl Player {
.unwrap() .unwrap()
.set_state(gst::State::Paused) .set_state(gst::State::Paused)
.unwrap(); .unwrap();
} else if *paused_bus_ctrl.read().unwrap() == false { } else if !(*paused_bus_ctrl.read().unwrap()) {
*buffer_bus_ctrl.write().unwrap() = None; *buffer_bus_ctrl.write().unwrap() = None;
playbin_bus_ctrl playbin_bus_ctrl
.write() .write()
@ -377,19 +377,17 @@ impl Player {
/// Seek absolutely /// Seek absolutely
pub fn seek_to(&mut self, target_pos: Duration) -> Result<(), Box<dyn Error>> { pub fn seek_to(&mut self, target_pos: Duration) -> Result<(), Box<dyn Error>> {
let start; let start = if self.start.read().unwrap().is_none() {
if self.start.read().unwrap().is_none() {
return Err("Failed to seek: No START time".into()); return Err("Failed to seek: No START time".into());
} else { } else {
start = self.start.read().unwrap().unwrap(); self.start.read().unwrap().unwrap()
} };
let end; let end = if self.end.read().unwrap().is_none() {
if self.end.read().unwrap().is_none() {
return Err("Failed to seek: No END time".into()); return Err("Failed to seek: No END time".into());
} else { } else {
end = self.end.read().unwrap().unwrap(); self.end.read().unwrap().unwrap()
} };
let adjusted_target = target_pos + start; let adjusted_target = target_pos + start;
let clamped_target = adjusted_target.clamp(start, end); let clamped_target = adjusted_target.clamp(start, end);

View file

@ -1,15 +1,13 @@
use std::path::PathBuf;
use chrono::{DateTime, TimeZone, Utc}; use chrono::{DateTime, TimeZone, Utc};
pub fn get_bytes<const S: usize>(iterator: &mut std::vec::IntoIter<u8>) -> [u8; S] { pub fn get_bytes<const S: usize>(iterator: &mut std::vec::IntoIter<u8>) -> [u8; S] {
let mut bytes = [0; S]; let mut bytes = [0; S];
for i in 0..S { for byte in bytes.iter_mut().take(S) {
bytes[i] = iterator.next().unwrap(); *byte = iterator.next().unwrap();
} }
return bytes; bytes
} }
pub fn get_bytes_vec(iterator: &mut std::vec::IntoIter<u8>, number: usize) -> Vec<u8> { pub fn get_bytes_vec(iterator: &mut std::vec::IntoIter<u8>, number: usize) -> Vec<u8> {
@ -19,7 +17,7 @@ pub fn get_bytes_vec(iterator: &mut std::vec::IntoIter<u8>, number: usize) -> Ve
bytes.push(iterator.next().unwrap()); bytes.push(iterator.next().unwrap());
} }
return bytes; bytes
} }
/// Converts the windows DateTime into Chrono DateTime /// Converts the windows DateTime into Chrono DateTime
@ -28,7 +26,7 @@ pub fn get_datetime(iterator: &mut std::vec::IntoIter<u8>, topbyte: bool) -> Dat
if topbyte { if topbyte {
// Zero the topmost byte // Zero the topmost byte
datetime_i64 = datetime_i64 & 0x00FFFFFFFFFFFFFFF; datetime_i64 &= 0x00FFFFFFFFFFFFFFF;
} }
if datetime_i64 <= 0 { if datetime_i64 <= 0 {

View file

@ -1,9 +1,9 @@
use std::path::PathBuf; use std::path::Path;
use crate::music_storage::library::Song; use crate::music_storage::library::Song;
pub trait ExternalLibrary { pub trait ExternalLibrary {
fn from_file(file: &PathBuf) -> Self; fn from_file(file: &Path) -> Self;
fn write(&self) { fn write(&self) {
unimplemented!(); unimplemented!();
} }

View file

@ -1,7 +1,10 @@
use chrono::{DateTime, Utc}; use std::collections::BTreeMap;
use std::{fs::File, io::Read, path::PathBuf, time::Duration}; use std::{fs::File, io::Read, path::Path, time::Duration};
use crate::music_storage::db_reader::common::{get_bytes, get_bytes_vec, get_datetime}; use crate::music_storage::db_reader::common::{get_bytes, get_bytes_vec};
use crate::music_storage::db_reader::extern_library::ExternalLibrary;
use crate::music_storage::library::{Song, URI};
use super::utils::meta_offset;
const MAGIC: [u8; 16] = [ const MAGIC: [u8; 16] = [
0xE1, 0xA0, 0x9C, 0x91, 0xF8, 0x3C, 0x77, 0x42, 0x85, 0x2C, 0x3B, 0xCC, 0x14, 0x01, 0xD3, 0xF2, 0xE1, 0xA0, 0x9C, 0x91, 0xF8, 0x3C, 0x77, 0x42, 0x85, 0x2C, 0x3B, 0xCC, 0x14, 0x01, 0xD3, 0xF2,
@ -9,69 +12,31 @@ const MAGIC: [u8; 16] = [
#[derive(Debug)] #[derive(Debug)]
pub struct FoobarPlaylist { pub struct FoobarPlaylist {
path: PathBuf,
metadata: Vec<u8>, metadata: Vec<u8>,
songs: Vec<FoobarPlaylistTrack>,
} }
#[derive(Debug, Default)] impl ExternalLibrary for FoobarPlaylist {
pub struct FoobarPlaylistTrack {
flags: i32,
file_name: String,
subsong_index: i32,
file_size: i64,
file_time: DateTime<Utc>,
duration: Duration,
rpg_album: u32,
rpg_track: u32,
rpk_album: u32,
rpk_track: u32,
entries: Vec<(String, String)>,
}
impl FoobarPlaylist {
pub fn new(path: &String) -> Self {
FoobarPlaylist {
path: PathBuf::from(path),
metadata: Vec::new(),
}
}
fn get_meta_offset(&self, offset: usize) -> String {
let mut result_vec = Vec::new();
let mut i = offset;
loop {
if self.metadata[i] == 0x00 {
break;
}
result_vec.push(self.metadata[i]);
i += 1;
}
String::from_utf8_lossy(&result_vec).into()
}
/// Reads the entire MusicBee library and returns relevant values /// Reads the entire MusicBee library and returns relevant values
/// as a `Vec` of `Song`s /// as a `Vec` of `Song`s
pub fn read(&mut self) -> Result<Vec<FoobarPlaylistTrack>, Box<dyn std::error::Error>> { fn from_file(file: &Path) -> Self {
let mut f = File::open(&self.path).unwrap(); let mut f = File::open(file).unwrap();
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut retrieved_songs: Vec<FoobarPlaylistTrack> = Vec::new(); let mut retrieved_songs: Vec<FoobarPlaylistTrack> = Vec::new();
// Read the whole file // Read the whole file
f.read_to_end(&mut buffer)?; f.read_to_end(&mut buffer).unwrap();
let mut buf_iter = buffer.into_iter(); let mut buf_iter = buffer.into_iter();
// Parse the header // Parse the header
let magic = get_bytes::<16>(&mut buf_iter); let magic = get_bytes::<16>(&mut buf_iter);
if magic != MAGIC { if magic != MAGIC {
return Err("Magic bytes mismatch!".into()); panic!("Magic bytes mismatch!");
} }
let meta_size = i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize; let meta_size = i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize;
self.metadata = get_bytes_vec(&mut buf_iter, meta_size); let metadata = &get_bytes_vec(&mut buf_iter, meta_size);
let track_count = i32::from_le_bytes(get_bytes(&mut buf_iter)); let track_count = i32::from_le_bytes(get_bytes(&mut buf_iter));
// Read all the track fields // Read all the track fields
@ -82,7 +47,7 @@ impl FoobarPlaylist {
let has_padding = (0x04 & flags) != 0; let has_padding = (0x04 & flags) != 0;
let file_name_offset = i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize; let file_name_offset = i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize;
let file_name = self.get_meta_offset(file_name_offset); let file_name = meta_offset(metadata, file_name_offset);
let subsong_index = i32::from_le_bytes(get_bytes(&mut buf_iter)); let subsong_index = i32::from_le_bytes(get_bytes(&mut buf_iter));
@ -98,17 +63,18 @@ impl FoobarPlaylist {
let file_size = i64::from_le_bytes(get_bytes(&mut buf_iter)); let file_size = i64::from_le_bytes(get_bytes(&mut buf_iter));
let file_time = get_datetime(&mut buf_iter, false); // TODO: Figure out how to make this work properly
let file_time = i64::from_le_bytes(get_bytes(&mut buf_iter));
let duration = Duration::from_nanos(u64::from_le_bytes(get_bytes(&mut buf_iter)) / 100); let duration = Duration::from_nanos(u64::from_le_bytes(get_bytes(&mut buf_iter)) / 100);
let rpg_album = u32::from_le_bytes(get_bytes(&mut buf_iter)); let rpg_album = f32::from_le_bytes(get_bytes(&mut buf_iter));
let rpg_track = u32::from_le_bytes(get_bytes(&mut buf_iter)); let rpg_track = f32::from_le_bytes(get_bytes(&mut buf_iter));
let rpk_album = u32::from_le_bytes(get_bytes(&mut buf_iter)); let rpk_album = f32::from_le_bytes(get_bytes(&mut buf_iter));
let rpk_track = u32::from_le_bytes(get_bytes(&mut buf_iter)); let rpk_track = f32::from_le_bytes(get_bytes(&mut buf_iter));
get_bytes::<4>(&mut buf_iter); get_bytes::<4>(&mut buf_iter);
@ -121,8 +87,7 @@ impl FoobarPlaylist {
for _ in 0..primary_count { for _ in 0..primary_count {
println!("{}", i32::from_le_bytes(get_bytes(&mut buf_iter))); println!("{}", i32::from_le_bytes(get_bytes(&mut buf_iter)));
let key = let key = meta_offset(metadata, i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
self.get_meta_offset(i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
entries.push((key, String::new())); entries.push((key, String::new()));
} }
@ -135,18 +100,15 @@ impl FoobarPlaylist {
for i in 0..primary_count { for i in 0..primary_count {
println!("primkey {i}"); println!("primkey {i}");
let value = let value = meta_offset(metadata, i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
self.get_meta_offset(i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
entries[i as usize].1 = value; entries[i as usize].1 = value;
} }
// Get secondary Keys // Get secondary Keys
for _ in 0..secondary_count { for _ in 0..secondary_count {
let key = let key = meta_offset(metadata, i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
self.get_meta_offset(i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize); let value = meta_offset(metadata, i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
let value =
self.get_meta_offset(i32::from_le_bytes(get_bytes(&mut buf_iter)) as usize);
entries.push((key, value)); entries.push((key, value));
} }
@ -171,6 +133,50 @@ impl FoobarPlaylist {
retrieved_songs.push(track); retrieved_songs.push(track);
} }
Ok(retrieved_songs) Self {
songs: retrieved_songs,
metadata: metadata.clone(),
}
}
fn to_songs(&self) -> Vec<Song> {
self.songs.iter().map(|song| song.find_song()).collect()
}
}
#[derive(Debug, Default)]
pub struct FoobarPlaylistTrack {
flags: i32,
file_name: String,
subsong_index: i32,
file_size: i64,
file_time: i64,
duration: Duration,
rpg_album: f32,
rpg_track: f32,
rpk_album: f32,
rpk_track: f32,
entries: Vec<(String, String)>,
}
impl FoobarPlaylistTrack {
fn find_song(&self) -> Song {
let location = URI::Local(self.file_name.clone().into());
Song {
location,
plays: 0,
skips: 0,
favorited: false,
rating: None,
format: None,
duration: self.duration,
play_time: Duration::from_secs(0),
last_played: None,
date_added: None,
date_modified: None,
album_art: Vec::new(),
tags: BTreeMap::new(),
}
} }
} }

View file

@ -0,0 +1,15 @@
pub fn meta_offset(metadata: &[u8], offset: usize) -> String {
let mut result_vec = Vec::new();
let mut i = offset;
loop {
if metadata[i] == 0x00 {
break;
}
result_vec.push(metadata[i]);
i += 1;
}
String::from_utf8_lossy(&result_vec).into()
}

View file

@ -29,7 +29,7 @@ impl MusicBeeDatabase {
// Get the song count from the first 4 bytes // Get the song count from the first 4 bytes
// and then right shift it by 8 for some reason // and then right shift it by 8 for some reason
let mut database_song_count = i32::from_le_bytes(get_bytes(&mut buf_iter)); let mut database_song_count = i32::from_le_bytes(get_bytes(&mut buf_iter));
database_song_count = database_song_count >> 8; database_song_count >>= 8;
let mut song_count = 0; let mut song_count = 0;
loop { loop {

View file

@ -27,7 +27,7 @@ impl XmlLibrary {
} }
} }
impl ExternalLibrary for XmlLibrary { impl ExternalLibrary for XmlLibrary {
fn from_file(file: &PathBuf) -> Self { fn from_file(file: &Path) -> Self {
let mut reader = Reader::from_file(file).unwrap(); let mut reader = Reader::from_file(file).unwrap();
reader.trim_text(true); reader.trim_text(true);
//count every event, for fun ig? //count every event, for fun ig?