コード例 #1
0
class Video(models.Model):
    """Central object in the system"""
    video_id = models.CharField(max_length=255, unique=True)
    title = models.CharField(max_length=2048, blank=True)
    description = models.TextField(blank=True)
    duration = models.PositiveIntegerField(null=True, blank=True)
    allow_community_edits = models.BooleanField()
    allow_video_urls_edit = models.BooleanField(default=True)
    writelock_time = models.DateTimeField(null=True, editable=False)
    writelock_session_key = models.CharField(max_length=255, editable=False)
    writelock_owner = models.ForeignKey(User,
                                        null=True,
                                        editable=False,
                                        related_name="writelock_owners")
    is_subtitled = models.BooleanField(default=False)
    was_subtitled = models.BooleanField(default=False, db_index=True)
    thumbnail = models.CharField(max_length=500, blank=True)
    s3_thumbnail = S3EnabledImageField(blank=True,
                                       upload_to='video/thumbnail/')
    edited = models.DateTimeField(null=True, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, null=True, blank=True)
    followers = models.ManyToManyField(User,
                                       blank=True,
                                       related_name='followed_videos')
    complete_date = models.DateTimeField(null=True, blank=True, editable=False)

    subtitles_fetched_count = models.IntegerField(default=0, db_index=True)
    widget_views_count = models.IntegerField(default=0, db_index=True)
    view_count = models.PositiveIntegerField(default=0, db_index=True)

    subtitles_fetched_counter = RedisSimpleField('video_id', changed_video_set)
    widget_views_counter = RedisSimpleField('video_id', changed_video_set)
    view_counter = RedisSimpleField('video_id', changed_video_set)

    # Denormalizing the subtitles(had_version) count, in order to get faster joins
    # updated from update_languages_count()
    languages_count = models.PositiveIntegerField(default=0, db_index=True)

    def __unicode__(self):
        title = self.title_display()
        if len(title) > 70:
            title = title[:70] + '...'
        return title

    def title_display(self):
        if self.title:
            return self.title

        try:
            url = self.videourl_set.all()[:1].get().url
            if not url:
                return 'No title'
        except models.ObjectDoesNotExist:
            return 'No title'

        url = url.strip('/')

        if url.startswith('http://'):
            url = url[7:]

        parts = url.split('/')
        if len(parts) > 1:
            title = '%s/.../%s' % (parts[0], parts[-1])
        else:
            title = url

        if title > 35:
            title = title[:35] + '...'

        return title

    def update_view_counter(self):
        self.view_counter.incr()
        video_view_counter.incr()

    def update_subtitles_fetched(self, lang=None):
        self.subtitles_fetched_counter.incr()
        #Video.objects.filter(pk=self.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1)
        update_subtitles_fetch_counter(self, lang)
        if lang:
            lang.subtitles_fetched_counter.incr()
            #SubtitleLanguage.objects.filter(pk=sub_lang.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1)

    def get_thumbnail(self):
        if self.s3_thumbnail:
            return self.s3_thumbnail.thumb_url(100, 100)

        if self.thumbnail:
            return self.thumbnail

        return ''

    def get_small_thumbnail(self):
        if self.s3_thumbnail:
            return self.s3_thumbnail.thumb_url(50, 50)

        return ''

    @models.permalink
    def video_link(self):
        return ('videos:history', [self.video_id])

    def thumbnail_link(self):
        if not self.thumbnail:
            return ''

        if self.thumbnail.startswith('http://'):
            return self.thumbnail

        return settings.MEDIA_URL + self.thumbnail

    def is_html5(self):
        try:
            return self.videourl_set.filter(original=True)[:1].get().is_html5()
        except models.ObjectDoesNotExist:
            return False

    def search_page_url(self):
        return self.get_absolute_url()

    def title_for_url(self):
        return self.title.replace('/', '-').replace('#', '').replace('?', '')

    @models.permalink
    def get_absolute_url(self, locale=None):
        kwargs = {}
        if locale:
            kwargs['locale'] = locale
        title = self.title_for_url()
        if title:
            return ('videos:video_with_title', [self.video_id, title], kwargs)
        return ('videos:video', [self.video_id], kwargs)

    def get_video_url(self):
        try:
            return self.videourl_set.filter(
                primary=True).all()[:1].get().effective_url
        except models.ObjectDoesNotExist:
            pass

    @classmethod
    def get_or_create_for_url(cls, video_url=None, vt=None, user=None):
        vt = vt or video_type_registrar.video_type_for_url(video_url)
        if not vt:
            return None, False

        try:
            video_url_obj = VideoUrl.objects.get(url=vt.convert_to_video_url())
            return video_url_obj.video, False
        except models.ObjectDoesNotExist:
            pass

        try:
            video_url_obj = VideoUrl.objects.get(type=vt.abbreviation,
                                                 **vt.create_kwars())
            if user:
                Action.create_video_handler(video_url_obj.video, user)
            return video_url_obj.video, False
        except models.ObjectDoesNotExist:
            obj = Video()
            obj = vt.set_values(obj)
            if obj.title:
                obj.slug = slugify(obj.title)
            obj.user = user
            obj.save()

            user and obj.followers.add(user)

            Action.create_video_handler(obj, user)

            SubtitleLanguage(video=obj, is_original=True,
                             is_forked=True).save()
            #Save video url
            video_url_obj = VideoUrl()
            if vt.video_id:
                video_url_obj.videoid = vt.video_id
            video_url_obj.url = vt.convert_to_video_url()
            video_url_obj.type = vt.abbreviation
            video_url_obj.original = True
            video_url_obj.primary = True
            video_url_obj.added_by = user
            video_url_obj.video = obj
            video_url_obj.save()

            return obj, True

    @property
    def language(self):
        ol = self._original_subtitle_language()

        if ol and ol.language:
            return ol.language

    @property
    def filename(self):
        from django.utils.text import get_valid_filename

        return get_valid_filename(self.__unicode__())

    def lang_filename(self, language):
        name = self.filename
        lang = language.language or u'original'
        return u'%s.%s' % (name, lang)

    @property
    def subtitle_state(self):
        """Subtitling state for this video 
        """
        return NO_SUBTITLES if self.latest_version() \
            is None else SUBTITLES_FINISHED

    def _original_subtitle_language(self):
        if not hasattr(self, '_original_subtitle'):
            try:
                original = self.subtitlelanguage_set.filter(
                    is_original=True)[:1].get()
            except models.ObjectDoesNotExist:
                original = None

            setattr(self, '_original_subtitle', original)

        return getattr(self, '_original_subtitle')

    def has_original_language(self):
        original_language = self._original_subtitle_language()
        if original_language:
            return original_language.language != ''

    def subtitle_language(self, language_code=None):
        try:
            if language_code is None:
                return self._original_subtitle_language()
            else:
                return self.subtitlelanguage_set.filter(
                    language=language_code).order_by(
                        '-subtitle_count')[:1].get()
        except models.ObjectDoesNotExist:
            return None

    def subtitle_languages(self, language_code):
        return self.subtitlelanguage_set.filter(language=language_code)

    def version(self, version_no=None, language=None):
        if language is None:
            language = self.subtitle_language()
        return None if language is None else language.version(version_no)

    def latest_version(self, language_code=None):
        language = self.subtitle_language(language_code)
        return None if language is None else language.latest_version()

    def subtitles(self, version_no=None, language_code=None):
        version = self.version(version_no, language_code)
        if version:
            return version.subtitles()
        else:
            return Subtitle.objects.none()

    def update_languages_count(self):
        self.languages_count = self.subtitlelanguage_set.filter(
            had_version=True).count()
        self.save()

    def latest_subtitles(self, language_code=None):
        version = self.latest_version(language_code)
        return [] if version is None else version.subtitles()

    def translation_language_codes(self):
        """All iso language codes with finished translations."""
        return set([
            sl.language for sl in self.subtitlelanguage_set.filter(
                is_complete=True).filter(is_original=False)
        ])

    @property
    def writelock_owner_name(self):
        """The user who currently has a subtitling writelock on this video."""
        if self.writelock_owner == None:
            return "anonymous"
        else:
            return self.writelock_owner.__unicode__()

    @property
    def is_writelocked(self):
        """Is this video writelocked for subtitling?"""
        if self.writelock_time == None:
            return False
        delta = datetime.now() - self.writelock_time
        seconds = delta.days * 24 * 60 * 60 + delta.seconds
        return seconds < WRITELOCK_EXPIRATION

    def can_writelock(self, request):
        """Can I place a writelock on this video for subtitling?"""
        return self.writelock_session_key == \
            request.browser_id or \
            not self.is_writelocked

    def writelock(self, request):
        """Writelock this video for subtitling."""
        self._make_writelock(request.user, request.browser_id)

    def _make_writelock(self, user, key):
        if user.is_authenticated():
            self.writelock_owner = user
        else:
            self.writelock_owner = None
        self.writelock_session_key = key
        self.writelock_time = datetime.now()

    def release_writelock(self):
        """Writelock this video for subtitling."""
        self.writelock_owner = None
        self.writelock_session_key = ''
        self.writelock_time = None

    def notification_list(self, exclude=None):
        qs = self.followers.exclude(changes_notification=False).exclude(
            is_active=False)
        if exclude:
            if not isinstance(exclude, (list, tuple)):
                exclude = [exclude]
            qs = qs.exclude(
                pk__in=[u.pk for u in exclude if u and u.is_authenticated()])
        return qs

    def notification_list_all(self, exclude=None):
        users = []
        for language in self.subtitlelanguage_set.all():
            for u in language.notification_list(exclude):
                if not u in users:
                    users.append(u)
        for user in self.notification_list(exclude):
            if not user in users:
                users.append(user)
        return users

    def update_complete_state(self):
        language = self.subtitle_language()
        if not language.has_version:
            self.is_subtitled = False
        else:
            self.is_subtitled = True
            self.was_subtitled = True

    def subtitle_language_dict(self):
        langs = {}
        for sl in self.subtitlelanguage_set.all():
            if not sl.language:
                continue
            if sl.language in langs:
                langs[sl.language].append(sl)
            else:
                langs[sl.language] = [sl]
        return langs
コード例 #2
0
class SubtitleLanguage(models.Model):
    video = models.ForeignKey(Video)
    is_original = models.BooleanField()
    language = models.CharField(max_length=16,
                                choices=ALL_LANGUAGES,
                                blank=True)
    writelock_time = models.DateTimeField(null=True, editable=False)
    writelock_session_key = models.CharField(max_length=255,
                                             blank=True,
                                             editable=False)
    writelock_owner = models.ForeignKey(User,
                                        null=True,
                                        blank=True,
                                        editable=False)
    is_complete = models.BooleanField(default=False)
    subtitle_count = models.IntegerField(default=0)
    has_version = models.BooleanField(default=False, editable=False)
    had_version = models.BooleanField(default=False, editable=False)
    is_forked = models.BooleanField(default=False, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    subtitles_fetched_count = models.IntegerField(default=0, editable=False)
    followers = models.ManyToManyField(User,
                                       blank=True,
                                       related_name='followed_languages',
                                       editable=False)
    title = models.CharField(max_length=2048, blank=True)
    percent_done = models.IntegerField(default=0, editable=False)
    standard_language = models.ForeignKey('self',
                                          null=True,
                                          blank=True,
                                          editable=False)
    last_version = models.ForeignKey('SubtitleVersion',
                                     null=True,
                                     blank=True,
                                     editable=False)

    subtitles_fetched_counter = RedisSimpleField()

    class Meta:
        unique_together = (('video', 'language', 'standard_language'), )

    def __unicode__(self):
        return self.language_display()

    def __init__(self, *args, **kwargs):
        super(SubtitleLanguage, self).__init__(*args, **kwargs)
        self.save_initial_values()

    def save(self, *args, **kwargs):
        super(SubtitleLanguage, self).save(*args, **kwargs)
        self.check_initial_values()
        self.save_initial_values()
        self.video.update_languages_count()

    def delete(self, *args, **kwargs):
        video_id = self.video_id
        super(SubtitleLanguage, self).delete(*args, **kwargs)
        #asynchronous call
        update_team_video.delay(video_id)

        if not self.video.subtitlelanguage_set.exclude(
                is_complete=False).exists():
            self.video.complete_date = None
            self.video.save()

        video_cache.invalidate_cache(self.video.video_id)
        self.video.update_languages_count()

    def save_initial_values(self):
        self._initial_values = {
            'is_complete': self.is_complete,
            'is_original': self.is_original,
            'percent_done': self.percent_done,
            'is_forked': self.is_forked
        }

    def check_initial_values(self):
        iv = self._initial_values

        if not iv['is_complete'] and self.is_complete:
            self.video.complete_date = datetime.now()
            self.video.save()
        elif iv['is_complete'] and not self.is_complete:
            if not self.video.subtitlelanguage_set.exclude(
                    is_complete=False).exists():
                self.video.complete_date = None
                self.video.save()

        if iv['is_complete'] != self.is_complete or iv['is_original'] != self.is_original \
            or iv['percent_done'] != self.percent_done or iv['is_forked'] != self.is_forked:
            #asynchronous call
            update_team_video_for_sl.delay(self.id)

    def get_title(self):
        if self.is_original:
            return self.video.title

        return self.title

    def update_complete_state(self):
        self._update_subtitle_count()
        version = self.latest_version()
        if version.subtitle_set.count() == 0:
            self.has_version = False
        else:
            self.has_version = True
            self.had_version = True

    def is_dependent(self):
        return not self.is_original and not self.is_forked

    def real_standard_language(self):
        if self.standard_language:
            return self.standard_language
        elif self.is_dependent():
            # This should only be needed temporarily until data is more cleaned up.
            # in other words, self.standard_language should never be None for a dependent SL
            self.standard_language = self.video.subtitle_language()
            self.save()
            return self.standard_language
        return None

    def is_dependable(self):
        if self.is_dependent():
            dep_lang = self.real_standard_language()
            return dep_lang and dep_lang.is_complete and self.percent_done > 10
        else:
            return self.is_complete

    def get_widget_url(self):
        # duplicates mirosubs.widget.SubtitleDialogOpener.prototype.openDialogOrRedirect_
        video = self.video
        video_url = video.get_video_url()
        config = {
            "videoID": video.video_id,
            "videoURL": video_url,
            "effectiveVideoURL": video_url,
            "languageCode": self.language,
            "subLanguagePK": self.pk,
            "originalLanguageCode": video.language
        }
        if self.is_dependent():
            config['baseLanguagePK'] = self.standard_language.pk
        return reverse('onsite_widget') + '?config=' + urlquote_plus(
            json.dumps(config))

    @models.permalink
    def get_absolute_url(self):
        if self.is_original:
            return ('videos:history', [self.video.video_id])
        else:
            return ('videos:translation_history',
                    [self.video.video_id, self.language, self.pk])

    def language_display(self):
        if self.is_original and not self.language:
            return 'Original'
        return self.get_language_display()

    @property
    def writelock_owner_name(self):
        if self.writelock_owner == None:
            return "anonymous"
        else:
            return self.writelock_owner.__unicode__()

    @property
    def is_writelocked(self):
        if self.writelock_time == None:
            return False
        delta = datetime.now() - self.writelock_time
        seconds = delta.days * 24 * 60 * 60 + delta.seconds
        return seconds < WRITELOCK_EXPIRATION

    def can_writelock(self, request):
        return self.writelock_session_key == \
            request.browser_id or \
            not self.is_writelocked

    def writelock(self, request):
        if request.user.is_authenticated():
            self.writelock_owner = request.user
        else:
            self.writelock_owner = None
        self.writelock_session_key = request.browser_id
        self.writelock_time = datetime.now()

    def release_writelock(self):
        self.writelock_owner = None
        self.writelock_session_key = ''
        self.writelock_time = None

    def version(self, version_no=None):
        if version_no is None:
            return self.latest_version()
        try:
            return self.subtitleversion_set.get(version_no=version_no)
        except models.ObjectDoesNotExist:
            pass

    def latest_version(self):
        #better get rid from this in future
        return self.last_version

    def latest_subtitles(self):
        version = self.latest_version()
        if version:
            return version.subtitles()
        return []

    def _update_subtitle_count(self):
        original_value = self.subtitle_count
        new_value = len(self.latest_subtitles())
        if original_value != new_value:
            self.subtitle_count = new_value
            self.save()

    def update_percent_done(self):
        original_value = self.percent_done
        if not self.is_original and not self.is_forked:
            try:
                translation_count = 0
                for item in self.latest_subtitles():
                    if item.text:
                        translation_count += 1
            except AttributeError:
                translation_count = 0

            if translation_count == 0:
                self.percent_done = 0

            if self.standard_language and self.is_dependent():
                last_version = self.standard_language.latest_version()
            else:
                last_version = self.video.latest_version()

            if last_version:
                subtitles_count = last_version.subtitle_set.count()
            else:
                subtitles_count = 0

            try:
                val = int(translation_count / 1. / subtitles_count * 100)
                self.percent_done = max(0, min(val, 100))
            except ZeroDivisionError:
                self.percent_done = 0
        else:
            self.percent_done = 100
        if original_value != self.percent_done:
            self.save()

    def notification_list(self, exclude=None):
        qs = self.followers.filter(changes_notification=True, is_active=True)

        if exclude:
            if not isinstance(exclude, (list, tuple)):
                exclude = [exclude]
            qs = qs.exclude(pk__in=[u.pk for u in exclude if u])
        return qs