ITunesDB/src/objects.rs

406 lines
10 KiB
Rust

use serde::{Deserialize, Serialize};
pub enum ChunkType {
Database,
DataSet,
AlbumList,
AlbumItem,
TrackList,
TrackItem,
StringTypes,
PlaylistList,
Playlist,
SongReference,
Unknown,
}
impl From<[u8; 4]> for ChunkType {
fn from(value: [u8; 4]) -> Self {
match value {
[0x6D, 0x68, 0x62, 0x64] => ChunkType::Database,
[0x6D, 0x68, 0x73, 0x64] => ChunkType::DataSet,
[0x6D, 0x68, 0x69, 0x61] => ChunkType::AlbumItem,
[0x6D, 0x68, 0x6C, 0x61] => ChunkType::AlbumList,
[0x6D, 0x68, 0x6C, 0x74] => ChunkType::TrackList,
[0x6D, 0x68, 0x69, 0x74] => ChunkType::TrackItem,
[0x6D, 0x68, 0x6F, 0x64] => ChunkType::StringTypes,
[0x6D, 0x68, 0x69, 0x70] => ChunkType::SongReference,
[0x6D, 0x68, 0x6C, 0x70] => ChunkType::PlaylistList,
[0x6D, 0x68, 0x79, 0x70] => ChunkType::Playlist,
_ => ChunkType::Unknown,
}
}
}
impl From<ChunkType> for [u8; 4] {
fn from(value: ChunkType) -> Self {
match value {
ChunkType::Database => [0x6D, 0x68, 0x62, 0x64],
ChunkType::DataSet => [0x6D, 0x68, 0x73, 0x64],
ChunkType::AlbumItem => [0x6D, 0x68, 0x69, 0x61],
ChunkType::AlbumList => [0x6D, 0x68, 0x6C, 0x61],
ChunkType::TrackList => [0x6D, 0x68, 0x6C, 0x74],
ChunkType::TrackItem => [0x6D, 0x68, 0x69, 0x74],
ChunkType::SongReference => [0x6D, 0x68, 0x69, 0x70],
ChunkType::StringTypes => [0x6D, 0x68, 0x6F, 0x64],
ChunkType::PlaylistList => [0x6D, 0x68, 0x6C, 0x70],
ChunkType::Playlist => [0x6D, 0x68, 0x79, 0x70],
ChunkType::Unknown => [0x00, 0x00, 0x00, 0x00],
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
pub struct ChunkHeader {
pub chunk_type: [u8; 4],
pub end_of_chunk: u32,
pub children_count: u32,
}
impl ChunkHeader {
pub(crate) fn empty() -> Self {
Self {
chunk_type: [0,0,0,0],
end_of_chunk: 0,
children_count: 0
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Database {
unknown: u32,
version: u32,
children_count: u32,
id: u64,
unknown1: [u8; 32],
language: u16,
persistent_id: u64,
hash: [u8; 20],
unk: [u8; 30],
unk1: [u8; 32],
unk2: [u8; 20],
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
pub struct DataSet {
pub data_type: u32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct AlbumItem {
number_of_strings: u32,
unknown: u16,
album_id_for_track: u16,
timestamp: u64,
unknown1: u32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
pub struct TrackItem {
pub number_of_strings: u32, // number of mhod's count
pub unique_id: u32,
visible: u32,
pub filetype: u32,
type1: u8,
type2: u8,
compilation_flag: u8,
pub stars: u8,
pub last_modified_time: u32,
pub size: u32,
pub length: u32,
track_number: u32,
total_tracks: u32,
pub year: u32,
pub bitrate: u32,
pub sample_rate: u32,
volume: u32,
start_time: u32,
stop_time: u32,
soundcheck: u32,
pub play_count: u32,
play_count2: u32,
last_played_time: u32,
disc_number: u32,
total_discs: u32,
userid: u32,
date_added: u32,
bookmark_time: u32,
pub dbid: u64,
checked: u8,
application_rating: u8,
pub bpm: u16,
artwork_count: u16,
unk9: u16,
artwork_size: u32,
unk11: u32,
sample_rate2: u32,
date_released: u32,
unk14: u32,
unk15: u32,
unk16: u32,
pub skip_count: u32,
last_skipped: u32,
pub has_artwork: u8,
skip_when_shuffling: u8,
remember_playback_position: u8,
flag4: u8,
pub dbid2: u64,
lyrics_flag: u8,
movie_file_flag: u8,
played_mark: u8,
unk17: u8,
unk21: u32,
pregap: u32,
sample_count: u64,
unk25: u32,
postgap: u32,
unk27: u32,
pub media_type: u32,
season_number: u32,
episode_number: u32,
unk31: [u8; 28],
gapless_data: u32,
unk38: u32,
gapless_track_flag: u16,
gapless_album_flag: u16,
unk39_hash: [u8; 20],
unk40: [u8; 18],
album_id: u16,
mhii_link: u32,
unk: [u8; 32],
unk1: [u8; 32],
unk2: [u8; 32],
unk3: [u8; 32],
unk4: [u8; 32],
unk5: [u8; 32],
unk6: [u8; 32],
}
impl TrackItem {
pub(crate) fn new(unique_id: u32, size: u32, length: u32, year: u32, bitrate: u32, sample_rate: u32, dbid: u64, sample_count: u64) -> Self {
Self {
number_of_strings: 0,
unique_id,
visible: 1,
filetype: 1297101600,
type1: 0,
type2: 1,
compilation_flag: 0,
stars: 0,
last_modified_time: 3786278955,
size,
length,
track_number: 0,
total_tracks: 0,
year,
bitrate,
sample_rate,
volume: 0,
start_time: 0,
stop_time: 0,
soundcheck: 0,
play_count: 0,
play_count2: 0,
last_played_time: 0,
disc_number: 0,
total_discs: 0,
userid: 0,
date_added: 3815861983,
bookmark_time: 0,
dbid,
checked: 0,
application_rating: 0,
bpm: 0,
artwork_count: 0,
unk9: 65535,
artwork_size: 0,
unk11: 0,
sample_rate2: sample_rate,
date_released: 0,
unk14: 12,
unk15: 0,
unk16: 0,
skip_count: 0,
last_skipped: 0,
has_artwork: 2,
skip_when_shuffling: 0,
remember_playback_position: 0,
flag4: 0,
dbid2: dbid,
lyrics_flag: 0,
movie_file_flag: 0,
played_mark: 0,
unk17: 0,
unk21: 0,
pregap: 528,
sample_count,
unk25: 0,
postgap: 566,
unk27: 33554435,
media_type: 1,
season_number: 0,
episode_number: 0,
unk31: [0; 28],
gapless_data: 8154240,
unk38: 0,
gapless_track_flag: 1,
gapless_album_flag: 0,
unk39_hash: [0; 20],
unk40: [0; 18],
album_id: 36682,
mhii_link: 8161920,
unk: [0; 32],
unk1: [0; 32],
unk2: [0; 32],
unk3: [0; 32],
unk4: [0; 32],
unk5: [0; 32],
unk6: [0; 32],
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct StringEntry {
// mhod
pub entry_type: u32,
pub unk1: u32,
pub unk2: u32,
pub position: u32,
pub length: u32,
pub unknown: u32,
pub unk4: u32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct PlaylistIndexEntry {
// mhod
entry_type: u32,
unk1: u32,
unk2: u32,
index_type: u32,
pub count: u32,
null_padding: u64,
null_padding1: u64,
null_padding2: u64,
null_padding3: u64,
null_padding4: u64,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct LetterJumpEntry {
entry_type: u32,
unk1: u32,
unk2: u32,
index_type: u32,
pub count: u32,
null_padding: u64,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct JumpTable {
letter: u32, // UTF-16 LE Uppercase with two padding null bytes
entry_num: u32, // the number of the first entry in the corresponding MHOD52 index starting with this letter. Zero-based and incremented by one for each entry, not 4.
count: u32, // the count of entries starting with this letter in the corresponding MHOD52.
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Playlist {
pub data_object_child_count: u32,
pub playlist_item_count: u32,
pub is_master_playlist_flag: u8,
unk: [u8; 3],
pub timestamp: u32,
pub persistent_playlist_id: u64,
unk3: u32,
pub string_mhod_count: u16,
podcast_flag: u16,
list_sort_order: u32,
unk1: [u8; 22],
unk2: [u8; 22],
}
impl Playlist {
pub fn new(persistent_playlist_id: u64, sort_order: ListSortOrder) -> Self {
Self {
data_object_child_count: 0,
playlist_item_count: 0,
is_master_playlist_flag: 0,
unk: [0; 3],
timestamp: 0,
persistent_playlist_id,
unk3: 0,
string_mhod_count: 0,
podcast_flag: 0,
list_sort_order: sort_order.into(),
unk1: [0; 22],
unk2: [0; 22],
}
}
}
pub enum ListSortOrder {
Manual,
SongTitle,
Album,
Artist,
Bitrate,
Genre,
Size,
Year,
SampleRate,
PlayCount,
LastPlayed,
MyRating,
BPM
}
impl From<ListSortOrder> for u32 {
fn from(value: ListSortOrder) -> Self {
match value {
ListSortOrder::Manual => 1,
ListSortOrder::SongTitle => 3,
ListSortOrder::Album => 4,
ListSortOrder::Artist => 5,
ListSortOrder::Bitrate => 6,
ListSortOrder::Genre => 7,
ListSortOrder::Size => 11,
ListSortOrder::Year => 13,
ListSortOrder::SampleRate => 14,
ListSortOrder::PlayCount => 20,
ListSortOrder::LastPlayed => 21,
ListSortOrder::MyRating => 23,
ListSortOrder::BPM => 25
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct PlaylistItem {
pub data_object_child_count: u32,
podcast_grouping_flag: u16,
unk4: u16,
pub group_id: u32,
pub track_id: u32,
timestamp: u32,
podcast_grouping_reference: u32,
unk: [u8; 30],
unk1: [u8; 10],
}
impl PlaylistItem {
pub fn new(track_id: u32, group_id: u32) -> Self {
Self {
data_object_child_count: 0,
podcast_grouping_flag: 0,
unk4: 0,
group_id,
track_id,
timestamp: 0,
podcast_grouping_reference: 0,
unk: [0; 30],
unk1: [0; 10],
}
}
}