mirror of
https://github.com/Dangoware/dango-music-player.git
synced 2025-04-19 10:02:53 -05:00
Merge branch 'main' of https://github.com/Dangoware/dango-music-player
This commit is contained in:
commit
8fda06a846
8 changed files with 102 additions and 84 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/music_storage/db_reader/foobar/utils.rs
Normal file
15
src/music_storage/db_reader/foobar/utils.rs
Normal 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()
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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?
|
||||||
|
|
Loading…
Reference in a new issue