Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 6 additions & 28 deletions src/twitch/api/chat_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use color_eyre::{Result, eyre::ContextCompat};
use reqwest::Client;
use serde::{Deserialize, Serialize};

use super::TWITCH_API_BASE_URL;
use super::{ModeratorQuery, ResponseList, TWITCH_API_BASE_URL};

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TwitchChatSettingsResponse {
Expand Down Expand Up @@ -44,11 +44,6 @@ impl TwitchChatSettingsResponse {
}
}

#[derive(Deserialize, Serialize, Debug, Clone)]
struct TwitchChatSettingsResponseList {
data: Vec<TwitchChatSettingsResponse>,
}

/// Get the settings of the given broadcaster's chat
///
/// <https://dev.twitch.tv/docs/api/reference/#get-chat-settings>
Expand All @@ -66,7 +61,7 @@ pub async fn get_chat_settings(
.send()
.await?
.error_for_status()?
.json::<TwitchChatSettingsResponseList>()
.json::<ResponseList<TwitchChatSettingsResponse>>()
.await?
.data
.first()
Expand All @@ -76,19 +71,6 @@ pub async fn get_chat_settings(
Ok(response_data)
}

pub struct UpdateTwitchChatSettingsQuery {
broadcaster_id: String,
moderator_id: String,
}
impl UpdateTwitchChatSettingsQuery {
pub const fn new(broadcaster_id: String, moderator_id: String) -> Self {
Self {
broadcaster_id,
moderator_id,
}
}
}

#[derive(Deserialize, Serialize, Debug, Clone, Default)]
pub struct UpdateTwitchChatSettingsPayload {
emote_mode: Option<bool>,
Expand Down Expand Up @@ -143,27 +125,23 @@ impl UpdateTwitchChatSettingsPayload {
/// <https://dev.twitch.tv/docs/api/reference/#update-chat-settings>
pub async fn update_chat_settings(
client: &Client,
query: UpdateTwitchChatSettingsQuery,
query: ModeratorQuery,
payload: UpdateTwitchChatSettingsPayload,
) -> Result<TwitchChatSettingsResponse> {
let settings_query = &[
("broadcaster_id", query.broadcaster_id),
("moderator_id", query.moderator_id),
];
let url = format!("{TWITCH_API_BASE_URL}/chat/settings");

let response_data = client
.patch(url)
.query(settings_query)
.query(&query)
.json(&payload)
.send()
.await?
.error_for_status()?
.json::<TwitchChatSettingsResponseList>()
.json::<ResponseList<TwitchChatSettingsResponse>>()
.await?
.data
.first()
.context("Failed to get chat settings response")?
.context("Failed to get update chat settings response")?
.clone();
Ok(response_data)
}
54 changes: 54 additions & 0 deletions src/twitch/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,58 @@ pub mod subscriptions;
pub mod timeouts;
pub mod vips;

use color_eyre::Result;
use reqwest::{Client, Method};
use serde::{Deserialize, Serialize};

pub static TWITCH_API_BASE_URL: &str = "https://api.twitch.tv/helix";

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct BroadcasterQuery {
broadcaster_id: String,
user_id: String,
}

impl BroadcasterQuery {
pub const fn new(broadcaster_id: String, user_id: String) -> Self {
Self {
broadcaster_id,
user_id,
}
}
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ModeratorQuery {
broadcaster_id: String,
moderator_id: String,
}

impl ModeratorQuery {
pub const fn new(broadcaster_id: String, moderator_id: String) -> Self {
Self {
broadcaster_id,
moderator_id,
}
}
}

pub async fn request_bodiless<T: Serialize>(
client: &Client,
method: Method,
url: String,
query: T,
) -> Result<()> {
client
.request(method, url)
.query(&query)
.send()
.await?
.error_for_status()?;
Ok(())
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ResponseList<T> {
data: Vec<T>,
}
54 changes: 6 additions & 48 deletions src/twitch/api/mods.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,20 @@
use color_eyre::Result;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use reqwest::{Client, Method};

use super::TWITCH_API_BASE_URL;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ModQuery {
broadcaster_id: String,
user_id: String,
}

impl ModQuery {
pub const fn new(broadcaster_id: String, user_id: String) -> Self {
Self {
broadcaster_id,
user_id,
}
}
}
use super::{BroadcasterQuery, TWITCH_API_BASE_URL, request_bodiless};

/// Adds a moderator to the broadcaster's chat room
///
/// <https://dev.twitch.tv/docs/api/reference/#add-channel-moderator>
pub async fn mod_twitch_user(client: &Client, query: ModQuery) -> Result<()> {
pub async fn mod_twitch_user(client: &Client, query: BroadcasterQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/moderation/moderators");

let mod_query = &[
("broadcaster_id", query.broadcaster_id),
("user_id", query.user_id),
];

client
.post(url)
.query(mod_query)
.send()
.await?
.error_for_status()?;

Ok(())
request_bodiless(client, Method::POST, url, query).await
}

/// Removes a moderator from the broadcaster's chat room
///
/// <https://dev.twitch.tv/docs/api/reference/#remove-channel-moderator>
pub async fn unmod_twitch_user(client: &Client, query: ModQuery) -> Result<()> {
pub async fn unmod_twitch_user(client: &Client, query: BroadcasterQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/moderation/moderators");

let unmod_query = &[
("broadcaster_id", query.broadcaster_id),
("user_id", query.user_id),
];

client
.delete(url)
.query(unmod_query)
.send()
.await?
.error_for_status()?;

Ok(())
request_bodiless(client, Method::DELETE, url, query).await
}
7 changes: 1 addition & 6 deletions src/twitch/api/raids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,9 @@ struct TwitchRaidResponseList {
pub async fn raid_twitch_user(client: &Client, query: RaidQuery) -> Result<TwitchRaidResponse> {
let url = format!("{TWITCH_API_BASE_URL}/raids");

let raid_query = &[
("from_broadcaster_id", query.from_broadcaster_id),
("to_broadcaster_id", query.to_broadcaster_id),
];

let response_data = client
.post(url)
.query(raid_query)
.query(&query)
.send()
.await?
.error_for_status()?
Expand Down
8 changes: 1 addition & 7 deletions src/twitch/api/shoutouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,9 @@ impl ShoutoutQuery {
pub async fn shoutout_twitch_user(client: &Client, query: ShoutoutQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/chat/shoutouts");

let mod_query = &[
("from_broadcaster_id", query.from_broadcaster_id),
("to_broadcaster_id", query.to_broadcaster_id),
("moderator_id", query.moderator_id),
];

client
.post(url)
.query(mod_query)
.query(&query)
.send()
.await?
.error_for_status()?;
Expand Down
44 changes: 7 additions & 37 deletions src/twitch/api/timeouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,8 @@ use color_eyre::{Result, eyre::ContextCompat};
use reqwest::Client;
use serde::{Deserialize, Serialize};

use super::TWITCH_API_BASE_URL;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TimeoutQuery {
broadcaster_id: String,
moderator_id: String,
}

impl TimeoutQuery {
pub const fn new(broadcaster_id: String, moderator_id: String) -> Self {
Self {
broadcaster_id,
moderator_id,
}
}
}
use super::{ModeratorQuery, TWITCH_API_BASE_URL};
use crate::twitch::api::ResponseList;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TimeoutInnerPayload {
Expand Down Expand Up @@ -61,40 +47,29 @@ pub struct TwitchTimeoutResponse {
end_time: Option<DateTime<Utc>>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
struct TwitchTimeoutResponseList {
data: Vec<TwitchTimeoutResponse>,
}

/// Bans a user from participating in the specified broadcaster’s chat room or puts them in a timeout.
///
/// <https://dev.twitch.tv/docs/api/reference/#ban-user>
pub async fn timeout_twitch_user(
client: &Client,
query: TimeoutQuery,
query: ModeratorQuery,
payload: TimeoutPayload,
) -> Result<TwitchTimeoutResponse> {
let url = format!("{TWITCH_API_BASE_URL}/moderation/bans");

let timeout_query = &[
("broadcaster_id", query.broadcaster_id),
("moderator_id", query.moderator_id),
];

let response_data = client
.post(url)
.query(&timeout_query)
.query(&query)
.json(&payload)
.send()
.await?
.error_for_status()?
.json::<TwitchTimeoutResponseList>()
.json::<ResponseList<TwitchTimeoutResponse>>()
.await?
.data
.first()
.context("Could not get Twitch timeout response")?
.context("Failed to get timeout response data")?
.clone();

Ok(response_data)
}

Expand All @@ -120,14 +95,9 @@ impl UnbanQuery {
/// <https://dev.twitch.tv/docs/api/reference/#unban-user>
pub async fn unban_twitch_user(client: &Client, query: UnbanQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/moderation/bans");
let unban_query = &[
("broadcaster_id", query.broadcaster_id),
("moderator_id", query.moderator_id),
("user_id", query.user_id),
];
client
.delete(&url)
.query(unban_query)
.query(&query)
.send()
.await?
.error_for_status()?;
Expand Down
54 changes: 6 additions & 48 deletions src/twitch/api/vips.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,20 @@
use color_eyre::Result;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use reqwest::{Client, Method};

use super::TWITCH_API_BASE_URL;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct VipQuery {
broadcaster_id: String,
user_id: String,
}

impl VipQuery {
pub const fn new(broadcaster_id: String, user_id: String) -> Self {
Self {
broadcaster_id,
user_id,
}
}
}
use super::{BroadcasterQuery, TWITCH_API_BASE_URL, request_bodiless};

/// Adds the specified user as a VIP in the broadcaster's channel
///
/// <https://dev.twitch.tv/docs/api/reference/#add-channel-vip>
pub async fn vip_twitch_user(client: &Client, query: VipQuery) -> Result<()> {
pub async fn vip_twitch_user(client: &Client, query: BroadcasterQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/channels/vips");

let vip_query = &[
("user_id", query.user_id),
("broadcaster_id", query.broadcaster_id),
];

client
.post(url)
.query(vip_query)
.send()
.await?
.error_for_status()?;

Ok(())
request_bodiless(client, Method::POST, url, query).await
}

/// Removes the specified user as a VIP in the broadcaster's channel
///
/// <https://dev.twitch.tv/docs/api/reference/#remove-channel-vip>
pub async fn unvip_twitch_user(client: &Client, query: VipQuery) -> Result<()> {
pub async fn unvip_twitch_user(client: &Client, query: BroadcasterQuery) -> Result<()> {
let url = format!("{TWITCH_API_BASE_URL}/channels/vips");

let unvip_query = &[
("user_id", query.user_id),
("broadcaster_id", query.broadcaster_id),
];

client
.delete(url)
.query(unvip_query)
.send()
.await?
.error_for_status()?;

Ok(())
request_bodiless(client, Method::DELETE, url, query).await
}
Loading