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") {
|
if types.contains("Episode") {
|
||||||
sort_by = "ParentIndexNumber,IndexNumber,SortName";
|
sort_by = "ParentIndexNumber,IndexNumber,SortName";
|
||||||
} else if types.contains("Audio") {
|
} 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 {
|
fn label(self) -> &'static str {
|
||||||
use SearchMode::*;
|
use SearchMode::*;
|
||||||
match self {
|
match self {
|
||||||
@@ -385,6 +399,10 @@ fn handle_key(app: &mut App, code: KeyCode) {
|
|||||||
search.mode = search.mode.next();
|
search.mode = search.mode.next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
KeyCode::Char('?') => {
|
||||||
|
search.mode = search.mode.prev();
|
||||||
|
return;
|
||||||
|
}
|
||||||
KeyCode::Char(c) => { search.input.push(c); return; }
|
KeyCode::Char(c) => { search.input.push(c); return; }
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
@@ -457,6 +475,16 @@ fn handle_key(app: &mut App, code: KeyCode) {
|
|||||||
}
|
}
|
||||||
return;
|
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') => {
|
KeyCode::Char('p') => {
|
||||||
// p = play selected item (spawn or replace)
|
// p = play selected item (spawn or replace)
|
||||||
let cfg = match &app.config {
|
let cfg = match &app.config {
|
||||||
@@ -793,8 +821,26 @@ fn ui(frame: &mut Frame, app: &App) {
|
|||||||
View::Categories => {
|
View::Categories => {
|
||||||
render_categories(frame, app, panes.left_main, panes.right_main);
|
render_categories(frame, app, panes.left_main, panes.right_main);
|
||||||
}
|
}
|
||||||
View::Library { title, items, selected, start_index, total, .. } => {
|
View::Library { title, query, items, selected, start_index, total, .. } => {
|
||||||
render_library(frame, title, *start_index, *total, items, *selected, panes.left_main, panes.right_main);
|
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 => {
|
View::Login => {
|
||||||
render_login(frame, app, panes.left_main, panes.right_main);
|
render_login(frame, app, panes.left_main, panes.right_main);
|
||||||
@@ -922,6 +968,7 @@ fn render_library(
|
|||||||
selected: usize,
|
selected: usize,
|
||||||
left: Rect,
|
left: Rect,
|
||||||
right: Rect,
|
right: Rect,
|
||||||
|
show_audio_track_numbers: bool,
|
||||||
) {
|
) {
|
||||||
let viewport = left.height.saturating_sub(2) as usize;
|
let viewport = left.height.saturating_sub(2) as usize;
|
||||||
|
|
||||||
@@ -934,10 +981,9 @@ fn render_library(
|
|||||||
matches!(item_type, Some("Movie" | "Series" | "MusicAlbum"))
|
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() {
|
match it.item_type.as_deref() {
|
||||||
Some("Episode") => {
|
Some("Episode") => {
|
||||||
// season x episode (01x02)
|
|
||||||
match (it.parent_index_number, it.index_number) {
|
match (it.parent_index_number, it.index_number) {
|
||||||
(Some(season), Some(ep)) => format!("{:02}x{:02} ", season, ep),
|
(Some(season), Some(ep)) => format!("{:02}x{:02} ", season, ep),
|
||||||
(_, Some(ep)) => format!("{:02} ", ep),
|
(_, Some(ep)) => format!("{:02} ", ep),
|
||||||
@@ -945,7 +991,9 @@ fn render_library(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("Audio") => {
|
Some("Audio") => {
|
||||||
// track number
|
if !show_audio_track_numbers {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
match it.index_number {
|
match it.index_number {
|
||||||
Some(n) => format!("{:02}. ", n),
|
Some(n) => format!("{:02}. ", n),
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
@@ -958,7 +1006,7 @@ fn render_library(
|
|||||||
let list_items: Vec<ListItem> = items[start..end]
|
let list_items: Vec<ListItem> = items[start..end]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|it| {
|
.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()) {
|
let year = if show_year_for(it.item_type.as_deref()) {
|
||||||
it.production_year.map(|y| format!(" ({y})")).unwrap_or_default()
|
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())
|
Err("mpv IPC socket did not appear".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn mpv_load_item(cfg: &core::config::Config, mpv: &MpvSession, item_id: &str) -> Result<(), 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 base = cfg.base_url.trim_end_matches('/');
|
||||||
let url = format!("{}/Items/{}/Download", base, item_id);
|
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"]}"#)
|
// 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 {
|
struct Panes {
|
||||||
top: Rect,
|
top: Rect,
|
||||||
left_main: Rect,
|
left_main: Rect,
|
||||||
|
|||||||
Reference in New Issue
Block a user