Skip to content

Commit

Permalink
Add a playlist to torrent
Browse files Browse the repository at this point in the history
  • Loading branch information
izderadicka committed Aug 4, 2024
1 parent 95f958e commit 510c2ee
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
43 changes: 42 additions & 1 deletion crates/librqbit/src/http_api.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Context;
use axum::body::Bytes;
use axum::extract::{Path, Query, State};
use axum::extract::{Path, Query, Request, State};
use axum::response::{IntoResponse, Redirect};
use axum::routing::{get, post};
use futures::future::BoxFuture;
Expand All @@ -26,6 +26,7 @@ use crate::torrent_state::peer::stats::snapshot::PeerStatsFilter;
type ApiState = Api;

use crate::api::Result;
use crate::ApiError;

/// An HTTP server for the API.
pub struct HttpApi {
Expand Down Expand Up @@ -128,6 +129,45 @@ impl HttpApi {
state.api_torrent_details(idx).map(axum::Json)
}

async fn torrent_playlist(
State(state): State<ApiState>,
headers: HeaderMap,
Path(idx): Path<usize>,
) -> Result<impl IntoResponse> {
let host = headers
.get("host")
.ok_or_else(|| {
ApiError::new_from_text(StatusCode::BAD_REQUEST, "Missing host header")
})?
.to_str()
.context("hostname is not string")?;

let playlist_items = state
.api_torrent_details(idx)?
.files
.into_iter()
.enumerate()
.filter_map(|(file_idx, f)| {
let file_name = f.name;
let is_playable = mime_guess::from_path(&file_name)
.first()
.map(|mime| {
mime.type_() == mime_guess::mime::VIDEO
|| mime.type_() == mime_guess::mime::AUDIO
})
.unwrap_or(false);
if is_playable {
Some(format!(
"http://{host}/torrents/{idx}/stream/{file_idx}/{file_name}"
))
} else {
None
}
});

Ok(playlist_items.collect::<Vec<_>>().join("\r\n"))
}

async fn torrent_haves(
State(state): State<ApiState>,
Path(idx): Path<usize>,
Expand Down Expand Up @@ -289,6 +329,7 @@ impl HttpApi {
.route("/torrents/:id/stats/v1", get(torrent_stats_v1))
.route("/torrents/:id/peer_stats", get(peer_stats))
.route("/torrents/:id/stream/:file_id", get(torrent_stream_file))
.route("/torrents/:id/playlist", get(torrent_playlist))
.route(
"/torrents/:id/stream/:file_id/*filename",
get(torrent_stream_file),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TorrentStats } from "../../api-types";
import { APIContext, RefreshTorrentStatsContext } from "../../context";
import { IconButton } from "./IconButton";
import { DeleteTorrentModal } from "../modal/DeleteTorrentModal";
import { FaCog, FaPause, FaPlay, FaTrash } from "react-icons/fa";
import { FaCog, FaPause, FaPlay, FaTrash, FaClipboardList } from "react-icons/fa";
import { useErrorStore } from "../../stores/errorStore";

export const TorrentActions: React.FC<{
Expand Down Expand Up @@ -94,6 +94,11 @@ export const TorrentActions: React.FC<{
<IconButton onClick={startDeleting} disabled={disabled}>
<FaTrash className="hover:text-red-500" />
</IconButton>
<IconButton onClick={() => {alert("Open this playlist link in external player like VLC")}}>
<a target="_blank" href={"/torrents/"+id+"/playlist"}>
<FaClipboardList className="hover:text-green-500"/>
</a>
</IconButton>
<DeleteTorrentModal id={id} show={deleting} onHide={cancelDeleting} />
</div>
);
Expand Down

0 comments on commit 510c2ee

Please sign in to comment.