angrybeanie_wagtail/env/lib/python3.12/site-packages/wagtailmedia/models.py

188 lines
5.4 KiB
Python
Raw Normal View History

2025-07-25 21:32:16 +10:00
import mimetypes
import os.path
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.validators import FileExtensionValidator, MinValueValidator
from django.db import models
from django.dispatch import Signal
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from taggit.managers import TaggableManager
from wagtail.models import CollectionMember, ReferenceIndex
from wagtail.search import index
from wagtail.search.queryset import SearchableQuerySetMixin
from wagtailmedia.settings import wagtailmedia_settings
ALLOWED_EXTENSIONS_THUMBNAIL = ["gif", "jpg", "jpeg", "png", "webp"]
class MediaType(models.TextChoices):
AUDIO = "audio", _("Audio file")
VIDEO = "video", _("Video file")
class MediaQuerySet(SearchableQuerySetMixin, models.QuerySet):
pass
class AbstractMedia(CollectionMember, index.Indexed, models.Model):
title = models.CharField(max_length=255, verbose_name=_("title"))
file = models.FileField(upload_to="media", verbose_name=_("file"))
type = models.CharField(
choices=MediaType.choices, max_length=255, blank=False, null=False
)
duration = models.FloatField(
blank=True,
default=0,
validators=[MinValueValidator(0)],
verbose_name=_("duration"),
help_text=_("Duration in seconds"),
)
width = models.PositiveIntegerField(null=True, blank=True, verbose_name=_("width"))
height = models.PositiveIntegerField(
null=True, blank=True, verbose_name=_("height")
)
thumbnail = models.FileField(
upload_to="media_thumbnails", blank=True, verbose_name=_("thumbnail")
)
created_at = models.DateTimeField(verbose_name=_("created at"), auto_now_add=True)
uploaded_by_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("uploaded by user"),
null=True,
blank=True,
editable=False,
on_delete=models.SET_NULL,
)
tags = TaggableManager(help_text=None, blank=True, verbose_name=_("tags"))
objects = MediaQuerySet.as_manager()
search_fields = CollectionMember.search_fields + [
index.SearchField("title", boost=10),
index.AutocompleteField("title", boost=10),
index.FilterField("title"),
index.RelatedFields(
"tags",
[
index.SearchField("name", boost=10),
index.AutocompleteField("name", boost=10),
],
),
index.FilterField("uploaded_by_user"),
]
admin_form_fields = (
"title",
"file",
"collection",
"duration",
"width",
"height",
"thumbnail",
"tags",
)
def __str__(self):
return self.title
@property
def icon(self):
return f"wagtailmedia-{self.type}"
@property
def filename(self):
return os.path.basename(self.file.name)
@property
def thumbnail_filename(self) -> str:
return os.path.basename(self.thumbnail.name) if self.thumbnail else ""
@property
def file_extension(self):
return os.path.splitext(self.filename)[1][1:]
@property
def url(self):
return self.file.url
@property
def sources(self):
return [
{
"src": self.url,
"type": mimetypes.guess_type(self.filename)[0]
or "application/octet-stream",
}
]
def get_usage(self):
return ReferenceIndex.get_references_to(self).group_by_source_object()
@property
def usage_url(self):
return reverse("wagtailmedia:media_usage", args=(self.id,))
def is_editable_by_user(self, user):
from wagtailmedia.permissions import permission_policy
return permission_policy.user_has_permission_for_instance(user, "change", self)
def clean(self, *args, **kwargs):
super().clean(*args, **kwargs)
if not self.duration:
self.duration = 0
if self.thumbnail:
validate = FileExtensionValidator(ALLOWED_EXTENSIONS_THUMBNAIL)
validate(self.thumbnail)
if self.type == "audio" and wagtailmedia_settings.AUDIO_EXTENSIONS:
validate = FileExtensionValidator(wagtailmedia_settings.AUDIO_EXTENSIONS)
validate(self.file)
elif self.type == "video" and wagtailmedia_settings.VIDEO_EXTENSIONS:
validate = FileExtensionValidator(wagtailmedia_settings.VIDEO_EXTENSIONS)
validate(self.file)
class Meta:
abstract = True
verbose_name = _("media")
verbose_name_plural = _("media items")
class Media(AbstractMedia):
pass
def get_media_model():
from django.apps import apps
from wagtailmedia.settings import wagtailmedia_settings
try:
app_label, model_name = wagtailmedia_settings.MEDIA_MODEL.split(".")
except AttributeError:
return Media
except ValueError as err:
raise ImproperlyConfigured(
"WAGTAILMEDIA[\"MEDIA_MODEL\"] must be of the form 'app_label.model_name'"
) from err
media_model = apps.get_model(app_label, model_name)
if media_model is None:
raise ImproperlyConfigured(
f"WAGTAILMEDIA[\"MEDIA_MODEL\"] refers to model '{wagtailmedia_settings.MEDIA_MODEL}' that has not been installed"
)
return media_model
# Provides `request` as an argument
media_served = Signal()