diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c06c500..3b5b5ff79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/README.md b/README.md index 41733f69d..ddad9acd6 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/backend/src/processing/processor/sort.rs b/backend/src/processing/processor/sort.rs index 3f2d2d26f..cd17b9f7d 100644 --- a/backend/src/processing/processor/sort.rs +++ b/backend/src/processing/processor/sort.rs @@ -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); } -} \ No newline at end of file +} diff --git a/shared/src/model/config/sort.rs b/shared/src/model/config/sort.rs index 30a152363..259499d6b 100644 --- a/shared/src/model/config/sort.rs +++ b/shared/src/model/config/sort.rs @@ -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(()) } -} \ No newline at end of file +}