From 690f92f565fab7b81dc92b25fc254d2c2099f54a Mon Sep 17 00:00:00 2001 From: Nathan Rashleigh Date: Thu, 25 Sep 2025 08:58:09 +1000 Subject: [PATCH] errores --- maple-rs/src/db.rs | 151 +++++++++++++++++++++++++++--------------- maple-rs/src/main.rs | 24 ++----- maple.sublime-project | 8 +-- 3 files changed, 102 insertions(+), 81 deletions(-) diff --git a/maple-rs/src/db.rs b/maple-rs/src/db.rs index 674066e..f3cef6f 100644 --- a/maple-rs/src/db.rs +++ b/maple-rs/src/db.rs @@ -1,8 +1,9 @@ -use rekordcrate::pdb::PageError; -use rekordcrate::pdb::RowGroup; +use rekordcrate::pdb::Page; +use rekordcrate::util::ColorIndex; +use rekordcrate::pdb::Color; +use rekordcrate::util::RekordcrateError; use rekordcrate::pdb::Artwork; use rekordcrate::pdb::ArtworkId; -use rekordcrate::pdb::Page; use rekordcrate::pdb::PageType; use rekordcrate::pdb::PageIndex; use std::io::Write; @@ -43,75 +44,111 @@ pub enum DbError { pub struct Database { pub header: Header, pub tracks: BTreeMap, - pub albums: BTreeMap, - pub artists: BTreeMap, - pub artwork: BTreeMap, pub genres: BTreeMap, - pub keys: BTreeMap, + pub artists: BTreeMap, + pub albums: BTreeMap, pub labels: BTreeMap, - pub nodes: BTreeMap, + pub keys: BTreeMap, + pub colors: BTreeMap, + pub playlist_tree: BTreeMap, // Keep playlist entries ordered by entry_index - pub entries: BTreeMap>, + pub playlist_entries: BTreeMap>, + pub artwork: BTreeMap, } const PAGE_SIZE: u16 = 4096; impl Database { - // pub fn export(self, path: &Path) -> Result<(), PageError> { + // pub fn export(self, path: &Path) -> Result<(), RekordcrateError> { // let table = Table::from_rows(PageType::Tracks, 1, PAGE_SIZE, self.tracks.values().cloned().map(Row::Track))?; // println!("{:?}", table); // Ok(()) // } - pub fn export(self, path: &Path) -> std::io::Result<()> { + /// Iterator over (PageType, rows) in file order. + fn table_rows(&self) -> Vec<(PageType, Vec)> { + let mut playlist_rows: Vec = Vec::new(); + for (_pid, mut es) in &self.playlist_entries { + let mut v = es.clone(); + v.sort_by_key(|e| e.entry_index); + playlist_rows.extend(v.into_iter().map(Row::PlaylistEntry)); + } + + vec![ + // (PageType::Tracks, self.tracks.values().cloned().map(Row::Track).collect()), + // (PageType::Genres, self.genres.values().cloned().map(Row::Genre).collect()), + // (PageType::Artists, self.artists.values().cloned().map(Row::Artist).collect()), + // (PageType::Albums, self.albums.values().cloned().map(Row::Album).collect()), + // (PageType::Labels, self.labels.values().cloned().map(Row::Label).collect()), + // (PageType::Keys, self.keys.values().cloned().map(Row::Key).collect()), + // (PageType::Colors, self.colors.values().cloned().map(Row::Color).collect()), + // (PageType::PlaylistTree, self.playlist_tree.values().cloned().map(Row::PlaylistTreeNode).collect()), + // (PageType::PlaylistEntries, playlist_rows), + // (PageType::HistoryPlaylists, Vec::new()), + // (PageType::HistoryEntries, Vec::new()), + // (PageType::Artwork, self.artwork.values().cloned().map(Row::Artwork).collect()), + // (PageType::Columns, Vec::new()), + // (PageType::History, Vec::new()), + (PageType::Tracks, vec![]), + (PageType::Genres, vec![]), + (PageType::Artists, vec![]), + (PageType::Albums, vec![]), + (PageType::Labels, vec![]), + (PageType::Keys, vec![]), + (PageType::Colors, vec![]), + (PageType::PlaylistTree, vec![]), + (PageType::PlaylistEntries, vec![]), + (PageType::HistoryPlaylists, Vec::new()), + (PageType::HistoryEntries, Vec::new()), + (PageType::Artwork, vec![]), + (PageType::Columns, Vec::new()), + (PageType::History, Vec::new()), + ] + } + + /// Write all tables, sequential pages, return header.tables and next_unused_page. + fn get_tables_and_pages( + &self, + start_index: u32, + page_size: u16, + ) -> Result<(Vec, Vec, u32), RekordcrateError> { + let mut next = start_index; + let mut tables = Vec::new(); + let mut pages = Vec::new(); + + for (pt, rows) in self.table_rows().into_iter() { + let (table, mut row_pages, np) = Table::from_rows(pt, next, page_size, rows)?; + pages.append(&mut row_pages); + tables.push(table); + next = np; + } + Ok((tables, pages, next)) + } + + pub fn export(self, path: &Path) -> Result<(), RekordcrateError> { let mut f = File::create(path)?; // reserve the file header space // tables begin at 28 f.write_all(&vec![0u8; 28 as usize])?; - // tables start here - let (tracks, tracks_pages) = Table::from_rows(PageType::Tracks, 1, PAGE_SIZE, self.tracks.values().cloned().take(2).map(Row::Track)).unwrap(); - // f.seek(SeekFrom::Start(0x1c)).unwrap(); - println!("Writing table at {:?}", f.stream_position()); - tracks.write_le(&mut f).unwrap(); + let (tables, pages, next_page) = self.get_tables_and_pages(1, PAGE_SIZE)?; + + for table in tables.clone() { + println!("Writing table={:?} at {:?}",table, f.stream_position()); + table.write_le(&mut f)?; + } f.seek(SeekFrom::Start(4096)).unwrap(); - println!("Writing tracks_pages at {:?}", f.stream_position()); - tracks_pages.write_le_args(&mut f, (PAGE_SIZE.into(),)).unwrap(); - println!("{:?}", f.stream_position()); - // page is somehow getting zeroed when ... writing? reading?? - // validate it by writing and reading it back + for page in pages { + println!("Writing page={:?} at {:?}", page, f.stream_position()); + page.write_le_args(&mut f, (PAGE_SIZE.into(),)).unwrap(); + } - // let (tree_first, tree_last) = - // Self::write_table(&mut f, PageType::PlaylistTree, next_page_index, self.nodes.values().cloned().map(Row::PlaylistTreeNode))?; - // next_page_index = tree_last + 1; - - // let plist_entries = self.entries.iter().flat_map(|(_pid, vec)| { - // // ensure contiguous entry_index - // let mut v = vec.clone(); - // v.sort_by_key(|e| e.entry_index); - // v.into_iter().map(Row::PlaylistEntry) - // }); - // let (entries_first, entries_last) = - // Self::write_table(&mut f, PageType::PlaylistEntries, next_page_index, plist_entries)?; - // next_page_index = entries_last + 1; - - // let (art_first, art_last) = - // Self::write_table(&mut f, PageType::Artwork, next_page_index, self.artwork.values().cloned().map(Row::Artwork))?; - // next_page_index = art_last + 1; - - // 3) Build header and back-patch at page 0 let header = Header { - // fill other required fields in your crate - sequence: 0, // or previous+1 - next_unused_page: PageIndex(tracks_pages.len() as u32 + 1), - tables: vec![ - tracks, - // Table { page_type: PageType::PlaylistTree, first_page: PageIndex(tree_first), last_page: PageIndex(tree_last), empty_candidate: 0, /* … */ }, - // Table { page_type: PageType::PlaylistEntries, first_page: PageIndex(entries_first), last_page: PageIndex(entries_last), empty_candidate: 0, /* … */ }, - // Table { page_type: PageType::Artwork, first_page: PageIndex(art_first), last_page: PageIndex(art_last), empty_candidate: 0, /* … */ }, - ], + sequence: 0, + next_unused_page: PageIndex(next_page), + tables, ..Default::default() }; @@ -187,12 +224,13 @@ impl Database { let mut albums: BTreeMap = BTreeMap::new(); let mut artists: BTreeMap = BTreeMap::new(); let mut artwork: BTreeMap = BTreeMap::new(); + let mut colors: BTreeMap = BTreeMap::new(); let mut genres: BTreeMap = BTreeMap::new(); let mut keys: BTreeMap = BTreeMap::new(); let mut labels: BTreeMap = BTreeMap::new(); - let mut nodes: BTreeMap = BTreeMap::new(); - let mut entries: BTreeMap> = BTreeMap::new(); + let mut playlist_tree: BTreeMap = BTreeMap::new(); + let mut playlist_entries: BTreeMap> = BTreeMap::new(); for table in &header.tables { let pages = header.read_pages(&mut f, Endian::Little, (&table.first_page, &table.last_page))?; @@ -210,6 +248,9 @@ impl Database { Row::Album(a) => { albums.insert(a.id, a.clone()); } + Row::Color(c) => { + colors.insert(c.color.clone(), c.clone()); + } Row::Genre(g) => { genres.insert(g.id, g.clone()); } @@ -220,10 +261,10 @@ impl Database { labels.insert(l.id, l.clone()); } Row::PlaylistTreeNode(n) => { - nodes.insert(n.id, n.clone()); + playlist_tree.insert(n.id, n.clone()); } Row::PlaylistEntry(e) => { - entries.entry(e.playlist_id).or_default().push(e.clone()); + playlist_entries.entry(e.playlist_id).or_default().push(e.clone()); } _ => {} } @@ -233,10 +274,10 @@ impl Database { } // Ensure deterministic ordering within each playlist - for v in entries.values_mut() { + for v in playlist_entries.values_mut() { v.sort_by_key(|e| e.entry_index); // needs `pub entry_index` } - Ok(Self { header, tracks, albums, artists, artwork, genres, keys, labels, nodes, entries }) + Ok(Self { header, tracks, albums, artists, artwork, genres, keys, labels, playlist_tree, playlist_entries, colors }) } } diff --git a/maple-rs/src/main.rs b/maple-rs/src/main.rs index d36a239..0001137 100644 --- a/maple-rs/src/main.rs +++ b/maple-rs/src/main.rs @@ -2,29 +2,15 @@ mod db; extern crate walkdir; -use rekordcrate::pdb::Page; -use rekordcrate::pdb::PageError; -use rekordcrate::pdb::PageIndex; -use rekordcrate::pdb::Row::PlaylistEntry; -use rekordcrate::pdb::string::DeviceSQLString; -use rekordcrate::pdb::RowGroup; -use rekordcrate::pdb::TrackId; -use rekordcrate::pdb::PageType; -use rekordcrate::pdb::Table; -use rekordcrate::pdb::{Header, PlaylistTreeNode, PlaylistTreeNodeId}; -use walkdir::WalkDir; -use std::env; -use std::fs::create_dir; -use std::fs::create_dir_all; -use std::{fs::exists, path::Path}; +use rekordcrate::util::RekordcrateError; +use std::path::Path; use db::Database; // Example -fn main() -> Result<(), PageError> { +fn main() -> Result<(), RekordcrateError> { let db = Database::load_from_pdb("ntr.pdb").unwrap(); - println!("tracks: {}, playlists: {}", db.tracks.len(), db.nodes.len()); - println!("tables: {:?}", db.header); - println!("tables: {:?}", db.header.tables); + + println!("{:?}", db.colors); let output = Path::new("./data/output.pdb"); db.export(&output).unwrap(); diff --git a/maple.sublime-project b/maple.sublime-project index c736d97..7373008 100755 --- a/maple.sublime-project +++ b/maple.sublime-project @@ -5,13 +5,7 @@ "path": ".", }, { - "path": "h:ome\\ntr\\code\\rekordcrate", - }, - { - "path": "C:\\Users\\ntr\\code\\rekordcrate", - }, - { - "path": "/Users/nathanrashleigh/code/code/rekordcrate" + "path": "/home/ntr/code/rekordcrate" }, ], "settings":