Add order: none handling to playlist sorting

This commit is contained in:
DarkBreakpoint
2025-11-19 22:12:53 -06:00
parent c3a41f6877
commit 88e92cd4a4
4 changed files with 17 additions and 5 deletions
+1
View File
@@ -9,6 +9,7 @@
- Added detailed shared-stream/buffer/provider logging to trace lag, cache persistence, and session/provider lifecycle events.
- Connection registration failures now trigger an explicit disconnect so zombie sockets don’t linger.
- Shared stream shutdown now drops registry locks before releasing provider handles to prevent cross-lock stalls.
- Added `order: none` support for group/channel sorting so mappings can opt out of any reordering and keep the source order.
# 3.2.0 (2025-11-14)
+2 -2
View File
@@ -864,13 +864,13 @@ Has three top level attributes
#### `groups`
Used for sorting at the group (category) level.
It has one top-level attribute `order` which can be set to `asc`or `desc`.
It has one top-level attribute `order` which can be set to `asc`, `desc`, or `none` to preserve the source order for that level.
#### `channels`
Used for sorting the channels within a group/category.
This is a list of sort configurations for groups. Each configuration has the following top-level entries:
- `field` - can be `title`, `name`, `caption` or `url`.
- `group_pattern` - a regular expression like `'^TR.:\s?(.*)'` matched against group title.
- `order` - can be `asc` or `desc`
- `order` - can be `asc`, `desc`, or `none` (which skips sorting for that group_pattern and keeps the playlist order coming from the sources).
- `sequence` _optional_ - a list of regexp matching field values (based on `field`). These are used to sort based on index. The `order` is ignored for this entries.
The pattern should be selected taking into account the processing sequence.
+10 -2
View File
@@ -10,6 +10,9 @@ fn playlist_comparator(
value_a: &str,
value_b: &str,
) -> Ordering {
if matches!(order, SortOrder::None) {
return Ordering::Equal;
}
if let Some(regex_list) = sequence {
let mut match_a = None;
let mut match_b = None;
@@ -123,10 +126,15 @@ pub(in crate::processing::processor) fn sort_playlist(target: &ConfigTarget, new
if let Some(sort) = &target.sort {
let match_as_ascii = sort.match_as_ascii;
if let Some(group_sort) = &sort.groups {
new_playlist.sort_by(|a, b| playlistgroup_comparator(a, b, group_sort, match_as_ascii));
if group_sort.order != SortOrder::None {
new_playlist.sort_by(|a, b| playlistgroup_comparator(a, b, group_sort, match_as_ascii));
}
}
if let Some(channel_sorts) = &sort.channels {
for channel_sort in channel_sorts {
if channel_sort.order == SortOrder::None {
continue;
}
let regexp = &channel_sort.group_pattern;
for group in new_playlist.iter_mut() {
let group_title = if match_as_ascii { deunicode(&group.title) } else { group.title.clone() };
@@ -223,4 +231,4 @@ mod tests {
let expected = vec!["US| EAST [UHD] m", "US| EAST [FHD] abc", "US| EAST [FHD] bc", "US| EAST [FHD] de", "US| EAST [FHD] def", "US| EAST [FHD] ghi", "US| EAST [HD] f", "US| EAST [HD] h", "US| EAST [HD] jkl", "US| EAST [HD] mno", "US| EAST [HD] pqrs", "US| EAST [HD] tuv", "US| EAST [HD] wxy", "US| EAST [HD] z", "US| EAST [SD] a", "US| EAST [SD] ijk", "US| EAST [SD] l", "US| WEST [FHD] no", "US| WEST [HD] qrst", "US| WEST [HD] uvw", "US| (West) xv", "US| East d", "US| West e", "US| West f"];
assert_eq!(expected, sorted);
}
}
}
+4 -1
View File
@@ -23,6 +23,8 @@ pub enum SortOrder {
Asc,
#[serde(rename = "desc")]
Desc,
#[serde(rename = "none")]
None,
}
impl Display for SortOrder {
@@ -30,6 +32,7 @@ impl Display for SortOrder {
let str = match self {
SortOrder::Asc => "asc".to_string(),
SortOrder::Desc => "desc".to_string(),
SortOrder::None => "none".to_string(),
};
write!(f, "{str}")
}
@@ -150,4 +153,4 @@ impl ConfigSortDto {
}
Ok(())
}
}
}