From a77c1caacef1f39bdc30d22ef71749f14d31b9f5 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 27 Jul 2024 11:44:15 +0200 Subject: [PATCH 1/4] Add contet-type to stream --- Cargo.lock | 20 ++++++++++++++++++++ crates/librqbit/Cargo.toml | 1 + crates/librqbit/src/api.rs | 31 +++++++++++++++++++++++++++++++ crates/librqbit/src/http_api.rs | 7 +++++++ 4 files changed, 59 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index d9de10a7..bf4672cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1317,6 +1317,7 @@ dependencies = [ "librqbit-upnp", "lru", "memmap2", + "mime_guess", "openssl", "parking_lot", "rand", @@ -1539,6 +1540,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2822,6 +2833,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/crates/librqbit/Cargo.toml b/crates/librqbit/Cargo.toml index e5fcf9e2..7fce752a 100644 --- a/crates/librqbit/Cargo.toml +++ b/crates/librqbit/Cargo.toml @@ -74,6 +74,7 @@ rlimit = "0.10.1" async-stream = "0.3.5" memmap2 = { version = "0.9.4" } lru = { version = "0.12.3", optional = true } +mime_guess = { version = "2.0.5", default-features = false} [dev-dependencies] futures = { version = "0.3" } diff --git a/crates/librqbit/src/api.rs b/crates/librqbit/src/api.rs index 2509963b..97af6d55 100644 --- a/crates/librqbit/src/api.rs +++ b/crates/librqbit/src/api.rs @@ -78,6 +78,12 @@ impl Api { make_torrent_details(&info_hash, &handle.info().info, only_files.as_deref()) } + pub fn torrent_file_mime_type(&self, idx: TorrentId, file_idx: usize) -> Result<&'static str> { + let handle = self.mgr_handle(idx)?; + let info = &handle.info().info; + torrent_file_mime_type(info, file_idx) + } + pub fn api_peer_stats( &self, idx: TorrentId, @@ -320,3 +326,28 @@ fn make_torrent_details( files, }) } + +fn torrent_file_mime_type( + info: &TorrentMetaV1Info, + file_idx: usize, +) -> Result<&'static str> { + let file_name = info + .iter_filenames_and_lengths()? + .enumerate() + .find_map(|(idx, (f, _))| { + if idx == file_idx { + f.iter_components() + .last() + .and_then(|r| r.ok()) + .and_then(|s| mime_guess::from_path(s).first_raw()) + } else { + None + } + }); + file_name.ok_or_else(|| { + ApiError::new_from_text( + StatusCode::INTERNAL_SERVER_ERROR, + "cannot determine mime type for file", + ) + }) +} diff --git a/crates/librqbit/src/http_api.rs b/crates/librqbit/src/http_api.rs index 280c7d69..890086fa 100644 --- a/crates/librqbit/src/http_api.rs +++ b/crates/librqbit/src/http_api.rs @@ -167,6 +167,13 @@ impl HttpApi { let mut output_headers = HeaderMap::new(); output_headers.insert("Accept-Ranges", HeaderValue::from_static("bytes")); + if let Ok(mime) = state.torrent_file_mime_type(idx, file_id) { + output_headers.insert( + http::header::CONTENT_TYPE, + HeaderValue::from_str(mime).context("bug - invalid MIME")?, + ); + } + let range_header = headers.get(http::header::RANGE); trace!(torrent_id=idx, file_id=file_id, range=?range_header, "request for HTTP stream"); From aa2bac8bf5d1b0fd6be049700a16ef90b086d458 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 28 Jul 2024 12:15:56 +0200 Subject: [PATCH 2/4] Use content-lengh when there is no ranges header --- crates/librqbit/src/http_api.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/librqbit/src/http_api.rs b/crates/librqbit/src/http_api.rs index 890086fa..753e3ce3 100644 --- a/crates/librqbit/src/http_api.rs +++ b/crates/librqbit/src/http_api.rs @@ -206,12 +206,12 @@ impl HttpApi { )) .context("bug")?, ); - } else { - output_headers.insert( - http::header::CONTENT_LENGTH, - HeaderValue::from_str(&format!("{}", stream.len())).context("bug")?, - ); } + } else { + output_headers.insert( + http::header::CONTENT_LENGTH, + HeaderValue::from_str(&format!("{}", stream.len())).context("bug")?, + ); } let s = tokio_util::io::ReaderStream::new(stream); From 85a81c55f60905766ee6781601994ccbcae02e94 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 28 Jul 2024 13:20:49 +0200 Subject: [PATCH 3/4] Modify webui - enable to stream any file - to new tab --- crates/librqbit/webui/src/components/FileListInput.tsx | 3 +-- crates/librqbit/webui/src/components/forms/FormCheckbox.tsx | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/librqbit/webui/src/components/FileListInput.tsx b/crates/librqbit/webui/src/components/FileListInput.tsx index 9ec54102..323ba1c0 100644 --- a/crates/librqbit/webui/src/components/FileListInput.tsx +++ b/crates/librqbit/webui/src/components/FileListInput.tsx @@ -158,8 +158,7 @@ const FileTreeComponent: React.FC<{ const fileLink = (file: TorrentFileForCheckbox) => { if ( allowStream && - torrentId != null && - /\.(mp4|mkv|avi)$/.test(file.filename) + torrentId != null ) { return API.getTorrentStreamUrl(torrentId, file.id, file.filename); } diff --git a/crates/librqbit/webui/src/components/forms/FormCheckbox.tsx b/crates/librqbit/webui/src/components/forms/FormCheckbox.tsx index dbe4f12a..f2e0a472 100644 --- a/crates/librqbit/webui/src/components/forms/FormCheckbox.tsx +++ b/crates/librqbit/webui/src/components/forms/FormCheckbox.tsx @@ -39,6 +39,7 @@ export const FormCheckbox: React.FC<{ {labelLink ? ( {label} From 970bdb86529cdb273f6ff5caa9ef31fa4da55cf2 Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 2 Aug 2024 13:29:20 +0200 Subject: [PATCH 4/4] Refactor - use better style --- crates/librqbit/src/api.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/crates/librqbit/src/api.rs b/crates/librqbit/src/api.rs index 97af6d55..78ed72b7 100644 --- a/crates/librqbit/src/api.rs +++ b/crates/librqbit/src/api.rs @@ -331,23 +331,18 @@ fn torrent_file_mime_type( info: &TorrentMetaV1Info, file_idx: usize, ) -> Result<&'static str> { - let file_name = info - .iter_filenames_and_lengths()? - .enumerate() - .find_map(|(idx, (f, _))| { - if idx == file_idx { - f.iter_components() - .last() - .and_then(|r| r.ok()) - .and_then(|s| mime_guess::from_path(s).first_raw()) - } else { - None - } - }); - file_name.ok_or_else(|| { - ApiError::new_from_text( - StatusCode::INTERNAL_SERVER_ERROR, - "cannot determine mime type for file", - ) - }) + info.iter_filenames_and_lengths()? + .nth(file_idx) + .and_then(|(f, _)| { + f.iter_components() + .last() + .and_then(|r| r.ok()) + .and_then(|s| mime_guess::from_path(s).first_raw()) + }) + .ok_or_else(|| { + ApiError::new_from_text( + StatusCode::INTERNAL_SERVER_ERROR, + "cannot determine mime type for file", + ) + }) }