Implement caching (closes: #3)

* Enable the `async` feature for the `cached` crate
* Make the types that we cache implement `Clone`
* Rename the argument of mixcloud::redirect_url` because of this issue:
  https://github.com/jaemk/cached/issues/114
This commit is contained in:
Paul van Tilburg 2022-05-26 21:20:10 +02:00
parent b4c0188fba
commit 451c07a09e
Signed by: paul
GPG Key ID: C6DE073EDA9EEC4D
2 changed files with 28 additions and 9 deletions

View File

@ -8,7 +8,7 @@ readme = "README.md"
license = "MIT"
[dependencies]
cached = "0.34.0"
cached = { version = "0.34.0", features = ["async"] }
chrono = { version = "0.4.19", features = ["serde"] }
reqwest = { version = "0.11.10", features = ["json"] }
rocket = { version = "0.5.0-rc.2", features = ["json"] }

View File

@ -3,6 +3,7 @@
//! It uses the Mixcloud API to retrieve the feed (user) and items (cloudcasts)).
//! See also: <https://www.mixcloud.com/developers/>
use cached::proc_macro::cached;
use chrono::{DateTime, Utc};
use reqwest::Url;
use rocket::serde::Deserialize;
@ -11,7 +12,7 @@ use youtube_dl::{YoutubeDl, YoutubeDlOutput};
use super::{Error, Result};
/// A Mixcloud user.
#[derive(Debug, Deserialize)]
#[derive(Clone, Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
pub(crate) struct User {
/// The name of the user.
@ -28,7 +29,7 @@ pub(crate) struct User {
}
/// A collection of different sizes/variants of a picture.
#[derive(Debug, Deserialize)]
#[derive(Clone, Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
pub(crate) struct Pictures {
/// The large picture of the user.
@ -44,7 +45,7 @@ pub(crate) struct CloudcastData {
}
/// A Mixcloud cloudcast.
#[derive(Debug, Deserialize)]
#[derive(Clone, Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
pub(crate) struct Cloudcast {
/// The key of the cloudcast.
@ -73,7 +74,7 @@ pub(crate) struct Cloudcast {
}
/// A Mixcloud cloudcast tag.
#[derive(Debug, Deserialize)]
#[derive(Clone, Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
pub(crate) struct Tag {
/// The name of the tag.
@ -108,6 +109,12 @@ pub(crate) fn estimated_file_size(duration: u32) -> u32 {
}
/// Retrieves the user data using the Mixcloud API.
#[cached(
key = "String",
convert = r#"{ username.to_owned() }"#,
time = 3600,
result = true
)]
pub(crate) async fn get_user(username: &str) -> Result<User> {
let mut url = Url::parse(API_BASE_URL).expect("URL can always be parsed");
url.set_path(username);
@ -120,6 +127,12 @@ pub(crate) async fn get_user(username: &str) -> Result<User> {
}
/// Retrieves the cloudcasts of the user using the Mixcloud API.
#[cached(
key = "String",
convert = r#"{ username.to_owned() }"#,
time = 3600,
result = true
)]
pub(crate) async fn get_cloudcasts(username: &str) -> Result<Vec<Cloudcast>> {
let mut url = Url::parse(API_BASE_URL).expect("URL can always be parsed");
url.set_path(&format!("{username}/cloudcasts/"));
@ -132,11 +145,17 @@ pub(crate) async fn get_cloudcasts(username: &str) -> Result<Vec<Cloudcast>> {
}
/// Retrieves the redirect URL for the provided Mixcloud cloudcast key.
pub(crate) async fn redirect_url(key: &str) -> Result<String> {
let url = format!("{FILES_BASE_URL}{key}");
#[cached(
key = "String",
convert = r#"{ download_key.to_owned() }"#,
time = 3600,
result = true
)]
pub(crate) async fn redirect_url(download_key: &str) -> Result<String> {
let url = format!("{FILES_BASE_URL}{download_key}");
println!("🌍 Determining direct URL for {key}...");
let output = YoutubeDl::new(&url).run_async().await?;
println!("🌍 Determining direct URL for {download_key}...");
let output = YoutubeDl::new(url).run_async().await?;
if let YoutubeDlOutput::SingleVideo(yt_item) = output {
yt_item.url.ok_or(Error::NoRedirectUrlFound)