143 lines
4.7 KiB
Rust
143 lines
4.7 KiB
Rust
use poise::CreateReply;
|
|
use radiobrowser::{ApiStation, StationSearchBuilder};
|
|
use regex::Regex;
|
|
use serenity::all::{CreateActionRow, CreateButton, CreateEmbed, CreateEmbedFooter, CreateInteractionResponse, CreateInteractionResponseMessage};
|
|
|
|
use crate::{commands::voice_types::NumberOfEntries, types::Context};
|
|
|
|
pub async fn paginate_search_stations(
|
|
ctx: &Context<'_>,
|
|
search_builder: &StationSearchBuilder,
|
|
limit: NumberOfEntries
|
|
) -> Result<(), serenity::Error> {
|
|
// Define some unique identifiers for the navigation buttons
|
|
let ctx_id = ctx.id();
|
|
let prev_button_id = format!("{}prev", ctx_id);
|
|
let next_button_id = format!("{}next", ctx_id);
|
|
|
|
let search_builder = search_builder;
|
|
|
|
let Ok(stations) = search_builder.clone().send().await else {
|
|
ctx.reply("Something went wrong, try searching again").await?;
|
|
return Ok(())
|
|
};
|
|
|
|
let mut page = 0;
|
|
|
|
let embed = create_station_list_embed(&stations, page);
|
|
|
|
// Send the embed with the first page as content
|
|
let reply = {
|
|
let components = CreateActionRow::Buttons(vec![
|
|
CreateButton::new(&prev_button_id).emoji('◀'),
|
|
CreateButton::new(&next_button_id).emoji('▶'),
|
|
]);
|
|
|
|
CreateReply::default()
|
|
.embed(embed)
|
|
.components(vec![components])
|
|
};
|
|
|
|
ctx.send(reply).await?;
|
|
|
|
// Loop through incoming interactions with the navigation buttons
|
|
let mut offset = 0;
|
|
let limit_int = limit as u32;
|
|
while let Some(press) = serenity::collector::ComponentInteractionCollector::new(ctx)
|
|
// We defined our button IDs to start with `ctx_id`. If they don't, some other command's
|
|
// button was pressed
|
|
.filter(move |press| press.data.custom_id.starts_with(&ctx_id.to_string()))
|
|
// Timeout when no navigation button has been pressed for 24 hours
|
|
.timeout(std::time::Duration::from_secs(3600 * 24))
|
|
.await
|
|
{
|
|
// Depending on which button was pressed, go to next or previous page
|
|
if press.data.custom_id == next_button_id {
|
|
offset += limit_int;
|
|
page += 1;
|
|
} else if press.data.custom_id == prev_button_id {
|
|
offset = if offset < limit_int { offset } else { offset - limit_int };
|
|
page = if page == 0 { 0 } else { page - 1 };
|
|
} else {
|
|
// This is an unrelated button interaction
|
|
continue;
|
|
}
|
|
|
|
let Ok(mut stations) = search_builder.clone().offset(offset.to_string()).send().await else {
|
|
ctx.reply("Something went wrong, try searching again").await?;
|
|
return Ok(())
|
|
};
|
|
|
|
if stations.is_empty() {
|
|
offset = 0;
|
|
page = 0;
|
|
|
|
let Ok(new_stations) = search_builder.clone().offset(offset.to_string()).send().await else {
|
|
ctx.reply("Something went wrong, try searching again").await?;
|
|
return Ok(())
|
|
};
|
|
stations = new_stations;
|
|
}
|
|
|
|
let embed = create_station_list_embed(&stations, page);
|
|
|
|
// Update the message with the new page contents
|
|
press
|
|
.create_response(
|
|
ctx.serenity_context(),
|
|
CreateInteractionResponse::UpdateMessage(
|
|
CreateInteractionResponseMessage::new()
|
|
.embed(embed),
|
|
),
|
|
)
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn create_station_list_embed(stations: &Vec<ApiStation>, page: u32) -> CreateEmbed {
|
|
let result = CreateEmbed::new()
|
|
.fields(
|
|
stations.iter().map(|station| {
|
|
(
|
|
station.name.clone(),
|
|
format!("Country: {} Stream: {}",
|
|
station.country, station.url),
|
|
false
|
|
)
|
|
})
|
|
)
|
|
.footer(CreateEmbedFooter::new(format!("Page: {}", page + 1)));
|
|
|
|
result
|
|
}
|
|
|
|
pub enum LinkString {
|
|
Link,
|
|
String
|
|
}
|
|
|
|
pub fn link_or_string(haystack: &str) -> LinkString {
|
|
let Ok(re) = Regex::new(r"^https?://([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$") else {
|
|
panic!("Wrong regex expression!");
|
|
};
|
|
|
|
return if re.is_match(haystack) { LinkString::Link } else { LinkString::String }
|
|
}
|
|
|
|
pub fn parse_radio_autocomplete(haystack: &str) -> Option<(String, String, String)> {
|
|
let Ok(re) = Regex::new(r"^Name: (.*) Country: (.*) Language: (.*)") else {
|
|
panic!("Wrong regex expression!");
|
|
};
|
|
|
|
let Some(captures) = re.captures(haystack) else {
|
|
return None
|
|
};
|
|
|
|
return Some((
|
|
String::from(&captures[1]),
|
|
String::from(&captures[2]),
|
|
String::from(&captures[3])
|
|
))
|
|
}
|