From 13bb433bfe92cf8e2bc3f5de2a2515f59276863e Mon Sep 17 00:00:00 2001
From: "alterwain@protonmail.com" <alterwain@protonmail.com>
Date: Mon, 24 Feb 2025 05:02:57 +0300
Subject: [PATCH] small upd

---
 Cargo.lock            |   8 +-
 Cargo.toml            |   4 +-
 README.md             |   9 +-
 src/config.rs         |   6 -
 src/dlp.rs            |  16 ++-
 src/file_system.rs    |  37 ++++--
 src/loading_screen.rs |  25 +++-
 src/main.rs           |  12 +-
 src/sync.rs           | 277 +++++++++++++++++++++++++-----------------
 9 files changed, 247 insertions(+), 147 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 1c46e90..cee09e1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1284,8 +1284,8 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "itunesdb"
-version = "0.1.90"
-source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#d37957a9a0b66577dadf3b305b02c72f1ca50a62"
+version = "0.1.95"
+source = "git+https://gitea.awain.net/alterwain/ITunesDB.git#2ecbe7666bf7c561c9ace767d2e4055e0d92127d"
 dependencies = [
  "bincode",
  "env_logger",
@@ -2349,8 +2349,8 @@ dependencies = [
 
 [[package]]
 name = "soundcloud"
-version = "0.1.8"
-source = "git+https://gitea.awain.net/alterwain/soundcloud_api.git#656aef28f356411ff25cee14214ea0e677563537"
+version = "0.1.9"
+source = "git+https://gitea.awain.net/alterwain/soundcloud_api.git#a6732847bebbcb6e59a1b8a44a965fe7092af6e9"
 dependencies = [
  "hyper-util",
  "regex",
diff --git a/Cargo.toml b/Cargo.toml
index 4b3310a..00eed0e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,8 +20,8 @@ crossterm = { version = "0.28.1", features = ["event-stream"] }
 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.90", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
+soundcloud = { version = "0.1.9", git = "https://gitea.awain.net/alterwain/soundcloud_api.git" }
+itunesdb = { version = "0.1.95", git = "https://gitea.awain.net/alterwain/ITunesDB.git" }
 rand = "0.8.5"
 tui-big-text = "0.7.1"
 throbber-widgets-tui = "0.8.0"
diff --git a/README.md b/README.md
index 22adc15..dd4300c 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,10 @@
 
 Lightweight iPod manager, batteries included.
 
-#     
+#       
 
 <div align="center">
-    <img src=""/>
+    <img src="https://w0n.zip/file/eZm8gd"/>
     <p>
         <small>Screenshot from MacOS Big Sur terminal</small>
     </p>
@@ -41,6 +41,5 @@ Lightweight iPod manager, batteries included.
 
 ## Todos
 
-- Implement artwork integration
-- Implement youtube api
-- Implement albums generation
\ No newline at end of file
+- Implement manual playlist editing
+- Implement youtube api
\ No newline at end of file
diff --git a/src/config.rs b/src/config.rs
index ff2806f..aee94f8 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -32,12 +32,6 @@ pub fn get_temp_itunesdb() -> PathBuf {
     p
 }
 
-pub fn get_db() -> PathBuf {
-    let mut p = get_configs_dir();
-    p.push("data.redb");
-    p
-}
-
 #[derive(Debug, Deserialize, Serialize)]
 pub struct YouTubeConfiguration {
     pub user_id: u64,
diff --git a/src/dlp.rs b/src/dlp.rs
index 1243148..59d12ec 100644
--- a/src/dlp.rs
+++ b/src/dlp.rs
@@ -1,7 +1,7 @@
-use std::{io, path::PathBuf, process::Stdio};
-
+use ratatui::style::Color;
 use regex::Regex;
 use serde::Deserialize;
+use std::{io, path::PathBuf, process::Stdio};
 use tokio::{
     io::{AsyncBufReadExt, BufReader},
     process::Command,
@@ -59,11 +59,15 @@ pub async fn download_track_from_soundcloud(
     while let Ok(Some(line)) = reader.next_line().await {
         if line.starts_with("{") {
             let progress: DownloadProgress = serde_json::from_str(&line).unwrap();
-            let _ = sender.send(AppEvent::OverallProgress((0, 1))).await;
+            let _ = sender
+                .send(AppEvent::OverallProgress((0, 1, Color::Green)))
+                .await;
             let _ = sender.send(AppEvent::CurrentProgress(progress)).await;
         }
     }
-    let _ = sender.send(AppEvent::OverallProgress((1, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((1, 1, Color::Green)))
+        .await;
     Ok(())
 }
 
@@ -114,7 +118,9 @@ pub async fn download_from_soundcloud(
                 let s: Vec<&str> = s.split(' ').collect();
                 let cur = s.first().unwrap().trim().parse().unwrap();
                 let max = s.last().unwrap().trim().parse().unwrap();
-                let _ = sender.send(AppEvent::OverallProgress((cur, max))).await;
+                let _ = sender
+                    .send(AppEvent::OverallProgress((cur, max, Color::Green)))
+                    .await;
             }
             None => {
                 if line.starts_with("{") {
diff --git a/src/file_system.rs b/src/file_system.rs
index b7f889e..9b23771 100644
--- a/src/file_system.rs
+++ b/src/file_system.rs
@@ -21,13 +21,30 @@ pub struct FileSystem {
     sender: UnboundedSender<AppEvent>,
 }
 
-fn check_extension_compatibility(ext: &OsStr) -> bool {
+fn check_extension_compatibility(ext: &str) -> bool {
     matches!(
-        ext.to_str().unwrap().to_lowercase().as_str(),
+        ext.to_lowercase().as_str(),
         "mp3" | "m4a" | "wav" | "aiff" | "aif"
     )
 }
 
+fn get_extension_from_filename(file_name: Option<&OsStr>) -> String {
+    if let Some(fname) = file_name {
+        let file_name = fname.to_str().unwrap();
+        let index = file_name
+            .chars()
+            .enumerate()
+            .filter(|(i, c)| *c == '.')
+            .map(|(i, c)| i)
+            .last();
+        if let Some(index) = index {
+            let extension: String = file_name.chars().skip(index).collect();
+            return extension;
+        }
+    }
+    "none".to_string()
+}
+
 fn list_files_recursively(p: PathBuf) -> Vec<PathBuf> {
     let mut files = Vec::new();
 
@@ -38,7 +55,14 @@ fn list_files_recursively(p: PathBuf) -> Vec<PathBuf> {
             continue;
         }
         let a = path.unwrap().path();
-        if a.is_file() && check_extension_compatibility(a.extension().unwrap()) {
+        if a.is_file()
+            && check_extension_compatibility(
+                a.extension()
+                    .map_or(&get_extension_from_filename(a.file_name()), |s| {
+                        s.to_str().unwrap()
+                    }),
+            )
+        {
             files.push(a.clone());
         }
         if a.is_dir() {
@@ -130,10 +154,9 @@ impl FileSystem {
         let mut dir = paths
             .filter_map(|res| res.ok())
             .filter(|p| {
-                p.path()
-                    .extension()
-                    .map_or(false, check_extension_compatibility)
-                    || p.path().is_dir()
+                p.path().extension().map_or(false, |s| {
+                    check_extension_compatibility(s.to_str().unwrap_or("none"))
+                }) || p.path().is_dir()
             })
             .collect::<Vec<DirEntry>>();
         dir.sort_by(|a, b| {
diff --git a/src/loading_screen.rs b/src/loading_screen.rs
index 249f8a4..591a60b 100644
--- a/src/loading_screen.rs
+++ b/src/loading_screen.rs
@@ -10,7 +10,8 @@ use crate::{dlp::DownloadProgress, screen::AppScreen, theme::Theme};
 
 #[derive(Default)]
 pub struct LoadingScreen {
-    pub progress: Option<(u32, u32)>,
+    pub progress: Option<(u32, u32, ratatui::style::Color)>,
+    pub artwork_progress: Option<(u32, u32)>,
     pub s_progress: Option<DownloadProgress>,
 }
 
@@ -61,11 +62,29 @@ impl LoadingScreen {
             self.render_overall(frame, chunks[1]);
         }
 
-        if self.s_progress.is_some() {
+        if self.artwork_progress.is_some() {
+            self.render_artwork_progress(frame, chunks[2]);
+        } else if self.s_progress.is_some() {
             self.render_current(frame, chunks[2]);
         }
     }
 
+    fn render_artwork_progress(&self, frame: &mut Frame, area: Rect) {
+        let gauge = Gauge::default()
+            .block(
+                Block::default()
+                    .borders(Borders::ALL)
+                    .title(" Generating album covers "),
+            )
+            .gauge_style(Style::default().fg(Color::LightBlue))
+            .ratio(
+                self.artwork_progress.unwrap().0 as f64 / self.artwork_progress.unwrap().1 as f64,
+            )
+            .label("Generating album covers...");
+
+        frame.render_widget(gauge, area);
+    }
+
     fn render_current(&self, frame: &mut Frame, area: Rect) {
         let s: String = self
             .s_progress
@@ -96,7 +115,7 @@ impl LoadingScreen {
                     .borders(Borders::ALL)
                     .title(" Downloading Playlist "),
             )
-            .gauge_style(Style::default().fg(Color::Green))
+            .gauge_style(Style::default().fg(self.progress.unwrap().2))
             .ratio(self.progress.unwrap().0 as f64 / self.progress.unwrap().1 as f64)
             .label(format!(
                 "{:}/{:}",
diff --git a/src/main.rs b/src/main.rs
index 3127574..c912930 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -121,14 +121,22 @@ impl App {
                         let screen: &mut MainScreen = self.get_screen(&AppState::MainScreen);
                         screen.set_soundcloud_playlists(playlists);
                     },
-                    AppEvent::OverallProgress((c, max)) => {
+                    AppEvent::OverallProgress((c, max, color)) => {
+                        self.state = AppState::LoadingScreen;
                         let screen: &mut LoadingScreen = self.get_screen(&AppState::LoadingScreen);
-                        screen.progress = Some((c, max));
+                        screen.progress = Some((c, max, color));
+                        screen.artwork_progress = None;
                     },
                     AppEvent::CurrentProgress(progress) => {
                         let screen: &mut LoadingScreen = self.get_screen(&AppState::LoadingScreen);
+                        screen.artwork_progress = None;
                         screen.s_progress = Some(progress);
                     },
+                    AppEvent::ArtworkProgress((c, max)) => {
+                        let screen: &mut LoadingScreen = self.get_screen(&AppState::LoadingScreen);
+                        screen.artwork_progress = Some((c, max));
+                        screen.s_progress = None;
+                    },
                     AppEvent::SwitchScreen(screen) => {
                         self.state = screen;
                     }
diff --git a/src/sync.rs b/src/sync.rs
index 52bdf12..ac02f1e 100644
--- a/src/sync.rs
+++ b/src/sync.rs
@@ -6,6 +6,7 @@ use itunesdb::artworkdb::aobjects::ADatabase;
 use itunesdb::objects::{ListSortOrder, PlaylistItem};
 use itunesdb::serializer;
 use itunesdb::xobjects::{XDatabase, XPlArgument, XPlaylist, XTrackItem};
+use ratatui::style::Color;
 use soundcloud::sobjects::{CloudPlaylist, CloudPlaylists, CloudTrack};
 use std::io::Read;
 use std::io::{Cursor, Write};
@@ -34,7 +35,8 @@ pub enum AppEvent {
     DownloadPlaylist(CloudPlaylist),
     DownloadTrack(CloudTrack),
     CurrentProgress(DownloadProgress),
-    OverallProgress((u32, u32)),
+    OverallProgress((u32, u32, ratatui::style::Color)),
+    ArtworkProgress((u32, u32)),
     SwitchScreen(AppState),
     LoadFromFS(PathBuf),
     LoadFromFSVec(Vec<PathBuf>),
@@ -51,7 +53,11 @@ pub struct DBPlaylist {
     pub tracks: Vec<XTrackItem>,
 }
 
-async fn track_from_soundcloud(value: &CloudTrack, ipod_path: String) -> Option<XTrackItem> {
+async fn track_from_soundcloud(
+    value: &CloudTrack,
+    ipod_path: String,
+    sender: &Sender<AppEvent>,
+) -> Option<XTrackItem> {
     let mut track_path = get_temp_dl_dir();
     track_path.push(value.id.to_string());
     track_path.set_extension("mp3");
@@ -62,7 +68,6 @@ async fn track_from_soundcloud(value: &CloudTrack, ipod_path: String) -> Option<
         .await
         .unwrap();
     let audio_info = &audio_file.audio_file.tracks.track;
-
     let song_dbid = util::hash_from_path(track_path);
 
     let mut track = XTrackItem::new(
@@ -77,20 +82,24 @@ async fn track_from_soundcloud(value: &CloudTrack, ipod_path: String) -> Option<
     );
 
     if image_path.exists() {
+        let _ = sender.send(AppEvent::ArtworkProgress((0, 2))).await;
         let mut adb = get_artwork_db(&ipod_path);
 
         let image_data = std::fs::read(image_path).unwrap();
 
-        let (small_img_name, large_img_name) = adb.add_images(song_dbid, util::hash(&image_data));
+        let cover_hash = util::hash(&image_data);
 
-        let mut dst = PathBuf::from(&ipod_path);
-        dst.push("iPod_Control");
-        dst.push("Artwork");
+        let if_cover_present = adb.if_cover_present(cover_hash);
+
+        let (small_img_name, large_img_name) = adb.add_images(song_dbid, cover_hash);
 
         let size = image_data.len();
 
-        make_cover_image(&image_data, &ipod_path, &small_img_name, (100, 100));
-        make_cover_image(&image_data, &ipod_path, &large_img_name, (200, 200));
+        if !if_cover_present {
+            make_cover_image(&image_data, &ipod_path, &small_img_name, (100, 100));
+            let _ = sender.send(AppEvent::ArtworkProgress((1, 2))).await;
+            make_cover_image(&image_data, &ipod_path, &large_img_name, (200, 200));
+        }
 
         write_artwork_db(adb, &ipod_path);
 
@@ -98,6 +107,7 @@ async fn track_from_soundcloud(value: &CloudTrack, ipod_path: String) -> Option<
         track.data.mhii_link = 0;
         track.data.has_artwork = 1;
         track.data.artwork_count = 1;
+        let _ = sender.send(AppEvent::ArtworkProgress((2, 2))).await;
     }
 
     audio_file.modify_xtrack(&mut track);
@@ -109,7 +119,9 @@ async fn track_from_soundcloud(value: &CloudTrack, ipod_path: String) -> Option<
             .clone()
             .map_or(String::new(), |a| a.username.unwrap_or(a.permalink)),
     );
-    track.set_genre(value.genre.clone().unwrap());
+    if value.genre.is_some() {
+        track.set_genre(value.genre.clone().unwrap());
+    }
     Some(track)
 }
 
@@ -207,11 +219,15 @@ async fn remove_track_from_playlist(
     sender: &Sender<AppEvent>,
     ipod_path: String,
 ) {
-    let _ = sender.send(AppEvent::OverallProgress((0, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((0, 1, Color::Red)))
+        .await;
 
     database.remove_track_from_playlist(track_id, pl_id);
 
-    let _ = sender.send(AppEvent::OverallProgress((1, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((1, 1, Color::Red)))
+        .await;
 
     let _ = sender
         .send(AppEvent::SwitchScreen(AppState::MainScreen))
@@ -242,18 +258,22 @@ async fn remove_playlist(
         let mut i = 1;
         for (item, args) in pl.elems.iter() {
             let _ = sender
-                .send(AppEvent::OverallProgress((i, max as u32)))
+                .send(AppEvent::OverallProgress((i, max as u32, Color::Red)))
                 .await;
             remove_track(item.track_id, database, sender, ipod_path.clone()).await;
             i += 1;
         }
     }
 
-    let _ = sender.send(AppEvent::OverallProgress((0, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((0, 1, Color::Red)))
+        .await;
 
     database.remove_playlist(pl_id);
 
-    let _ = sender.send(AppEvent::OverallProgress((1, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((1, 1, Color::Red)))
+        .await;
 
     let _ = sender
         .send(AppEvent::SwitchScreen(AppState::MainScreen))
@@ -272,14 +292,18 @@ async fn remove_track(
     sender: &Sender<AppEvent>,
     ipod_path: String,
 ) {
-    let _ = sender.send(AppEvent::OverallProgress((0, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((0, 1, Color::Red)))
+        .await;
     database.remove_track_completely(id);
     for ext in ["mp3", "m4a", "wav", "aif"].iter() {
         let dest = get_full_track_location(PathBuf::from(ipod_path.clone()), id, ext);
         let _ = std::fs::remove_file(dest);
     }
 
-    let _ = sender.send(AppEvent::OverallProgress((1, 1))).await;
+    let _ = sender
+        .send(AppEvent::OverallProgress((1, 1, Color::Red)))
+        .await;
 
     let _ = sender
         .send(AppEvent::SwitchScreen(AppState::MainScreen))
@@ -305,7 +329,11 @@ async fn load_files_from_fs_as_playlist(
 
     for (i, file) in files.iter().enumerate() {
         let _ = sender
-            .send(AppEvent::OverallProgress((i as u32, files.len() as u32)))
+            .send(AppEvent::OverallProgress((
+                i as u32,
+                files.len() as u32,
+                Color::Green,
+            )))
             .await;
         let id = load_from_fs(file.clone(), database, sender, ipod_path.clone()).await;
 
@@ -333,7 +361,11 @@ async fn load_files_from_fs(
 ) {
     for (i, file) in files.iter().enumerate() {
         let _ = sender
-            .send(AppEvent::OverallProgress((i as u32, files.len() as u32)))
+            .send(AppEvent::OverallProgress((
+                i as u32,
+                files.len() as u32,
+                Color::Green,
+            )))
             .await;
         load_from_fs(file.clone(), database, sender, ipod_path.clone()).await;
     }
@@ -347,7 +379,7 @@ async fn load_from_fs(
 ) -> u32 {
     let tag = Tag::new().read_from_path(&path).unwrap();
 
-    let id = database.get_unique_id();
+    let mut id = database.get_unique_id();
 
     let audio_file = audio_file_info::from_path(path.to_str().unwrap())
         .await
@@ -356,75 +388,86 @@ async fn load_from_fs(
 
     let song_dbid = util::hash_from_path(path.clone());
 
-    let mut track = XTrackItem::new(
-        id,
-        audio_info.audio_bytes as u32,
-        (audio_info.duration * 1000.0) as u32,
-        tag.year().unwrap_or(0) as u32,
-        (audio_info.bit_rate / 1000) as u32,
-        audio_info.sample_rate as u32,
-        song_dbid,
-        0,
-    );
+    if !database.if_track_in_library(song_dbid) {
+        let mut track = XTrackItem::new(
+            id,
+            audio_info.audio_bytes as u32,
+            (audio_info.duration * 1000.0) as u32,
+            tag.year().unwrap_or(0) as u32,
+            (audio_info.bit_rate / 1000) as u32,
+            audio_info.sample_rate as u32,
+            song_dbid,
+            0,
+        );
 
-    audio_file.modify_xtrack(&mut track);
+        audio_file.modify_xtrack(&mut track);
 
-    if let Some(title) = tag.title() {
-        track.set_title(title.to_string());
-    } else {
-        track.set_title(path.file_name().unwrap().to_str().unwrap().to_string());
+        if let Some(title) = tag.title() {
+            track.set_title(title.to_string());
+        } else {
+            track.set_title(path.file_name().unwrap().to_str().unwrap().to_string());
+        }
+
+        if let Some(genre) = tag.genre() {
+            track.set_genre(genre.to_string());
+        }
+
+        if let Some(artist) = tag.artist() {
+            track.set_artist(artist.to_string());
+        }
+
+        if let Some(cover) = tag.album_cover() {
+            let _ = sender.send(AppEvent::ArtworkProgress((0, 2))).await;
+
+            let mut adb = get_artwork_db(&ipod_path);
+
+            let cover_hash = util::hash(cover.data);
+
+            let if_cover_present = adb.if_cover_present(cover_hash);
+
+            let (small_img_name, large_img_name) = adb.add_images(song_dbid, cover_hash);
+
+            let size = cover.data.len();
+
+            if !if_cover_present {
+                make_cover_image(cover.data, &ipod_path, &small_img_name, (100, 100));
+                let _ = sender.send(AppEvent::ArtworkProgress((1, 2))).await;
+                make_cover_image(cover.data, &ipod_path, &large_img_name, (200, 200));
+            }
+
+            write_artwork_db(adb, &ipod_path);
+
+            track.data.artwork_size = size as u32;
+            track.data.mhii_link = 0;
+            track.data.has_artwork = 1;
+            track.data.artwork_count = 1;
+
+            let _ = sender.send(AppEvent::ArtworkProgress((2, 2))).await;
+        }
+
+        if let Some(album) = tag.album() {
+            track.set_album(album.title.to_string());
+            // TODO: Add new album into iTunesDB
+        }
+
+        track.set_location(get_track_location(
+            track.data.unique_id,
+            audio_file.get_audio_extension(),
+        ));
+
+        let dest = get_full_track_location(
+            PathBuf::from(ipod_path.clone()),
+            track.data.unique_id,
+            audio_file.get_audio_extension(),
+        );
+
+        let _ = std::fs::copy(path.to_str().unwrap(), dest.to_str().unwrap());
+
+        database.add_track(track);
+    } else if let Some(unique_id) = database.get_unique_id_by_dbid(song_dbid) {
+        id = unique_id;
     }
 
-    if let Some(genre) = tag.genre() {
-        track.set_genre(genre.to_string());
-    }
-
-    if let Some(artist) = tag.artist() {
-        track.set_artist(artist.to_string());
-    }
-
-    if let Some(cover) = tag.album_cover() {
-        let mut adb = get_artwork_db(&ipod_path);
-
-        let (small_img_name, large_img_name) = adb.add_images(song_dbid, util::hash(cover.data));
-
-        let mut dst = PathBuf::from(&ipod_path);
-        dst.push("iPod_Control");
-        dst.push("Artwork");
-
-        let size = cover.data.len();
-
-        make_cover_image(cover.data, &ipod_path, &small_img_name, (100, 100));
-        make_cover_image(cover.data, &ipod_path, &large_img_name, (200, 200));
-
-        write_artwork_db(adb, &ipod_path);
-
-        track.data.artwork_size = size as u32;
-        track.data.mhii_link = 0;
-        track.data.has_artwork = 1;
-        track.data.artwork_count = 1;
-    }
-
-    if let Some(album) = tag.album() {
-        track.set_album(album.title.to_string());
-        // TODO: Add new album into iTunesDB
-    }
-
-    track.set_location(get_track_location(
-        track.data.unique_id,
-        audio_file.get_audio_extension(),
-    ));
-
-    let dest = get_full_track_location(
-        PathBuf::from(ipod_path.clone()),
-        track.data.unique_id,
-        audio_file.get_audio_extension(),
-    );
-
-    let _ = std::fs::copy(path.to_str().unwrap(), dest.to_str().unwrap());
-
-    database.add_track(track);
-
     let _ = sender
         .send(AppEvent::SwitchScreen(AppState::MainScreen))
         .await;
@@ -522,18 +565,20 @@ async fn download_track(
     {
         let p: PathBuf = Path::new(&ipod_path).into();
 
-        if let Some(mut t) = track_from_soundcloud(&track, ipod_path.clone()).await {
-            t.data.unique_id = database.get_unique_id();
-            t.set_location(get_track_location(t.data.unique_id, "mp3"));
-            let dest = get_full_track_location(p.clone(), t.data.unique_id, "mp3");
+        if let Some(mut t) = track_from_soundcloud(&track, ipod_path.clone(), sender).await {
+            if !database.if_track_in_library(t.data.dbid) {
+                t.data.unique_id = database.get_unique_id();
+                t.set_location(get_track_location(t.data.unique_id, "mp3"));
+                let dest = get_full_track_location(p.clone(), t.data.unique_id, "mp3");
 
-            let mut track_path = get_temp_dl_dir();
-            track_path.push(track.id.to_string());
-            track_path.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.to_str().unwrap(), dest.to_str().unwrap());
+                let _ = std::fs::copy(track_path.to_str().unwrap(), dest.to_str().unwrap());
 
-            database.add_track(t);
+                database.add_track(t);
+            }
         }
     }
 
@@ -572,18 +617,21 @@ async fn download_playlist(
             if track.title.is_none() {
                 continue;
             }
-            if let Some(mut t) = track_from_soundcloud(&track, ipod_path.clone()).await {
-                t.data.unique_id = database.get_unique_id();
-                new_playlist.add_elem(t.data.unique_id);
-                t.set_location(get_track_location(t.data.unique_id, "mp3"));
-                let dest = get_full_track_location(p.clone(), t.data.unique_id, "mp3");
-                let mut track_path = get_temp_dl_dir();
-                track_path.push(track.id.to_string());
-                track_path.set_extension("mp3");
+            if let Some(mut t) = track_from_soundcloud(&track, ipod_path.clone(), sender).await {
+                if !database.if_track_in_library(t.data.dbid) {
+                    t.data.unique_id = database.get_unique_id();
+                    new_playlist.add_elem(t.data.unique_id);
+                    t.set_location(get_track_location(t.data.unique_id, "mp3"));
+                    let dest = get_full_track_location(p.clone(), t.data.unique_id, "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.to_str().unwrap(), dest.to_str().unwrap());
-
-                database.add_track(t);
+                    let _ = std::fs::copy(track_path.to_str().unwrap(), dest.to_str().unwrap());
+                    database.add_track(t);
+                } else if let Some(unique_id) = database.get_unique_id_by_dbid(t.data.dbid) {
+                    new_playlist.add_elem(unique_id);
+                }
             }
         }
 
@@ -663,14 +711,17 @@ async fn parse_itunes(sender: &Sender<AppEvent>, path: String) -> XDatabase {
     let mut playlists = playlists.collection;
 
     for playlist in playlists.iter_mut() {
-        if let Ok(tracks) = soundcloud::get_tracks(
-            playlist.tracks.clone(),
-            client_id.clone(),
-            app_version.clone(),
-        )
-        .await
-        {
-            playlist.tracks = tracks;
+        let trr = playlist.tracks.clone();
+        playlist.tracks = Vec::new();
+        for pl_tracks in trr.clone().chunks(45) {
+            if let Ok(tracks) =
+                soundcloud::get_tracks(pl_tracks.to_vec(), client_id.clone(), app_version.clone())
+                    .await
+            {
+                let mut tracks = tracks;
+                tracks.retain(|t| t.title.is_some());
+                playlist.tracks.append(&mut tracks);
+            }
         }
     }