diff --git a/README.md b/README.md new file mode 100644 index 0000000..7515bdc --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ + + +**Lyrica** + +Lightweight iPod manager, batteries included. + + +# +
+ +

+ Screenshot from MacOS Big Sur terminal +

+
+ +## Features + +- **Basic operations**: Load songs from filesystem to ipod. Manually delete anything if needed. +- **Streamings**: Download playlists from Soundcloud, Youtube, Spotify to your iPod. +- **No mindf_ck**: Albums are generated automatically from tracks metadata. No human processing required +- **Playlists**: Create/remove/edit playlists on your ipod +- **Smart playlists**: Smart playlists manager included. + +## Requirements + +- iPod classic +- Mac OS +- [YT-DLP](https://github.com/yt-dlp/yt-dlp) A feature-rich command-line audio/video downloader. + +## Installation + +### Auto install + +```bash + +``` + +### Manually \ No newline at end of file diff --git a/src/main_screen.rs b/src/main_screen.rs index 677c097..47e84ee 100644 --- a/src/main_screen.rs +++ b/src/main_screen.rs @@ -1,22 +1,25 @@ +use chrono::{DateTime, Utc}; use color_eyre::owo_colors::OwoColorize; use crossterm::event::{KeyCode, KeyEvent}; use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style, Stylize}, text::{Line, Span}, - widgets::{Block, Borders, Gauge, Paragraph, Tabs}, + widgets::{Block, Borders, Gauge, Paragraph, Row, Table, Tabs}, Frame, }; use soundcloud::sobjects::CloudPlaylists; use strum::IntoEnumIterator; use tokio::sync::mpsc::UnboundedSender; -use crate::{playlist_icon::PlaylistIcon, screen::AppScreen, sync::AppEvent}; +use crate::{screen::AppScreen, sync::AppEvent}; struct Playlist { - name: String, - thumbnail: PlaylistIcon, + id: u64, + title: String, link: String, + created_at: String, + track_count: u32, } pub struct MainScreen { @@ -168,30 +171,16 @@ impl MainScreen { pl.collection .iter() .map(|p| Playlist { - name: p.title.clone(), - thumbnail: p - .artwork_url - .as_deref() - .map_or(PlaylistIcon::default(), |u| self.ascii_art_from_url(u)), + id: p.id, + created_at: p.created_at.clone(), + title: p.title.clone(), link: p.permalink_url.clone(), + track_count: p.track_count, }) .collect(), ); } - fn ascii_art_from_url(&self, url: &str) -> PlaylistIcon { - let img = image::load_from_memory( - &ureq::get(url) - .call() - .unwrap() - .body_mut() - .read_to_vec() - .unwrap(), - ) - .unwrap(); - PlaylistIcon::new(img.clone()) - } - fn render_progress(&self, frame: &mut Frame, area: Rect) { let chunks = Layout::default() .direction(Direction::Vertical) @@ -225,78 +214,49 @@ impl MainScreen { fn render_tab(&self, frame: &mut Frame, area: Rect) /*-> Table<'_>*/ { - if self.selected_tab == 1 { - // SC - /*let mut v = Vec::new(); - v.push(Row::new(vec!["Id", "Title", "Songs Count", "Date", "IS"]).style(Style::default().fg(Color::Gray))); - if let Some(s) = &self.soundcloud { - for (i, playlist) in (&s.collection).iter().enumerate() { - let date: DateTime = playlist.created_at.parse().unwrap(); - let mut row = Row::new( - vec![ - playlist.id.to_string(), - playlist.title.clone(), - [playlist.track_count.to_string(), " songs".to_string()].concat(), - format!("{}", date.format("%Y-%m-%d %H:%M")), - "NO".to_string() - ] - ); - if self.selected_row == i as i32 { - row = row.style(Style::default().bg(Color::Yellow)); - } - v.push(row); - } - } - v*/ - let v = self.soundcloud.as_deref().unwrap_or(&[]); - - let rows = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![ - Constraint::Percentage(100); - math::round::ceil(v.len() as f64 / 3_f64, 0) as usize - ]) // Two rows - .split(area); - - for (i, row) in rows.iter().enumerate() { - let cols = Layout::default() - .direction(Direction::Horizontal) - .constraints(vec![Constraint::Percentage(33); 3]) // Three columns - .split(*row); - - for (j, col) in cols.iter().enumerate() { - let index = i * 3 + j; - if index < v.len() { - let p = &v[index]; - - /*let url_cl = p.thumbnail_url.clone(); - let s = url_cl.lines().map(Line::from).collect::>();*/ - - let paragraph = Paragraph::new(Line::from(p.name.clone())) - .block(Block::default().borders(Borders::ALL)) - .style(Style::default()); - - let pl = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(70), Constraint::Percentage(30)]) - .split(*col); - - frame.render_widget(p.thumbnail.clone(), pl[0]); - frame.render_widget(paragraph, pl[1]); + let rows = match self.selected_tab { + 1 => { + // SC + let mut v = Vec::new(); + v.push( + Row::new(vec!["Id", "Title", "Songs Count", "Date", "IS"]) + .style(Style::default().fg(Color::Gray)), + ); + if let Some(s) = &self.soundcloud { + for (i, playlist) in s.iter().enumerate() { + let date: DateTime = playlist.created_at.parse().unwrap(); + let mut row = Row::new(vec![ + playlist.id.to_string(), + playlist.title.clone(), + [playlist.track_count.to_string(), " songs".to_string()].concat(), + format!("{}", date.format("%Y-%m-%d %H:%M")), + "NO".to_string(), + ]); + if self.selected_row == i as i32 { + row = row.style(Style::default().bg(Color::Yellow)); + } + v.push(row); } } + v } + _ => Vec::new(), }; // Create the table - /* Table::new(rows, &[ - Constraint::Length(3), // ID column - Constraint::Percentage(50), // Playlist name column - Constraint::Percentage(20), // Song count column - Constraint::Percentage(30), - Constraint::Length(2) - ]) + let table = Table::new( + rows, + &[ + Constraint::Length(3), // ID column + Constraint::Percentage(50), // Playlist name column + Constraint::Percentage(20), // Song count column + Constraint::Percentage(30), + Constraint::Length(2), + ], + ) .block(Block::default().borders(Borders::ALL).title(" Playlists ")) - .style(Style::default().fg(Color::White)) */ + .style(Style::default().fg(Color::White)); + + frame.render_widget(table, area); } }