use crate::server::MediaViewerType;
use std::path::Path;
pub fn build_url_path(
relative_path: &Path,
is_directory: bool,
markdown_extensions: &[String],
) -> String {
let relative_str = crate::url_path::path_to_url(relative_path);
if is_directory {
if relative_str.is_empty() {
String::new()
} else {
format!("{}/", relative_str)
}
} else {
replace_markdown_extension_with_slash(&relative_str, markdown_extensions)
}
}
fn replace_markdown_extension_with_slash(s: &str, extensions: &[String]) -> String {
if let Some((base, extension)) = s.rsplit_once('.') {
match extensions
.iter()
.find(|cur_ext| extension == cur_ext.as_str())
{
Some(_) => format!("{}/", base), None => s.to_string(), }
} else {
s.to_string() }
}
pub fn build_media_viewer_url(media_type: MediaViewerType, file_url_path: &str) -> String {
use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
const QUERY_ENCODE_SET: &AsciiSet = &CONTROLS
.add(b' ')
.add(b'"')
.add(b'#')
.add(b'%')
.add(b'&')
.add(b'+')
.add(b'=')
.add(b'?');
let full_path = if file_url_path.starts_with('/') {
file_url_path.to_string()
} else {
format!("/{file_url_path}")
};
let encoded_path = utf8_percent_encode(&full_path, QUERY_ENCODE_SET).to_string();
format!("{}?path={}", media_type.route_path(), encoded_path)
}
pub fn resolve_launch_url_path(
relative_path: &Path,
is_directory: bool,
markdown_extensions: &[String],
) -> String {
if !is_directory && let Some(media_type) = MediaViewerType::from_path(relative_path) {
let file_url_path = build_url_path(relative_path, false, markdown_extensions);
return build_media_viewer_url(media_type, &file_url_path);
}
build_url_path(relative_path, is_directory, markdown_extensions)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
#[test]
fn test_build_url_path_root_directory() {
let path = Path::new("");
let extensions = vec!["md".to_string()];
assert_eq!(build_url_path(path, true, &extensions), "");
}
#[test]
fn test_build_url_path_subdirectory() {
let path = Path::new("docs/api");
let extensions = vec!["md".to_string()];
assert_eq!(build_url_path(path, true, &extensions), "docs/api/");
}
#[test]
fn test_build_url_path_markdown_file() {
let path = Path::new("readme.md");
let extensions = vec!["md".to_string()];
assert_eq!(build_url_path(path, false, &extensions), "readme/");
}
#[test]
fn test_build_url_path_markdown_file_in_subdir() {
let path = Path::new("docs/guide.md");
let extensions = vec!["md".to_string()];
assert_eq!(build_url_path(path, false, &extensions), "docs/guide/");
}
#[test]
fn test_build_url_path_alternate_extension() {
let path = Path::new("notes.markdown");
let extensions = vec!["md".to_string(), "markdown".to_string()];
assert_eq!(build_url_path(path, false, &extensions), "notes/");
}
#[test]
fn test_build_url_path_non_markdown_file() {
let path = Path::new("image.png");
let extensions = vec!["md".to_string()];
assert_eq!(build_url_path(path, false, &extensions), "image.png");
}
#[test]
fn test_replace_markdown_extension_with_slash() {
let extensions = ["md".to_string()];
assert_eq!(
replace_markdown_extension_with_slash("test.md", &extensions),
"test/"
);
assert_eq!(
replace_markdown_extension_with_slash("test.txt", &extensions),
"test.txt"
);
assert_eq!(
replace_markdown_extension_with_slash("noext", &extensions),
"noext"
);
}
#[test]
fn test_build_media_viewer_url_video() {
let url = build_media_viewer_url(MediaViewerType::Video, "videos/example.mp4");
assert_eq!(url, "/.mbr/videos/?path=/videos/example.mp4");
}
#[test]
fn test_build_media_viewer_url_audio() {
let url = build_media_viewer_url(MediaViewerType::Audio, "music/song.mp3");
assert_eq!(url, "/.mbr/audio/?path=/music/song.mp3");
}
#[test]
fn test_build_media_viewer_url_image() {
let url = build_media_viewer_url(MediaViewerType::Image, "images/photo.jpg");
assert_eq!(url, "/.mbr/images/?path=/images/photo.jpg");
}
#[test]
fn test_build_media_viewer_url_pdf() {
let url = build_media_viewer_url(MediaViewerType::Pdf, "docs/paper.pdf");
assert_eq!(url, "/.mbr/pdfs/?path=/docs/paper.pdf");
}
#[test]
fn test_build_media_viewer_url_with_leading_slash() {
let url = build_media_viewer_url(MediaViewerType::Video, "/videos/example.mp4");
assert_eq!(url, "/.mbr/videos/?path=/videos/example.mp4");
}
#[test]
fn test_build_media_viewer_url_encodes_spaces() {
let url = build_media_viewer_url(MediaViewerType::Video, "videos/my video.mp4");
assert!(url.contains("path=/videos/my%20video.mp4"));
}
#[test]
fn test_build_media_viewer_url_encodes_special_chars() {
let url = build_media_viewer_url(MediaViewerType::Video, "videos/file#1&2=3.mp4");
assert!(url.contains("path=/videos/file%231%262%3D3.mp4"));
}
#[test]
fn test_resolve_launch_url_path_directory() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("docs/guide"), true, &extensions),
"docs/guide/"
);
}
#[test]
fn test_resolve_launch_url_path_root_directory() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new(""), true, &extensions),
""
);
}
#[test]
fn test_resolve_launch_url_path_markdown_file() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("docs/guide.md"), false, &extensions),
"docs/guide/"
);
}
#[test]
fn test_resolve_launch_url_path_video_file() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("videos/demo.mp4"), false, &extensions),
"/.mbr/videos/?path=/videos/demo.mp4"
);
}
#[test]
fn test_resolve_launch_url_path_pdf_file() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("docs/paper.pdf"), false, &extensions),
"/.mbr/pdfs/?path=/docs/paper.pdf"
);
}
#[test]
fn test_resolve_launch_url_path_plain_file() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("data.csv"), false, &extensions),
"data.csv"
);
}
#[test]
fn test_resolve_launch_url_path_directory_short_circuits_media_check() {
let extensions = vec!["md".to_string()];
assert_eq!(
resolve_launch_url_path(Path::new("videos/demo.mp4"), true, &extensions),
"videos/demo.mp4/"
);
}
}