Блокнот разработчика
Генерация изображения предпросмотра из загруженного видео
Часто возникает необходимость создания картинки предпросмотра для загруженного видеоролика на сайте. Это удобнее, чем вручную создавать скриншот, особенно при загрузке множества файлов, а уж про автоматизированные задачи говорить и не приходится. А выводить ради каждого ролика флешплеер неэкономично. Ниже я даю собственное видение этого функционала:
class Resource(Publisher, CommentableModel, SortableModel):
title = models.CharField(max_length=255)
slug = models.SlugField()
attachment = models.FileField(upload_to=upload_file)
type = models.IntegerField(choices=TYPE_CHOICES, editable=False)
description = models.TextField(blank=True, default='')
date_created = models.DateTimeField(default=datetime.now, editable=False)
category = models.ManyToManyField(Category, related_name='resources')
snapshot = models.ImageField(
blank = True,
null = True,
upload_to = upload_snapshot,
help_text = _('Snapshot for resource, not required'),
)
class Video(Resource):
objects = VideoManager()
def get_type(self):
return FMT_VID
class Meta:
verbose_name = _('video')
verbose_name_plural = _('videos')
proxy = True
models.signals.pre_save.connect(new_video_thumbnail, sender=Video)
models.signals.post_save.connect(generate_video_thumbnail, sender=Video)
Как видно из кода, к модели Video присоединяется два сигнала — перед сохранением в базу данных и после.
Вот код самих сигналов:
def generate_thumbnail(source_file_path, tmp_file_path):
args = ['-y', '-i', source_file_path, '-vframes', '1', '-ss', '00:00:02', '-an',
'-vcodec', 'png', '-f', 'rawvideo', tmp_file_path]
if os.path.exists(tmp_file_path):
os.remove(tmp_file_path)
p = subprocess.Popen(args, executable='ffmpeg')
p.wait()
return tmp_file_path
def get_tmp_path(source_path):
return os.path.splitext(source_path)[0] + '.tmp'
def generate_video_thumbnail(sender, **kwargs):
instance = kwargs.get('instance', None)
created = kwargs.get('created', None)
if created:
instance.save()
elif os.path.exists(instance.snapshot.path):
tmp_file_path = get_tmp_path(instance.attachment.path)
os.remove(tmp_file_path)
def new_video_thumbnail(sender, **kwargs):
instance = kwargs.get('instance', None)
if os.path.exists(instance.attachment.path):
if instance.snapshot and os.path.exists(instance.snapshot.path):
os.remove(instance.snapshot.path)
tmp = generate_thumbnail(
source_file_path = instance.attachment.path,
tmp_file_path = get_tmp_path(instance.attachment.path)
)
source_filename = os.path.basename(instance.attachment.path)
snapshot_name = os.path.splitext(source_filename)[0] + '.png'
instance.snapshot = File(open(tmp), snapshot_name)
Всё волшебство происходит в методе generate_thumbnail, остальное разнообразие служит для корректной обработки создания нового экземпляра и редактирования существующего, когда изображение нужно сгенерировать заново, при замене видеоролика.
- 11 Сен 13:50
