small update
This commit is contained in:
parent
b29ef4901e
commit
92d3f7ba77
102
Cargo.lock
generated
102
Cargo.lock
generated
@ -112,15 +112,6 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614aa3f2bac03707e62a84d18a48dd3d9ea6171313fd5e6a53b5054d8ae74601"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
@ -266,16 +257,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
@ -320,16 +301,6 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
@ -547,16 +518,6 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@ -975,8 +936,8 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "itunesdb"
|
||||
version = "0.1.11"
|
||||
source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#4204fdcda886438d815da7b70f736506e06a22e3"
|
||||
version = "0.1.19"
|
||||
source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#e1e8d0a12ca2c3825191ff1d815645a704e1b646"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"env_logger",
|
||||
@ -1071,15 +1032,15 @@ dependencies = [
|
||||
name = "lyrica"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"dirs",
|
||||
"futures",
|
||||
"itunesdb",
|
||||
"md-5",
|
||||
"mp3-duration",
|
||||
"puremp3",
|
||||
"rand",
|
||||
"ratatui",
|
||||
"regex",
|
||||
"rusb",
|
||||
@ -1091,16 +1052,6 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -1134,6 +1085,15 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mp3-duration"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "348bdc7300502f0801e5b57c448815713cd843b744ef9bda252a2698fdf90a0f"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.13"
|
||||
@ -1411,7 +1371,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
"thiserror 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1883,13 +1843,33 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2114,12 +2094,6 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
@ -2196,12 +2170,6 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
@ -12,7 +12,6 @@ dirs = "6.0.0"
|
||||
toml = "0.8.20"
|
||||
serde = "1.0.217"
|
||||
serde_json = "1.0"
|
||||
bincode = "1.3.3"
|
||||
regex = "1.11.1"
|
||||
ratatui = { version = "0.29.0", features = ["all-widgets"] }
|
||||
color-eyre = "0.6.3"
|
||||
@ -21,6 +20,7 @@ futures = "0.3"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-util = { version = "0.7.12", features = ["codec"] }
|
||||
soundcloud = { version = "0.1.8", git = "https://gitea.awain.net/alterwain/soundcloud_api.git" }
|
||||
itunesdb = { version = "0.1.11", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
|
||||
md-5 = "0.10.6"
|
||||
itunesdb = { version = "0.1.19", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
|
||||
puremp3 = "0.1.0"
|
||||
mp3-duration = "0.1.10"
|
||||
rand = "0.8.5"
|
@ -1,15 +1,71 @@
|
||||
use crate::{screen::AppScreen, theme::Theme};
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::prelude::{Color, Line, Style, Stylize};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph, Row, Table};
|
||||
use ratatui::Frame;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FileSystem {}
|
||||
|
||||
impl AppScreen for FileSystem {
|
||||
fn handle_key_event(&mut self, key_event: crossterm::event::KeyEvent) {}
|
||||
|
||||
fn render(&self, frame: &mut ratatui::Frame, theme: &Theme) {
|
||||
todo!()
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Min(0), // Main content area
|
||||
Constraint::Length(1), // Status bar
|
||||
])
|
||||
.split(frame.area());
|
||||
|
||||
self.render_main(frame, chunks[0]);
|
||||
|
||||
// Render Status Bar
|
||||
let status_bar = Paragraph::new(Line::from(vec![
|
||||
"<F5> SAVE AS PLAYLIST".bold(),
|
||||
" | ".dark_gray(),
|
||||
"<F6> SAVE AS IS".bold(),
|
||||
" | ".dark_gray(),
|
||||
"<F8> SELECT".bold(),
|
||||
" | ".dark_gray(),
|
||||
"<F9> DESELECT".bold(),
|
||||
" | ".dark_gray(),
|
||||
"<Q> QUIT".bold(),
|
||||
]))
|
||||
.centered();
|
||||
frame.render_widget(status_bar, chunks[1]); // Render into third chunk
|
||||
}
|
||||
|
||||
fn as_any(&mut self) -> &mut dyn std::any::Any {
|
||||
todo!()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSystem {
|
||||
fn render_main(&self, frame: &mut Frame, area: Rect) {
|
||||
let mut v = vec![Row::new(vec!["Name", "Type", "Size", "Modified"])
|
||||
.style(Style::default().fg(Color::Gray))];
|
||||
|
||||
// move this out to make hdd not suffer
|
||||
let paths = std::fs::read_dir("~/Documents").unwrap();
|
||||
|
||||
for path in paths {
|
||||
v.push();
|
||||
}
|
||||
|
||||
let table = Table::new(
|
||||
v,
|
||||
&[
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Length(5),
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(30),
|
||||
],
|
||||
)
|
||||
.block(Block::default().borders(Borders::ALL).title(" Documents "))
|
||||
.style(Style::default().fg(Color::Black));
|
||||
|
||||
frame.render_widget(table, area);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use std::{collections::HashMap, error::Error, io};
|
||||
|
||||
use crate::file_system::FileSystem;
|
||||
use crate::theme::Theme;
|
||||
use color_eyre::Result;
|
||||
use crossterm::{
|
||||
@ -19,6 +18,7 @@ use ratatui::{
|
||||
Frame, Terminal,
|
||||
};
|
||||
use screen::AppScreen;
|
||||
use std::{collections::HashMap, error::Error, io};
|
||||
use sync::AppEvent;
|
||||
use tokio::sync::mpsc::{self, Receiver, UnboundedSender};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
@ -66,6 +66,7 @@ impl Default for App {
|
||||
screens.insert(AppState::IPodWait, Box::new(WaitScreen::default()));
|
||||
screens.insert(AppState::MainScreen, Box::new(MainScreen::new(jx.clone())));
|
||||
screens.insert(AppState::LoadingScreen, Box::new(LoadingScreen::default()));
|
||||
screens.insert(AppState::FileSystem, Box::new(FileSystem::default()));
|
||||
|
||||
Self {
|
||||
receiver: rx,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use itunesdb::xobjects::XPlaylist;
|
||||
use ratatui::{
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style, Stylize},
|
||||
@ -11,8 +10,8 @@ use ratatui::{
|
||||
use soundcloud::sobjects::{CloudPlaylist, CloudPlaylists};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
use crate::{screen::AppScreen, sync::AppEvent, theme::Theme};
|
||||
use crate::sync::DBPlaylist;
|
||||
use crate::{screen::AppScreen, sync::AppEvent, theme::Theme, AppState};
|
||||
|
||||
pub struct MainScreen {
|
||||
mode: bool,
|
||||
@ -36,6 +35,10 @@ impl AppScreen for MainScreen {
|
||||
KeyCode::Down => self.next_row(),
|
||||
KeyCode::F(6) => self.download_row(),
|
||||
KeyCode::Tab => self.switch_mode(),
|
||||
KeyCode::F(2) => {
|
||||
self.sender
|
||||
.send(AppEvent::SwitchScreen(AppState::FileSystem));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -82,7 +85,7 @@ impl AppScreen for MainScreen {
|
||||
"<Q> QUIT".bold(),
|
||||
]))
|
||||
.centered();
|
||||
frame.render_widget(status_bar, chunks[2]); // Render into third chunk
|
||||
frame.render_widget(status_bar, chunks[2]);
|
||||
}
|
||||
|
||||
fn as_any(&mut self) -> &mut dyn std::any::Any {
|
||||
@ -203,7 +206,7 @@ impl MainScreen {
|
||||
self.update_max_rows();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn set_itunes(&mut self, pl: Vec<DBPlaylist>) {
|
||||
self.playlists = Some(pl);
|
||||
if self.selected_tab == 2 {
|
||||
@ -247,11 +250,11 @@ impl MainScreen {
|
||||
);
|
||||
if let Some(s) = &self.playlists {
|
||||
for (i, playlist) in s.iter().enumerate() {
|
||||
let date = Utc.timestamp_millis_opt(playlist.data.timestamp as i64).unwrap();
|
||||
let date = Utc.timestamp_millis_opt(playlist.timestamp as i64).unwrap();
|
||||
let mut row = Row::new(vec![
|
||||
playlist.data.persistent_playlist_id.to_string(),
|
||||
playlist.id.to_string(),
|
||||
"".to_string(),
|
||||
playlist.elems.len().to_string(),
|
||||
playlist.tracks.len().to_string(),
|
||||
format!("{}", date.format("%Y-%m-%d %H:%M")),
|
||||
"YES".to_string(),
|
||||
]);
|
||||
@ -320,7 +323,7 @@ impl MainScreen {
|
||||
}
|
||||
}
|
||||
v
|
||||
},
|
||||
}
|
||||
2 => {
|
||||
// local
|
||||
let mut v = Vec::new();
|
||||
@ -329,14 +332,14 @@ impl MainScreen {
|
||||
.style(Style::default().fg(Color::Gray)),
|
||||
);
|
||||
if let Some(pls) = &self.playlists {
|
||||
let s = &pls.get(self.selected_playlist as usize).unwrap().elems;
|
||||
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.location.clone(),
|
||||
track.bitrate.to_string(),
|
||||
track.genre.clone(),
|
||||
track.data.unique_id.to_string(),
|
||||
track.get_title(),
|
||||
track.get_location(),
|
||||
track.data.bitrate.to_string(),
|
||||
track.get_genre(),
|
||||
]);
|
||||
if self.selected_song == i as i32 {
|
||||
row = row.style(Style::default().bg(Color::LightBlue).fg(Color::White));
|
||||
|
131
src/sync.rs
131
src/sync.rs
@ -1,7 +1,9 @@
|
||||
use itunesdb::objects::{ListSortOrder, PlaylistItem};
|
||||
use itunesdb::serializer;
|
||||
use itunesdb::xobjects::{XDatabase, XPlArgument, XPlaylist, XTrackItem};
|
||||
use soundcloud::sobjects::{CloudPlaylist, CloudPlaylists, CloudTrack};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use itunesdb::xobjects::{XDatabase, XTrackItem};
|
||||
use soundcloud::sobjects::{CloudPlaylist, CloudPlaylists};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
@ -9,9 +11,13 @@ use tokio::{
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::{config::{
|
||||
get_config_path, get_configs_dir, get_temp_dl_dir, get_temp_itunesdb, LyricaConfiguration,
|
||||
}, dlp::{self, DownloadProgress}, util, AppState};
|
||||
use crate::{
|
||||
config::{
|
||||
get_config_path, get_configs_dir, get_temp_dl_dir, get_temp_itunesdb, LyricaConfiguration,
|
||||
},
|
||||
dlp::{self, DownloadProgress},
|
||||
util, AppState,
|
||||
};
|
||||
|
||||
pub enum AppEvent {
|
||||
SearchIPod,
|
||||
@ -28,7 +34,54 @@ pub struct DBPlaylist {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub timestamp: u32,
|
||||
pub tracks: Vec<XTrackItem>
|
||||
pub tracks: Vec<XTrackItem>,
|
||||
}
|
||||
|
||||
fn track_from_soundcloud(value: &CloudTrack) -> XTrackItem {
|
||||
let mut track_path = get_temp_dl_dir();
|
||||
track_path.push(value.id.to_string());
|
||||
track_path.set_extension("mp3");
|
||||
let f = std::fs::File::open(&track_path).unwrap();
|
||||
let mut data = &std::fs::read(&track_path).unwrap()[..];
|
||||
let (header, _samples) = puremp3::read_mp3(data).unwrap();
|
||||
|
||||
let duration = mp3_duration::from_read(&mut data).unwrap();
|
||||
|
||||
let mut track = XTrackItem::new(
|
||||
value.id as u32,
|
||||
f.metadata().unwrap().len() as u32,
|
||||
duration.as_millis() as u32,
|
||||
0,
|
||||
header.bitrate.bps() / 1000,
|
||||
header.sample_rate.hz(),
|
||||
hash(),
|
||||
0,
|
||||
);
|
||||
track.set_title(value.title.clone().unwrap());
|
||||
track.set_artist(
|
||||
value
|
||||
.user
|
||||
.clone()
|
||||
.map_or(String::new(), |a| a.username.unwrap_or(a.permalink)),
|
||||
);
|
||||
track.set_genre(value.genre.clone().unwrap());
|
||||
track.update_arg(6, String::from("MPEG audio file"));
|
||||
track
|
||||
}
|
||||
|
||||
// note: this hash function is used to make unique ids for each track. It doesn't aim to generate secure ones.
|
||||
fn hash() -> u64 {
|
||||
rand::random::<u64>()
|
||||
}
|
||||
|
||||
fn overwrite_database(database: &mut XDatabase, ipod_path: &String) {
|
||||
let data = serializer::to_bytes(database);
|
||||
let mut p: PathBuf = Path::new(ipod_path).into();
|
||||
p.push("iPod_Control");
|
||||
p.push("iTunes");
|
||||
p.push("iTunesDB");
|
||||
let mut file = std::fs::File::create(p).unwrap();
|
||||
let _ = file.write(&data);
|
||||
}
|
||||
|
||||
pub fn initialize_async_service(
|
||||
@ -60,7 +113,8 @@ pub fn initialize_async_service(
|
||||
let _ = sender.send(AppEvent::IPodNotFound).await;
|
||||
}
|
||||
},
|
||||
AppEvent::DownloadPlaylist(playlist) => download_playlist(playlist, &mut database.as_mut().unwrap(), &sender, ipod_db.clone().unwrap()).await,
|
||||
AppEvent::DownloadPlaylist(playlist) => download_playlist(playlist, database.as_mut().unwrap(), &sender, ipod_db.clone().unwrap()).await,
|
||||
AppEvent::SwitchScreen(state) => { let _ = sender.send(AppEvent::SwitchScreen(state)).await;},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -74,7 +128,7 @@ async fn download_playlist(
|
||||
playlist: CloudPlaylist,
|
||||
database: &mut XDatabase,
|
||||
sender: &Sender<AppEvent>,
|
||||
ipod_path: String
|
||||
ipod_path: String,
|
||||
) {
|
||||
if let Ok(()) =
|
||||
dlp::download_from_soundcloud(&playlist.permalink_url, &get_temp_dl_dir(), sender.clone())
|
||||
@ -82,35 +136,61 @@ async fn download_playlist(
|
||||
{
|
||||
let tracks = playlist.tracks;
|
||||
|
||||
let mut p: PathBuf = Path::new(&ipod_path).into();
|
||||
let p: PathBuf = Path::new(&ipod_path).into();
|
||||
|
||||
let mut new_playlist = XPlaylist::new(rand::random(), ListSortOrder::SongTitle);
|
||||
|
||||
new_playlist.set_title(playlist.title);
|
||||
|
||||
for track in tracks {
|
||||
if track.title.is_none() {
|
||||
continue;
|
||||
}
|
||||
let mut t: XTrackItem = track.into();
|
||||
let mut t: XTrackItem = track_from_soundcloud(&track);
|
||||
t.data.unique_id = database.get_unique_id();
|
||||
new_playlist.add_elem(t.data.unique_id);
|
||||
let mut tp = PathBuf::new();
|
||||
tp.push("iPod_Control");
|
||||
tp.push(":iPod_Control");
|
||||
tp.push("Music");
|
||||
tp.push(["F", &format!("{:02}", &(t.data.unique_id % 100))].concat());
|
||||
tp.push(format!("{:X}", t.data.unique_id));
|
||||
tp.set_extension("mp3");
|
||||
t.set_location(tp.to_str().unwrap().to_string().replace("/", ":").to_string());
|
||||
t.set_location(
|
||||
tp.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.replace("/", ":")
|
||||
.to_string(),
|
||||
);
|
||||
let mut dest = p.clone();
|
||||
dest.push(tp);
|
||||
dest.push("iPod_Control");
|
||||
dest.push("Music");
|
||||
dest.push(["F", &format!("{:02}", &(t.data.unique_id % 100))].concat());
|
||||
let _ = std::fs::create_dir_all(dest.to_str().unwrap());
|
||||
dest.push(format!("{:X}", t.data.unique_id));
|
||||
dest.set_extension("mp3");
|
||||
|
||||
let mut track_path = get_temp_dl_dir();
|
||||
track_path.push(track.id.to_string());
|
||||
track_path.set_extension("mp3");
|
||||
|
||||
let _ = std::fs::copy(track_path, dest);
|
||||
let _ = std::fs::copy(track_path.to_str().unwrap(), dest.to_str().unwrap());
|
||||
|
||||
let _ = database.add_track(t);
|
||||
database.add_track(t);
|
||||
}
|
||||
|
||||
database.add_playlist(new_playlist);
|
||||
}
|
||||
|
||||
let _ = sender
|
||||
.send(AppEvent::SwitchScreen(AppState::MainScreen))
|
||||
.await;
|
||||
|
||||
let _ = sender
|
||||
.send(AppEvent::ITunesParsed(get_playlists(database)))
|
||||
.await;
|
||||
|
||||
overwrite_database(database, &ipod_path);
|
||||
}
|
||||
|
||||
fn get_playlists(db: &mut XDatabase) -> Vec<DBPlaylist> {
|
||||
@ -120,7 +200,19 @@ fn get_playlists(db: &mut XDatabase) -> Vec<DBPlaylist> {
|
||||
id: t.data.persistent_playlist_id,
|
||||
title: t.get_title(),
|
||||
timestamp: t.data.timestamp,
|
||||
tracks: t.elems.iter().map(|(i, _a)| db.get_track(i.track_id)).filter(|t| t.is_some()).map(|t| t.unwrap().clone()).collect()}).collect()
|
||||
tracks: to_tracks(db, t.elems.clone()),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn to_tracks(db: &mut XDatabase, elems: Vec<(PlaylistItem, Vec<XPlArgument>)>) -> Vec<XTrackItem> {
|
||||
elems
|
||||
.iter()
|
||||
.map(|(i, _a)| i.track_id)
|
||||
.map(|id| db.get_track(id))
|
||||
.filter(|i| i.is_some())
|
||||
.map(|i| i.unwrap().clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn parse_itunes(sender: &Sender<AppEvent>, path: String) -> XDatabase {
|
||||
@ -129,7 +221,6 @@ async fn parse_itunes(sender: &Sender<AppEvent>, path: String) -> XDatabase {
|
||||
p.push("iPod_Control");
|
||||
p.push("iTunes");
|
||||
p.push("iTunesDB");
|
||||
println!("{}", p.to_str().unwrap());
|
||||
let _ = std::fs::copy(p, &cd);
|
||||
let mut file = File::open(cd).await.unwrap();
|
||||
let mut contents = vec![];
|
||||
@ -137,9 +228,7 @@ async fn parse_itunes(sender: &Sender<AppEvent>, path: String) -> XDatabase {
|
||||
let mut database = itunesdb::deserializer::parse_bytes(&contents);
|
||||
|
||||
let _ = sender
|
||||
.send(AppEvent::ITunesParsed(
|
||||
get_playlists(&mut database),
|
||||
))
|
||||
.send(AppEvent::ITunesParsed(get_playlists(&mut database)))
|
||||
.await;
|
||||
|
||||
let p = get_config_path();
|
||||
|
Loading…
x
Reference in New Issue
Block a user