Compare commits

..

6 Commits

Author SHA1 Message Date
Paul van Tilburg d93faf022a
Use a MIME DB to determine the download URL file extensions
* Also apply it to the default MIME type for Mixcloud posts
* Add a dependency on the `mime_db` crate
2022-08-15 21:08:08 +02:00
Paul van Tilburg b3d6839759
Add first version of the YouTube back-end 2022-08-15 21:08:08 +02:00
Paul van Tilburg fa8fc40b58
Add missing trait derives on back-end types 2022-08-15 21:07:53 +02:00
Paul van Tilburg 101df7d486
Add missing/fix cache-related comments 2022-08-15 20:24:13 +02:00
Paul van Tilburg 76f1e01657
Make channel/item image optional; change item length type
This allows more back-ends to be compatible.
2022-08-15 20:22:15 +02:00
Paul van Tilburg 49e0e47ba2
Introduce enum and enum dispatching for backends
This way handlers don't need to do case matching on backend ID strings
anymore.

* Rename `backend` to `backend_id` where we have a backend ID
* Add `get` function and `Backends` enum to the `backend` module
* Add a depend on the `enum_dispatch` crate
2022-08-15 20:21:42 +02:00
6 changed files with 42 additions and 19 deletions

12
Cargo.lock generated
View File

@ -1145,6 +1145,17 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mime-db"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7c816ec30c41f873e1eea969aa2261d78756629e468a427244ff8658b75e7d"
dependencies = [
"reqwest",
"serde",
"tokio",
]
[[package]]
name = "mio"
version = "0.6.23"
@ -1547,6 +1558,7 @@ dependencies = [
"cached",
"chrono",
"enum_dispatch",
"mime-db",
"reqwest",
"rocket",
"rocket_dyn_templates",

View File

@ -12,6 +12,7 @@ async-trait = "0.1.57"
cached = { version = "0.38.0", features = ["async"] }
chrono = { version = "0.4.19", features = ["serde"] }
enum_dispatch = "0.3.8"
mime-db = "1.6.0"
reqwest = { version = "0.11.10", features = ["json"] }
rocket = { version = "0.5.0-rc.2", features = ["json"] }
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }

View File

@ -18,18 +18,21 @@ pub(crate) mod mixcloud;
pub(crate) mod youtube;
/// Retrieves the back-end for the provided ID (if supported).
pub(crate) fn get(backend_id: &str) -> Result<Backends> {
match backend_id {
pub(crate) fn get(backend: &str) -> Result<Backends> {
match backend {
"mixcloud" => Ok(Backends::Mixcloud(mixcloud::backend())),
"youtube" => Ok(Backends::YouTube(youtube::backend())),
_ => Err(Error::UnsupportedBackend(backend_id.to_string())),
_ => Err(Error::UnsupportedBackend(backend.to_string())),
}
}
/// The support back-ends.
/// The supported back-ends.
#[enum_dispatch(Backend)]
pub(crate) enum Backends {
/// Mixcloud (<https://www.mixcloud.com>)
Mixcloud(mixcloud::Backend),
/// YouTube (<https://www.youtube.com>)
YouTube(youtube::Backend),
}
@ -48,6 +51,7 @@ pub(crate) trait Backend {
}
/// The metadata of a collection of content items.
#[derive(Clone, Debug)]
pub(crate) struct Channel {
/// The title of the channel.
pub(crate) title: String,
@ -74,6 +78,7 @@ pub(crate) struct Channel {
}
/// A content item belonging to a channel.
#[derive(Clone, Debug)]
pub(crate) struct Item {
/// The title of the item.
pub(crate) title: String,
@ -109,6 +114,7 @@ pub(crate) struct Item {
}
/// The enclosed media content of an item.
#[derive(Clone, Debug)]
pub(crate) struct Enclosure {
/// The path of the download file associated with the item enclosure.
///

View File

@ -199,7 +199,8 @@ impl From<UserWithCloudcasts> for Channel {
impl From<Cloudcast> for Item {
fn from(cloudcast: Cloudcast) -> Self {
let mut file = PathBuf::from(cloudcast.key.trim_end_matches('/'));
file.set_extension("m4a"); // FIXME: Don't hardcoded the extension!
let extension = mime_db::extension(DEFAULT_FILE_TYPE).expect("MIME type has extension");
file.set_extension(extension);
// FIXME: Don't hardcode the description!
let description = Some(format!("Taken from Mixcloud: {0}", cloudcast.url));

View File

@ -165,19 +165,25 @@ impl From<YouTubeVideoWithStream> for Item {
YouTubeVideoWithStream {
video,
stream,
content_length,
content_length: length,
}: YouTubeVideoWithStream,
) -> Self {
let id = video.id().to_string();
let mut link = Url::parse(VIDEO_BASE_URL).expect("valid URL");
let description = Some(format!("Taken from YouTube: {0}", link));
link.query_pairs_mut().append_pair("v", &id);
let mime_type = stream.mime_type().to_string();
// Ignore everything from MIME type parameter seperator on for extension look-up.
let mime_sep = mime_type.find(';').unwrap_or(mime_type.len());
let extension = mime_db::extension(&mime_type[..mime_sep]).unwrap_or_default();
let file = PathBuf::from(&id).with_extension(extension);
let enclosure = Enclosure {
file: PathBuf::from(&format!("{id}.webm")), // FIXME: Don't hardcode the extension!
mime_type: stream.mime_type().to_string(),
length: content_length,
file,
mime_type,
length,
};
let mut link = Url::parse(VIDEO_BASE_URL).expect("valid URL");
link.query_pairs_mut().append_pair("v", &id);
let description = Some(format!("Taken from YouTube: {0}", link));
let duration = Some(video.length().as_secs() as u32);
let image = video
.thumbnails()
@ -204,12 +210,11 @@ impl From<YouTubeVideoWithStream> for Item {
///
/// If the result is [`Ok`], the playlist will be cached for 24 hours for the given playlist ID.
#[cached(
key = "String",
convert = r#"{ playlist_id.to_owned() }"#,
key = "(String, Option<usize>)",
convert = r#"{ (playlist_id.to_owned(), item_limit) }"#,
time = 86400,
result = true
)]
// FIXME: Caching disregards the item limit!
async fn fetch_playlist_videos(
client: &Client,
playlist_id: &str,
@ -240,12 +245,11 @@ async fn fetch_playlist_videos(
/// Fetches the YouTube channel videos for the given ID.
#[cached(
key = "String",
convert = r#"{ channel_id.to_owned() }"#,
key = "(String, Option<usize>)",
convert = r#"{ (channel_id.to_owned(), item_limit) }"#,
time = 86400,
result = true
)]
// FIXME: Caching disregards the item limit!
async fn fetch_channel_videos(
client: &Client,
channel_id: &str,

View File

@ -117,7 +117,6 @@ async fn get_feed(
limit: Option<usize>,
config: &State<Config>,
) -> Result<RssFeed> {
dbg!(limit);
let backend = backends::get(backend_id)?;
let channel = backend.channel(channel_id, limit).await?;
let feed = feed::construct(backend_id, config, channel);