268 lines
7.5 KiB
Rust
268 lines
7.5 KiB
Rust
use rand::Rng;
|
|
|
|
use crate::objects::{AlbumItem, ChunkHeader, DataSet, Database, JumpTable, LetterJumpEntry, ListSortOrder, Playlist, PlaylistIndexEntry, PlaylistItem, TrackItem};
|
|
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct XDatabase {
|
|
pub header: Option<ChunkHeader>,
|
|
pub data: Option<Database>,
|
|
pub children: Vec<XDataSet>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct XDataSet {
|
|
pub header: ChunkHeader,
|
|
pub data: DataSet,
|
|
pub child: XSomeList
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub struct XTrackItem {
|
|
pub header: ChunkHeader,
|
|
pub data: TrackItem,
|
|
pub args: Vec<XArgument>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct XAlbumItem {
|
|
pub header: ChunkHeader,
|
|
pub data: AlbumItem,
|
|
pub args: Vec<XArgument>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub struct XPlaylist {
|
|
pub header: ChunkHeader,
|
|
pub data: Playlist,
|
|
pub args: Vec<XPlArgument>,
|
|
pub elems: Vec<(PlaylistItem, Vec<XPlArgument>)>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub enum XPlArgument {
|
|
String(XArgument),
|
|
IndexEntry(XPlaylistIndexEntry),
|
|
LetterJumpEntry(XLetterJump),
|
|
RawArgument(Vec<u8>)
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub struct XPlaylistIndexEntry {
|
|
pub data: PlaylistIndexEntry,
|
|
pub v: Vec<u32>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub struct XLetterJump {
|
|
pub data: LetterJumpEntry,
|
|
pub v: Vec<JumpTable>
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize, Clone)]
|
|
pub struct XArgument {
|
|
pub arg_type: u32,
|
|
pub val: String
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub enum XSomeList {
|
|
Playlists(Vec<XPlaylist>),
|
|
TrackList(Vec<XTrackItem>),
|
|
AlbumList(Vec<XAlbumItem>)
|
|
}
|
|
|
|
impl XPlaylist {
|
|
pub fn set_title(&mut self, title: String) {
|
|
self.update_arg(1, title);
|
|
}
|
|
|
|
pub fn get_title(&self) -> String {
|
|
self.get_arg(1)
|
|
}
|
|
|
|
fn get_arg(&self, id: u32) -> String {
|
|
for arg in self.args.iter() {
|
|
if let XPlArgument::String(val) = arg {
|
|
if val.arg_type == id {
|
|
return val.val.clone();
|
|
}
|
|
}
|
|
}
|
|
String::new()
|
|
}
|
|
|
|
fn update_arg(&mut self, id: u32, val: String) {
|
|
self.args.retain(|t| {
|
|
if let XPlArgument::String(s) = t {
|
|
if s.arg_type == id {
|
|
return false;
|
|
}
|
|
}
|
|
true
|
|
});
|
|
self.args.push(XPlArgument::String(XArgument { arg_type: id, val }));
|
|
self.data.string_mhod_count = self.args.len() as u16;
|
|
self.data.data_object_child_count = self.args.len() as u32;
|
|
}
|
|
|
|
pub fn new(persistent_playlist_id: u64, sort_order: ListSortOrder) -> Self {
|
|
Self {
|
|
header: ChunkHeader::empty(),
|
|
data: Playlist::new(persistent_playlist_id, sort_order),
|
|
args: vec![],
|
|
elems: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn add_elem(&mut self, track_id: u32) {
|
|
let group_id: u32 = rand::random();
|
|
self.elems.push((PlaylistItem::new(track_id, group_id), Vec::new()));
|
|
self.data.playlist_item_count += 1;
|
|
}
|
|
}
|
|
|
|
impl XTrackItem {
|
|
|
|
pub fn new(unique_id: u32, size: u32, length: u32, year: u32, bitrate: u32, sample_rate: u32, dbid: u64, sample_count: u64) -> Self {
|
|
Self {
|
|
header: ChunkHeader::empty(),
|
|
data: TrackItem::new(unique_id, size, length, year, bitrate, sample_rate, dbid, sample_count),
|
|
args: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn set_location(&mut self, location: String) {
|
|
self.update_arg(2, location);
|
|
}
|
|
|
|
pub fn set_title(&mut self, title: String) {
|
|
self.update_arg(1, title);
|
|
}
|
|
|
|
pub fn set_artist(&mut self, artist: String) {
|
|
self.update_arg(4, artist);
|
|
}
|
|
|
|
pub fn set_album(&mut self, album: String) {
|
|
self.update_arg(3, album);
|
|
}
|
|
|
|
pub fn set_genre(&mut self, genre: String) {
|
|
self.update_arg(5, genre);
|
|
}
|
|
|
|
pub fn get_location(&self) -> String {
|
|
self.get_arg(2)
|
|
}
|
|
|
|
pub fn get_title(&self) -> String {
|
|
self.get_arg(1)
|
|
}
|
|
|
|
pub fn get_artist(&self) -> String {
|
|
self.get_arg(4)
|
|
}
|
|
|
|
pub fn get_album(&self) -> String {
|
|
self.get_arg(3)
|
|
}
|
|
|
|
pub fn get_genre(&self) -> String {
|
|
self.get_arg(5)
|
|
}
|
|
|
|
fn get_arg(&self, id: u32) -> String {
|
|
self.args.iter().find(|t| t.arg_type == id).map_or(String::new(), |t| t.val.clone())
|
|
}
|
|
|
|
pub fn update_arg(&mut self, id: u32, val: String) {
|
|
self.args.retain(|t| t.arg_type != id);
|
|
self.args.push(XArgument { arg_type: id, val});
|
|
self.data.number_of_strings = self.args.len() as u32;
|
|
}
|
|
}
|
|
|
|
impl XDatabase {
|
|
pub fn find_dataset(&mut self, data_type: u32) -> &mut XDataSet {
|
|
self.children.iter_mut().find(|d| d.data.data_type == data_type).unwrap()
|
|
}
|
|
|
|
pub fn remove_track(&mut self, unique_id: u32) {
|
|
if let XSomeList::TrackList(tracks) = &mut self.find_dataset(1).child {
|
|
tracks.retain_mut(|t| t.data.unique_id != unique_id);
|
|
}
|
|
|
|
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(2).child {
|
|
for playlist in playlists.iter_mut() {
|
|
playlist.elems.retain_mut(|t| t.0.track_id != unique_id);
|
|
}
|
|
}
|
|
|
|
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(3).child {
|
|
for playlist in playlists.iter_mut() {
|
|
playlist.elems.retain_mut(|t| t.0.track_id != unique_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn get_playlists(&mut self) -> Vec<XPlaylist> {
|
|
let mut res_pls = Vec::new();
|
|
|
|
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(2).child {
|
|
res_pls = playlists.to_vec();
|
|
}
|
|
|
|
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(3).child {
|
|
res_pls = [res_pls, playlists.to_vec()].concat();
|
|
}
|
|
|
|
res_pls
|
|
}
|
|
|
|
pub fn get_unique_id(&mut self) -> u32 {
|
|
if let XSomeList::TrackList(tracks) = &mut self.find_dataset(1).child {
|
|
if let Some(n) = tracks.iter().map(|t| t.data.unique_id).max() {
|
|
return n + 1;
|
|
}
|
|
}
|
|
1
|
|
}
|
|
|
|
pub fn get_track(&mut self, id: u32) -> Option<XTrackItem> {
|
|
if let XSomeList::TrackList(tracks) = &mut self.find_dataset(1).child {
|
|
return tracks.iter().find(|t| t.data.unique_id == id).cloned()
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn add_track(&mut self, track: XTrackItem) {
|
|
self.add_track_to_playlists(2, &track);
|
|
self.add_track_to_playlists(3, &track);
|
|
|
|
if let XSomeList::TrackList(tracks) = &mut self.find_dataset(1).child {
|
|
tracks.push(track);
|
|
}
|
|
}
|
|
|
|
fn add_track_to_playlists(&mut self, n: u32, track: &XTrackItem) {
|
|
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(n).child {
|
|
let playlist = playlists.iter_mut().find(|t| t.data.is_master_playlist_flag != 0);
|
|
if playlist.is_none() { return; }
|
|
let playlist = playlist.unwrap();
|
|
playlist.data.playlist_item_count += 1;
|
|
|
|
let elem = playlist.elems.last().unwrap();
|
|
let mut pl_item = elem.0.clone();
|
|
pl_item.track_id = track.data.unique_id;
|
|
|
|
pl_item.group_id = rand::thread_rng().gen_range(10..255);
|
|
let mut args = elem.1.clone();
|
|
if let XPlArgument::RawArgument(raw) = args.last_mut().unwrap() {
|
|
raw[24] = pl_item.group_id as u8;
|
|
}
|
|
|
|
playlist.elems.push((pl_item, args));
|
|
}
|
|
}
|
|
} |