Use redirection instead of streaming

This might solve some issues with clients that don't get the file type
and size and don't know what to do?
Also, we're not longer involved in the download, yay! (For now.)
This commit is contained in:
Paul van Tilburg 2022-05-23 22:21:38 +02:00
parent 1ab89f87c4
commit a4546c1641
Signed by: paul
GPG Key ID: C6DE073EDA9EEC4D
2 changed files with 37 additions and 25 deletions

View File

@ -7,19 +7,16 @@
)]
#![deny(missing_docs)]
use std::process::Stdio;
use chrono::{DateTime, NaiveDateTime, Utc};
use reqwest::Url;
use rocket::fairing::AdHoc;
use rocket::response::stream::ReaderStream;
use rocket::response::Redirect;
use rocket::serde::{Deserialize, Serialize};
use rocket::{get, routes, Build, Responder, Rocket, State};
use rss::extension::itunes::ITunesItemExtensionBuilder;
use rss::{
CategoryBuilder, ChannelBuilder, EnclosureBuilder, GuidBuilder, ImageBuilder, ItemBuilder,
};
use tokio::process::{ChildStdout, Command};
pub(crate) mod mixcloud;
@ -127,27 +124,12 @@ async fn feed(username: &str, config: &State<Config>) -> Option<RssFeed> {
}
/// Retrieves a download using youtube-dl.
#[get("/?<backend>&<url>")]
pub(crate) async fn download(backend: &str, url: &str) -> Option<ReaderStream![ChildStdout]> {
let parsed_url = Url::parse(url).ok()?;
let mut cmd = Command::new("youtube-dl");
cmd.args(&["--output", "-"])
.arg(parsed_url.as_str())
.stdout(Stdio::piped());
println!("▶️ Streaming enclosure from {parsed_url} using youtube-dl...");
let mut child = cmd.spawn().ok()?;
let stdout = child.stdout.take()?;
tokio::spawn(async move {
let status = child
.wait()
.await
.expect("child process encounterd an error");
println!("✅ youtube-dl finished with {}", status);
});
Some(ReaderStream::one(stdout))
#[get("/?<backend>&<id>")]
pub(crate) async fn download(backend: &str, id: &str) -> Option<Redirect> {
match backend {
"mixcloud" => mixcloud::redirect_url(id).await.map(Redirect::to),
_ => None,
}
}
/// Sets up Rocket.

View File

@ -3,9 +3,12 @@
//! It uses the Mixcloud API to retrieve the feed (user) and items (cloudcasts)).
//! See also: <https://www.mixcloud.com/developers/>
use std::process::Stdio;
use chrono::{DateTime, Utc};
use reqwest::Url;
use rocket::serde::Deserialize;
use tokio::process::Command;
/// A Mixcloud user.
#[derive(Debug, Deserialize)]
@ -44,6 +47,9 @@ pub(crate) struct CloudcastData {
#[derive(Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
pub(crate) struct Cloudcast {
/// The key of the cloudcast.
pub(crate) key: String,
/// The name of the cloudcast.
pub(crate) name: String,
@ -80,6 +86,9 @@ pub(crate) struct Tag {
/// The base URL for the Mixcloud API.
const API_BASE_URL: &str = "https://api.mixcloud.com";
/// The base URL for downloading Mixcloud files.
const FILES_BASE_URL: &str = "https://www.mixcloud.com";
/// The default bitrate used by
const DEFAULT_BITRATE: u32 = 64 * 1024;
@ -127,3 +136,24 @@ pub(crate) async fn get_cloudcasts(username: &str) -> Option<Vec<Cloudcast>> {
Some(cloudcasts.data)
}
/// Retrieves the redirect URL for the provided Mixcloud cloudcast key.
pub(crate) async fn redirect_url(key: &str) -> Option<String> {
let mut cmd = Command::new("youtube-dl");
cmd.args(&["--format", "http"])
.arg("--get-url")
.arg(&format!("{FILES_BASE_URL}{key}"))
.stdout(Stdio::piped());
let output = cmd.output().await.ok()?;
if output.status.success() {
let direct_url = String::from_utf8_lossy(&output.stdout)
.trim_end()
.to_owned();
println!("🌍 Determined direct URL for {key}: {direct_url}...");
Some(direct_url)
} else {
None
}
}