Compare commits
No commits in common. "master" and "9c6b18af9368abbfbf0daf436010ded794dbf074" have entirely different histories.
master
...
9c6b18af93
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1463,7 +1463,7 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "titlebot"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "titlebot"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
authors = ["Yash Karandikar <nerdstep710@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
120
src/main.rs
120
src/main.rs
|
@ -1,27 +1,12 @@
|
|||
use anyhow::anyhow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use futures::prelude::*;
|
||||
use htmlescape::decode_html;
|
||||
use irc::client::prelude::*;
|
||||
use onig::Regex;
|
||||
use rspotify::{ClientCredsSpotify, Credentials};
|
||||
use rspotify::model::{Id, PlayableItem};
|
||||
use rspotify::prelude::BaseClient;
|
||||
use rspotify::{ClientCredsSpotify, Credentials};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! cloned {
|
||||
($i:ident => $e:expr) => {{
|
||||
let $i = $i.clone();
|
||||
$e
|
||||
}};
|
||||
(($($i:ident),+) => $e:expr) => {{
|
||||
$(
|
||||
let $i = $i.clone();
|
||||
)*
|
||||
|
||||
$e
|
||||
}}
|
||||
}
|
||||
|
||||
fn calculate_playtime(secs: u64) -> (u64, u64) {
|
||||
let mut dur_sec = secs;
|
||||
|
@ -30,11 +15,7 @@ fn calculate_playtime(secs: u64) -> (u64, u64) {
|
|||
(dur_min, dur_sec)
|
||||
}
|
||||
|
||||
async fn resolve_spotify(
|
||||
spotify: &mut ClientCredsSpotify,
|
||||
resource_type: &str,
|
||||
resource_id: &str,
|
||||
) -> anyhow::Result<String> {
|
||||
async fn resolve_spotify(spotify: &mut ClientCredsSpotify, resource_type: &str, resource_id: &str) -> anyhow::Result<String> {
|
||||
if spotify.token.as_ref().unwrap().is_expired() {
|
||||
spotify.request_token().await?;
|
||||
}
|
||||
|
@ -47,27 +28,15 @@ async fn resolve_spotify(
|
|||
}
|
||||
"artist" => {
|
||||
let artist = spotify.artist(Id::from_id(resource_id)?).await?;
|
||||
Ok(format!(
|
||||
"\x037[Spotify]\x03 Artist: \x039\"{}\" \x0311|\x03 Genres:\x039 {} \x0311|",
|
||||
artist.name,
|
||||
artist.genres.join(", ")
|
||||
))
|
||||
Ok(format!("\x037[Spotify]\x03 Artist: \x039\"{}\" \x0311|\x03 Genres:\x039 {} \x0311|", artist.name, artist.genres.join(", ")))
|
||||
}
|
||||
"album" => {
|
||||
let album = spotify.album(Id::from_id(resource_id)?).await?;
|
||||
let playtime = calculate_playtime(
|
||||
album
|
||||
.tracks
|
||||
.items
|
||||
.iter()
|
||||
.fold(0, |acc, x| acc + x.duration.as_secs()),
|
||||
);
|
||||
let playtime = calculate_playtime(album.tracks.items.iter().fold(0, |acc, x| acc + x.duration.as_secs()));
|
||||
Ok(format!("\x037[Spotify]\x03 Album: \x039\"{}\" \x0311|\x03 Tracks:\x0315 {} \x0311|\x03 Release date:\x039 {} \x0311|\x03 Length:\x0315 {}:{:02} \x0311|", album.name, album.tracks.total, album.release_date, playtime.0, playtime.1))
|
||||
}
|
||||
"playlist" => {
|
||||
let playlist = spotify
|
||||
.playlist(Id::from_id(resource_id)?, None, None)
|
||||
.await?;
|
||||
let playlist = spotify.playlist(Id::from_id(resource_id)?, None, None).await?;
|
||||
let mut tracks = 0;
|
||||
let playtime = calculate_playtime(playlist.tracks.items.iter().fold(0, |acc, x| {
|
||||
x.track.as_ref().map_or(acc, |item| match item {
|
||||
|
@ -83,7 +52,7 @@ async fn resolve_spotify(
|
|||
}));
|
||||
Ok(format!("\x037[Spotify]\x03 Playlist: \x039\"{}\" \x0311|\x03 Tracks/Episodes:\x0315 {} \x0311|\x03 Length:\x0315 {}:{:02} \x0311|\x03 Description: \x039\"{}\" \x0311|", playlist.name, tracks, playtime.0, playtime.1, playlist.description.unwrap_or_else(|| "<empty>".into())))
|
||||
}
|
||||
_ => Ok("\x037[Spotify]\x03 Error: Invalid resource type".into()),
|
||||
_ => Ok("\x037[Spotify]\x03 Error: Invalid resource type".into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,57 +66,57 @@ async fn main() -> anyhow::Result<()> {
|
|||
}, config.nickname.as_ref().unwrap(), config.channels.join(", "), config.umodes.as_ref().unwrap());
|
||||
let mut spotify = ClientCredsSpotify::new(Credentials::from_env().unwrap());
|
||||
spotify.request_token().await.unwrap();
|
||||
let mut client = Arc::new(Client::from_config(config).await?);
|
||||
let mut client = Client::from_config(config).await?;
|
||||
client.identify()?;
|
||||
let vlog = match std::env::var("TITLEBOT_VERBOSE_LOG") {
|
||||
Ok(o) => o.eq_ignore_ascii_case("true"),
|
||||
Err(_) => false,
|
||||
Err(_) => false
|
||||
};
|
||||
if vlog {
|
||||
println!("Verbose logging enabled.");
|
||||
}
|
||||
println!("Connected!");
|
||||
|
||||
let mut stream = Arc::get_mut(&mut client).unwrap().stream()?;
|
||||
let mut stream = client.stream()?;
|
||||
|
||||
let url_regex = Regex::new(r"https?://\w+\.\w+[/\S+]*").unwrap();
|
||||
let title_regex = Arc::new(Regex::new(r"(?<=<title>)(.*)(?=</title>)").unwrap());
|
||||
let title_regex = Regex::new(r"(?<=<title>)(.*)(?=</title>)").unwrap();
|
||||
let spotify_regex = Regex::new(r"(?:https?|spotify):(?://open\.spotify\.com/)?(track|artist|album|playlist)[/:]([a-zA-Z0-9]*)").unwrap();
|
||||
|
||||
let hclient = reqwest::Client::new();
|
||||
let mut cache: HashMap<String, String> = HashMap::new();
|
||||
|
||||
while let Some(message) = stream.next().await.transpose()? {
|
||||
if vlog {
|
||||
print!("[IRC] {}", message)
|
||||
}
|
||||
if vlog { print!("[IRC] {}", message) }
|
||||
|
||||
if let Command::PRIVMSG(channel, message) = message.command {
|
||||
if let Some(m) = spotify_regex.captures(&message) {
|
||||
let tp_group = m.pos(1).unwrap();
|
||||
let id_group = m.pos(2).unwrap();
|
||||
match resolve_spotify(
|
||||
&mut spotify,
|
||||
&message[tp_group.0..tp_group.1],
|
||||
&message[id_group.0..id_group.1],
|
||||
)
|
||||
.await
|
||||
{
|
||||
match resolve_spotify(&mut spotify, &message[tp_group.0..tp_group.1], &message[id_group.0..id_group.1]).await {
|
||||
Ok(o) => client.send_privmsg(&channel, o)?,
|
||||
Err(e) => {
|
||||
client.send_privmsg(
|
||||
&channel,
|
||||
"\x037[Spotify]\x03 An error has occurred.",
|
||||
)?;
|
||||
client.send_privmsg(&channel, "\x037[Spotify]\x03 An error has occurred.")?;
|
||||
println!("[Spotify] Error! {}", e);
|
||||
}
|
||||
}
|
||||
} else if let Some(m) = url_regex.find(&message) {
|
||||
let url = message[m.0..m.1].to_string();
|
||||
tokio::spawn(cloned!((client, hclient, title_regex, url) => async move {
|
||||
if let Ok(title) = resolve_url(&hclient, &url, &title_regex).await {
|
||||
client.send_privmsg(&channel, title).unwrap();
|
||||
let url = &message[m.0..m.1];
|
||||
if let Some(entry) = cache.get(&url.to_string()) {
|
||||
client.send_privmsg(&channel, format!("\x039[Title]\x0311 {}", entry))?;
|
||||
continue;
|
||||
}
|
||||
match reqwest::get(url).await {
|
||||
Ok(o) => {
|
||||
let body = o.text().await?;
|
||||
if let Some(tm) = title_regex.find(&body) {
|
||||
let title_match = &body[tm.0..tm.1];
|
||||
let result = decode_html(title_match).unwrap_or_else(|_| title_match.to_string());
|
||||
client.send_privmsg(&channel, format!("\x039[Title]\x0311 {}", result))?;
|
||||
cache.insert(url.to_string(), result.to_string());
|
||||
}
|
||||
}
|
||||
}));
|
||||
Err(e) => println!("[Title] Error! {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,28 +125,3 @@ async fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn resolve_url(
|
||||
hclient: &reqwest::Client,
|
||||
url: &str,
|
||||
title_regex: &Regex,
|
||||
) -> anyhow::Result<String> {
|
||||
let o = hclient.head(url).send().await?;
|
||||
let headers = o.headers();
|
||||
let ctype = headers
|
||||
.get("Content-Type")
|
||||
.ok_or(anyhow!("Content-Type not set"))?;
|
||||
let ctype = ctype.to_str()?;
|
||||
if !ctype.starts_with("text/html") {
|
||||
return Err(anyhow!("Incorrect Content-Type"));
|
||||
}
|
||||
let o = hclient.get(url).send().await?;
|
||||
let body = o.text().await?;
|
||||
if let Some(tm) = title_regex.find(&body) {
|
||||
let title_match = &body[tm.0..tm.1];
|
||||
let result = decode_html(title_match).unwrap_or_else(|_| title_match.to_string());
|
||||
return Ok(format!("\x039[Title]\x0311 {}", result));
|
||||
} else {
|
||||
return Ok(String::new());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue