diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 079904a..989d692 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -50,9 +50,9 @@ pub mod youjizz; pub mod chaturbate; pub mod freepornvideosxxx; pub mod heavyfetish; -pub mod hsex; pub mod hentaihaven; pub mod hqporner; +pub mod hsex; pub mod hypnotube; pub mod javtiful; pub mod noodlemagazine; @@ -437,7 +437,8 @@ pub fn decorate_channel(channel: Channel) -> ChannelView { categories: channel.categories, options: channel.options, nsfw: channel.nsfw, - group: metadata.map(|value| value.group_id.to_string()), + groupKey: metadata.map(|value| value.group_id.to_string()), + sortOrder: None, tags: metadata.map(|value| { value .tags @@ -455,34 +456,74 @@ pub fn build_channel_groups(channels: &[ChannelView]) -> Vec { let mut group_ids = channels .iter() - .filter_map(|channel| channel.group.clone()) + .filter_map(|channel| channel.groupKey.clone()) .collect::>(); group_ids.sort_by_key(|group_id| (channel_group_order(group_id), group_id.clone())); group_ids.dedup(); for group_id in group_ids { - let mut channel_ids = channels + let mut grouped_channels = channels .iter() - .filter(|channel| channel.group.as_deref() == Some(group_id.as_str())) + .filter(|channel| channel.groupKey.as_deref() == Some(group_id.as_str())) + .collect::>(); + grouped_channels.sort_by(|a, b| { + (a.sortOrder.unwrap_or(u32::MAX), &a.name, &a.id).cmp(&( + b.sortOrder.unwrap_or(u32::MAX), + &b.name, + &b.id, + )) + }); + let channel_ids = grouped_channels + .into_iter() .map(|channel| channel.id.clone()) .collect::>(); - channel_ids.sort(); groups.push(ChannelGroup { id: group_id.clone(), title: channel_group_title(&group_id).to_string(), - channels: channel_ids, + channelIds: channel_ids, }); } groups } +fn assign_channel_sort_order(channels: &mut [ChannelView]) { + let mut ordered = channels + .iter() + .enumerate() + .map(|(index, channel)| { + ( + index, + channel.groupKey.clone(), + channel.name.to_ascii_lowercase(), + channel.id.to_ascii_lowercase(), + ) + }) + .collect::>(); + + ordered.sort_by(|a, b| { + let a_group = a.1.as_deref().unwrap_or(""); + let b_group = b.1.as_deref().unwrap_or(""); + (channel_group_order(a_group), a_group, &a.2, &a.3).cmp(&( + channel_group_order(b_group), + b_group, + &b.2, + &b.3, + )) + }); + + for (sort_index, (channel_index, _, _, _)) in ordered.into_iter().enumerate() { + channels[channel_index].sortOrder = Some((sort_index + 1) as u32); + } +} + pub fn build_status_response(status: Status) -> StatusResponse { - let channels = status + let mut channels = status .channels .into_iter() .map(decorate_channel) .collect::>(); + assign_channel_sort_order(&mut channels); let channelGroups = build_channel_groups(&channels); StatusResponse { @@ -561,14 +602,17 @@ mod tests { #[test] fn decorates_channel_with_group_and_tags() { let channel = decorate_channel(base_channel("hsex")); - assert_eq!(channel.group.as_deref(), Some("amateur-homemade")); + assert_eq!(channel.groupKey.as_deref(), Some("amateur-homemade")); + assert_eq!(channel.sortOrder, None); assert_eq!( channel.tags.as_deref(), - Some(&[ - "amateur".to_string(), - "chinese".to_string(), - "homemade".to_string(), - ][..]) + Some( + &[ + "amateur".to_string(), + "chinese".to_string(), + "homemade".to_string(), + ][..] + ) ); } @@ -584,4 +628,33 @@ mod tests { assert_eq!(groups[1].id, "amateur-homemade"); assert_eq!(groups[2].id, "asian-jav"); } + + #[test] + fn status_response_uses_documented_group_keys() { + let mut status = Status::new(); + status.channels = vec![ + base_channel("missav"), + base_channel("hsex"), + base_channel("all"), + ]; + + let json = serde_json::to_value(build_status_response(status)).expect("valid status json"); + + let channels = json["channels"].as_array().expect("channels array"); + let all_channel = channels + .iter() + .find(|channel| channel["id"] == "all") + .expect("all channel present"); + assert_eq!(all_channel["groupKey"], "meta-search"); + assert!(all_channel.get("group").is_none()); + assert!(all_channel["sortOrder"].is_number()); + + let groups = json["channelGroups"].as_array().expect("group array"); + let meta_group = groups + .iter() + .find(|group| group["id"] == "meta-search") + .expect("meta group present"); + assert_eq!(meta_group["channelIds"], serde_json::json!(["all"])); + assert!(meta_group.get("channels").is_none()); + } } diff --git a/src/status.rs b/src/status.rs index 1c7ae28..c90821e 100644 --- a/src/status.rs +++ b/src/status.rs @@ -26,7 +26,7 @@ pub struct Channel { pub struct ChannelGroup { pub id: String, pub title: String, - pub channels: Vec, + pub channelIds: Vec, } #[derive(serde::Serialize)] @@ -146,7 +146,9 @@ pub struct ChannelView { pub options: Vec, pub nsfw: bool, #[serde(skip_serializing_if = "Option::is_none")] - pub group: Option, + pub groupKey: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub sortOrder: Option, #[serde(skip_serializing_if = "Option::is_none")] pub tags: Option>, #[serde(skip_serializing_if = "Option::is_none")]