def get_object(self, request, channel_slug=None): self._root_url = get_base_url(request) if channel_slug: self.channel = get_object_or_404(Channel, slug__iexact=channel_slug) else: self.channel = Channel.objects.get( slug=settings.DEFAULT_CHANNEL_SLUG) if self.channel.cover_art: self.itunes_lg_url = thumbnail(self.channel.cover_art, '1400x1400').url self.itunes_sm_url = thumbnail(self.channel.cover_art, '144x144').url if self.itunes_lg_url.startswith('//'): # e.g. //cdn.example.com/media/cache/file.png protocol = self._root_url.split('//')[0] self.itunes_lg_url = protocol + self.itunes_lg_url self.itunes_sm_url = protocol + self.itunes_sm_url elif '://' not in self.itunes_lg_url: self.itunes_lg_url = self._root_url + self.itunes_lg_url self.itunes_sm_url = self._root_url + self.itunes_sm_url else: # Use the default ones self.itunes_sm_url = get_abs_static( 'main/img/podcast-cover-144x144.png', request) self.itunes_lg_url = get_abs_static( 'main/img/podcast-cover-1400x1400.png', request) super(ITunesFeed, self).get_object(request)
def event_processing_timenails(request, slug): event = get_object_or_404(Event, slug=slug) if not event.duration: return {'pictures': []} form = forms.ProcessingTimenailsForm(request.GET) if not form.is_valid(): return http.HttpResponseBadRequest(form.errors) percentage = min(100.0, form.cleaned_data['percent'] or 100.0) max_ = form.cleaned_data['max'] point = event.duration * percentage / 100.0 pictures = Picture.objects.filter( event=event, timestamp__isnull=False, timestamp__lte=point, ) pictures_ = [] for picture in pictures.order_by('-timestamp')[:max_]: # NOTE! This code is the same as used # in then EventChaptersThumbnailsView.get view. thumb = thumbnail( picture.file, '160x90', crop='center' ) pictures_.append({ 'id': picture.id, 'timestamp': picture.timestamp, 'thumbnail': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height, }, }) pictures_.reverse() return {'pictures': pictures_}
def event_to_dict(event): picture_id = event.picture.id if event.picture else None data = { 'event_id': event.id, 'title': event.title, 'description': event.description, 'short_description': event.short_description, 'channels': [x.pk for x in event.channels.all()], 'tags': [x.pk for x in event.tags.all()], 'call_info': event.call_info, 'additional_links': event.additional_links, 'recruitmentmessage': None, 'picture': picture_id } if event.recruitmentmessage_id: data['recruitmentmessage'] = event.recruitmentmessage_id if event.placeholder_img: data['placeholder_img'] = event.placeholder_img.url if event.picture: file = event.picture.file else: file = event.placeholder_img data['thumbnail_url'] = ( thumbnail( file, '121x68', crop='center' ).url ) return data
def event_to_dict(event): picture_id = event.picture.id if event.picture else None data = { 'event_id': event.id, 'title': event.title, 'description': event.description, 'short_description': event.short_description, 'channels': [x.pk for x in event.channels.all()], 'tags': [x.pk for x in event.tags.all()], 'call_info': event.call_info, 'additional_links': event.additional_links, 'picture': picture_id } if event.placeholder_img: data['placeholder_img'] = event.placeholder_img.url if event.picture: file = event.picture.file else: file = event.placeholder_img data['thumbnail_url'] = ( thumbnail( file, '121x68', crop='center' ).url ) return data
def event_processing_timenails(request, slug): event = get_object_or_404(Event, slug=slug) if not event.duration: return {'pictures': []} form = forms.ProcessingTimenailsForm(request.GET) if not form.is_valid(): return http.HttpResponseBadRequest(form.errors) percentage = min(100.0, form.cleaned_data['percent'] or 100.0) max_ = form.cleaned_data['max'] point = event.duration * percentage / 100.0 pictures = Picture.objects.filter( event=event, timestamp__isnull=False, timestamp__lte=point, ) pictures_ = [] for picture in pictures.order_by('-timestamp')[:max_]: # NOTE! This code is the same as used # in then EventChaptersThumbnailsView.get view. thumb = thumbnail(picture.file, '160x90', crop='center') pictures_.append({ 'id': picture.id, 'timestamp': picture.timestamp, 'thumbnail': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height, }, }) pictures_.reverse() return {'pictures': pictures_}
def render(self, name, value, attrs): pictures = [] qs = Picture.objects.all() if self.event: qs = qs.exclude(timestamp__isnull=False) qs = qs.filter(Q(event__isnull=True) | Q(event=self.event)) # If the current event does use an inactive picture, # let it still be a choice. if self.event.picture_id: qs = qs.filter(Q(is_active=True) | Q(id=self.event.picture_id)) else: qs = qs.filter(is_active=True) else: qs = qs.filter( event__isnull=True, is_active=True, ) for pic in qs.order_by('event', '-created'): thumb = thumbnail(pic.file, '160x90', crop='center') pictures.append({ 'thumb': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height }, 'notes': pic.notes, 'selected': value == pic.id, 'id': pic.id, }) context = {'pictures': pictures, 'current_id': value, 'name': name} return mark_safe(render_to_response('gallery.html', context).content)
def render(self, name, value, attrs=None, **__): if value: picture = Picture.objects.get(id=value) thumb = thumbnail(picture.file, '96x54', crop='center') img = ('<img src="%s" width="%d" height="%d" alt="%s">' % (thumb.url, thumb.width, thumb.height, picture.notes and cgi.escape(picture.notes) or '')) html = ('<input type="hidden" name="%s" value="%d">' '<a href="%s" title="Current picture">%s</a> ' % ( name, picture.id, reverse('manage:picture_edit', args=(picture.id, )), img, )) if self.editable: html += ('<a href="%s?event=%d" ' 'title="This will leave the editing without saving"' '>Pick another</a>' % (reverse('manage:picturegallery'), self.instance.id)) else: html += ('You can pick a different picture later') return mark_safe(html) else: html = ('<a href="%s?event=%d" ' 'title="This will leave the editing without saving">' 'Pick a picture from the gallery</a>' % ( reverse('manage:picturegallery'), self.instance.id, )) return mark_safe(html)
def get(self, request, slug): event = self.get_event(slug, request) if not self.can_view_event(event, request): return self.cant_view_event(event, request) if not self.can_edit_event(event, request): return self.cant_edit_event(event, request) pictures = [] missing = [] fetch = [] base_qs = Picture.objects.filter(event=event) prev = None for at in get_timenail_timestamps(event): qs = base_qs.filter(timestamp=at) for picture in qs.order_by('-modified')[:1]: thumb = thumbnail( picture.file, '160x90', crop='center' ) similarity = None img = Image.open(picture.file) if prev is not None: cmp = FuzzyImageCompare(prev, img) similarity = cmp.similarity() prev = img pictures.append({ 'at': picture.timestamp, 'thumbnail': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height, }, 'similarity': similarity }) break else: missing.append(at) lock = 'lock-{}-{}'.format(event.id, at) if not cache.get(lock): fetch.append(at) cache.set(lock, True, 60 * 10) if fetch: # break it up so that we only ask for 10 at a time fetches = [fetch[i:i + 10] for i in range(0, len(fetch), 10)] for group in fetches: tasks.create_timestamp_pictures.delay(event.id, group) return http.JsonResponse({ 'pictures': pictures, 'missing': len(missing), })
def get_object(self, request, channel_slug=None): self._root_url = get_base_url(request) if channel_slug: self.channel = get_object_or_404( Channel, slug__iexact=channel_slug ) else: self.channel = Channel.objects.get( slug=settings.DEFAULT_CHANNEL_SLUG ) if self.channel.cover_art: self.itunes_lg_url = thumbnail( self.channel.cover_art, '1400x1400' ).url self.itunes_sm_url = thumbnail( self.channel.cover_art, '144x144' ).url if self.itunes_lg_url.startswith('//'): # e.g. //cdn.example.com/media/cache/file.png protocol = self._root_url.split('//')[0] self.itunes_lg_url = protocol + self.itunes_lg_url self.itunes_sm_url = protocol + self.itunes_sm_url elif '://' not in self.itunes_lg_url: self.itunes_lg_url = self._root_url + self.itunes_lg_url self.itunes_sm_url = self._root_url + self.itunes_sm_url else: # Use the default ones self.itunes_sm_url = get_abs_static( 'main/img/podcast-cover-144x144.png', request ) self.itunes_lg_url = get_abs_static( 'main/img/podcast-cover-1400x1400.png', request ) super(ITunesFeed, self).get_object(request)
def upload_video(event): if isinstance(event, basestring): # pragma: no cover # This is only really used when you use the commandline tool, like # ./manage.py debug-amara upload_video my-cool-slug if event.isdigit(): event = Event.objects.get(id=event) else: event = Event.objects.get( Q(slug=event) | Q(title=event) ) video_url, _ = videoinfo.get_video_url( event, True, False, ) # Same dimensions we use for the Open Graph in main/event.html picture = event.picture and event.picture.file or event.placeholder_img thumb = thumbnail(picture, '385x218', crop='center') data = { 'video_url': video_url, 'title': event.title, 'description': event.short_description or event.description, 'duration': event.duration, # 'primary_audio_language_code': event.primary_audio_language_code, 'team': settings.AMARA_TEAM, 'project': settings.AMARA_PROJECT, 'thumbnail': build_absolute_url(thumb.url), } response = requests.post( settings.AMARA_BASE_URL + '/api/videos/', data=data, headers=_get_headers() ) if not response.status_code == 201: raise UploadError(response.status_code, response.content) upload_info = response.json() amara_video, _ = AmaraVideo.objects.get_or_create( event=event, video_url=video_url, video_id=upload_info['id'], upload_info=upload_info, ) return amara_video
def thumbnails(request): form = forms.ThumbnailsForm(request.GET) if not form.is_valid(): return http.HttpResponseBadRequest(form.errors) id = form.cleaned_data['id'] width = form.cleaned_data['width'] height = form.cleaned_data['height'] geometry = '%sx%s' % (width, height) event = get_object_or_404(Event, id=id) thumbnails = [] for picture in Picture.objects.filter(event=event).order_by('created'): thumb = thumbnail(picture.file, geometry, crop='center') thumbnails.append(thumb.url) return {'thumbnails': thumbnails}
def upload_video(event): if isinstance(event, basestring): # pragma: no cover # This is only really used when you use the commandline tool, like # ./manage.py debug-amara upload_video my-cool-slug if event.isdigit(): event = Event.objects.get(id=event) else: event = Event.objects.get(Q(slug=event) | Q(title=event)) video_url, _ = videoinfo.get_video_url( event, True, False, ) # Same dimensions we use for the Open Graph in main/event.html picture = event.picture and event.picture.file or event.placeholder_img thumb = thumbnail(picture, '385x218', crop='center') data = { 'video_url': video_url, 'title': event.title, 'description': event.short_description or event.description, 'duration': event.duration, # 'primary_audio_language_code': event.primary_audio_language_code, 'team': settings.AMARA_TEAM, 'project': settings.AMARA_PROJECT, 'thumbnail': build_absolute_url(thumb.url), } response = requests.post(settings.AMARA_BASE_URL + '/api/videos/', data=data, headers=_get_headers()) if not response.status_code == 201: raise UploadError(response.status_code, response.content) upload_info = response.json() amara_video, _ = AmaraVideo.objects.get_or_create( event=event, video_url=video_url, video_id=upload_info['id'], upload_info=upload_info, ) return amara_video
def __init__(self, event, *args, **kwargs): super(EventTweetForm, self).__init__(*args, **kwargs) self.fields['text'].help_text = ( '<b class="char-counter">140</b> characters left. ' '<span class="char-counter-warning"><b>Note!</b> Sometimes ' 'Twitter can count it as longer than it appears if you ' 'include a URL. ' 'It\'s usually best to leave a little room.</span>' ) # it's a NOT NULL field but it defaults to NOW() # in the views code self.fields['send_date'].required = False if event.tags.all(): def pack_tags(tags): return '[%s]' % (','.join('"%s"' % x for x in tags)) self.fields['text'].help_text += ( '<br><a href="#" class="include-event-tags" ' 'data-tags=\'%s\'>include all event tags</a>' % pack_tags([x.name for x in event.tags.all()]) ) if event.placeholder_img or event.picture: from airmozilla.main.templatetags.jinja_helpers import thumbnail if event.picture: pic = event.picture.file else: pic = event.placeholder_img thumb = thumbnail(pic, '160x90', crop='center') self.fields['include_placeholder'].help_text = ( '<img src="%(url)s" alt="placeholder" class="thumbnail" ' 'width="%(width)s" width="%(height)s">' % { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height } ) else: del self.fields['include_placeholder'] self.fields['send_date'].help_text = 'Timezone is UTC'
def render(self, name, value, attrs=None, **__): if value: picture = Picture.objects.get(id=value) thumb = thumbnail(picture.file, '96x54', crop='center') img = ( '<img src="%s" width="%d" height="%d" alt="%s">' % ( thumb.url, thumb.width, thumb.height, picture.notes and cgi.escape(picture.notes) or '' ) ) html = ( '<input type="hidden" name="%s" value="%d">' '<a href="%s" title="Current picture">%s</a> ' % ( name, picture.id, reverse('manage:picture_edit', args=(picture.id,)), img, ) ) if self.editable: html += ( '<a href="%s?event=%d" ' 'title="This will leave the editing without saving"' '>Pick another</a>' % ( reverse('manage:picturegallery'), self.instance.id ) ) else: html += ( 'You can pick a different picture later' ) return mark_safe(html) else: html = ( '<a href="%s?event=%d" ' 'title="This will leave the editing without saving">' 'Pick a picture from the gallery</a>' % ( reverse('manage:picturegallery'), self.instance.id, ) ) return mark_safe(html)
def render(self, name, value, attrs): pictures = [] qs = Picture.objects.all() if self.event: qs = qs.exclude( timestamp__isnull=False ) qs = qs.filter( Q(event__isnull=True) | Q(event=self.event) ) # If the current event does use an inactive picture, # let it still be a choice. if self.event.picture_id: qs = qs.filter( Q(is_active=True) | Q(id=self.event.picture_id) ) else: qs = qs.filter(is_active=True) else: qs = qs.filter( event__isnull=True, is_active=True, ) for pic in qs.order_by('event', '-created'): thumb = thumbnail(pic.file, '160x90', crop='center') pictures.append({ 'thumb': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height }, 'notes': pic.notes, 'selected': value == pic.id, 'id': pic.id, }) context = { 'pictures': pictures, 'current_id': value, 'name': name } return mark_safe(render_to_response('gallery.html', context).content)
def test_thumbnail_with_some_integrityerrors( self, mocked_get_thumbnail, mocked_time ): runs = [] def proxy(*args, **kwargs): runs.append(args) if len(runs) < 3: raise IntegrityError('bla') return get_thumbnail(*args, **kwargs) mocked_get_thumbnail.side_effect = proxy nailed = thumbnail(os.path.basename(self.destination), '10x10') eq_(nailed.width, 10) # we don't want these lying around in local install nailed.delete()
def __init__(self, event, *args, **kwargs): super(EventTweetForm, self).__init__(*args, **kwargs) self.fields['text'].help_text = ( '<b class="char-counter">140</b> characters left. ' '<span class="char-counter-warning"><b>Note!</b> Sometimes ' 'Twitter can count it as longer than it appears if you ' 'include a URL. ' 'It\'s usually best to leave a little room.</span>') # it's a NOT NULL field but it defaults to NOW() # in the views code self.fields['send_date'].required = False if event.tags.all(): def pack_tags(tags): return '[%s]' % (','.join('"%s"' % x for x in tags)) self.fields['text'].help_text += ( '<br><a href="#" class="include-event-tags" ' 'data-tags=\'%s\'>include all event tags</a>' % pack_tags([x.name for x in event.tags.all()])) if event.placeholder_img or event.picture: from airmozilla.main.templatetags.jinja_helpers import thumbnail if event.picture: pic = event.picture.file else: pic = event.placeholder_img thumb = thumbnail(pic, '160x90', crop='center') self.fields['include_placeholder'].help_text = ( '<img src="%(url)s" alt="placeholder" class="thumbnail" ' 'width="%(width)s" width="%(height)s">' % { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height }) else: del self.fields['include_placeholder'] self.fields['send_date'].help_text = 'Timezone is UTC'
def send_tweet(event_tweet, save=True): if event_tweet.include_placeholder: if event_tweet.event.picture: pic = event_tweet.event.picture.file else: pic = event_tweet.event.placeholder_img thumb = thumbnail( pic, '385x218', # 16/9 ratio crop='center' ) file_path = thumb.storage.path(thumb.name) else: file_path = None try: tweet_id = _send(event_tweet.text, file_path=file_path) event_tweet.tweet_id = tweet_id event_tweet.error = None except Exception, msg: logging.error("Failed to send tweet", exc_info=True) event_tweet.error = str(msg) event_tweet.failed_attempts += 1
def redirect_picture_thumbnail(request, id): picture = get_object_or_404(Picture, id=id) geometry = request.GET.get('geometry', '100x100') crop = request.GET.get('crop', 'center') thumb = thumbnail(picture.file, geometry, crop=crop) return redirect(thumb.url)
def test_thumbnail(self): nailed = thumbnail(os.path.basename(self.destination), '10x10') eq_(nailed.width, 10) # we don't want these lying around in local install nailed.delete()
def poster_url(geometry='896x504', crop='center'): image = event.picture and event.picture.file or event.placeholder_img return thumbnail(image, geometry, crop=crop).url
def get(self, request, slug): event = self.get_event(slug, request) if not self.can_view_event(event, request): return self.cant_view_event(event, request) if not self.can_edit_event(event, request): return self.cant_edit_event(event, request) pictures = [] missing = [] fetch = [] base_qs = Picture.objects.filter(event=event) def make_similarity_cache_key(picture1, picture2): if picture2: modify_times = picture1.modified.strftime('%f') modify_times += picture2.modified.strftime('%f') return 'similarity:' + modify_times prev = None for at in get_timenail_timestamps(event): qs = base_qs.filter(timestamp=at) for picture in qs.order_by('-modified')[:1]: thumb = thumbnail( picture.file, # size shown with width set in CSS '160x90', crop='center', ) similarity = -1 similarity_cache_key = make_similarity_cache_key( picture, prev, ) if similarity_cache_key: similarity = cache.get(similarity_cache_key, -1) # still here? if similarity == -1: similarity = None if prev is not None: cmp = FuzzyImageCompare( Image.open(prev.file), Image.open(picture.file), ) similarity = cmp.similarity() cache.set( similarity_cache_key, similarity, 60 * 60 * 24 * 7 # 7 days ) prev = picture pictures.append({ 'at': picture.timestamp, 'thumbnail': { 'url': thumb.url, 'width': thumb.width, 'height': thumb.height, }, 'similarity': similarity }) break else: missing.append(at) lock = 'lock-{}-{}'.format(event.id, at) if not cache.get(lock): fetch.append(at) cache.set(lock, True, 60 * 10) if fetch: # break it up so that we only ask for 10 at a time fetches = [fetch[i:i + 10] for i in range(0, len(fetch), 10)] for group in fetches: tasks.create_timestamp_pictures.delay(event.id, group) return http.JsonResponse({ 'pictures': pictures, 'missing': len(missing), })
def get_thumbnail(event): image = event.picture and event.picture.file or event.placeholder_img geometry = '160x90' crop = 'center' return thumbnail(image, geometry, crop=crop)