Skip to main content

kick_api/api/
channels.rs

1use crate::error::{KickApiError, Result};
2use crate::models::{Channel, UpdateChannelRequest};
3use reqwest;
4
5/// Channels API - handles all channel-related endpoints
6pub struct ChannelsApi<'a> {
7    client: &'a reqwest::Client,
8    token: &'a Option<String>,
9    base_url: &'a str,
10}
11
12impl<'a> ChannelsApi<'a> {
13    /// Create a new ChannelsApi instance
14    pub(crate) fn new(
15        client: &'a reqwest::Client,
16        token: &'a Option<String>,
17        base_url: &'a str,
18    ) -> Self {
19        Self {
20            client,
21            token,
22            base_url,
23        }
24    }
25
26    /// Get a channel by slug
27    ///
28    /// Requires OAuth token with `channel:read` scope
29    ///
30    /// # Example
31    /// ```no_run
32    /// let channel = client.channels().get("xqc").await?;
33    /// println!("Channel: {}", channel.slug);
34    /// ```
35    pub async fn get(&self, channel_slug: &str) -> Result<Channel> {
36        super::require_token(self.token)?;
37
38        let url = format!("{}/channels", self.base_url);
39        let request = self
40            .client
41            .get(&url)
42            .header("Accept", "*/*")
43            .query(&[("slug", channel_slug)])
44            .bearer_auth(self.token.as_ref().unwrap());
45
46        let response = crate::http::send_with_retry(self.client, request).await?;
47        if response.status().is_success() {
48            let body = response.text().await?;
49
50            #[derive(serde::Deserialize)]
51            struct ChannelsResponse {
52                data: Vec<Channel>,
53            }
54
55            let resp: ChannelsResponse = serde_json::from_str(&body)
56                .map_err(|e| KickApiError::ApiError(format!("JSON parse error: {}", e)))?;
57
58            resp.data
59                .into_iter()
60                .next()
61                .ok_or_else(|| KickApiError::ApiError("Channel not found".to_string()))
62        } else {
63            Err(KickApiError::ApiError(format!(
64                "Failed to get channel: {}",
65                response.status()
66            )))
67        }
68    }
69
70    /// Update channel/livestream metadata
71    ///
72    /// Requires OAuth token with `channel:write` scope.
73    /// At least one field in the request must be set.
74    ///
75    /// # Example
76    /// ```no_run
77    /// use kick_api::UpdateChannelRequest;
78    /// let update = UpdateChannelRequest {
79    ///     stream_title: Some("New title!".to_string()),
80    ///     category_id: None,
81    ///     custom_tags: Some(vec!["rust".to_string()]),
82    /// };
83    /// client.channels().update(update).await?;
84    /// ```
85    pub async fn update(&self, request: UpdateChannelRequest) -> Result<()> {
86        super::require_token(self.token)?;
87
88        let url = format!("{}/channels", self.base_url);
89        let req = self
90            .client
91            .patch(&url)
92            .header("Accept", "*/*")
93            .bearer_auth(self.token.as_ref().unwrap())
94            .json(&request);
95
96        let response = crate::http::send_with_retry(self.client, req).await?;
97        let status = response.status();
98        if status.is_success() {
99            Ok(())
100        } else {
101            let body = response.text().await.unwrap_or_default();
102            Err(KickApiError::ApiError(format!(
103                "Failed to update channel: {} - {}",
104                status, body
105            )))
106        }
107    }
108
109    /// Get your own channels (the authenticated user's channels)
110    ///
111    /// Requires OAuth token with `channel:read` scope
112    ///
113    /// # Example
114    /// ```no_run
115    /// let my_channels = client.channels().get_mine().await?;
116    /// for channel in my_channels {
117    ///     println!("My channel: {}", channel.slug);
118    /// }
119    /// ```
120    pub async fn get_mine(&self) -> Result<Vec<Channel>> {
121        super::require_token(self.token)?;
122
123        let url = format!("{}/channels", self.base_url);
124        let request = self
125            .client
126            .get(&url)
127            .header("Accept", "*/*")
128            .bearer_auth(self.token.as_ref().unwrap());
129
130        let response = crate::http::send_with_retry(self.client, request).await?;
131        if response.status().is_success() {
132            let body = response.text().await?;
133
134            #[derive(serde::Deserialize)]
135            struct ChannelsResponse {
136                data: Vec<Channel>,
137            }
138
139            let resp: ChannelsResponse = serde_json::from_str(&body)
140                .map_err(|e| KickApiError::ApiError(format!("JSON parse error: {}", e)))?;
141
142            Ok(resp.data)
143        } else {
144            Err(KickApiError::ApiError(format!(
145                "Failed to get channels: {}",
146                response.status()
147            )))
148        }
149    }
150}