Ejemplo n.º 1
0
class BaseFileModel(models.Model):
    name = models.CharField(_('Name'), max_length=255)
    description = models.CharField(max_length=255, blank=True)
    folder = select2_fields.ForeignKey(UserFolder)
    uploaded_at = models.DateTimeField(auto_now_add=True)
    created_by = select2_fields.ForeignKey(
        User,
        related_name='%(app_label)s_%(class)s_created',
        on_delete=models.CASCADE)

    def save(self, **kwargs):
        path, ext = os.path.splitext(self.file.name)
        # if not self.name or self.name == "":
        self.name = os.path.basename(path)
        return super(BaseFileModel, self).save(**kwargs)

    def class_name(self):
        return self.__class__.__name__

    def file_exist(self):
        return (self.file and os.path.isfile(self.file.path))

    class Meta:
        abstract = True
        ordering = ['name']
Ejemplo n.º 2
0
class Broadcaster(models.Model):
    name = models.CharField(_('name'), max_length=200, unique=True)
    slug = models.SlugField(
        _('Slug'),
        unique=True,
        max_length=200,
        help_text=_(
            u'Used to access this instance, the "slug" is a short label ' +
            'containing only letters, numbers, underscore or dash top.'),
        editable=False,
        default="")  # default empty, fill it in save
    building = models.ForeignKey('Building', verbose_name=_('Building'))
    description = RichTextField(_('description'),
                                config_name='complete',
                                blank=True)
    poster = models.ForeignKey(CustomImageModel,
                               models.SET_NULL,
                               blank=True,
                               null=True,
                               verbose_name=_('Poster'))
    url = models.URLField(_('URL'),
                          help_text=_('Url of the stream'),
                          unique=True)
    video_on_hold = select2_fields.ForeignKey(
        Video,
        help_text=_(
            'This video will be displayed when there is no live stream.'),
        blank=True,
        null=True,
        verbose_name=_('Video on hold'))
    status = models.BooleanField(
        default=0,
        help_text=_('Check if the broadcaster is currently sending stream.'))
    is_restricted = models.BooleanField(
        verbose_name=_(u'Restricted access'),
        help_text=_('Live is accessible only to authenticated users.'),
        default=False)

    def __str__(self):
        return "%s - %s" % (self.name, self.url)

    def get_poster_url(self):
        if self.poster:
            return self.poster.file.url
        else:
            thumbnail_url = ''.join([settings.STATIC_URL, DEFAULT_THUMBNAIL])
            return thumbnail_url

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Broadcaster, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Broadcaster")
        verbose_name_plural = _("Broadcasters")
        ordering = ['building', 'name']

    @property
    def sites(self):
        return self.building.sites
Ejemplo n.º 3
0
class Recording(models.Model):
    recorder = models.ForeignKey(
        Recorder,
        on_delete=models.CASCADE,
        verbose_name=_("Recorder"),
        default=DEFAULT_RECORDER_ID,
        help_text=_("Recorder that made this recording."),
    )
    user = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={"is_staff": True},
        default=DEFAULT_RECORDER_USER_ID,
        help_text=_("User who has made the recording"),
    )
    title = models.CharField(_("title"), max_length=200)
    type = models.CharField(
        _("Recording Type"),
        max_length=50,
        choices=RECORDER_TYPE,
        default=RECORDER_TYPE[0][0],
    )
    source_file = models.FilePathField(
        max_length=200, path=DEFAULT_RECORDER_PATH, unique=True, recursive=True
    )
    comment = models.TextField(_("Comment"), blank=True, default="")
    date_added = models.DateTimeField("date added", default=timezone.now, editable=False)

    @property
    def sites(self):
        return self.recorder.sites

    def __str__(self):
        return "%s" % self.title

    class Meta:
        verbose_name = _("Recording")
        verbose_name_plural = _("Recordings")

    def save(self, *args, **kwargs):
        super(Recording, self).save(*args, **kwargs)

    def clean(self):
        msg = list()
        msg = self.verify_attributs()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_attributs(self):
        msg = list()
        if not self.type:
            msg.append(_("Please specify a type."))
        elif self.type not in dict(RECORDER_TYPE):
            msg.append(_("Please use the only type in type choices."))
        if not self.source_file:
            msg.append(_("Please specify a source file."))
        elif not os.path.exists(self.source_file):
            msg.append(_("Source file doesn't exists"))
        return msg
Ejemplo n.º 4
0
class UserFolder(models.Model):
    name = models.CharField(_("Name"), max_length=255)
    # parent = models.ForeignKey(
    #    'self', blank=True, null=True, related_name='children')
    owner = select2_fields.ForeignKey(User, verbose_name=_("Owner"))
    created_at = models.DateTimeField(auto_now_add=True)
    access_groups = select2_fields.ManyToManyField(
        "authentication.AccessGroup",
        blank=True,
        verbose_name=_("Groups"),
        help_text=_("Select one or more groups who"
                    " can access in read only to this folder"),
    )
    users = select2_fields.ManyToManyField(
        User,
        blank=True,
        verbose_name=_("Users"),
        related_name="shared_files",
        help_text=_("Select one or more users who"
                    " can access in read only to this folder"),
    )

    class Meta:
        unique_together = (("name", "owner"), )
        verbose_name = _("User directory")
        verbose_name_plural = _("User directories")
        ordering = ["name"]
        app_label = "podfile"

    def clean(self):
        if self.name == "Home":
            same_home = UserFolder.objects.filter(owner=self.owner,
                                                  name="Home")
            if same_home:
                raise ValidationError(
                    "A user cannot have have multiple home directories.")

    def __str__(self):
        return "{0}".format(self.name)

    def get_all_files(self):
        file_list = self.customfilemodel_set.all()
        image_list = self.customimagemodel_set.all()
        result_list = sorted(chain(image_list, file_list),
                             key=attrgetter("uploaded_at"))
        return result_list

    def delete(self):
        for file in self.customfilemodel_set.all():
            file.delete()
        for img in self.customimagemodel_set.all():
            img.delete()
        super(UserFolder, self).delete()
Ejemplo n.º 5
0
class Attendee(models.Model):
    # Meeting for which this user was a moderator
    meeting = models.ForeignKey(Meeting,
                                on_delete=models.CASCADE,
                                verbose_name=_("Meeting"))
    # Full name (First_name Last_name) of the user from BigBlueButton
    full_name = models.CharField(
        _("Full name"),
        max_length=200,
        help_text=_("Full name of the user from BBB."),
    )
    # Role of this user (only MODERATOR for the moment)
    role = models.CharField(
        _("User role"),
        max_length=200,
        help_text=_("Role of the user from BBB."),
    )
    # Username of this user, if the BBB user was translated with a Pod user
    # Redundant information with user, but can be useful.
    username = models.CharField(
        _("Username / User id"),
        max_length=150,
        help_text=_(
            "Username / User id, if the BBB user was matching a Pod user."),
    )

    # Pod user, if the BBB user was translated with a Pod user
    user = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={"is_staff": True},
        verbose_name=_("User"),
        null=True,
        blank=True,
        help_text=_("User from the Pod database, if user found."),
    )

    def __unicode__(self):
        return "%s - %s" % (self.full_name, self.role)

    def __str__(self):
        return "%s - %s" % (self.full_name, self.role)

    def save(self, *args, **kwargs):
        super(Attendee, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Attendee")
        verbose_name_plural = _("Attendees")
        ordering = ["full_name"]
Ejemplo n.º 6
0
class PlaylistElement(models.Model):
    playlist = select2_fields.ForeignKey(Playlist, verbose_name=_('Playlist'))
    video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
    position = models.PositiveSmallIntegerField(
        _('Position'),
        default=1,
        help_text=_('Position of the video in a playlist.'))

    class Meta:
        unique_together = (
            'playlist',
            'video',
        )
        ordering = ['position', 'id']
        verbose_name = _('Playlist element')
        verbose_name_plural = _('Playlist elements')

    def clean(self):
        if self.video.is_draft:
            raise ValidationError(
                _('A video in draft mode cannot be added to a playlist.'))
        if self.video.password:
            raise ValidationError(
                _('A video with a password cannot be added to a playlist.'))

    def save(self, *args, **kwargs):
        self.full_clean()
        return super(PlaylistElement, self).save(*args, **kwargs)

    def delete(self):
        elements = PlaylistElement.objects.filter(playlist=self.playlist,
                                                  position__gt=self.position)
        for element in elements:
            element.position = element.position - 1
            element.save()
        super(PlaylistElement, self).delete()
Ejemplo n.º 7
0
class Document(models.Model):
    video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
    document = models.ForeignKey(CustomFileModel,
                                 null=True,
                                 blank=True,
                                 verbose_name=_('Document'))

    class Meta:
        verbose_name = _('Document')
        verbose_name_plural = _('Documents')

    @property
    def sites(self):
        return self.video.sites

    def clean(self):
        msg = list()
        msg = self.verify_document() + self.verify_not_same_document()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_document(self):
        msg = list()
        if not self.document:
            msg.append(_('Please enter a document.'))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_not_same_document(self):
        msg = list()
        list_doc = Document.objects.filter(video=self.video)
        if self.id:
            list_doc = list_doc.exclude(id=self.id)
        if len(list_doc) > 0:
            for element in list_doc:
                if self.document == element.document:
                    msg.append(
                        _('This document is already contained ' +
                          'in the list'))
            if len(msg) > 0:
                return msg
        return list()

    def __str__(self):
        return u'Document: {0} - Video: {1}'.format(self.document.name,
                                                    self.video)
Ejemplo n.º 8
0
class UserFolder(models.Model):
    name = models.CharField(_('Name'), max_length=255)
    # parent = models.ForeignKey(
    #    'self', blank=True, null=True, related_name='children')
    owner = select2_fields.ForeignKey(User, verbose_name=_('Owner'))
    created_at = models.DateTimeField(auto_now_add=True)
    groups = select2_fields.ManyToManyField(
        Group, blank=True, verbose_name=_('Groups'),
        help_text=_('Select one or more groups who'
                    ' can access in read only to this folder'))
    users = select2_fields.ManyToManyField(
        User, blank=True, verbose_name=_('Users'),
        related_name="shared_files",
        help_text=_('Select one or more users who'
                    ' can access in read only to this folder'))

    class Meta:
        unique_together = (('name', 'owner'),)
        verbose_name = _('User directory')
        verbose_name_plural = _('User directories')
        ordering = ['name']
        app_label = 'podfile'

    def clean(self):
        if self.name == 'Home':
            same_home = UserFolder.objects.filter(
                owner=self.owner, name='Home')
            if same_home:
                raise ValidationError(
                    'A user cannot have have multiple home directories.')

    def __str__(self):
        return '{0}'.format(self.name)

    def get_all_files(self):
        file_list = self.customfilemodel_set.all()
        image_list = self.customimagemodel_set.all()
        result_list = sorted(
            chain(image_list, file_list),
            key=attrgetter('uploaded_at'))
        return result_list

    def delete(self):
        for file in self.customfilemodel_set.all():
            file.delete()
        for img in self.customimagemodel_set.all():
            img.delete()
        super(UserFolder, self).delete()
Ejemplo n.º 9
0
class User(models.Model):
    # User who performed the session in BigBlueButton
    meeting = models.ForeignKey(Meeting,
                                on_delete=models.CASCADE,
                                verbose_name=_('Meeting'))
    # Full name (First_name Last_name) of the user from BigBlueButton
    full_name = models.CharField(_('Full name'), max_length=200, help_text=_(
        'Full name of the user from BBB.')
    )
    # Role of this user (only MODERATOR for the moment)
    role = models.CharField(_('User role'), max_length=200, help_text=_(
        'Role of the user from BBB.')
    )
    # Username of this user, if the BBB user was translated with a Pod user
    # Redundant information with user, but can be useful.
    username = models.CharField(_('Username / User id'),
                                max_length=150, help_text=_(
        'Username / User id, if the BBB user was matching a Pod user.')
    )

    # Pod user, if the BBB user was translated with a Pod user
    user = select2_fields.ForeignKey(
        User, on_delete=models.CASCADE,
        limit_choices_to={'is_staff': True},
        verbose_name=_('User'), null=True, blank=True, help_text=_(
            'User from the Pod database, if user found.')
    )

    def __unicode__(self):
        return "%s - %s" % (self.full_name, self.role)

    def __str__(self):
        return "%s - %s" % (self.full_name, self.role)

    def save(self, *args, **kwargs):
        super(User, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("User")
        verbose_name_plural = _("Users")
        ordering = ['full_name']
Ejemplo n.º 10
0
class Contributor(models.Model):

    video = select2_fields.ForeignKey(Video, verbose_name=_('video'))
    name = models.CharField(_('lastname / firstname'), max_length=200)
    email_address = models.EmailField(_('mail'),
                                      null=True,
                                      blank=True,
                                      default='')
    role = models.CharField(_(u'role'),
                            max_length=200,
                            choices=ROLE_CHOICES,
                            default='author')
    weblink = models.URLField(_(u'Web link'),
                              max_length=200,
                              null=True,
                              blank=True)

    class Meta:
        verbose_name = _('Contributor')
        verbose_name_plural = _('Contributors')

    @property
    def sites(self):
        return self.video.sites

    def clean(self):
        msg = list()
        msg = self.verify_attributs() + self.verify_not_same_contributor()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_attributs(self):
        msg = list()
        if not self.name or self.name == '':
            msg.append(_('Please enter a name.'))
        elif len(self.name) < 2 or len(self.name) > 200:
            msg.append(_('Please enter a name from 2 to 200 caracters.'))
        if self.weblink and len(self.weblink) > 200:
            msg.append(
                _('You cannot enter a weblink with more than 200 caracters.'))
        if not self.role:
            msg.append(_('Please enter a role.'))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_not_same_contributor(self):
        msg = list()
        list_contributor = Contributor.objects.filter(video=self.video)
        if self.id:
            list_contributor = list_contributor.exclude(id=self.id)
        if len(list_contributor) > 0:
            for element in list_contributor:
                if self.name == element.name and self.role == element.role:
                    msg.append(
                        _('There is already a contributor with the same ' +
                          'name and role in the list.'))
                    return msg
        return list()

    def __str__(self):
        return u'Video:{0} - Name:{1} - Role:{2}'.format(
            self.video, self.name, self.role)

    def get_base_mail(self):
        data = base64.b64encode(self.email_address.encode())
        return data

    def get_noscript_mail(self):
        return self.email_address.replace('@', "__AT__")
Ejemplo n.º 11
0
class Overlay(models.Model):

    POSITION_CHOICES = (
        ('top-left', _(u'top-left')),
        ('top', _(u'top')),
        ('top-right', _(u'top-right')),
        ('right', _(u'right')),
        ('bottom-right', _(u'bottom-right')),
        ('bottom', _(u'bottom')),
        ('bottom-left', _(u'bottom-left')),
        ('left', _(u'left')),
    )

    video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
    title = models.CharField(_('Title'), max_length=100)
    slug = models.SlugField(
        _('Slug'),
        unique=True,
        max_length=105,
        help_text=_('Used to access this instance, the "slug" is a short' +
                    ' label containing only letters, numbers, underscore' +
                    ' or dash top.'),
        editable=False)
    time_start = models.PositiveIntegerField(
        _('Start time'),
        default=1,
        help_text=_(u'Start time of the overlay, in seconds.'))
    time_end = models.PositiveIntegerField(
        _('End time'),
        default=2,
        help_text=_(u'End time of the overlay, in seconds.'))
    content = RichTextField(_('Content'),
                            null=False,
                            blank=False,
                            config_name='complete')
    position = models.CharField(_('Position'),
                                max_length=100,
                                null=True,
                                blank=False,
                                choices=POSITION_CHOICES,
                                default='bottom-right',
                                help_text=_(u'Position of the overlay.'))
    background = models.BooleanField(
        _('Show background'),
        default=True,
        help_text=_(u'Show the background of the overlay.'))

    @property
    def sites(self):
        return self.video.sites

    class Meta:
        verbose_name = _('Overlay')
        verbose_name_plural = _('Overlays')
        ordering = ['time_start']

    def clean(self):
        msg = list()
        msg += self.verify_title_items()
        msg += self.verify_time_items()
        msg += self.verify_overlap()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_title_items(self):
        msg = list()
        if not self.title or self.title == '':
            msg.append(_('Please enter a title.'))
        elif len(self.title) < 2 or len(self.title) > 100:
            msg.append(_('Please enter a title from 2 to 100 characters.'))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_time_items(self):
        msg = list()
        if self.time_start > self.time_end:
            msg.append(
                _('The value of the time start field is greater than ' +
                  'the value of the end time field.'))
        elif self.time_end > self.video.duration:
            msg.append(
                _('The value of time end field is greater than the ' +
                  'video duration.'))
        elif self.time_start == self.time_end:
            msg.append(
                _('Time end field and time start field can\'t ' + 'be equal.'))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_overlap(self):
        msg = list()
        instance = None
        if self.slug:
            instance = Overlay.objects.get(slug=self.slug)
        list_overlay = Overlay.objects.filter(video=self.video)
        if instance:
            list_overlay = list_overlay.exclude(id=instance.id)
        if len(list_overlay) > 0:
            for element in list_overlay:
                if not (self.time_start < element.time_start
                        and self.time_end <= element.time_start
                        or self.time_start >= element.time_end
                        and self.time_end > element.time_end):
                    msg.append(
                        _("There is an overlap with the overlay {0},"
                          " please change time start and/or "
                          "time end values.").format(element.title))
            if len(msg) > 0:
                return msg
        return list()

    def save(self, *args, **kwargs):
        newid = -1
        if not self.id:
            try:
                newid = get_nextautoincrement(Overlay)
            except Exception:
                try:
                    newid = Overlay.objects.latest('id').id
                    newid += 1
                except Exception:
                    newid = 1
        else:
            newid = self.id
        newid = '{0}'.format(newid)
        self.slug = '{0}-{1}'.format(newid, slugify(self.title))
        super(Overlay, self).save(*args, **kwargs)

    def __str__(self):
        return 'Overlay: {0} - Video: {1}'.format(self.title, self.video)
Ejemplo n.º 12
0
class Track(models.Model):

    video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
    kind = models.CharField(_('Kind'),
                            max_length=10,
                            choices=KIND_CHOICES,
                            default='subtitles')
    lang = models.CharField(_('Language'), max_length=2, choices=LANG_CHOICES)
    src = models.ForeignKey(CustomFileModel,
                            blank=True,
                            null=True,
                            verbose_name=_('Subtitle file'))

    @property
    def sites(self):
        return self.video.sites

    def get_label_lang(self):
        return "%s" % LANG_CHOICES_DICT[self.lang]

    class Meta:
        verbose_name = _('Track')
        verbose_name_plural = _('Tracks')

    def clean(self):
        msg = list()
        msg = self.verify_attributs() + self.verify_not_same_track()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_attributs(self):
        msg = list()
        if not self.kind:
            msg.append(_('Please enter a kind.'))
        elif self.kind != 'subtitles' and self.kind != 'captions':
            msg.append(_('Please enter a correct kind.'))
        if not self.lang:
            msg.append(_('Please enter a language.'))
        if not self.src:
            msg.append(_('Please specify a track file.'))
        elif 'vtt' not in self.src.file_type:
            msg.append(_('Only ".vtt" format is allowed.'))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_not_same_track(self):
        msg = list()
        list_track = Track.objects.filter(video=self.video)
        if self.id:
            list_track = list_track.exclude(id=self.id)
        if len(list_track) > 0:
            for element in list_track:
                if self.kind == element.kind and self.lang == element.lang:
                    msg.append(
                        _('There is already a subtitle with the ' +
                          'same kind and language in the list.'))
                    return msg
        return list()

    def __str__(self):
        return u'{0} - File: {1} - Video: {2}'.format(self.kind, self.src.name,
                                                      self.video)
Ejemplo n.º 13
0
class Meeting(models.Model):
    # Meeting id for the BBB session
    meeting_id = models.CharField(
        _('Meeting id'), max_length=200,
        help_text=_('Id of the BBB meeting.')
    )
    # Internal meeting id for the BBB session
    internal_meeting_id = models.CharField(
        _('Internal meeting id'),
        max_length=200, help_text=_('Internal id of the BBB meeting.')
    )
    # Meeting name for the BBB session
    meeting_name = models.CharField(
        _('Meeting name'),
        max_length=200, help_text=_('Name of the BBB meeting.')
    )
    # Date of the BBB session
    session_date = models.DateTimeField(
        _('Session date'), default=timezone.now)
    # Encoding step / status of the process. Possible values are :
    #  - 0 : default (Publish is possible)
    #  - 1 : Waiting for encoding
    #  - 2 : Encoding in progress
    #  - 3 : Already published
    encoding_step = models.IntegerField(
        _('Encoding step'),
        help_text=_('Encoding step for conversion of the '
                    'BBB presentation to video file.'),
        default=0)
    # Is this meeting was recorded in BigBlueButton ?
    recorded = models.BooleanField(
        _('Recorded'),
        help_text=_('BBB presentation recorded ?'),
        default=False)
    # Is the recording of the presentation is available in BigBlueButton ?
    recording_available = models.BooleanField(
        _('Recording available'),
        help_text=_('BBB presentation recording is available ?'),
        default=False)
    # URL of the recording of the BigBlueButton presentation
    recording_url = models.CharField(
        _('Recording url'),
        help_text=_('URL of the recording of the BBB presentation.'),
        max_length=200
    )
    # URL of the recording thumbnail of the BigBlueButton presentation
    thumbnail_url = models.CharField(
        _('Thumbnail url'),
        help_text=_('URL of the recording thumbnail of the BBB presentation.'),
        max_length=200
    )
    # User who converted the BigBlueButton presentation to video file
    encoded_by = select2_fields.ForeignKey(
        User, on_delete=models.CASCADE,
        limit_choices_to={'is_staff': True},
        verbose_name=_('User'), null=True, blank=True, help_text=_(
            'User who converted the BBB presentation to video file.')
    )

    def __unicode__(self):
        return "%s - %s" % (self.meeting_name, self.meeting_id)

    def __str__(self):
        return "%s - %s" % (self.meeting_name, self.meeting_id)

    def save(self, *args, **kwargs):
        super(Meeting, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Meeting")
        verbose_name_plural = _("Meetings")
        ordering = ['session_date']
Ejemplo n.º 14
0
class Recorder(models.Model):
    # Recorder name
    name = models.CharField(_("name"), max_length=200, unique=True)
    # Description of the recorder
    description = RichTextField(_("description"), config_name="complete", blank=True)
    # IP address of the recorder
    address_ip = models.GenericIPAddressField(
        _("Address IP"), unique=True, help_text=_("IP address of the recorder.")
    )
    # Salt for
    salt = models.CharField(
        _("salt"), max_length=50, blank=True, help_text=_("Recorder salt.")
    )

    # Recording type (video, AUdioVideoCasst, etc)
    recording_type = models.CharField(
        _("Recording Type"),
        max_length=50,
        choices=RECORDER_TYPE,
        default=RECORDER_TYPE[0][0],
    )
    # Manager of the recorder who received mails
    user = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={"is_staff": True},
        help_text=_(
            "Manager of this recorder. This manager will receive recorder "
            "emails and he will be the owner of the published videos. If no "
            "user is selected, this recorder will use manual assign system."
        ),
        verbose_name=_("User"),
        null=True,
        blank=True,
    )
    # Additionnal additional_users
    additional_users = select2_fields.ManyToManyField(
        User,
        blank=True,
        ajax=True,
        js_options={"width": "off"},
        verbose_name=_("Additional users"),
        search_field=select_recorder_user(),
        related_name="users_recorders",
        help_text=_(
            "You can add additionals users to the recorder. They "
            "will become the additionnals owners of the published videos "
            "and will have the same rights as the owner except that they "
            "can't delete the published videos."
        ),
    )
    # Default type of published videos by this recorder
    type = models.ForeignKey(
        Type, on_delete=models.CASCADE, help_text=_("Video type by default.")
    )
    is_draft = models.BooleanField(
        verbose_name=_("Draft"),
        help_text=_(
            "If this box is checked, "
            "the video will be visible and accessible only by you "
            "and the additional owners."
        ),
        default=True,
    )
    is_restricted = models.BooleanField(
        verbose_name=_("Restricted access"),
        help_text=_(
            "If this box is checked, "
            "the video will only be accessible to authenticated users."
        ),
        default=False,
    )
    restrict_access_to_groups = select2_fields.ManyToManyField(
        Group,
        blank=True,
        verbose_name=_("Groups"),
        help_text=_("Select one or more groups who can access to this video"),
    )
    password = models.CharField(
        _("password"),
        help_text=_("Viewing this video will not be possible without this password."),
        max_length=50,
        blank=True,
        null=True,
    )
    cursus = models.CharField(
        _("University course"),
        max_length=1,
        choices=CURSUS_CODES,
        default="0",
        help_text=_("Select an university course as audience target of the content."),
    )
    main_lang = models.CharField(
        _("Main language"),
        max_length=2,
        choices=LANG_CHOICES,
        default=get_language(),
        help_text=_("Select the main language used in the content."),
    )
    transcript = models.BooleanField(
        _("Transcript"),
        default=False,
        help_text=_("Check this box if you want to transcript the audio. (beta version)"),
    )
    tags = TagField(
        help_text=_(
            "Separate tags with spaces, "
            "enclose the tags consist of several words in quotation marks."
        ),
        verbose_name=_("Tags"),
    )
    discipline = select2_fields.ManyToManyField(
        Discipline, blank=True, verbose_name=_("Disciplines")
    )
    licence = models.CharField(
        _("Licence"),
        max_length=8,
        choices=LICENCE_CHOICES,
        blank=True,
        null=True,
    )
    channel = select2_fields.ManyToManyField(
        Channel, verbose_name=_("Channels"), blank=True
    )
    theme = models.ManyToManyField(
        Theme,
        verbose_name=_("Themes"),
        blank=True,
        help_text=_(
            'Hold down "Control", or "Command" ' "on a Mac, to select more than one."
        ),
    )
    allow_downloading = models.BooleanField(
        _("allow downloading"),
        default=False,
        help_text=_("Check this box if you to allow downloading of the encoded files"),
    )
    is_360 = models.BooleanField(
        _("video 360"),
        default=False,
        help_text=_("Check this box if you want to use the 360 player for the video"),
    )
    disable_comment = models.BooleanField(
        _("Disable comment"),
        help_text=_("Allows you to turn off all comments on this video."),
        default=False,
    )

    # Directory name where videos of this recorder are published
    directory = models.CharField(
        _("Publication directory"),
        max_length=50,
        unique=True,
        help_text=_("Basic directory containing the videos published by the recorder."),
    )
    sites = models.ManyToManyField(Site)

    def __unicode__(self):
        return "%s - %s" % (self.name, self.address_ip)

    def __str__(self):
        return "%s - %s" % (self.name, self.address_ip)

    def ipunder(self):
        return self.address_ip.replace(".", "_")

    def save(self, *args, **kwargs):
        super(Recorder, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Recorder")
        verbose_name_plural = _("Recorders")
        ordering = ["name"]
Ejemplo n.º 15
0
class Livestream(models.Model):
    # Meeting
    meeting = models.ForeignKey(Meeting,
                                on_delete=models.CASCADE,
                                verbose_name=_("Meeting"))
    # Start date of the live
    start_date = models.DateTimeField(
        _("Start date"),
        default=timezone.now,
        help_text=_("Start date of the live."),
    )
    # End date of the live
    end_date = models.DateTimeField(
        _("End date"),
        null=True,
        blank=True,
        help_text=_("End date of the live."),
    )
    # Live status
    STATUS = (
        (0, _("Live not started")),
        (1, _("Live in progress")),
        (2, _("Live stopped")),
    )
    status = models.IntegerField(_("Live status"), choices=STATUS, default=0)
    # Server/Process performing the live
    server = models.CharField(
        _("Server"),
        max_length=20,
        null=True,
        blank=True,
        help_text=_("Server/process performing the live."),
    )
    # User that want to perform the live
    user = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={"is_staff": True},
        verbose_name=_("User"),
        null=True,
        blank=True,
        help_text=_("Username / User id, that want to perform the live."),
    )
    # Restricted access to the created live
    is_restricted = models.BooleanField(
        verbose_name=_("Restricted access"),
        help_text=_("Is live only accessible to authenticated users?"),
        default=False,
    )
    # Broadcaster in charge to perform the live
    broadcaster_id = models.IntegerField(
        null=True,
        blank=True,
        verbose_name=_("Broadcaster"),
        help_text=_("Broadcaster in charge to perform live."),
    )
    # If the user wants that show the public chat in the live
    show_chat = models.BooleanField(
        verbose_name=_("Show public chat"),
        help_text=_("Do you want to show the public chat in the live?"),
        default=True,
    )
    # If the user wants to download the video of this meeting after the live
    download_meeting = models.BooleanField(
        verbose_name=_("Save meeting in My videos"),
        help_text=_(
            "Do you want to save the video of "
            'this meeting, at the end of the live, directly in "My videos"?'),
        default=False,
    )
    # If the user wants that students have a chat in the live page
    enable_chat = models.BooleanField(
        verbose_name=_("Enable chat"),
        help_text=_(
            "Do you want a chat on the live page "
            "for students? Messages sent in this live page's chat will "
            "end up in BigBlueButton's public chat."),
        default=False,
    )
    # Redis hostname, useful for chat
    redis_hostname = models.CharField(
        _("Redis hostname"),
        max_length=200,
        null=True,
        blank=True,
        help_text=_("Redis hostname, useful for chat"),
    )
    # Redis port, useful for chat
    redis_port = models.IntegerField(
        _("Redis port"),
        null=True,
        blank=True,
        help_text=_("Redis port, useful for chat"),
    )
    # Redis channel, useful for chat
    redis_channel = models.CharField(
        _("Redis channel"),
        max_length=200,
        null=True,
        blank=True,
        help_text=_("Redis channel, useful for chat"),
    )

    def __unicode__(self):
        return "%s - %s" % (self.meeting, self.status)

    def __str__(self):
        return "%s - %s" % (self.meeting, self.status)

    def save(self, *args, **kwargs):
        super(Livestream, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Livestream")
        verbose_name_plural = _("Livestreams")
        ordering = ["start_date"]
Ejemplo n.º 16
0
class Meeting(models.Model):
    # Meeting id for the BBB session
    meeting_id = models.CharField(_("Meeting id"),
                                  max_length=200,
                                  help_text=_("Id of the BBB meeting."))
    # Internal meeting id for the BBB session
    internal_meeting_id = models.CharField(
        _("Internal meeting id"),
        max_length=200,
        help_text=_("Internal id of the BBB meeting."),
    )
    # Meeting name for the BBB session
    meeting_name = models.CharField(
        _("Meeting name"),
        max_length=200,
        help_text=_("Name of the BBB meeting."),
    )
    # Date of the BBB session
    session_date = models.DateTimeField(_("Session date"),
                                        default=timezone.now)
    # Encoding step / status of the process
    ENCODING_STEP = (
        (0, _("Publish is possible")),
        (1, _("Waiting for encoding")),
        (2, _("Encoding in progress")),
        (3, _("Already published")),
    )
    encoding_step = models.IntegerField(
        _("Encoding step"),
        choices=ENCODING_STEP,
        help_text=_("Encoding step for conversion of the "
                    "BBB presentation to video file."),
        default=0,
    )
    # Is this meeting was recorded in BigBlueButton?
    recorded = models.BooleanField(_("Recorded"),
                                   help_text=_("BBB presentation recorded?"),
                                   default=False)
    # Is the recording of the presentation is available in BigBlueButton?
    recording_available = models.BooleanField(
        _("Recording available"),
        help_text=_("BBB presentation recording is available?"),
        default=False,
    )
    # URL of the recording of the BigBlueButton presentation
    recording_url = models.CharField(
        _("Recording url"),
        help_text=_("URL of the recording of the BBB presentation."),
        max_length=200,
    )
    # URL of the recording thumbnail of the BigBlueButton presentation
    thumbnail_url = models.CharField(
        _("Thumbnail url"),
        help_text=_("URL of the recording thumbnail of the BBB presentation."),
        max_length=200,
    )
    # User who converted the BigBlueButton presentation to video file
    encoded_by = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={"is_staff": True},
        verbose_name=_("User"),
        null=True,
        blank=True,
        help_text=_("User who converted the BBB presentation to video file."),
    )
    # Last date of the BBB session in progress
    last_date_in_progress = models.DateTimeField(
        _("Last date in progress"),
        default=timezone.now,
        help_text=_("Last date where BBB session was in progress."),
    )

    def __unicode__(self):
        return "%s - %s" % (self.meeting_name, self.meeting_id)

    def __str__(self):
        return "%s - %s" % (self.meeting_name, self.meeting_id)

    def save(self, *args, **kwargs):
        super(Meeting, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Meeting")
        verbose_name_plural = _("Meetings")
        ordering = ["session_date"]
Ejemplo n.º 17
0
class Recorder(models.Model):
    # Recorder name
    name = models.CharField(_('name'), max_length=200, unique=True)
    # Description of the recorder
    description = RichTextField(_('description'),
                                config_name='complete',
                                blank=True)
    # IP address of the recorder
    address_ip = models.GenericIPAddressField(
        _('Address IP'),
        unique=True,
        help_text=_('IP address of the recorder.'))
    # Salt for
    salt = models.CharField(_('salt'),
                            max_length=50,
                            blank=True,
                            help_text=_('Recorder salt.'))
    # Manager of the recorder who received mails
    user = select2_fields.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={'is_staff': True},
        help_text=_(
            'Manager of this recorder. This manager will receive recorder '
            'emails and he will be the owner of the published videos. If no '
            'user is selected, this recorder will use manual assign system.'),
        verbose_name=_('User'),
        null=True,
        blank=True)
    # Default type of published videos by this recorder
    type = models.ForeignKey(Type,
                             on_delete=models.CASCADE,
                             help_text=_('Video type by default.'))

    recording_type = models.CharField(_('Recording Type'),
                                      max_length=50,
                                      choices=RECORDER_TYPE,
                                      default=RECORDER_TYPE[0][0])
    # Directory name where videos of this recorder are published
    directory = models.CharField(
        _('Publication directory'),
        max_length=50,
        unique=True,
        help_text=_(
            'Basic directory containing the videos published by the recorder.')
    )
    sites = models.ManyToManyField(Site)

    def __unicode__(self):
        return "%s - %s" % (self.name, self.address_ip)

    def __str__(self):
        return "%s - %s" % (self.name, self.address_ip)

    def ipunder(self):
        return self.address_ip.replace(".", "_")

    def save(self, *args, **kwargs):
        super(Recorder, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Recorder")
        verbose_name_plural = _("Recorders")
        ordering = ['name']
Ejemplo n.º 18
0
class Chapter(models.Model):
    video = select2_fields.ForeignKey(Video, verbose_name=_("video"))
    title = models.CharField(_("title"), max_length=100)
    slug = models.SlugField(
        _("slug"),
        unique=True,
        max_length=105,
        help_text=_(
            'Used to access this instance, the "slug" is a short'
            + " label containing only letters, numbers, underscore"
            + " or dash top."
        ),
        editable=False,
    )
    time_start = models.PositiveIntegerField(
        _("Start time"),
        default=0,
        help_text=_(u"Start time of the chapter, in seconds."),
    )

    class Meta:
        verbose_name = _("Chapter")
        verbose_name_plural = _("Chapters")
        ordering = ["time_start"]
        unique_together = (
            "title",
            "time_start",
            "video",
        )

    def clean(self):
        msg = list()
        msg = self.verify_title_items() + self.verify_time()
        msg = msg + self.verify_overlap()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_title_items(self):
        msg = list()
        if (
            not self.title
            or self.title == ""
            or len(self.title) < 2
            or len(self.title) > 100
        ):
            msg.append(_("Please enter a title from 2 to 100 characters."))
        if len(msg) > 0:
            return msg
        return list()

    def verify_time(self):
        msg = list()
        if (
            self.time_start == ""
            or self.time_start < 0
            or self.time_start >= self.video.duration
        ):
            msg.append(
                _(
                    "Please enter a correct start field between 0 and "
                    + "{0}".format(self.video.duration - 1)
                )
            )
        if len(msg) > 0:
            return msg
        return list()

    def verify_overlap(self):
        msg = list()
        instance = None
        if self.slug:
            instance = Chapter.objects.get(slug=self.slug)
        list_chapter = Chapter.objects.filter(video=self.video)
        if instance:
            list_chapter = list_chapter.exclude(id=instance.id)
        if len(list_chapter) > 0:
            for element in list_chapter:
                if self.time_start == element.time_start:
                    msg.append(
                        _(
                            "There is an overlap with the chapter "
                            + "{0}, please change start and/or "
                            + "end values."
                        ).format(element.title)
                    )
            if len(msg) > 0:
                return msg
        return list()

    def save(self, *args, **kwargs):
        newid = -1
        if not self.id:
            try:
                newid = get_nextautoincrement(Chapter)
            except Exception:
                try:
                    newid = Chapter.objects.latest("id").id
                    newid += 1
                except Exception:
                    newid = 1
        else:
            newid = self.id
        newid = "{0}".format(newid)
        self.slug = "{0}-{1}".format(newid, slugify(self.title))
        super(Chapter, self).save(*args, **kwargs)

    @property
    def chapter_in_time(self):
        return time.strftime("%H:%M:%S", time.gmtime(self.time_start))

    chapter_in_time.fget.short_description = _("Start time")

    @property
    def sites(self):
        return self.video.sites

    def __str__(self):
        return u"Chapter: {0} - video: {1}".format(self.title, self.video)
Ejemplo n.º 19
0
class Enrichment(models.Model):

    ENRICH_CHOICES = (
        ('image', _("image")),
        ('richtext', _("richtext")),
        ('weblink', _("weblink")),
        ('document', _("document")),
        ('embed', _("embed")),
    )

    video = select2_fields.ForeignKey(Video, verbose_name=_('video'))
    title = models.CharField(_('title'), max_length=100)
    slug = models.SlugField(
        _('slug'),
        unique=True,
        max_length=105,
        help_text=_('Used to access this instance, the "slug" is a short' +
                    ' label containing only letters, numbers, underscore' +
                    ' or dash top.'),
        editable=False)
    stop_video = models.BooleanField(
        _('Stop video'),
        default=False,
        help_text=_(u'The video will pause when displaying the enrichment.'))
    start = models.PositiveIntegerField(
        _('Start'),
        default=0,
        help_text=_('Start of enrichment display in seconds.'))
    end = models.PositiveIntegerField(
        _('End'),
        default=1,
        help_text=_('End of enrichment display in seconds.'))
    type = models.CharField(_('Type'),
                            max_length=10,
                            choices=ENRICH_CHOICES,
                            null=True,
                            blank=True)

    image = models.ForeignKey(CustomImageModel,
                              verbose_name=_('Image'),
                              null=True,
                              blank=True)
    document = models.ForeignKey(
        CustomFileModel,
        verbose_name=_('Document'),
        null=True,
        blank=True,
        help_text=_(u'Integrate an document (PDF, text, html)'))
    richtext = RichTextField(_('Richtext'), config_name='complete', blank=True)
    weblink = models.URLField(_(u'Web link'),
                              max_length=200,
                              null=True,
                              blank=True)
    embed = models.TextField(_('Embed'),
                             null=True,
                             blank=True,
                             help_text=_(u'Integrate an external source.'))

    class Meta:
        verbose_name = _('Enrichment')
        verbose_name_plural = _('Enrichments')
        ordering = ['start']

    @property
    def sites(self):
        return self.video.sites

    def clean(self):
        msg = list()
        msg = self.verify_all_fields()
        if len(msg) > 0:
            raise ValidationError(msg)
        msg = self.verify_end_start_item() + self.overlap()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_type(self, type):
        typelist = {
            'image': self.image,
            'richtext': self.richtext,
            'weblink': self.weblink,
            'document': self.document,
            'embed': self.embed
        }
        if type not in typelist:
            return _('Please enter a correct {0}.'.format(type))

    def verify_all_fields(self):
        msg = list()
        if (not self.title or self.title == '' or len(self.title) < 2
                or len(self.title) > 100):
            msg.append(_('Please enter a title from 2 to 100 characters.'))
        if (self.start is None or self.start == '' or self.start < 0
                or self.start >= self.video.duration):
            msg.append(
                _('Please enter a correct start field between 0 and ' +
                  '{0}.'.format(self.video.duration - 1)))
        if (not self.end or self.end == '' or self.end <= 0
                or self.end > self.video.duration):
            msg.append(
                _('Please enter a correct end field between 1 and ' +
                  '{0}.'.format(self.video.duration)))
        if self.type:
            if self.verify_type(self.type):
                msg.append(self.verify_type(self.type))
        else:
            msg.append(_('Please enter a type.'))

        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_end_start_item(self):
        msg = list()
        video = Video.objects.get(id=self.video.id)
        if self.start > self.end:
            msg.append(
                _('The value of the start field is greater than the value ' +
                  'of end field.'))
        if self.end > video.duration:
            msg.append(
                _('The value of end field is greater than ' +
                  'the video duration.'))
        if self.end and self.start == self.end:
            msg.append(_('End field and start field can\'t be equal.'))

        if len(msg) > 0:
            return msg
        else:
            return list()

    def overlap(self):
        msg = list()
        instance = None
        if self.slug:
            instance = Enrichment.objects.get(slug=self.slug)
        list_enrichment = Enrichment.objects.filter(video=self.video)
        if instance:
            list_enrichment = list_enrichment.exclude(id=instance.id)
        if len(list_enrichment) > 0:
            for element in list_enrichment:
                if not (
                    (self.start < element.start and self.end <= element.start)
                        or
                    (self.start >= element.end and self.end > element.end)):
                    msg.append(
                        _("There is an overlap with the enrichment {0},"
                          " please change time start and/or "
                          "time end values.").format(element.title))
            if len(msg) > 0:
                return msg
        return list()

    def save(self, *args, **kwargs):
        newid = -1
        if not self.id:
            try:
                newid = get_nextautoincrement(Enrichment)
            except Exception:
                try:
                    newid = Enrichment.objects.latest('id').id
                    newid += 1
                except Exception:
                    newid = 1
        else:
            newid = self.id
        newid = '{0}'.format(newid)
        self.slug = '{0} - {1}'.format(newid, slugify(self.title))
        super(Enrichment, self).save(*args, **kwargs)

    def __str__(self):
        return u'Media : {0} - Video: {1}'.format(self.title, self.video)
Ejemplo n.º 20
0
class Playlist(models.Model):
    title = models.CharField(_('Title'), max_length=100, unique=True)
    slug = models.SlugField(
        _('Slug'),
        unique=True,
        max_length=100,
        help_text=_('Used to access this instance, the "slug" is a short' +
                    ' label containing only letters, numbers, underscore' +
                    ' or dash top.'))
    owner = select2_fields.ForeignKey(User, verbose_name=_('Owner'))
    description = models.TextField(
        _('Description'),
        max_length=255,
        null=True,
        blank=True,
        help_text=_('Short description of the playlist.'))
    visible = models.BooleanField(
        _('Visible'),
        default=False,
        help_text=_('If checked, the playlist can be visible to users' +
                    ' other than the owner.'))

    class Meta:
        ordering = ['title', 'id']
        verbose_name = _('Playlist')
        verbose_name_plural = _('Playlists')

    def save(self, *args, **kwargs):
        newid = -1
        if not self.id:
            try:
                newid = get_nextautoincrement(Playlist)
            except Exception:
                try:
                    newid = Playlist.objects.latest('id').id
                    newid += 1
                except Exception:
                    newid = 1
        else:
            newid = self.id
        newid = '{0}'.format(newid)
        self.slug = '{0}-{1}'.format(newid, slugify(self.title))
        super(Playlist, self).save(*args, **kwargs)

    def __str__(self):
        return '{0}'.format(self.title)

    def first(self):
        return PlaylistElement.objects.get(playlist=self, position=1)

    def last(self):
        last = PlaylistElement.objects.filter(
            playlist=self).order_by('-position')
        if last:
            return last[0].position + 1
        else:
            return 1

    def videos(self):
        videos = list()
        elements = PlaylistElement.objects.filter(playlist=self)
        for element in elements:
            videos.append(element.video)
        return videos
Ejemplo n.º 21
0
class Broadcaster(models.Model):
    name = models.CharField(_('name'), max_length=200, unique=True)
    slug = models.SlugField(
        _('Slug'),
        unique=True,
        max_length=200,
        help_text=_(
            u'Used to access this instance, the "slug" is a short label ' +
            'containing only letters, numbers, underscore or dash top.'),
        editable=False,
        default="")  # default empty, fill it in save
    building = models.ForeignKey('Building', verbose_name=_('Building'))
    description = RichTextField(_('description'),
                                config_name='complete',
                                blank=True)
    poster = models.ForeignKey(CustomImageModel,
                               models.SET_NULL,
                               blank=True,
                               null=True,
                               verbose_name=_('Poster'))
    url = models.URLField(_('URL'),
                          help_text=_('Url of the stream'),
                          unique=True)
    video_on_hold = select2_fields.ForeignKey(
        Video,
        help_text=_(
            'This video will be displayed when there is no live stream.'),
        blank=True,
        null=True,
        verbose_name=_('Video on hold'))
    iframe_url = models.URLField(
        _('Embedded Site URL'),
        help_text=_('Url of the embedded site to display'),
        null=True,
        blank=True)
    iframe_height = models.IntegerField(
        _('Embedded Site Height'),
        null=True,
        blank=True,
        help_text=_('Height of the embedded site (in pixels)'))
    status = models.BooleanField(
        default=0,
        help_text=_('Check if the broadcaster is currently sending stream.'))
    enable_viewer_count = models.BooleanField(
        default=1,
        verbose_name=_(u'Enable viewers count'),
        help_text=_('Enable viewers count on live.'))
    is_restricted = models.BooleanField(
        verbose_name=_(u'Restricted access'),
        help_text=_('Live is accessible only to authenticated users.'),
        default=False)
    public = models.BooleanField(
        verbose_name=_(u'Show in live tab'),
        help_text=_('Live is accessible from the Live tab'),
        default=True)
    password = models.CharField(
        _('password'),
        help_text=_(
            'Viewing this live will not be possible without this password.'),
        max_length=50,
        blank=True,
        null=True)
    viewcount = models.IntegerField(_('Number of viewers'),
                                    default=0,
                                    editable=False)
    viewers = models.ManyToManyField(User, editable=False)

    def get_absolute_url(self):
        return reverse('live:video_live', args=[str(self.slug)])

    def __str__(self):
        return "%s - %s" % (self.name, self.url)

    def get_poster_url(self):
        if self.poster:
            return self.poster.file.url
        else:
            thumbnail_url = ''.join([settings.STATIC_URL, DEFAULT_THUMBNAIL])
            return thumbnail_url

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Broadcaster, self).save(*args, **kwargs)

    class Meta:
        verbose_name = _("Broadcaster")
        verbose_name_plural = _("Broadcasters")
        ordering = ['building', 'name']

    @property
    def sites(self):
        return self.building.sites
Ejemplo n.º 22
0
class Overlay(models.Model):

    POSITION_CHOICES = (
        ("top-left", _("top-left")),
        ("top", _("top")),
        ("top-right", _("top-right")),
        ("right", _("right")),
        ("bottom-right", _("bottom-right")),
        ("bottom", _("bottom")),
        ("bottom-left", _("bottom-left")),
        ("left", _("left")),
    )

    video = select2_fields.ForeignKey(Video, verbose_name=_("Video"))
    title = models.CharField(_("Title"), max_length=100)
    slug = models.SlugField(
        _("Slug"),
        unique=True,
        max_length=105,
        help_text=_('Used to access this instance, the "slug" is a short' +
                    " label containing only letters, numbers, underscore" +
                    " or dash top."),
        editable=False,
    )
    time_start = models.PositiveIntegerField(
        _("Start time"),
        default=1,
        help_text=_("Start time of the overlay, in seconds."),
    )
    time_end = models.PositiveIntegerField(
        _("End time"),
        default=2,
        help_text=_("End time of the overlay, in seconds."),
    )
    content = RichTextField(_("Content"),
                            null=False,
                            blank=False,
                            config_name="complete")
    position = models.CharField(
        _("Position"),
        max_length=100,
        null=True,
        blank=False,
        choices=POSITION_CHOICES,
        default="bottom-right",
        help_text=_("Position of the overlay."),
    )
    background = models.BooleanField(
        _("Show background"),
        default=True,
        help_text=_("Show the background of the overlay."),
    )

    @property
    def sites(self):
        return self.video.sites

    class Meta:
        verbose_name = _("Overlay")
        verbose_name_plural = _("Overlays")
        ordering = ["time_start"]

    def clean(self):
        msg = list()
        msg += self.verify_title_items()
        msg += self.verify_time_items()
        msg += self.verify_overlap()
        if len(msg) > 0:
            raise ValidationError(msg)

    def verify_title_items(self):
        msg = list()
        if not self.title or self.title == "":
            msg.append(_("Please enter a title."))
        elif len(self.title) < 2 or len(self.title) > 100:
            msg.append(_("Please enter a title from 2 to 100 characters."))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_time_items(self):
        msg = list()
        if self.time_start > self.time_end:
            msg.append(
                _("The value of the time start field is greater than " +
                  "the value of the end time field."))
        elif self.time_end > self.video.duration:
            msg.append(
                _("The value of time end field is greater than the " +
                  "video duration."))
        elif self.time_start == self.time_end:
            msg.append(
                _("Time end field and time start field can't " + "be equal."))
        if len(msg) > 0:
            return msg
        else:
            return list()

    def verify_overlap(self):
        msg = list()
        instance = None
        if self.slug:
            instance = Overlay.objects.get(slug=self.slug)
        list_overlay = Overlay.objects.filter(video=self.video)
        if instance:
            list_overlay = list_overlay.exclude(id=instance.id)
        if len(list_overlay) > 0:
            for element in list_overlay:
                if not (self.time_start < element.time_start
                        and self.time_end <= element.time_start
                        or self.time_start >= element.time_end
                        and self.time_end > element.time_end):
                    msg.append(
                        _("There is an overlap with the overlay {0},"
                          " please change time start and/or "
                          "time end values.").format(element.title))
            if len(msg) > 0:
                return msg
        return list()

    def save(self, *args, **kwargs):
        newid = -1
        if not self.id:
            try:
                newid = get_nextautoincrement(Overlay)
            except Exception:
                try:
                    newid = Overlay.objects.latest("id").id
                    newid += 1
                except Exception:
                    newid = 1
        else:
            newid = self.id
        newid = "{0}".format(newid)
        self.slug = "{0}-{1}".format(newid, slugify(self.title))
        super(Overlay, self).save(*args, **kwargs)

    def __str__(self):
        return "Overlay: {0} - Video: {1}".format(self.title, self.video)