upd
This commit is contained in:
parent
7a0468d0a8
commit
e6dcb1bae6
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -433,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1021,8 +1021,8 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itunesdb"
|
name = "itunesdb"
|
||||||
version = "0.1.2"
|
version = "0.1.6"
|
||||||
source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#2db99df934c29f03b842a43245f1e93d7d4ade27"
|
source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#eac020520b7efa2173065772105ab0b2c4ba6da6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@ -1662,7 +1662,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2029,7 +2029,7 @@ dependencies = [
|
|||||||
"getrandom 0.3.1",
|
"getrandom 0.3.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2532,7 +2532,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -23,7 +23,7 @@ tokio = { version = "1", features = ["full"] }
|
|||||||
tokio-util = { version = "0.7.12", features = ["codec"] }
|
tokio-util = { version = "0.7.12", features = ["codec"] }
|
||||||
strum = { version = "0.27", features = ["derive"] }
|
strum = { version = "0.27", features = ["derive"] }
|
||||||
soundcloud = { version = "0.1.8", git = "https://gitea.awain.net/alterwain/soundcloud_api.git" }
|
soundcloud = { version = "0.1.8", git = "https://gitea.awain.net/alterwain/soundcloud_api.git" }
|
||||||
itunesdb = { version = "0.1.2", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
|
itunesdb = { version = "0.1.6", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
|
||||||
ureq = "3.0.5"
|
ureq = "3.0.5"
|
||||||
color-thief = "0.2"
|
color-thief = "0.2"
|
||||||
redb = "2.4.0"
|
redb = "2.4.0"
|
||||||
|
74
src/db.rs
74
src/db.rs
@ -1,6 +1,6 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use itunesdb::xobjects::{XArgument, XTrackItem};
|
use itunesdb::xobjects::{XArgument, XPlaylist, XTrackItem};
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use redb::{Database, Error, ReadableTable, TableDefinition};
|
use redb::{Database, Error, ReadableTable, TableDefinition};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -9,6 +9,7 @@ use soundcloud::sobjects::CloudTrack;
|
|||||||
use crate::config::{get_db, get_temp_dl_dir};
|
use crate::config::{get_db, get_temp_dl_dir};
|
||||||
|
|
||||||
const TRACKS: TableDefinition<u32, Vec<u8>> = TableDefinition::new("tracks");
|
const TRACKS: TableDefinition<u32, Vec<u8>> = TableDefinition::new("tracks");
|
||||||
|
const PLAYLISTS: TableDefinition<u64, Vec<u8>> = TableDefinition::new("playlists");
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Track {
|
pub struct Track {
|
||||||
@ -17,7 +18,7 @@ pub struct Track {
|
|||||||
stars: u8,
|
stars: u8,
|
||||||
last_modified_time: u32,
|
last_modified_time: u32,
|
||||||
size: u32,
|
size: u32,
|
||||||
length: u32,
|
pub length: u32,
|
||||||
year: u32,
|
year: u32,
|
||||||
pub bitrate: u32,
|
pub bitrate: u32,
|
||||||
sample_rate: u32,
|
sample_rate: u32,
|
||||||
@ -31,7 +32,25 @@ pub struct Track {
|
|||||||
location: String,
|
location: String,
|
||||||
album: String,
|
album: String,
|
||||||
pub artist: String,
|
pub artist: String,
|
||||||
genre: String,
|
pub genre: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct DBPlaylist {
|
||||||
|
pub persistent_playlist_id: u64,
|
||||||
|
pub title: String,
|
||||||
|
pub timestamp: u32,
|
||||||
|
pub is_master: bool,
|
||||||
|
pub tracks: Vec<Track>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Playlist {
|
||||||
|
pub persistent_playlist_id: u64,
|
||||||
|
pub title: String,
|
||||||
|
pub timestamp: u32,
|
||||||
|
pub is_master: bool,
|
||||||
|
pub tracks: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CloudTrack> for Track {
|
impl From<CloudTrack> for Track {
|
||||||
@ -100,12 +119,57 @@ impl From<XTrackItem> for Track {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement From (or Into) for Track, convert from Soundcloud Audio or iTunes
|
|
||||||
|
|
||||||
pub fn init_db() -> Database {
|
pub fn init_db() -> Database {
|
||||||
Database::create(get_db()).unwrap()
|
Database::create(get_db()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_playlist(db: &Database, playlist: Playlist) -> Result<(), Error> {
|
||||||
|
let write_txn = db.begin_write()?;
|
||||||
|
{
|
||||||
|
let mut table = write_txn.open_table(PLAYLISTS)?;
|
||||||
|
let uid = playlist.persistent_playlist_id;
|
||||||
|
let data = bincode::serialize(&playlist).unwrap();
|
||||||
|
table.insert(uid, data)?;
|
||||||
|
}
|
||||||
|
write_txn.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_playlist(db: &Database, id: u64) -> Result<DBPlaylist, Error> {
|
||||||
|
let read_txn = db.begin_read()?;
|
||||||
|
let table = read_txn.open_table(PLAYLISTS)?;
|
||||||
|
let b = table.get(id)?.unwrap().value();
|
||||||
|
let value: Playlist = bincode::deserialize(&b).unwrap();
|
||||||
|
let playlist = DBPlaylist {
|
||||||
|
persistent_playlist_id: value.persistent_playlist_id,
|
||||||
|
timestamp: value.timestamp,
|
||||||
|
title: value.title,
|
||||||
|
is_master: value.is_master,
|
||||||
|
tracks: value.tracks.iter().map(|id| get_track(db, *id)).filter(|t| t.is_ok()).map(|t| t.unwrap()).collect(),
|
||||||
|
};
|
||||||
|
Ok(playlist.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all_playlists(db: &Database) -> Result<Vec<DBPlaylist>, Error> {
|
||||||
|
let read_txn = db.begin_read()?;
|
||||||
|
let table = read_txn.open_table(PLAYLISTS)?;
|
||||||
|
Ok(table
|
||||||
|
.iter()
|
||||||
|
.unwrap()
|
||||||
|
.flatten()
|
||||||
|
.map(|d| bincode::deserialize(&d.1.value()).unwrap())
|
||||||
|
.collect::<Vec<Playlist>>()
|
||||||
|
.iter()
|
||||||
|
.map(|p| DBPlaylist{
|
||||||
|
persistent_playlist_id: p.persistent_playlist_id,
|
||||||
|
timestamp: p.timestamp,
|
||||||
|
title: p.title.clone(),
|
||||||
|
is_master: p.is_master,
|
||||||
|
tracks: p.tracks.iter().map(|id| get_track(db, *id)).filter(|t| t.is_ok()).map(|t| t.unwrap()).collect()
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_track(db: &Database, track: Track) -> Result<(), Error> {
|
pub fn insert_track(db: &Database, track: Track) -> Result<(), Error> {
|
||||||
let write_txn = db.begin_write()?;
|
let write_txn = db.begin_write()?;
|
||||||
{
|
{
|
||||||
|
@ -111,9 +111,9 @@ impl App {
|
|||||||
AppEvent::IPodNotFound => {
|
AppEvent::IPodNotFound => {
|
||||||
let _ = self.sender.send(AppEvent::SearchIPod);
|
let _ = self.sender.send(AppEvent::SearchIPod);
|
||||||
},
|
},
|
||||||
AppEvent::ITunesParsed(tracks) => {
|
AppEvent::ITunesParsed(playlists) => {
|
||||||
let screen: &mut MainScreen = self.get_screen(&AppState::MainScreen);
|
let screen: &mut MainScreen = self.get_screen(&AppState::MainScreen);
|
||||||
screen.tracks = Some(tracks);
|
screen.set_itunes(playlists);
|
||||||
},
|
},
|
||||||
AppEvent::SoundcloudGot(playlists) => {
|
AppEvent::SoundcloudGot(playlists) => {
|
||||||
let screen: &mut MainScreen = self.get_screen(&AppState::MainScreen);
|
let screen: &mut MainScreen = self.get_screen(&AppState::MainScreen);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
@ -11,6 +11,7 @@ use soundcloud::sobjects::{CloudPlaylist, CloudPlaylists};
|
|||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
use crate::{db::Track, screen::AppScreen, sync::AppEvent, theme::Theme};
|
use crate::{db::Track, screen::AppScreen, sync::AppEvent, theme::Theme};
|
||||||
|
use crate::db::DBPlaylist;
|
||||||
|
|
||||||
pub struct MainScreen {
|
pub struct MainScreen {
|
||||||
mode: bool,
|
mode: bool,
|
||||||
@ -21,7 +22,7 @@ pub struct MainScreen {
|
|||||||
max_songs: i32,
|
max_songs: i32,
|
||||||
tab_titles: Vec<String>,
|
tab_titles: Vec<String>,
|
||||||
soundcloud: Option<Vec<CloudPlaylist>>,
|
soundcloud: Option<Vec<CloudPlaylist>>,
|
||||||
pub tracks: Option<Vec<Track>>,
|
playlists: Option<Vec<DBPlaylist>>,
|
||||||
sender: UnboundedSender<AppEvent>,
|
sender: UnboundedSender<AppEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +98,12 @@ impl MainScreen {
|
|||||||
max_pls: 0,
|
max_pls: 0,
|
||||||
max_songs: 0,
|
max_songs: 0,
|
||||||
soundcloud: None,
|
soundcloud: None,
|
||||||
tracks: None,
|
playlists: None,
|
||||||
selected_tab: 0,
|
selected_tab: 0,
|
||||||
tab_titles: vec![
|
tab_titles: vec![
|
||||||
"YouTube".to_string(),
|
"YouTube".to_string(),
|
||||||
"SoundCloud".to_string(),
|
"SoundCloud".to_string(),
|
||||||
"Local Playlists".to_string(),
|
"iPod".to_string(),
|
||||||
"Settings".to_string(),
|
"Settings".to_string(),
|
||||||
],
|
],
|
||||||
sender,
|
sender,
|
||||||
@ -115,7 +116,7 @@ impl MainScreen {
|
|||||||
self.max_songs = 0;
|
self.max_songs = 0;
|
||||||
self.max_pls = match self.selected_tab {
|
self.max_pls = match self.selected_tab {
|
||||||
1 => self.soundcloud.as_deref().unwrap_or(&[]).len(),
|
1 => self.soundcloud.as_deref().unwrap_or(&[]).len(),
|
||||||
2 => self.tracks.as_deref().unwrap_or(&[]).len(),
|
2 => self.playlists.as_deref().unwrap_or(&[]).len(),
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
.try_into()
|
.try_into()
|
||||||
@ -201,6 +202,13 @@ impl MainScreen {
|
|||||||
self.update_max_rows();
|
self.update_max_rows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_itunes(&mut self, pl: Vec<DBPlaylist>) {
|
||||||
|
self.playlists = Some(pl);
|
||||||
|
if self.selected_tab == 2 {
|
||||||
|
self.update_max_rows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn render_tab(&self, frame: &mut Frame, area: Rect) {
|
fn render_tab(&self, frame: &mut Frame, area: Rect) {
|
||||||
let rows = match self.selected_tab {
|
let rows = match self.selected_tab {
|
||||||
@ -233,17 +241,18 @@ impl MainScreen {
|
|||||||
// local
|
// local
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.push(
|
v.push(
|
||||||
Row::new(vec!["Id", "Title", "Artist", "Bitrate", "Hash"])
|
Row::new(vec!["Id", "Title", "Songs Count", "Date", "IS"])
|
||||||
.style(Style::default().fg(Color::Gray)),
|
.style(Style::default().fg(Color::Gray)),
|
||||||
);
|
);
|
||||||
if let Some(s) = &self.tracks {
|
if let Some(s) = &self.playlists {
|
||||||
for (i, track) in s.iter().enumerate() {
|
for (i, playlist) in s.iter().enumerate() {
|
||||||
|
let date = Utc.timestamp_millis_opt(playlist.timestamp as i64).unwrap();
|
||||||
let mut row = Row::new(vec![
|
let mut row = Row::new(vec![
|
||||||
track.unique_id.to_string(),
|
playlist.persistent_playlist_id.to_string(),
|
||||||
track.title.clone(),
|
"".to_string(),
|
||||||
track.artist.clone(),
|
playlist.tracks.len().to_string(),
|
||||||
track.bitrate.to_string(),
|
format!("{}", date.format("%Y-%m-%d %H:%M")),
|
||||||
format!("{:X}", track.dbid),
|
"YES".to_string(),
|
||||||
]);
|
]);
|
||||||
if self.selected_playlist == i as i32 {
|
if self.selected_playlist == i as i32 {
|
||||||
row = row.style(Style::default().bg(Color::LightBlue).fg(Color::White));
|
row = row.style(Style::default().bg(Color::LightBlue).fg(Color::White));
|
||||||
@ -282,7 +291,7 @@ impl MainScreen {
|
|||||||
|
|
||||||
let rows = match self.selected_tab {
|
let rows = match self.selected_tab {
|
||||||
1 => {
|
1 => {
|
||||||
// local
|
// sc
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.push(
|
v.push(
|
||||||
Row::new(vec!["Id", "Title", "Artist", "Duration", "Genre"])
|
Row::new(vec!["Id", "Title", "Artist", "Duration", "Genre"])
|
||||||
@ -310,6 +319,31 @@ impl MainScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
// local
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.push(
|
||||||
|
Row::new(vec!["Id", "Title", "Artist", "Bitrate", "Genre"])
|
||||||
|
.style(Style::default().fg(Color::Gray)),
|
||||||
|
);
|
||||||
|
if let Some(pls) = &self.playlists {
|
||||||
|
let s = &pls.get(self.selected_playlist as usize).unwrap().tracks;
|
||||||
|
for (i, track) in s.iter().enumerate() {
|
||||||
|
let mut row = Row::new(vec![
|
||||||
|
track.unique_id.to_string(),
|
||||||
|
track.title.clone(),
|
||||||
|
track.artist.clone(),
|
||||||
|
track.bitrate.to_string(),
|
||||||
|
track.genre.clone(),
|
||||||
|
]);
|
||||||
|
if self.selected_song == i as i32 {
|
||||||
|
row = row.style(Style::default().bg(Color::LightBlue).fg(Color::White));
|
||||||
|
}
|
||||||
|
v.push(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
}
|
}
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
};
|
};
|
||||||
|
50
src/sync.rs
50
src/sync.rs
@ -10,19 +10,15 @@ use tokio::{
|
|||||||
};
|
};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use crate::{
|
use crate::{config::{
|
||||||
config::{
|
get_config_path, get_configs_dir, get_temp_dl_dir, get_temp_itunesdb, LyricaConfiguration,
|
||||||
get_config_path, get_configs_dir, get_temp_dl_dir, get_temp_itunesdb, LyricaConfiguration,
|
}, db::{self, Track}, dlp::{self, DownloadProgress}, util, AppState};
|
||||||
},
|
use crate::db::{DBPlaylist, Playlist};
|
||||||
db::{self, Track},
|
|
||||||
dlp::{self, DownloadProgress},
|
|
||||||
AppState,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum AppEvent {
|
pub enum AppEvent {
|
||||||
SearchIPod,
|
SearchIPod,
|
||||||
IPodNotFound,
|
IPodNotFound,
|
||||||
ITunesParsed(Vec<Track>),
|
ITunesParsed(Vec<DBPlaylist>),
|
||||||
SoundcloudGot(CloudPlaylists),
|
SoundcloudGot(CloudPlaylists),
|
||||||
DownloadPlaylist(CloudPlaylist),
|
DownloadPlaylist(CloudPlaylist),
|
||||||
CurrentProgress(DownloadProgress),
|
CurrentProgress(DownloadProgress),
|
||||||
@ -38,6 +34,8 @@ pub fn initialize_async_service(
|
|||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let _ = std::fs::create_dir_all(get_configs_dir());
|
let _ = std::fs::create_dir_all(get_configs_dir());
|
||||||
|
|
||||||
|
let mut ipod_db = None;
|
||||||
|
|
||||||
let database = db::init_db();
|
let database = db::init_db();
|
||||||
|
|
||||||
let mut receiver = receiver;
|
let mut receiver = receiver;
|
||||||
@ -49,13 +47,13 @@ pub fn initialize_async_service(
|
|||||||
if let Some(request) = r {
|
if let Some(request) = r {
|
||||||
match request {
|
match request {
|
||||||
AppEvent::SearchIPod => {
|
AppEvent::SearchIPod => {
|
||||||
/*if let Some(p) = util::search_ipod() {
|
if let Some(p) = util::search_ipod() {
|
||||||
let _ = sender.send(AppEvent::IPodFound(p)).await;
|
let _ = sender.send(AppEvent::SwitchScreen(AppState::MainScreen)).await;
|
||||||
|
ipod_db = Some(p.clone());
|
||||||
|
parse_itunes(&database, &sender, p).await;
|
||||||
} else {
|
} else {
|
||||||
let _ = sender.send(AppEvent::IPodNotFound).await;
|
let _ = sender.send(AppEvent::IPodNotFound).await;
|
||||||
}*/
|
}
|
||||||
let _ = sender.send(AppEvent::SwitchScreen(AppState::MainScreen)).await;
|
|
||||||
parse_itunes(&database, &sender, "/Users/michael/Documents/ipod/iTunes/iTunesDB".to_string()).await;
|
|
||||||
},
|
},
|
||||||
AppEvent::DownloadPlaylist(playlist) => download_playlist(playlist, &database, &sender).await,
|
AppEvent::DownloadPlaylist(playlist) => download_playlist(playlist, &database, &sender).await,
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -92,12 +90,11 @@ async fn download_playlist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_itunes(database: &Database, sender: &Sender<AppEvent>, path: String) {
|
async fn parse_itunes(database: &Database, sender: &Sender<AppEvent>, path: String) {
|
||||||
// todo: parse itunes
|
|
||||||
let cd = get_temp_itunesdb();
|
let cd = get_temp_itunesdb();
|
||||||
let p: PathBuf = Path::new(&path).into();
|
let mut p: PathBuf = Path::new(&path).into();
|
||||||
// p.push("iPod_Control");
|
p.push("iPod_Control");
|
||||||
// p.push("iTunes");
|
p.push("iTunes");
|
||||||
// p.set_file_name("iTunesDB");
|
p.set_file_name("iTunesDB");
|
||||||
let _ = std::fs::copy(p, &cd);
|
let _ = std::fs::copy(p, &cd);
|
||||||
let mut file = File::open(cd).await.unwrap();
|
let mut file = File::open(cd).await.unwrap();
|
||||||
let mut contents = vec![];
|
let mut contents = vec![];
|
||||||
@ -111,9 +108,22 @@ async fn parse_itunes(database: &Database, sender: &Sender<AppEvent>, path: Stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let XSomeList::Playlists(playlists) = &xdb.find_dataset(3).child {
|
||||||
|
for playlist in playlists {
|
||||||
|
let pl = Playlist {
|
||||||
|
persistent_playlist_id: playlist.data.persistent_playlist_id,
|
||||||
|
timestamp: playlist.data.timestamp,
|
||||||
|
title: String::new() ,
|
||||||
|
is_master: playlist.data.is_master_playlist_flag != 0,
|
||||||
|
tracks: playlist.elems.iter().map(|e| e.0.track_id).collect()
|
||||||
|
};
|
||||||
|
let _ = db::insert_playlist(database, pl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let _ = sender
|
let _ = sender
|
||||||
.send(AppEvent::ITunesParsed(
|
.send(AppEvent::ITunesParsed(
|
||||||
db::get_all_tracks(database).unwrap(),
|
db::get_all_playlists(database).unwrap(),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user