Exemple #1
0
def generate_alternate_formats(post: model.Post, content: bytes) \
        -> List[Tuple[model.Post, List[model.Tag]]]:
    assert post
    assert content
    new_posts = []
    if mime.is_animated_gif(content):
        tag_names = [tag.first_name for tag in post.tags]

        if config.config['convert']['gif']['to_mp4']:
            mp4_post, new_tags = create_post(
                images.Image(content).to_mp4(), tag_names, post.user)
            update_post_flags(mp4_post, ['loop'])
            update_post_safety(mp4_post, post.safety)
            update_post_source(mp4_post, post.source)
            new_posts += [(mp4_post, new_tags)]

        if config.config['convert']['gif']['to_webm']:
            webm_post, new_tags = create_post(
                images.Image(content).to_webm(), tag_names, post.user)
            update_post_flags(webm_post, ['loop'])
            update_post_safety(webm_post, post.safety)
            update_post_source(webm_post, post.source)
            new_posts += [(webm_post, new_tags)]

        db.session.flush()

        new_posts = [p for p in new_posts if p[0] is not None]

        new_relations = [p[0].post_id for p in new_posts]
        if len(new_relations) > 0:
            update_post_relations(post, new_relations)

    return new_posts
Exemple #2
0
def test_update_post_thumbnail_with_broken_thumbnail(
        tmpdir, config_injector, read_asset, post_factory, is_existing):
    config_injector({
        'data_dir': str(tmpdir.mkdir('data')),
        'thumbnails': {
            'post_width': 300,
            'post_height': 300,
        },
    })
    post = post_factory()
    db.session.add(post)
    if is_existing:
        db.session.flush()
        assert post.post_id
    else:
        assert not post.post_id
    generated_path = str(tmpdir) + '/data/generated-thumbnails/1.jpg'
    source_path = str(tmpdir) + '/data/posts/custom-thumbnails/1.dat'
    assert not os.path.exists(generated_path)
    assert not os.path.exists(source_path)
    posts.update_post_content(post, read_asset('png.png'))
    posts.update_post_thumbnail(post, read_asset('png-broken.png'))
    assert not os.path.exists(generated_path)
    assert not os.path.exists(source_path)
    db.session.flush()
    assert os.path.exists(generated_path)
    assert os.path.exists(source_path)
    with open(source_path, 'rb') as handle:
        assert handle.read() == read_asset('png-broken.png')
    with open(generated_path, 'rb') as handle:
        image = images.Image(handle.read())
        assert image.width == 1
        assert image.height == 1
Exemple #3
0
def get_default_flags(content: bytes) -> List[str]:
    assert content
    ret = []
    if mime.is_video(mime.get_mime_type(content)):
        ret.append(model.Post.FLAG_LOOP)
        if images.Image(content).check_for_sound():
            ret.append(model.Post.FLAG_SOUND)
    return ret
Exemple #4
0
def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
    assert post
    if not content:
        raise InvalidPostContentError('Post content missing.')

    update_signature = False
    post.mime_type = mime.get_mime_type(content)
    if mime.is_flash(post.mime_type):
        post.type = model.Post.TYPE_FLASH
    elif mime.is_image(post.mime_type):
        update_signature = True
        if mime.is_animated_gif(content):
            post.type = model.Post.TYPE_ANIMATION
        else:
            post.type = model.Post.TYPE_IMAGE
    elif mime.is_video(post.mime_type):
        post.type = model.Post.TYPE_VIDEO
    else:
        raise InvalidPostContentError(
            'Unhandled file type: %r' % post.mime_type)

    post.checksum = util.get_sha1(content)
    other_post = (
        db.session
        .query(model.Post)
        .filter(model.Post.checksum == post.checksum)
        .filter(model.Post.post_id != post.post_id)
        .one_or_none())
    if other_post \
            and other_post.post_id \
            and other_post.post_id != post.post_id:
        raise PostAlreadyUploadedError(other_post)

    if update_signature:
        purge_post_signature(post)
        post.signature = generate_post_signature(post, content)

    post.file_size = len(content)
    try:
        image = images.Image(content)
        post.canvas_width = image.width
        post.canvas_height = image.height
    except errors.ProcessingError:
        if not config.config['allow_broken_uploads']:
            raise InvalidPostContentError(
                'Unable to process image metadata')
        else:
            post.canvas_width = None
            post.canvas_height = None
    if (post.canvas_width is not None and post.canvas_width <= 0) \
            or (post.canvas_height is not None and post.canvas_height <= 0):
        if not config.config['allow_broken_uploads']:
            raise InvalidPostContentError(
                'Invalid image dimensions returned during processing')
        else:
            post.canvas_width = None
            post.canvas_height = None
    setattr(post, '__content', content)
Exemple #5
0
def test_sound(post: model.Post, content: bytes) -> None:
    assert post
    assert content
    if mime.is_video(mime.get_mime_type(content)):
        if images.Image(content).check_for_sound():
            flags = [x for x in post.flags.split(',') if x]
            if model.Post.FLAG_SOUND not in flags:
                flags.append(model.Post.FLAG_SOUND)
            update_post_flags(post, flags)
Exemple #6
0
def generate_post_thumbnail(post):
    if files.has(get_post_thumbnail_backup_path(post)):
        content = files.get(get_post_thumbnail_backup_path(post))
    else:
        content = files.get(get_post_content_path(post))
    try:
        image = images.Image(content)
        image.resize_fill(
            int(config.config['thumbnails']['post_width']),
            int(config.config['thumbnails']['post_height']))
        files.save(get_post_thumbnail_path(post), image.to_jpeg())
    except errors.ProcessingError:
        files.save(get_post_thumbnail_path(post), EMPTY_PIXEL)
Exemple #7
0
def update_user_avatar(user, avatar_style, avatar_content):
    if avatar_style == 'gravatar':
        user.avatar_style = user.AVATAR_GRAVATAR
    elif avatar_style == 'manual':
        user.avatar_style = user.AVATAR_MANUAL
        if not avatar_content:
            raise InvalidAvatarError('Avatar content missing.')
        image = images.Image(avatar_content)
        image.resize_fill(int(config.config['thumbnails']['avatar_width']),
                          int(config.config['thumbnails']['avatar_height']))
        files.save('avatars/' + user.name.lower() + '.png', image.to_png())
    else:
        raise InvalidAvatarError(
            'Avatar style %r is invalid. Valid avatar styles: %r.' %
            (avatar_style, ['gravatar', 'manual']))
Exemple #8
0
def generate_post_thumbnail(post: model.Post) -> None:
    assert post
    if files.has(get_post_thumbnail_backup_path(post)):
        content = files.get(get_post_thumbnail_backup_path(post))
    else:
        content = files.get(get_post_content_path(post))
    try:
        assert content
        image = images.Image(content)
        image.resize_fill(
            int(config.config["thumbnails"]["post_width"]),
            int(config.config["thumbnails"]["post_height"]),
        )
        files.save(get_post_thumbnail_path(post), image.to_jpeg())
    except errors.ProcessingError:
        files.save(get_post_thumbnail_path(post), EMPTY_PIXEL)
Exemple #9
0
def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
    assert post
    if not content:
        raise InvalidPostContentError('Post content missing.')
    post.mime_type = mime.get_mime_type(content)
    if mime.is_flash(post.mime_type):
        post.type = model.Post.TYPE_FLASH
    elif mime.is_image(post.mime_type):
        if mime.is_animated_gif(content):
            post.type = model.Post.TYPE_ANIMATION
        else:
            post.type = model.Post.TYPE_IMAGE
    elif mime.is_video(post.mime_type):
        post.type = model.Post.TYPE_VIDEO
    else:
        raise InvalidPostContentError('Unhandled file type: %r' %
                                      post.mime_type)

    post.checksum = util.get_sha1(content)
    other_post = db.session \
        .query(model.Post) \
        .filter(model.Post.checksum == post.checksum) \
        .filter(model.Post.post_id != post.post_id) \
        .one_or_none()
    if other_post \
            and other_post.post_id \
            and other_post.post_id != post.post_id:
        raise PostAlreadyUploadedError(other_post)

    post.file_size = len(content)
    try:
        image = images.Image(content)
        post.canvas_width = image.width
        post.canvas_height = image.height
    except errors.ProcessingError:
        post.canvas_width = None
        post.canvas_height = None
    if (post.canvas_width is not None and post.canvas_width <= 0) \
            or (post.canvas_height is not None and post.canvas_height <= 0):
        post.canvas_width = None
        post.canvas_height = None
    setattr(post, '__content', content)
Exemple #10
0
def test_update_post_thumbnail_with_broken_thumbnail(
    tmpdir, config_injector, read_asset, post_factory, is_existing
):
    config_injector(
        {
            "data_dir": str(tmpdir.mkdir("data")),
            "thumbnails": {
                "post_width": 300,
                "post_height": 300,
            },
            "secret": "test",
            "allow_broken_uploads": False,
        }
    )
    post = post_factory(id=1)
    db.session.add(post)
    if is_existing:
        db.session.flush()
    assert post.post_id
    generated_path = (
        "{}/data/generated-thumbnails/".format(tmpdir)
        + "1_244c8840887984c4.jpg"
    )
    source_path = (
        "{}/data/posts/custom-thumbnails/".format(tmpdir)
        + "1_244c8840887984c4.dat"
    )
    assert not os.path.exists(generated_path)
    assert not os.path.exists(source_path)
    posts.update_post_content(post, read_asset("png.png"))
    posts.update_post_thumbnail(post, read_asset("png-broken.png"))
    assert not os.path.exists(generated_path)
    assert not os.path.exists(source_path)
    db.session.flush()
    assert os.path.exists(generated_path)
    assert os.path.exists(source_path)
    with open(source_path, "rb") as handle:
        assert handle.read() == read_asset("png-broken.png")
    with open(generated_path, "rb") as handle:
        image = images.Image(handle.read())
        assert image.width == 1
        assert image.height == 1
Exemple #11
0
def update_user_avatar(user: model.User,
                       avatar_style: str,
                       avatar_content: Optional[bytes] = None) -> None:
    assert user
    if avatar_style == 'gravatar':
        user.avatar_style = user.AVATAR_GRAVATAR
    elif avatar_style == 'manual':
        user.avatar_style = user.AVATAR_MANUAL
        avatar_path = 'avatars/' + user.name.lower() + '.png'
        if not avatar_content:
            if files.has(avatar_path):
                return
            raise InvalidAvatarError('아바타 컨텐츠가 누락되었습니다.')
        image = images.Image(avatar_content)
        image.resize_fill(int(config.config['thumbnails']['avatar_width']),
                          int(config.config['thumbnails']['avatar_height']))
        files.save(avatar_path, image.to_png())
    else:
        raise InvalidAvatarError('아바타 스타일 %r 은(는) 잘못된 값입니다. 올바른 스타일 값: %r.' %
                                 (avatar_style, ['gravatar', 'manual']))
Exemple #12
0
def generate_post_thumbnail(post: model.Post) -> None:
    assert post
    if files.has(get_post_thumbnail_backup_path(post)):
        content = files.get(get_post_thumbnail_backup_path(post))
    else:
        content = files.get(get_post_content_path(post))
    try:
        assert content
        if post.type == model.Post.TYPE_IMAGE:
            media = images.Image(content)
        elif post.type == model.Post.TYPE_VIDEO:
            media = images.Video(content)

        thumb = media.to_thumbnail(
            int(config.config["thumbnails"]["post_width"]),
            int(config.config["thumbnails"]["post_height"]),
        )

        files.save(get_post_thumbnail_path(post), thumb)
    except errors.ProcessingError:
        files.save(get_post_thumbnail_path(post), EMPTY_PIXEL)
Exemple #13
0
def update_user_avatar(user: model.User,
                       avatar_style: str,
                       avatar_content: Optional[bytes] = None) -> None:
    assert user
    if avatar_style == "gravatar":
        user.avatar_style = user.AVATAR_GRAVATAR
    elif avatar_style == "manual":
        user.avatar_style = user.AVATAR_MANUAL
        avatar_path = "avatars/" + user.name.lower() + ".png"
        if not avatar_content:
            if files.has(avatar_path):
                return
            raise InvalidAvatarError("Avatar content missing.")
        image = images.Image(avatar_content)
        image.resize_fill(
            int(config.config["thumbnails"]["avatar_width"]),
            int(config.config["thumbnails"]["avatar_height"]),
        )
        files.save(avatar_path, image.to_png())
    else:
        raise InvalidAvatarError(
            "Avatar style %r is invalid. Valid avatar styles: %r." %
            (avatar_style, ["gravatar", "manual"]))
Exemple #14
0
def test_update_post_thumbnail_broken_thumbnail(tmpdir, config_injector,
                                                read_asset, post_factory):
    config_injector({
        'data_dir': str(tmpdir.mkdir('data')),
        'thumbnails': {
            'post_width': 300,
            'post_height': 300,
        },
    })
    post = post_factory(id=1)
    db.session.add(post)
    db.session.flush()
    posts.update_post_content(post, read_asset('png.png'))
    posts.update_post_thumbnail(post, read_asset('png-broken.png'))
    assert os.path.exists(str(tmpdir) + '/data/posts/custom-thumbnails/1.dat')
    assert os.path.exists(str(tmpdir) + '/data/generated-thumbnails/1.jpg')
    with open(str(tmpdir) + '/data/posts/custom-thumbnails/1.dat',
              'rb') as handle:
        assert handle.read() == read_asset('png-broken.png')
    with open(str(tmpdir) + '/data/generated-thumbnails/1.jpg',
              'rb') as handle:
        image = images.Image(handle.read())
        assert image.width == 1
        assert image.height == 1
Exemple #15
0
def update_post_content(post, content):
    if not content:
        raise InvalidPostContentError('Post content missing.')
    post.mime_type = mime.get_mime_type(content)
    if mime.is_flash(post.mime_type):
        post.type = db.Post.TYPE_FLASH
    elif mime.is_image(post.mime_type):
        if mime.is_animated_gif(content):
            post.type = db.Post.TYPE_ANIMATION
        else:
            post.type = db.Post.TYPE_IMAGE
    elif mime.is_video(post.mime_type):
        post.type = db.Post.TYPE_VIDEO
    else:
        raise InvalidPostContentError('Unhandled file type: %r' % post.mime_type)

    post.checksum = util.get_md5(content)
    other_post = db.session \
        .query(db.Post) \
        .filter(db.Post.checksum == post.checksum) \
        .filter(db.Post.post_id != post.post_id) \
        .one_or_none()
    if other_post:
        raise PostAlreadyUploadedError(
            'Post already uploaded (%d)' % other_post.post_id)

    post.file_size = len(content)
    try:
        image = images.Image(content)
        post.canvas_width = image.width
        post.canvas_height = image.height
    except errors.ProcessingError:
        post.canvas_width = None
        post.canvas_height = None
    files.save(get_post_content_path(post), content)
    update_post_thumbnail(post, content=None, delete=False)
Exemple #16
0
def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
    assert post
    if not content:
        raise InvalidPostContentError("Post content missing.")

    update_signature = False
    post.mime_type = mime.get_mime_type(content)
    if mime.is_flash(post.mime_type):
        raise InvalidPostContentError(
            "Flash animations are deprecated in this build and are slowly " +
            "being phased out.")
    elif mime.is_image(post.mime_type):
        update_signature = True
        if mime.is_animated_gif(content):
            post.type = model.Post.TYPE_ANIMATION
        else:
            post.type = model.Post.TYPE_IMAGE
    elif mime.is_video(post.mime_type):
        post.type = model.Post.TYPE_VIDEO
    else:
        raise InvalidPostContentError(f"Unhandled file type: {post.mime_type}")

    post.checksum = util.get_sha1(content)
    post.checksum_md5 = util.get_md5(content)
    other_post = (db.session.query(
        model.Post).filter(model.Post.checksum == post.checksum).filter(
            model.Post.post_id != post.post_id).one_or_none())
    if (other_post and other_post.post_id
            and other_post.post_id != post.post_id):
        raise PostAlreadyUploadedError(other_post)

    if update_signature:
        purge_post_signature(post)
        post.signature = generate_post_signature(post, content)

    post.file_size = len(content)

    post.canvas_width = None
    post.canvas_height = None
    post.date_taken = None
    post.camera = None

    try:
        if post.type == model.Post.TYPE_IMAGE:
            media = images.Image(content)
        elif post.type in (model.Post.TYPE_ANIMATION, model.Post.TYPE_VIDEO):
            media = images.Video(content)
    except Exception as ex:
        logger.exception(ex)
        if not config.config["allow_broken_uploads"]:
            raise InvalidPostContentError("Unable to process image metadata")
    else:
        if not media.width or not media.height:
            if not config.config["allow_broken_uploads"]:
                raise InvalidPostContentError(
                    "Invalid image dimensions returned during processing")

        post.canvas_width = media.width
        post.canvas_height = media.height
        post.date_taken = media.date_taken
        post.camera = media.camera

    setattr(post, "__content", content)