diff --git a/new.zip b/new.zip new file mode 100644 index 0000000..d0d0434 Binary files /dev/null and b/new.zip differ diff --git a/revert.zip b/revert.zip deleted file mode 100644 index 018b401..0000000 Binary files a/revert.zip and /dev/null differ diff --git a/src/core/jellyfin.rs b/src/core/jellyfin.rs index 34188ba..3dda7b6 100644 --- a/src/core/jellyfin.rs +++ b/src/core/jellyfin.rs @@ -124,7 +124,7 @@ impl JellyfinClient { if types.contains("Episode") { sort_by = "ParentIndexNumber,IndexNumber,SortName"; } else if types.contains("Audio") { - sort_by = "IndexNumber,SortName"; + sort_by = "SortName"; } } diff --git a/src/main.rs b/src/main.rs index 52bda3e..aec633e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,6 +76,20 @@ impl SearchMode { } } + fn prev(self) -> Self { + use SearchMode::*; + match self { + All => Artists, + ShowsMovies => All, + Shows => ShowsMovies, + Movies => Shows, + Episodes => Movies, + Music => Episodes, + Albums => Music, + Artists => Albums, + } + } + fn label(self) -> &'static str { use SearchMode::*; match self { @@ -385,6 +399,10 @@ fn handle_key(app: &mut App, code: KeyCode) { search.mode = search.mode.next(); return; } + KeyCode::Char('?') => { + search.mode = search.mode.prev(); + return; + } KeyCode::Char(c) => { search.input.push(c); return; } _ => return, } @@ -457,6 +475,16 @@ fn handle_key(app: &mut App, code: KeyCode) { } return; } + KeyCode::Char(' ') => { + if let Some(mpv) = &app.mpv { + if let Err(e) = mpv_cycle_pause(mpv) { + app.status = format!("mpv pause: {e}"); + } + } else { + app.status = "mpv not running (press 'p' to play)".into(); + } + return; + } KeyCode::Char('p') => { // p = play selected item (spawn or replace) let cfg = match &app.config { @@ -793,8 +821,26 @@ fn ui(frame: &mut Frame, app: &App) { View::Categories => { render_categories(frame, app, panes.left_main, panes.right_main); } - View::Library { title, items, selected, start_index, total, .. } => { - render_library(frame, title, *start_index, *total, items, *selected, panes.left_main, panes.right_main); + View::Library { title, query, items, selected, start_index, total, .. } => { + let is_audio = query + .include_item_types + .as_deref() + .map(|t| t.split(',').any(|x| x.trim() == "Audio")) + .unwrap_or(false); + + let show_audio_track_numbers = is_audio && query.parent_id.is_some(); + + render_library( + frame, + title, + *start_index, + *total, + items, + *selected, + panes.left_main, + panes.right_main, + show_audio_track_numbers, + ); } View::Login => { render_login(frame, app, panes.left_main, panes.right_main); @@ -922,6 +968,7 @@ fn render_library( selected: usize, left: Rect, right: Rect, + show_audio_track_numbers: bool, ) { let viewport = left.height.saturating_sub(2) as usize; @@ -934,10 +981,9 @@ fn render_library( matches!(item_type, Some("Movie" | "Series" | "MusicAlbum")) } - fn left_number_prefix(it: &core::jellyfin::JfItem) -> String { + fn left_number_prefix(it: &core::jellyfin::JfItem, show_audio_track_numbers: bool) -> String { match it.item_type.as_deref() { Some("Episode") => { - // season x episode (01x02) match (it.parent_index_number, it.index_number) { (Some(season), Some(ep)) => format!("{:02}x{:02} ", season, ep), (_, Some(ep)) => format!("{:02} ", ep), @@ -945,7 +991,9 @@ fn render_library( } } Some("Audio") => { - // track number + if !show_audio_track_numbers { + return String::new(); + } match it.index_number { Some(n) => format!("{:02}. ", n), None => String::new(), @@ -958,7 +1006,7 @@ fn render_library( let list_items: Vec = items[start..end] .iter() .map(|it| { - let prefix = left_number_prefix(it); + let prefix = left_number_prefix(it, show_audio_track_numbers); let year = if show_year_for(it.item_type.as_deref()) { it.production_year.map(|y| format!(" ({y})")).unwrap_or_default() @@ -1100,7 +1148,6 @@ fn spawn_mpv(cfg: &core::config::Config, first_item_id: &str) -> Result Result<(), String> { let base = cfg.base_url.trim_end_matches('/'); let url = format!("{}/Items/{}/Download", base, item_id); @@ -1137,6 +1184,10 @@ fn mpv_toggle_fullscreen(mpv: &MpvSession) -> Result<(), String> { // mpv_cmd(&mpv.socket_path, r#"{"command":["set_property","fullscreen","yes"]}"#) } +fn mpv_cycle_pause(mpv: &MpvSession) -> Result<(), String> { + mpv_cmd(&mpv.socket_path, r#"{"command":["cycle","pause"]}"#) +} + struct Panes { top: Rect, left_main: Rect,