Players

Media player components for video, audio, image, and document preview.

Text Preview Utilities

Helpers for detecting and reading text-previewable files.


is_text_previewable


def is_text_previewable(
    file_info:FileInfo, # File to check
)->bool: # True if file can be previewed as text

Check if a file can be previewed as text content.


read_text_content


def read_text_content(
    file_path:str, # Path to the file
    max_size:int=10485760, # Maximum file size in bytes (default 10MB)
)->Tuple: # (content, error_message)

Read text file content with encoding fallback.

# Test text preview utilities
import tempfile
from pathlib import Path

# Test is_text_previewable
py_file = FileInfo(
    name="script.py", path="/script.py", is_directory=False,
    file_type=FileType.CODE, extension="py"
)
assert is_text_previewable(py_file) == True

json_file = FileInfo(
    name="data.json", path="/data.json", is_directory=False,
    file_type=FileType.DATA, extension="json"
)
assert is_text_previewable(json_file) == True

md_file = FileInfo(
    name="readme.md", path="/readme.md", is_directory=False,
    file_type=FileType.DOCUMENT, extension="md"
)
assert is_text_previewable(md_file) == True

# Non-text files
pdf_file = FileInfo(
    name="doc.pdf", path="/doc.pdf", is_directory=False,
    file_type=FileType.DOCUMENT, extension="pdf"
)
assert is_text_previewable(pdf_file) == False

image_file = FileInfo(
    name="photo.jpg", path="/photo.jpg", is_directory=False,
    file_type=FileType.IMAGE, extension="jpg"
)
assert is_text_previewable(image_file) == False

# Test read_text_content
with tempfile.TemporaryDirectory() as tmpdir:
    # Test reading UTF-8 file
    test_file = Path(tmpdir) / "test.txt"
    test_file.write_text("Hello, World!\nLine 2", encoding='utf-8')
    content, error = read_text_content(str(test_file))
    assert content == "Hello, World!\nLine 2"
    assert error is None
    
    # Test file size limit
    content, error = read_text_content(str(test_file), max_size=5)
    assert content is None
    assert "too large" in error
    
    # Test non-existent file
    content, error = read_text_content(str(Path(tmpdir) / "nonexistent.txt"))
    assert content is None
    assert error is not None

print("Text preview utilities tests passed!")
Text preview utilities tests passed!

Video Player

HTML5 video player with native controls.


render_video_player


def render_video_player(
    file_url:str, # URL to the video file
    file_info:Optional=None, # File metadata for MIME type
    autoplay:bool=False, # Autoplay video on load
    loop:bool=False, # Loop video playback
    muted:bool=False, # Start muted
    poster:Optional=None, # Poster image URL
    cls:str='', # Additional CSS classes
)->Any: # Video element

Render an HTML5 video player.

from fasthtml.common import to_xml

# Test video player
video = render_video_player("/media/test.mp4")
html = to_xml(video)
assert "<video" in html
assert "controls" in html
assert "/media/test.mp4" in html

# Test with file info
file_info = FileInfo(
    name="video.mp4", path="/video.mp4", is_directory=False,
    file_type=FileType.VIDEO, extension="mp4"
)
video = render_video_player("/media/video.mp4", file_info=file_info)
html = to_xml(video)
assert "video/mp4" in html

# Test with options
video = render_video_player(
    "/media/video.mp4",
    autoplay=True,
    muted=True,
    loop=True
)
html = to_xml(video)
assert "autoplay" in html
assert "muted" in html
assert "loop" in html

print("render_video_player tests passed!")
render_video_player tests passed!

Audio Player

HTML5 audio player with native controls.


render_audio_player


def render_audio_player(
    file_url:str, # URL to the audio file
    file_info:Optional=None, # File metadata for MIME type
    autoplay:bool=False, # Autoplay audio on load
    loop:bool=False, # Loop audio playback
    cls:str='', # Additional CSS classes
)->Any: # Audio element container

Render an HTML5 audio player.

# Test audio player
audio = render_audio_player("/media/song.mp3")
html = to_xml(audio)
assert "<audio" in html
assert "controls" in html
assert "/media/song.mp3" in html

# Test with file info
file_info = FileInfo(
    name="song.mp3", path="/song.mp3", is_directory=False,
    file_type=FileType.AUDIO, extension="mp3"
)
audio = render_audio_player("/media/song.mp3", file_info=file_info)
html = to_xml(audio)
assert "audio/mpeg" in html

# Test with options
audio = render_audio_player("/media/song.mp3", autoplay=True, loop=True)
html = to_xml(audio)
assert "autoplay" in html
assert "loop" in html

print("render_audio_player tests passed!")
render_audio_player tests passed!

Image Viewer

Image display with responsive sizing.


render_image_viewer


def render_image_viewer(
    file_url:str, # URL to the image file
    file_info:Optional=None, # File metadata for alt text
    alt:Optional=None, # Alt text (uses filename if not provided)
    cls:str='', # Additional CSS classes
)->Any: # Image element

Render an image viewer.

# Test image viewer
img = render_image_viewer("/media/photo.jpg")
html = to_xml(img)
assert "<img" in html
assert "/media/photo.jpg" in html
assert "object-contain" in html
assert 'loading="lazy"' in html

# Test with file info
file_info = FileInfo(
    name="vacation.jpg", path="/vacation.jpg", is_directory=False,
    file_type=FileType.IMAGE, extension="jpg"
)
img = render_image_viewer("/media/vacation.jpg", file_info=file_info)
html = to_xml(img)
assert 'alt="vacation.jpg"' in html

# Test with custom alt
img = render_image_viewer("/media/photo.jpg", alt="My Photo")
html = to_xml(img)
assert 'alt="My Photo"' in html

print("render_image_viewer tests passed!")
render_image_viewer tests passed!

Text Viewer

Scrollable text display for code, data, and text files.


render_text_viewer


def render_text_viewer(
    content:str, # Text content to display
    file_info:Optional=None, # File metadata for extension-based styling
    error:Optional=None, # Error message if content couldn't be read
    cls:str='', # Additional CSS classes
)->Any: # Text viewer component

Render a scrollable text viewer.

# Test text viewer
from fasthtml.common import to_xml

# Test basic text rendering
viewer = render_text_viewer("def hello():\n    print('Hello!')")
html = to_xml(viewer)
assert "<pre" in html
assert "<code" in html
assert "def hello()" in html
assert "font-mono" in html
assert "whitespace-pre" in html
assert "overflow-auto" in html

# Test with file info
py_file = FileInfo(
    name="script.py", path="/script.py", is_directory=False,
    file_type=FileType.CODE, extension="py"
)
viewer = render_text_viewer("# Python code", file_info=py_file)
html = to_xml(viewer)
assert "<pre" in html

# Test error display
viewer = render_text_viewer("", error="File too large")
html = to_xml(viewer)
assert "Unable to preview" in html
assert "File too large" in html
assert "<pre" not in html

print("render_text_viewer tests passed!")
render_text_viewer tests passed!

Document Preview

Document preview with PDF iframe or text placeholder.


render_document_preview


def render_document_preview(
    file_url:str, # URL to the document file
    file_info:Optional=None, # File metadata
    cls:str='', # Additional CSS classes
)->Any: # Document preview element

Render a document preview.

# Test document preview - PDF
pdf_preview = render_document_preview("/media/document.pdf")
html = to_xml(pdf_preview)
assert "<iframe" in html
assert "/media/document.pdf" in html

# Test with file info
file_info = FileInfo(
    name="report.pdf", path="/report.pdf", is_directory=False,
    file_type=FileType.DOCUMENT, extension="pdf"
)
pdf_preview = render_document_preview("/media/report.pdf", file_info=file_info)
html = to_xml(pdf_preview)
assert 'title="report.pdf"' in html

# Test non-PDF document (shows placeholder)
file_info = FileInfo(
    name="document.docx", path="/document.docx", is_directory=False,
    file_type=FileType.DOCUMENT, extension="docx"
)
doc_preview = render_document_preview("/media/document.docx", file_info=file_info)
html = to_xml(doc_preview)
assert "<div" in html  # Placeholder div, not iframe
assert "document.docx" in html
assert "DOCX" in html

print("render_document_preview tests passed!")
render_document_preview tests passed!

Unified Player Function

Single function that dispatches to the appropriate player based on file type.


render_media_player


def render_media_player(
    file_url:str, # URL to the media file
    file_info:FileInfo, # File metadata
    autoplay:bool=False, # Autoplay audio/video
    text_content:Optional=None, # Pre-read text content for text files
    text_error:Optional=None, # Error message if text reading failed
    cls:str='', # Additional CSS classes
)->Any: # Media player component

Render the appropriate media player based on file type.

# Test unified player

# Video file
video_file = FileInfo(
    name="video.mp4", path="/video.mp4", is_directory=False,
    file_type=FileType.VIDEO, extension="mp4"
)
player = render_media_player("/media/video.mp4", video_file)
html = to_xml(player)
assert "<video" in html

# Audio file
audio_file = FileInfo(
    name="song.mp3", path="/song.mp3", is_directory=False,
    file_type=FileType.AUDIO, extension="mp3"
)
player = render_media_player("/media/song.mp3", audio_file)
html = to_xml(player)
assert "<audio" in html

# Image file
image_file = FileInfo(
    name="photo.jpg", path="/photo.jpg", is_directory=False,
    file_type=FileType.IMAGE, extension="jpg"
)
player = render_media_player("/media/photo.jpg", image_file)
html = to_xml(player)
assert "<img" in html

# Document file (PDF)
doc_file = FileInfo(
    name="doc.pdf", path="/doc.pdf", is_directory=False,
    file_type=FileType.DOCUMENT, extension="pdf"
)
player = render_media_player("/media/doc.pdf", doc_file)
html = to_xml(player)
assert "<iframe" in html

# Text file with content
py_file = FileInfo(
    name="script.py", path="/script.py", is_directory=False,
    file_type=FileType.CODE, extension="py"
)
player = render_media_player(
    "/media/script.py", py_file,
    text_content="def hello():\n    pass"
)
html = to_xml(player)
assert "<pre" in html
assert "def hello()" in html

# Text file with error
player = render_media_player(
    "/media/script.py", py_file,
    text_error="File too large"
)
html = to_xml(player)
assert "Unable to preview" in html
assert "File too large" in html

# JSON data file with content
json_file = FileInfo(
    name="config.json", path="/config.json", is_directory=False,
    file_type=FileType.DATA, extension="json"
)
player = render_media_player(
    "/media/config.json", json_file,
    text_content='{"key": "value"}'
)
html = to_xml(player)
assert "<pre" in html
assert '"key"' in html

# Text-previewable file without content (falls back to document preview)
player = render_media_player("/media/script.py", py_file)
html = to_xml(player)
assert "<div" in html  # Document-style placeholder

print("render_media_player tests passed!")
render_media_player tests passed!