API Documentation

Kiosk.show Replacement - A self-hosted digital signage solution.

This package provides a Flask-based web application for managing digital signage displays and slideshows, serving as a replacement for the defunct kiosk.show service.

The application serves two primary functions: 1. Allow users to create and manage slideshows through a web interface 2. Serve slideshow content to connected display devices

Key Components: - Flask web application with both API and server-side rendered interfaces - SQLAlchemy-based data models for users, displays, slideshows, and content - File upload and management for images and videos - Real-time updates via Server-Sent Events - Responsive admin interface built with React - Display interface optimized for kiosk devices

This package is designed for collaborative human-AI development with comprehensive testing, documentation, and deployment automation.

kiosk_show_replacement.create_app(config_name: str | None = None) Flask[source]

Create and configure the Flask application.

Parameters:

config_name – The configuration name to use (development, production, testing)

Returns:

Configured Flask application instance

Return type:

Flask

Core Modules

Application Factory

Flask application factory for kiosk-show-replacement.

This module contains the Flask application factory that creates and configures the Flask app instance with all necessary blueprints, extensions, and configuration.

kiosk_show_replacement.app.sanitize_database_uri(uri: str) str[source]

Sanitize database URI by removing password information for logging.

Parameters:

uri – Database URI that may contain sensitive information

Returns:

Sanitized URI safe for logging

Return type:

str

kiosk_show_replacement.app.create_app(config_name: str | None = None) Flask[source]

Create and configure the Flask application.

Parameters:

config_name – The configuration name to use (development, production, testing)

Returns:

Configured Flask application instance

Return type:

Flask

Database Models

Database models module for the Kiosk.show Replacement application.

This module contains SQLAlchemy model definitions for: - User: Authentication and audit information - Display: Connected kiosk device information - Slideshow: Collection of slideshow items with metadata - SlideshowItem: Individual content items within slideshows

All models include proper relationships, constraints, and audit fields for tracking creation and modification. Designed for easy migration between different database engines (SQLite, PostgreSQL, MariaDB).

class kiosk_show_replacement.models.User(**kwargs)[source]

Bases: Model

Model representing a user account.

id: Mapped[int]
username: Mapped[str]
email: Mapped[str | None]
password_hash: Mapped[str]
is_active: Mapped[bool]
is_admin: Mapped[bool]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
last_login_at: Mapped[datetime | None]
created_by_id: Mapped[int | None]
updated_by_id: Mapped[int | None]
created_by: Mapped['User' | None]
updated_by: Mapped['User' | None]
slideshows: Mapped[List['Slideshow']]
displays: Mapped[List['Display']]
set_password(password: str) None[source]

Set password hash from plain text password.

check_password(password: str) bool[source]

Check if provided password matches stored hash.

to_dict(include_sensitive: bool = False) dict[source]

Convert user to dictionary for JSON serialization.

validate_username(key: str, username: str) str[source]

Validate username format and length.

validate_email(key: str, email: str | None) str | None[source]

Validate email format.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.Display(**kwargs)[source]

Bases: Model

Model representing a display device/kiosk.

id: Mapped[int]
name: Mapped[str]
description: Mapped[str | None]
resolution_width: Mapped[int | None]
resolution_height: Mapped[int | None]
rotation: Mapped[int]
location: Mapped[str | None]
is_active: Mapped[bool]
is_archived: Mapped[bool]
show_info_overlay: Mapped[bool]
archived_at: Mapped[datetime | None]
archived_by_id: Mapped[int | None]
last_seen_at: Mapped[datetime | None]
heartbeat_interval: Mapped[int]
owner_id: Mapped[int | None]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
created_by_id: Mapped[int | None]
updated_by_id: Mapped[int | None]
current_slideshow_id: Mapped[int | None]
owner: Mapped['User' | None]
created_by: Mapped['User' | None]
updated_by: Mapped['User' | None]
archived_by: Mapped['User' | None]
current_slideshow: Mapped['Slideshow' | None]
property is_online: bool

Check if display is considered online based on last heartbeat.

property resolution_string: str | None

Get display resolution as formatted string.

property resolution: str | None

Alias for resolution_string for backward compatibility.

update_heartbeat() None[source]

Update the last seen timestamp to current time.

property last_heartbeat: datetime | None

Alias for last_seen_at for backward compatibility.

property missed_heartbeats: int

Calculate the number of missed heartbeats based on last_seen_at.

Returns:

Number of missed heartbeats (0 if seen recently, increases with time)

property connection_quality: str

Calculate connection quality based on missed heartbeats.

Returns:

‘excellent’, ‘good’, ‘poor’, or ‘offline’

Return type:

Connection quality

property sse_connected: bool

Check if this display has an active SSE connection.

Returns:

True if the display has an active SSE connection, False otherwise

to_status_dict() dict[source]

Convert display to status dictionary for the status API.

This includes all standard display info plus enhanced status fields like connection_quality, missed_heartbeats, and sse_connected.

Returns:

Dictionary with display status information

to_dict() dict[source]

Convert display to dictionary for JSON serialization.

validate_name(key: str, name: str) str[source]

Validate display name format and length.

validate_resolution(key: str, value: int | None) int | None[source]

Validate resolution values.

validate_rotation(key: str, rotation: int) int[source]

Validate rotation value.

validate_show_info_overlay(key: str, value: bool) bool[source]

Validate show_info_overlay is a boolean.

archive(archived_by_user: User) None[source]

Archive this display.

restore() None[source]

Restore this display from archive.

property can_be_assigned: bool

Check if display can be assigned a slideshow.

get_configuration_dict() dict[source]

Get display configuration for templates and migration.

apply_configuration(config: dict, updated_by_user: User) None[source]

Apply configuration from template or migration.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.Slideshow(**kwargs)[source]

Bases: Model

Model representing a slideshow collection.

id: Mapped[int]
name: Mapped[str]
description: Mapped[str | None]
is_active: Mapped[bool]
is_default: Mapped[bool]
default_item_duration: Mapped[int]
transition_type: Mapped[str]
owner_id: Mapped[int]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
created_by_id: Mapped[int | None]
updated_by_id: Mapped[int | None]
owner: Mapped['User']
created_by: Mapped['User' | None]
updated_by: Mapped['User' | None]
items: Mapped[List['SlideshowItem']]
property total_duration: int

Calculate total slideshow duration in seconds.

property active_items_count: int

Get count of active slideshow items.

property item_count: int

Alias for active_items_count for backward compatibility.

property default_duration: int

Alias for default_item_duration for backward compatibility.

to_dict(include_items: bool = False) dict[source]

Convert slideshow to dictionary for JSON serialization.

validate_name(key: str, name: str) str[source]

Validate slideshow name format and length.

validate_default_duration(key: str, duration: int) int[source]

Validate default item duration.

validate_transition_type(key: str, transition_type: str) str[source]

Validate transition type.

property slides: List[SlideshowItem]

Alias for items to maintain backward compatibility with templates.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.SlideshowItem(**kwargs)[source]

Bases: Model

Model representing individual slideshow items.

id: Mapped[int]
slideshow_id: Mapped[int]
title: Mapped[str | None]
content_type: Mapped[str]
content_url: Mapped[str | None]
content_text: Mapped[str | None]
content_file_path: Mapped[str | None]
display_duration: Mapped[int | None]
order_index: Mapped[int]
is_active: Mapped[bool]
scale_factor: Mapped[int | None]
ical_feed_id: Mapped[int | None]
ical_refresh_minutes: Mapped[int | None]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
created_by_id: Mapped[int | None]
updated_by_id: Mapped[int | None]
slideshow: Mapped['Slideshow']
created_by: Mapped['User' | None]
updated_by: Mapped['User' | None]
ical_feed: Mapped['ICalFeed' | None]
property effective_duration: int

Get effective display duration (item-specific or slideshow default).

property content_source: str | None

Get the active content source based on content type.

property display_url: str | None

Get the URL for displaying this content in the slideshow.

to_dict() dict[source]

Convert slideshow item to dictionary for JSON serialization.

validate_content_type(key: str, content_type: str) str[source]

Validate content type.

validate_content_url(key: str, content_url: str | None) str | None[source]

Validate content URL format.

validate_display_duration(key: str, duration: int | None) int | None[source]

Validate display duration.

validate_order_index(key: str, order_index: int) int[source]

Validate order index.

validate_scale_factor(key: str, scale_factor: int | None) int | None[source]

Validate scale factor for URL slides.

Scale factor represents zoom percentage (10-100). NULL or 100 means no scaling (normal view). Lower values zoom out to show more content.

validate_ical_refresh_minutes(key: str, refresh_minutes: int | None) int | None[source]

Validate iCal refresh interval.

Refresh interval must be between 1 and 1440 minutes (1 day).

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.AssignmentHistory(**kwargs)[source]

Bases: Model

Model for tracking slideshow assignment history and audit trail.

id: Mapped[int]
display_id: Mapped[int]
previous_slideshow_id: Mapped[int | None]
new_slideshow_id: Mapped[int | None]
action: Mapped[str]
reason: Mapped[str | None]
created_at: Mapped[datetime]
created_by_id: Mapped[int | None]
display: Mapped['Display']
previous_slideshow: Mapped['Slideshow' | None]
new_slideshow: Mapped['Slideshow' | None]
created_by: Mapped['User' | None]
validate_action(key: str, action: str) str[source]

Validate assignment action type.

to_dict() dict[source]

Convert assignment history to dictionary for JSON serialization.

classmethod create_assignment_record(display_id: int, previous_slideshow_id: int | None, new_slideshow_id: int | None, created_by_id: int | None = None, reason: str | None = None) AssignmentHistory[source]

Create an assignment history record based on the change type.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.DisplayConfigurationTemplate(**kwargs)[source]

Bases: Model

Model for storing display configuration templates.

id: Mapped[int]
name: Mapped[str]
description: Mapped[str | None]
template_resolution_width: Mapped[int | None]
template_resolution_height: Mapped[int | None]
template_rotation: Mapped[int]
template_heartbeat_interval: Mapped[int]
template_location: Mapped[str | None]
is_default: Mapped[bool]
is_active: Mapped[bool]
owner_id: Mapped[int]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
created_by_id: Mapped[int]
updated_by_id: Mapped[int | None]
owner: Mapped['User']
created_by: Mapped['User']
updated_by: Mapped['User' | None]
to_dict() dict[source]

Convert template to dictionary for JSON serialization.

to_configuration_dict() dict[source]

Convert template to configuration dictionary for applying to displays.

validate_name(key: str, name: str) str[source]

Validate template name format and length.

validate_template_rotation(key: str, rotation: int) int[source]

Validate template rotation value.

validate_template_resolution(key: str, value: int | None) int | None[source]

Validate template resolution values.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.ICalFeed(**kwargs)[source]

Bases: Model

Model representing an iCal/ICS feed URL.

Stores the feed URL and metadata about the last fetch. Multiple SlideshowItems can reference the same feed to avoid duplicate fetches and event storage.

id: Mapped[int]
url: Mapped[str]
last_fetched: Mapped[datetime | None]
last_error: Mapped[str | None]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
events: Mapped[List['ICalEvent']]
slideshow_items: Mapped[List['SlideshowItem']]
to_dict() dict[source]

Convert feed to dictionary for JSON serialization.

validate_url(key: str, url: str) str[source]

Validate feed URL format.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

class kiosk_show_replacement.models.ICalEvent(**kwargs)[source]

Bases: Model

Model representing an individual event from an iCal feed.

Events are stored with their original ICS UID to allow for efficient upserts when refreshing the feed.

id: Mapped[int]
feed_id: Mapped[int]
uid: Mapped[str]
summary: Mapped[str]
description: Mapped[str | None]
start_time: Mapped[datetime]
end_time: Mapped[datetime]
resources: Mapped[str | None]
attendee_name: Mapped[str | None]
attendee_email: Mapped[str | None]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
feed: Mapped['ICalFeed']
to_dict() dict[source]

Convert event to dictionary for JSON serialization.

validate_summary(key: str, summary: str) str[source]

Validate event summary.

validate_uid(key: str, uid: str) str[source]

Validate event UID.

__init__(**kwargs)

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

query: t.ClassVar[Query]

A SQLAlchemy query for a model. Equivalent to db.session.query(Model). Can be customized per-model by overriding query_class.

Warning

The query interface is considered legacy in SQLAlchemy. Prefer using session.execute(select()) instead.

REST API

API module for the Kiosk.show Replacement application.

This module provides RESTful API endpoints for: - Slideshow management (CRUD operations) - Slideshow item management - Display management and monitoring

The API is versioned with v1 endpoints available at /api/v1/*

kiosk_show_replacement.api.api_root() dict[str, object][source]

API root endpoint providing version information.

kiosk_show_replacement.api.api_health() dict[str, object][source]

API health check endpoint.

Display Module

Display module for the Kiosk.show Replacement application.

This module handles display-related functionality including: - Display registration and auto-discovery - Resolution detection and management - Slideshow rendering and playback - Content scaling and optimization - Display heartbeat and status monitoring - Server-side templates for kiosk devices

Optimized for reliability and performance on kiosk hardware with minimal JavaScript dependencies and graceful error handling.

This module provides the main display interface for viewing slideshows in kiosk mode.

Slideshow Management

Slideshow module for the Kiosk.show Replacement application.

This module handles slideshow-related functionality including: - Slideshow creation, editing, and management - Slideshow item ordering and reordering - Content type handling (images, videos, web pages) - File upload and storage management - Slideshow validation and business logic - Default slideshow management

Provides both API endpoints and utilities for slideshow operations with comprehensive validation and error handling.

This module provides web interface for managing slideshows and slides.

Configuration

Configuration module for kiosk-show-replacement.

This module handles different configuration environments and settings.

kiosk_show_replacement.config.build_mysql_url_from_env() str | None[source]

Construct a MySQL connection URL from individual MYSQL_* environment variables.

Returns a mysql+pymysql:// URL if MYSQL_HOST and all required variables (MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE) are set. Returns None if MYSQL_HOST is not set or if any required variable is missing (partial config is caught by validate_database_config()).

Returns:

MySQL connection URL string, or None

kiosk_show_replacement.config.validate_database_config(config_name: str, resolved_uri: str) list[tuple[str, str]][source]

Validate the database configuration and return any issues found.

Parameters:
  • config_name – The active configuration name (e.g. “production”, “development”)

  • resolved_uri – The resolved SQLALCHEMY_DATABASE_URI value

Returns:

List of (level, message) tuples where level is “error” or “warning”

class kiosk_show_replacement.config.Config[source]

Bases: object

Base configuration class.

SECRET_KEY = 'dev-secret-key-change-me-in-production'
SQLALCHEMY_DATABASE_URI = 'sqlite:///kiosk_show.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_FOLDER = 'instance/uploads'
MAX_CONTENT_LENGTH = 524288000
MAX_IMAGE_SIZE = 52428800
MAX_VIDEO_SIZE = 524288000
ALLOWED_IMAGE_EXTENSIONS = {'bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'webp'}
ALLOWED_VIDEO_EXTENSIONS = {'avi', 'flv', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'webm', 'wmv'}
ALLOWED_EXTENSIONS = {'avi', 'bmp', 'flv', 'gif', 'jpeg', 'jpg', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'png', 'tiff', 'webm', 'webp', 'wmv'}
PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=1)
CORS_ORIGINS = ['*']
class kiosk_show_replacement.config.DevelopmentConfig[source]

Bases: Config

Development configuration.

DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:////home/runner/work/kiosk-show-replacement/kiosk-show-replacement/instance/kiosk_show_dev.db'
class kiosk_show_replacement.config.ProductionConfig[source]

Bases: Config

Production configuration.

DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite:///kiosk_show.db'
class kiosk_show_replacement.config.TestingConfig[source]

Bases: Config

Testing configuration.

TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
WTF_CSRF_ENABLED = False

Command Line Interface

Command Line Interface module for the Kiosk.show Replacement application.

This module provides CLI commands for: - Starting the development server - Database operations (create, migrate, seed) - User management - System administration tasks - Configuration management

Uses Click framework for command definition and argument parsing.

Utilities

Utility functions for kiosk-show-replacement.

This module contains helper functions for file handling, URL validation, and other common operations.

kiosk_show_replacement.utils.generate_random_password(length: int = 8) str[source]

Generate a random password of the specified length.

Parameters:

length – The desired password length (default: 8)

Returns:

A random password string containing letters and digits.

kiosk_show_replacement.utils.is_valid_url(url: str) bool[source]

Check if a URL is valid and accessible.

Parameters:

url (str) – URL to validate

Returns:

True if URL is valid and accessible

Return type:

bool

kiosk_show_replacement.utils.is_image_url(url: str) bool[source]

Check if a URL points to an image file.

Parameters:

url (str) – URL to check

Returns:

True if URL appears to be an image

Return type:

bool

kiosk_show_replacement.utils.validate_image_file(file_path: str) bool[source]

Validate that a file is a valid image.

Parameters:

file_path (str) – Path to the image file

Returns:

True if file is a valid image

Return type:

bool

kiosk_show_replacement.utils.get_file_mimetype(file_path: str) str | None[source]

Get the MIME type of a file.

Parameters:

file_path (str) – Path to the file

Returns:

MIME type of the file

Return type:

str

kiosk_show_replacement.utils.ensure_directory_exists(directory_path: str) None[source]

Ensure that a directory exists, creating it if necessary.

Parameters:

directory_path (str) – Path to the directory

kiosk_show_replacement.utils.sanitize_filename(filename: str) str[source]

Sanitize a filename by removing potentially dangerous characters.

Parameters:

filename (str) – Original filename

Returns:

Sanitized filename

Return type:

str