diff --git a/frontend.html b/frontend.html
index 9d2b1d1..a2a0e7d 100644
--- a/frontend.html
+++ b/frontend.html
@@ -14,16 +14,14 @@
overflow: hidden;
zoom: 1;
}
- #img {
+ .media {
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
cursor: pointer;
- background-image: url($img_url);
- background-size: contain; /* Important for proper scaling */
- background-position: center;
- background-repeat: no-repeat;
+ object-fit: contain;
+ display: block;
}
.chevron {
position: absolute;
@@ -75,7 +73,7 @@
text-wrap-mode: nowrap;
}
#sidebar a:hover {
- background: #3a3a3a;
+ background: #3a3a3a;
color: #fff;
}
.breadcrumb {
@@ -131,7 +129,7 @@
-
+
$media_element
‹
›
$play_button
diff --git a/main.py b/main.py
index 69516fc..d5109db 100644
--- a/main.py
+++ b/main.py
@@ -413,10 +413,27 @@ def _render_page(
)
sidebar_class = ""
+ # Build the media element based on file type
+ img_url = "{root_path}/api/{file_hash}/data".format(
+ root_path=root_path, file_hash=navigation_data["file_hash"]
+ )
+ content_type, _ = mimetypes.guess_type(file_path or "")
+ data_attrs = f'data-hash="{navigation_data["file_hash"]}"'
+ if navigate_enabled:
+ data_attrs += f' data-path="{file_path}"'
+ if content_type and content_type.startswith("video"):
+ media_element = (
+ f'
'
+ )
+ else:
+ media_element = (
+ f'

'
+ )
+
content = template.substitute(
- img_url="{root_path}/api/{file_hash}/data".format(
- root_path=root_path, file_hash=navigation_data["file_hash"]
- ),
+ media_element=media_element,
image_click_url=image_click_url or _get_random_hash(),
next_url=next_url,
prev_url=prev_url,
@@ -809,7 +826,7 @@ def _render_folder_index_page(
)
content = template.substitute(
- img_url="#",
+ media_element="",
image_click_url="#",
next_url="#",
prev_url="#",
diff --git a/tests/conftest.py b/tests/conftest.py
index cb7a6c1..bcbd2ac 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -53,6 +53,9 @@ def sample_files(tmp_path: Path) -> dict[str, Path]:
files["image_file"] = tmp_path / "photo.jpg"
files["image_file"].write_bytes(b"\xff\xd8\xff\xe0fake_jpeg_data")
+ files["video_file"] = tmp_path / "clip.mp4"
+ files["video_file"].write_bytes(b"\x00\x00\x00\x1cftypfake_mp4_data")
+
return files
diff --git a/tests/test_file_indexer.py b/tests/test_file_indexer.py
index 2f7f810..bd7c0a4 100644
--- a/tests/test_file_indexer.py
+++ b/tests/test_file_indexer.py
@@ -87,8 +87,8 @@ class TestIndex:
"""All files in the directory tree are indexed."""
indexer = FileIndexer(str(sample_files["root_file"].parent), salt="test")
assert (
- len(indexer._file_mapping) == 4
- ) # root.txt, nested.txt, data.bin, photo.jpg
+ len(indexer._file_mapping) == 5
+ ) # root.txt, nested.txt, data.bin, photo.jpg, clip.mp4
def test_hash_maps_to_correct_path(self, sample_files: dict[str, Path]) -> None:
"""Each hash maps to the correct file path."""
diff --git a/tests/test_media_elements.py b/tests/test_media_elements.py
new file mode 100644
index 0000000..3c21242
--- /dev/null
+++ b/tests/test_media_elements.py
@@ -0,0 +1,219 @@
+"""Tests for media element rendering (images vs videos)."""
+
+from httpx import AsyncClient
+
+import main
+
+
+class TestMediaElementRendering:
+ """Tests for GET /{file_hash} media element selection."""
+
+ async def test_image_file_renders_img_tag(self, client_dir: AsyncClient) -> None:
+ """Image files should render an
![]()
element."""
+ file_hash = None
+ for h, path in main.file_mapping.items():
+ if path.endswith(".jpg"):
+ file_hash = h
+ break
+
+ assert file_hash is not None
+ response = await client_dir.get(f"/{file_hash}")
+ assert response.status_code == 200
+ assert "
![]()
None:
+ """Video files should render a