예제 #1
0
def s3_create_default_thumbs_for(item):
    """Create copies of the default thumbs for the given item.

    This copies the default files (all named with an id of 'new') to
    use the given item's id. This means there could be lots of duplicate
    copies of the default thumbs, but at least we can always use the
    same url when rendering.

    :param item: A 2-tuple with a subdir name and an ID. If given a
        ORM mapped class with _thumb_dir and id attributes, the info
        can be extracted automatically.
    :type item: ``tuple`` or mapped class instance
    """
    # fallback to normal thumb handling if no S3 engine is enabled.
    storage = get_s3_storage()
    if not storage:
        return None
    bucket = storage.connect_to_bucket()

    image_dir, item_id = normalize_thumb_item(item)

    for key in config['thumb_sizes'][image_dir].iterkeys():
        src_file = os.path.join(config['cache.dir'], 'images', thumb_path((image_dir, 'new'), key))
        dst_file = thumb_path(item, key)
        key = Key(bucket)
        key.key = dst_file

        key.set_metadata('is_default_thumb', '1')
        key.set_contents_from_filename(src_file, {'Content-Type': 'image/jpeg'})
        key.set_acl('public-read')
    return True
예제 #2
0
def s3_create_thumbs_for(item, image_file, image_filename):
    """Creates thumbnails in all sizes for a given Media or Podcast object.

    Side effects: Closes the open file handle passed in as image_file.

    :param item: A 2-tuple with a subdir name and an ID. If given a
        ORM mapped class with _thumb_dir and id attributes, the info
        can be extracted automatically.
    :type item: ``tuple`` or mapped class instance
    :param image_file: An open file handle for the original image file.
    :type image_file: file
    :param image_filename: The original filename of the thumbnail image.
    :type image_filename: unicode
    """
    # fallback to normal thumb handling if no S3 engine is enabled.
    storage = get_s3_storage()
    if not storage:
        return None
    bucket = storage.connect_to_bucket()

    image_dir, item_id = normalize_thumb_item(item)
    img = Image.open(image_file)

    # TODO: Allow other formats?
    for key, xy in config['thumb_sizes'][item._thumb_dir].iteritems():
        path = thumb_path(item, key)
        thumb_img = resize_thumb(img, xy)
        if thumb_img.mode != "RGB":
            thumb_img = thumb_img.convert("RGB")

        tmpfile = TemporaryFile()
        thumb_img.save(tmpfile, 'JPEG')

        key = Key(bucket)
        key.key = path
        key.set_contents_from_file(tmpfile, {'Content-Type': 'image/jpeg'})
        key.set_acl('public-read')

    # Backup the original image, ensuring there's no odd chars in the ext.
    # Thumbs from DailyMotion include an extra query string that needs to be
    # stripped off here.
    ext = os.path.splitext(image_filename)[1].lower()
    ext_match = _ext_filter.match(ext)
    if ext_match:
        backup_type = ext_match.group(1)
        backup_path = thumb_path(item, 'orig', ext=backup_type)
        image_file.seek(0)

        key = Key(bucket)
        key.key = backup_path
        key.set_contents_from_file(image_file,
            {'Content-Type': mimetypes.guess_type(backup_path)[0]})
        key.set_acl('public-read')

        image_file.close()
    return True
예제 #3
0
def s3_has_default_thumbs(item):
    """Return True if the thumbs for the given item are the defaults.

    :param item: A 2-tuple with a subdir name and an ID. If given a
        ORM mapped class with _thumb_dir and id attributes, the info
        can be extracted automatically.
    :type item: ``tuple`` or mapped class instance
    """
    # fallback to normal thumb handling if no S3 engine is enabled.
    storage = get_s3_storage()
    if not storage:
        return None
    bucket = storage.connect_to_bucket()
    image_dir, item_id = normalize_thumb_item(item)
    key = bucket.get_key(thumb_path(item, 's'))
    return key and key.get_metadata('is_default_thumb') == '1'
예제 #4
0
 def test_add_vimeo_video(self):
     pylons.app_globals.settings['use_embed_thumbnails'] = 'true'
     media = save_media_obj(
         u'Fake Name',
         u'*****@*****.**',
         u'Python Code Swarm',
         u'A visualization of all activity in the Python repository.',
         u'',
         None,
         u'http://www.vimeo.com/1093745'
     )
     # XXX: The following values are based on the values provided by the
     #      remote site at the time this test was written. They may change
     #      in future.
     assert media.duration == 282
     thumbnail_path = thumb_path(media, 's', exists=True)
     assert thumbnail_path is not None
     img = open(thumbnail_path)
     s = sha1(img.read()).hexdigest()
     img.close()
     assert s == '1eb9442b7864841e0f48270de7e3e871050b3876'
예제 #5
0
 def test_add_google_video(self):
     pylons.app_globals.settings['use_embed_thumbnails'] = 'true'
     media = save_media_obj(
         u'Fake Name',
         u'*****@*****.**',
         u'Pictures at an Exhibition',
         u'A nice, long, production of the orchestrated Pictures...',
         u'',
         None,
         u'http://video.google.com/videoplay?docid=8997593004077118819'
     )
     # XXX: The following values are based on the values provided by the
     #      remote site at the time this test was written. They may change
     #      in future.
     assert media.duration == 1121
     thumbnail_path = thumb_path(media, 's', exists=True)
     assert thumbnail_path is not None
     img = open(thumbnail_path)
     s = sha1(img.read()).hexdigest()
     img.close()
     assert s == 'f8e84e4a487c9ff6ea69ac696c199ae6ac222e38'
예제 #6
0
 def test_add_youtube_video(self):
     pylons.app_globals.settings['use_embed_thumbnails'] = 'true'
     media = save_media_obj(
         u'Fake Name',
         u'*****@*****.**',
         u'Old Spice',
         u'Isiah Mustafa stars in...',
         u'',
         None,
         u'http://www.youtube.com/watch?v=uLTIowBF0kE'
     )
     # XXX: The following values are based on the values provided by the
     #      remote site at the time this test was written. They may change
     #      in future.
     assert media.duration == 32
     thumbnail_path = thumb_path(media, 's', exists=True)
     assert thumbnail_path is not None
     img = open(thumbnail_path)
     s = sha1(img.read()).hexdigest()
     img.close()
     assert s == 'f0a3f5991fa032077faf2d3c698a6cf3e9dcadc1'
예제 #7
0
    def merge_stubs(self, orig_id, input_id, **kwargs):
        """Merge in a newly created media item.

        This is merges media that has just been created. It must have:
            1. a non-default thumbnail, or
            2. a file, or
            3. a title, description, etc

        :param orig_id: Media ID to copy data to
        :type orig_id: ``int``
        :param input_id: Media ID to source files, thumbs, etc from
        :type input_id: ``int``
        :returns: JSON dict

        """
        orig = fetch_row(Media, orig_id)
        input = fetch_row(Media, input_id)
        merged_files = []

        # Merge in the file(s) from the input stub
        if input.slug.startswith('_stub_') and input.files:
            for file in input.files[:]:
                # XXX: The filename will still use the old ID
                file.media = orig
                merged_files.append(file)
            DBSession.delete(input)

        # The original is a file or thumb stub, copy in the new values
        elif orig.slug.startswith('_stub_') \
        and not input.slug.startswith('_stub_'):
            DBSession.delete(input)
            DBSession.flush()
            orig.podcast = input.podcast
            orig.title = input.title
            orig.subtitle = input.subtitle
            orig.slug = input.slug
            orig.author = input.author
            orig.description = input.description
            orig.notes = input.notes
            orig.duration = input.duration
            orig.views = input.views
            orig.likes = input.likes
            orig.publish_on = input.publish_on
            orig.publish_until = input.publish_until
            orig.categories = input.categories
            orig.tags = input.tags
            orig.update_popularity()

        # Copy the input thumb over the default thumbnail
        elif input.slug.startswith('_stub_') \
        and has_default_thumbs(orig) \
        and not has_default_thumbs(input):
            for key, dst_path in thumb_paths(orig).iteritems():
                src_path = thumb_path(input, key)
                # This will raise an OSError on Windows, but not *nix
                os.rename(src_path, dst_path)
            DBSession.delete(input)

        # Report an error
        else:
            return dict(
                success = False,
                message = u'No merge operation fits.',
            )

        orig.update_status()

        status_form_xhtml = unicode(update_status_form.display(
            action=url_for(action='update_status', id=orig.id),
            media=orig))

        file_xhtml = {}
        for file in merged_files:
            file_xhtml[file.id] = unicode(edit_file_form.display(
                action=url_for(action='edit_file', id=orig.id),
                file=file))

        return dict(
            success = True,
            media_id = orig.id,
            title = orig.title,
            link = url_for(action='edit', id=orig.id),
            status_form = status_form_xhtml,
            file_forms = file_xhtml,
        )
예제 #8
0
    def merge_stubs(self, orig_id, input_id, **kwargs):
        """Merge in a newly created media item.

        This is merges media that has just been created. It must have:
            1. a non-default thumbnail, or
            2. a file, or
            3. a title, description, etc

        :param orig_id: Media ID to copy data to
        :type orig_id: ``int``
        :param input_id: Media ID to source files, thumbs, etc from
        :type input_id: ``int``
        :returns: JSON dict

        """
        orig = fetch_row(Media, orig_id)
        input = fetch_row(Media, input_id)
        merged_files = []

        # Merge in the file(s) from the input stub
        if input.slug.startswith('_stub_') and input.files:
            for file in input.files[:]:
                # XXX: The filename will still use the old ID
                file.media = orig
                merged_files.append(file)
            DBSession.delete(input)

        # The original is a file or thumb stub, copy in the new values
        elif orig.slug.startswith('_stub_') \
        and not input.slug.startswith('_stub_'):
            DBSession.delete(input)
            DBSession.flush()
            orig.podcast = input.podcast
            orig.title = input.title
            orig.subtitle = input.subtitle
            orig.slug = input.slug
            orig.author = input.author
            orig.description = input.description
            orig.notes = input.notes
            orig.duration = input.duration
            orig.views = input.views
            orig.likes = input.likes
            orig.publish_on = input.publish_on
            orig.publish_until = input.publish_until
            orig.categories = input.categories
            orig.tags = input.tags
            orig.update_popularity()

        # Copy the input thumb over the default thumbnail
        elif input.slug.startswith('_stub_') \
        and has_default_thumbs(orig) \
        and not has_default_thumbs(input):
            for key, dst_path in thumb_paths(orig).iteritems():
                src_path = thumb_path(input, key)
                # This will raise an OSError on Windows, but not *nix
                os.rename(src_path, dst_path)
            DBSession.delete(input)

        # Report an error
        else:
            return dict(
                success = False,
                message = u'No merge operation fits.',
            )

        orig.update_status()

        status_form_xhtml = unicode(update_status_form.display(
            action=url_for(action='update_status', id=orig.id),
            media=orig))

        file_xhtml = {}
        for file in merged_files:
            file_xhtml[file.id] = unicode(edit_file_form.display(
                action=url_for(action='edit_file', id=orig.id),
                file=file))

        return dict(
            success = True,
            media_id = orig.id,
            title = orig.title,
            link = url_for(action='edit', id=orig.id),
            status_form = status_form_xhtml,
            file_forms = file_xhtml,
        )