Add media browser with grid/compact/list views and single-click playback

- Add browser UI with three view modes (grid, compact, list) and pagination
- Add file browsing, thumbnail loading, download, and play endpoints
- Add duration extraction via mutagen for media files
- Single-click plays media or navigates folders, with play overlay on hover
- Add type badges, file size display, and duration metadata
- Add localization keys for browser UI (en/ru)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 23:34:38 +03:00
parent 32b058c5fb
commit e16674c658
7 changed files with 784 additions and 66 deletions

View File

@@ -8,6 +8,12 @@ from typing import Optional
from ..config import settings
try:
from mutagen import File as MutagenFile
HAS_MUTAGEN = True
except ImportError:
HAS_MUTAGEN = False
logger = logging.getLogger(__name__)
# Media file extensions
@@ -109,6 +115,26 @@ class BrowserService:
else:
return "other"
@staticmethod
def get_duration(file_path: Path) -> Optional[float]:
"""Get duration of a media file in seconds (header-only read).
Args:
file_path: Path to the media file.
Returns:
Duration in seconds, or None if unavailable.
"""
if not HAS_MUTAGEN:
return None
try:
audio = MutagenFile(str(file_path))
if audio is not None and hasattr(audio, "info") and hasattr(audio.info, "length"):
return round(audio.info.length, 2)
except Exception:
pass
return None
@staticmethod
def browse_directory(
folder_id: str,
@@ -202,6 +228,14 @@ class BrowserService:
total = len(all_items)
items = all_items[offset:offset + limit]
# Extract duration for media files in the current page
for item in items:
if item["is_media"]:
item_path = full_path / item["name"]
item["duration"] = BrowserService.get_duration(item_path)
else:
item["duration"] = None
return {
"folder_id": folder_id,
"current_path": current_path,