Re-organized providers and added a few
CI / check (push) Failing after 1m10s
CI / docker (push) Has been skipped

This commit is contained in:
Connor Johnstone
2026-03-20 14:52:16 -04:00
parent d3f4dc33d5
commit 4ec47252d9
19 changed files with 1302 additions and 6 deletions
+61
View File
@@ -0,0 +1,61 @@
use std::time::Duration;
use tokio::sync::Mutex;
use tokio::time::Instant;
/// A simple rate limiter that enforces a minimum interval between requests.
pub struct RateLimiter {
last_request: Mutex<Instant>,
interval: Duration,
}
impl RateLimiter {
pub fn new(interval: Duration) -> Self {
Self {
last_request: Mutex::new(Instant::now() - interval),
interval,
}
}
/// Wait if needed so we don't exceed the rate limit.
pub async fn wait(&self) {
let mut last = self.last_request.lock().await;
let elapsed = last.elapsed();
if elapsed < self.interval {
tokio::time::sleep(self.interval - elapsed).await;
}
*last = Instant::now();
}
}
/// Build a reqwest client with a custom user agent and timeout.
pub fn build_client(user_agent: &str, timeout_secs: u64) -> reqwest::Result<reqwest::Client> {
reqwest::Client::builder()
.user_agent(user_agent)
.timeout(Duration::from_secs(timeout_secs))
.build()
}
/// Simple URL-encode for query parameters.
pub fn urlencoded(s: &str) -> String {
s.replace(' ', "+")
.replace('&', "%26")
.replace('=', "%3D")
.replace('#', "%23")
}
/// Escape special characters for MusicBrainz Lucene query syntax.
pub fn escape_lucene(s: &str) -> String {
let special = [
'+', '-', '&', '|', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '\\',
'/',
];
let mut result = String::with_capacity(s.len());
for c in s.chars() {
if special.contains(&c) {
result.push('\\');
}
result.push(c);
}
result
}