diff --git a/client/components/editor/Video.tsx b/client/components/editor/Video.tsx index fc348c021..a70179e54 100644 --- a/client/components/editor/Video.tsx +++ b/client/components/editor/Video.tsx @@ -9,7 +9,7 @@ import CameraIcon from 'icons/camera.svg'; export default function Video(props) { const sampleFields = { - posterFrame: document.getElementById('id_poster_frame') as HTMLInputElement, + sampleStart: document.getElementById('id_sample_start') as HTMLInputElement, }; const settings = useContext(FinderSettings); const style = { @@ -36,7 +36,7 @@ export default function Video(props) { const setPosterFrame = () => { const currentTime = videoRef.current.getCurrentTime(); - sampleFields.posterFrame.value = currentTime; + sampleFields.sampleStart.value = currentTime; } const controlButtons = [(isPlaying ? diff --git a/client/components/folder/Video.tsx b/client/components/folder/Video.tsx index 7c5d5d063..a62ba0966 100644 --- a/client/components/folder/Video.tsx +++ b/client/components/folder/Video.tsx @@ -16,6 +16,7 @@ export default function Video(props) { } return ( + props.sampleUrl ? onPlayPause(false)} onMouseLeave={() => onPlayPause(true)} @@ -26,6 +27,7 @@ export default function Video(props) { ref={videoRef} width="100%" height="100%" - /> + /> : + ); } diff --git a/finder/contrib/video/admin.py b/finder/contrib/video/admin.py index 6e283961f..d458bd47a 100644 --- a/finder/contrib/video/admin.py +++ b/finder/contrib/video/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.forms.fields import CharField, FloatField from django.forms.widgets import TextInput, NumberInput +from django.utils.translation import gettext_lazy as _ from entangled.forms import EntangledModelForm @@ -12,15 +13,15 @@ class VideoForm(EntangledModelForm): name = CharField( widget=TextInput(attrs={'size': 100}), ) - poster_frame = FloatField( - initial=0, + sample_start = FloatField( + label=_("Poster timestamp"), widget=NumberInput(attrs={'readonly': 'readonly'}), required=False, ) class Meta: model = VideoFileModel - entangled_fields = {'meta_data': ['poster_frame']} + entangled_fields = {'meta_data': ['sample_start']} untangled_fields = ['name'] class Media: diff --git a/finder/contrib/video/models.py b/finder/contrib/video/models.py index 151a4b620..d7b884d41 100644 --- a/finder/contrib/video/models.py +++ b/finder/contrib/video/models.py @@ -25,13 +25,13 @@ class Meta: app_label = 'finder' def get_sample_url(self): - poster_frame = self.meta_data.get('poster_frame') - if poster_frame is None: + sample_start = self.meta_data.get('sample_start') + if sample_start is None: return - sample_path = self.get_sample_path(poster_frame) + sample_path = self.get_sample_path(sample_start) if not default_storage.exists(sample_path): (default_storage.base_location / sample_path.parent).mkdir(parents=True, exist_ok=True) - stream = ffmpeg.input(default_storage.path(self.file_path), ss=poster_frame) + stream = ffmpeg.input(default_storage.path(self.file_path), ss=sample_start) video_stream = ffmpeg.trim(stream.video, duration=SAMPLE_DURATION) video_stream = ffmpeg.filter(video_stream, 'crop', 'min(iw,ih)', 'min(iw,ih)') video_stream = ffmpeg.filter(video_stream, 'scale', self.thumbnail_size, -1) @@ -45,32 +45,31 @@ def get_sample_url(self): return default_storage.url(sample_path) def get_thumbnail_url(self): - poster_frame = self.meta_data.get('poster_frame') - if poster_frame is None: + sample_start = self.meta_data.get('sample_start') + if sample_start is None: return self.fallback_thumbnail_url - poster_path = self.get_sample_path(poster_frame, suffix='.jpg') + poster_path = self.get_sample_path(sample_start, suffix='.jpg') if not default_storage.exists(poster_path): (default_storage.base_location / poster_path.parent).mkdir(parents=True, exist_ok=True) - stream = ffmpeg.input(default_storage.path(self.file_path), ss=poster_frame) - stream = ffmpeg.filter(stream, 'crop', 'min(iw,ih)', 'min(iw,ih)') - stream = ffmpeg.filter(stream, 'scale', self.thumbnail_size, -1) - stream = ffmpeg.output(stream, default_storage.path(poster_path), vframes=1) + stream = ffmpeg.input(default_storage.path(self.file_path), ss=sample_start) + video_stream = ffmpeg.filter(stream.video, 'crop', 'min(iw,ih)', 'min(iw,ih)') + video_stream = ffmpeg.filter(video_stream, 'scale', self.thumbnail_size, -1) + stream = ffmpeg.output(video_stream, default_storage.path(poster_path), vframes=1) try: ffmpeg.run(stream) except ffmpeg.Error as exp: - print(exp) return self.fallback_thumbnail_url return default_storage.url(poster_path) - def get_sample_path(self, poster_frame, suffix=None): + def get_sample_path(self, sample_start, suffix=None): id = str(self.id) thumbnail_folder = self.filer_public_thumbnails / f'{id[0:2]}/{id[2:4]}/{id}' thumbnail_path = Path(self.file_name) - poster_frame = int(poster_frame * 100) - poster_path_template = '{stem}__{poster_frame}{suffix}' + sample_start = int(sample_start * 100) + poster_path_template = '{stem}__{sample_start}{suffix}' suffix = suffix or thumbnail_path.suffix return thumbnail_folder / poster_path_template.format( stem=thumbnail_path.stem, - poster_frame=poster_frame, + sample_start=sample_start, suffix=suffix, )