music sorting, search cycling, pause cycling
This commit is contained in:
BIN
revert.zip
BIN
revert.zip
Binary file not shown.
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
65
src/main.rs
65
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<ListItem> = 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<MpvSessi
|
||||
Err("mpv IPC socket did not appear".to_string())
|
||||
}
|
||||
|
||||
|
||||
fn mpv_load_item(cfg: &core::config::Config, mpv: &MpvSession, item_id: &str) -> 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,
|
||||
|
||||
Reference in New Issue
Block a user