use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct ChannelInfo {
pub id: u64,
pub user_id: u64,
pub slug: String,
#[serde(default)]
pub is_banned: bool,
#[serde(default)]
pub vod_enabled: bool,
#[serde(default)]
pub subscription_enabled: bool,
#[serde(default)]
pub is_affiliate: bool,
#[serde(default)]
pub verified: bool,
#[serde(default)]
pub followers_count: u64,
#[serde(default)]
pub can_host: bool,
pub chatroom: ChatroomInfo,
#[serde(default)]
pub subscriber_badges: Vec<SubscriberBadge>,
#[serde(default)]
pub user: Option<ChannelUser>,
#[serde(default)]
pub livestream: Option<LivestreamInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ChatroomInfo {
pub id: u64,
#[serde(default)]
pub channel_id: Option<u64>,
#[serde(default)]
pub chat_mode: Option<String>,
#[serde(default)]
pub slow_mode: bool,
#[serde(default)]
pub followers_mode: bool,
#[serde(default)]
pub subscribers_mode: bool,
#[serde(default)]
pub emotes_mode: bool,
#[serde(default)]
pub message_interval: u32,
#[serde(default)]
pub following_min_duration: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SubscriberBadge {
pub id: u64,
#[serde(default)]
pub channel_id: Option<u64>,
pub months: u32,
pub badge_image: BadgeImage,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BadgeImage {
pub src: String,
#[serde(default)]
pub srcset: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ChannelUser {
pub id: u64,
pub username: String,
#[serde(default)]
pub bio: Option<String>,
#[serde(default)]
pub profile_pic: Option<String>,
#[serde(default)]
pub instagram: Option<String>,
#[serde(default)]
pub twitter: Option<String>,
#[serde(default)]
pub youtube: Option<String>,
#[serde(default)]
pub discord: Option<String>,
#[serde(default)]
pub tiktok: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LivestreamInfo {
pub id: u64,
#[serde(default)]
pub slug: Option<String>,
#[serde(default)]
pub channel_id: Option<u64>,
#[serde(default)]
pub session_title: Option<String>,
#[serde(default)]
pub is_live: bool,
#[serde(default)]
pub is_mature: bool,
#[serde(default)]
pub language: Option<String>,
#[serde(default)]
pub viewer_count: u64,
#[serde(default)]
pub start_time: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub categories: Vec<LivestreamCategory>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LivestreamCategory {
pub id: u64,
pub name: String,
pub slug: String,
#[serde(default)]
pub tags: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_channel_info() {
let json = r##"{
"id": 44192640,
"user_id": 45297540,
"slug": "hello_kiko",
"is_banned": false,
"vod_enabled": true,
"subscription_enabled": true,
"is_affiliate": true,
"verified": true,
"followers_count": 8393,
"can_host": true,
"chatroom": {
"id": 43904307,
"channel_id": 44192640,
"chat_mode": "public",
"slow_mode": false,
"followers_mode": false,
"subscribers_mode": false,
"emotes_mode": false,
"message_interval": 5,
"following_min_duration": 0
},
"subscriber_badges": [
{
"id": 499365,
"channel_id": 44192640,
"months": 1,
"badge_image": {
"srcset": "",
"src": "https://files.kick.com/channel_subscriber_badges/499365/original"
}
},
{
"id": 499366,
"channel_id": 44192640,
"months": 2,
"badge_image": {
"srcset": "",
"src": "https://files.kick.com/channel_subscriber_badges/499366/original"
}
}
],
"user": {
"id": 45297540,
"username": "hello_kiko",
"bio": "Hi I'm Kiko",
"profile_pic": "https://files.kick.com/images/user/45297540/profile_image.webp",
"instagram": "bye.kiko",
"twitter": "hello_kiko",
"youtube": "hello_kiko",
"discord": "hellokiko",
"tiktok": "bye.kiko"
},
"livestream": {
"id": 103692434,
"slug": "some-stream-slug",
"channel_id": 44192640,
"session_title": "Just Chatting stream!",
"is_live": true,
"is_mature": false,
"language": "English",
"viewer_count": 99,
"start_time": "2026-04-06 05:03:57",
"tags": ["Japan", "Korean"],
"categories": [
{
"id": 15,
"name": "Just Chatting",
"slug": "just-chatting",
"tags": ["IRL", "Casual"]
}
]
}
}"##;
let info: ChannelInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.id, 44192640);
assert_eq!(info.user_id, 45297540);
assert_eq!(info.slug, "hello_kiko");
assert!(!info.is_banned);
assert!(info.verified);
assert!(info.is_affiliate);
assert_eq!(info.followers_count, 8393);
assert_eq!(info.chatroom.id, 43904307);
assert_eq!(info.chatroom.chat_mode, Some("public".into()));
assert!(!info.chatroom.slow_mode);
assert!(!info.chatroom.followers_mode);
assert!(!info.chatroom.subscribers_mode);
assert_eq!(info.chatroom.message_interval, 5);
assert_eq!(info.subscriber_badges.len(), 2);
assert_eq!(info.subscriber_badges[0].months, 1);
assert!(info.subscriber_badges[0].badge_image.src.contains("499365"));
assert_eq!(info.subscriber_badges[1].months, 2);
let user = info.user.unwrap();
assert_eq!(user.username, "hello_kiko");
assert_eq!(user.bio, Some("Hi I'm Kiko".into()));
assert_eq!(user.discord, Some("hellokiko".into()));
let stream = info.livestream.unwrap();
assert!(stream.is_live);
assert_eq!(stream.viewer_count, 99);
assert_eq!(stream.session_title, Some("Just Chatting stream!".into()));
assert_eq!(stream.tags, vec!["Japan", "Korean"]);
assert_eq!(stream.categories.len(), 1);
assert_eq!(stream.categories[0].name, "Just Chatting");
}
#[test]
fn test_deserialize_offline_channel() {
let json = r##"{
"id": 12345,
"user_id": 67890,
"slug": "offline_user",
"chatroom": {
"id": 11111,
"slow_mode": true,
"followers_mode": true,
"subscribers_mode": false,
"emotes_mode": false,
"message_interval": 10,
"following_min_duration": 30
},
"subscriber_badges": [],
"livestream": null
}"##;
let info: ChannelInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.slug, "offline_user");
assert!(info.livestream.is_none());
assert!(info.chatroom.slow_mode);
assert!(info.chatroom.followers_mode);
assert_eq!(info.chatroom.message_interval, 10);
assert_eq!(info.chatroom.following_min_duration, 30);
assert!(info.subscriber_badges.is_empty());
assert!(info.user.is_none());
}
#[test]
fn test_deserialize_minimal_channel() {
let json = r##"{
"id": 1,
"user_id": 2,
"slug": "test",
"chatroom": { "id": 3 }
}"##;
let info: ChannelInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.id, 1);
assert_eq!(info.chatroom.id, 3);
assert!(!info.chatroom.slow_mode);
assert_eq!(info.followers_count, 0);
assert!(!info.verified);
assert!(info.subscriber_badges.is_empty());
}
}