Source code for signac_dashboard.modules.video_viewer

# Copyright (c) 2022 The Regents of the University of Michigan
# All rights reserved.
# This software is licensed under the BSD 3-Clause License.
import glob
import itertools
import os

from flask import render_template

from signac_dashboard.module import Module


[docs]class VideoViewer(Module): """Displays videos that match a glob. The VideoViewer module displays videos using an HTML ``<video>`` tag. The module defaults to showing all videos of MP4 or M4V types in the job or project directory. A filename or glob can be defined to select specific filenames, which may be of any format supported by your browser with the ``<video>`` tag. Each matching file yields a card. A "poster" can be defined, which shows a thumbnail with that filename before the video is started. Videos do not preload by default since file sizes can be large and there may be many videos on a page. To enable preloading, use the argument ``preload='auto'`` or ``preload='metadata'``. Multiple VideoViewer modules can be defined with different filenames or globs to enable/disable cards individually. :Example: .. code-block:: python from signac_dashboard.modules import VideoViewer video_mod = VideoViewer() # Shows all MP4/M4V videos video_mod = VideoViewer(name='Cool Science Video', context="ProjectContext", video_globs=['cool_science.mp4'], poster='cool_science_thumbnail.jpg', preload='none') :param context: Supports :code:`'JobContext'` and :code:`'ProjectContext'`. :type context: str :param video_globs: A list of glob expressions or exact filenames, relative to the job or project directory, to be displayed (default: :code:`['*.mp4', '*.m4v']`). :type video_globs: list :param preload: Option for preloading videos, one of :code:`'auto'`, :code:`'metadata'`, or :code:`'none'` (default: :code:`'none'`). :type preload: str :param poster: A path in the job directory or project directory for a poster image to be shown before a video begins playback (default: :code:`None`). :type poster: str :type sort_key: callable :param sort_key: Key to sort the video files, passed internally to :code:`sorted`. """ _supported_contexts = {"JobContext", "ProjectContext"} def __init__( self, name="Video Viewer", context="JobContext", template="cards/video_viewer.html", video_globs=("*.mp4", "*.m4v"), preload="none", # auto|metadata|none poster=None, sort_key=None, **kwargs, ): super().__init__( name=name, context=context, template=template, **kwargs, ) self.video_globs = video_globs self.preload = preload self.poster = poster self.sort_key = sort_key def get_cards(self, job_or_project): if self.context == "JobContext": jobid = job_or_project._id elif self.context == "ProjectContext": jobid = None def make_card(filename): if not job_or_project.isfile(filename): raise FileNotFoundError( "The filename {} could not be found " "for {}.".format( filename, "the project" if jobid is None else f"job {jobid}" ) ) return { "name": self.name + ": " + filename, "content": render_template( self.template, jobid=jobid, poster=self.poster if self.poster and job_or_project.isfile(self.poster) else None, preload=self.preload, filename=filename, ), } video_globs = [ glob.iglob(job_or_project.fn(video_glob)) for video_glob in self.video_globs ] video_files = itertools.chain(*video_globs) video_files = sorted(video_files, key=self.sort_key) for filepath in video_files: yield make_card(os.path.relpath(filepath, job_or_project.fn("")))