aboutsummaryrefslogtreecommitdiff
path: root/server/szurubooru
diff options
context:
space:
mode:
authorReAnzu2018-03-08 00:47:58 -0600
committerrr-2018-03-08 07:48:45 +0100
commit12ec43f09887ca1682c6d02557336f3f45c7ba30 (patch)
treee61519c4a7e1ee90621f7ec51879e3f2629867cc /server/szurubooru
parent4ff8be6a2f0f2156a42790bcb56dee6f53acea92 (diff)
server/posts: auto convert GIFs to WEBMs/MP4s
- Default setting is false for both conversions, as this will require additional resources of the server, but is bandwidth friendly for viewers - WEBM conversion is slow, but better quality than MP4 conversion with a typically smaller file size - Tags are copied over from the original upload - Snapshots are generated for the new auto posts
Diffstat (limited to 'server/szurubooru')
-rw-r--r--server/szurubooru/api/post_api.py21
-rw-r--r--server/szurubooru/func/images.py62
-rw-r--r--server/szurubooru/func/posts.py45
-rw-r--r--server/szurubooru/func/util.py10
4 files changed, 132 insertions, 6 deletions
diff --git a/server/szurubooru/api/post_api.py b/server/szurubooru/api/post_api.py
index 27f10c1..aaa7437 100644
--- a/server/szurubooru/api/post_api.py
+++ b/server/szurubooru/api/post_api.py
@@ -1,4 +1,4 @@
-from typing import Optional, Dict
+from typing import Optional, Dict, List
from datetime import datetime
from szurubooru import db, model, errors, rest, search
from szurubooru.func import (
@@ -69,13 +69,26 @@ def create_post(
posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
ctx.session.add(post)
ctx.session.flush()
- snapshots.create(post, None if anonymous else ctx.user)
- for tag in new_tags:
- snapshots.create(tag, None if anonymous else ctx.user)
+ create_snapshots_for_post(post, new_tags, None if anonymous else ctx.user)
+ alternate_format_posts = posts.generate_alternate_formats(post, content)
+ for alternate_post, alternate_post_new_tags in alternate_format_posts:
+ create_snapshots_for_post(
+ alternate_post,
+ alternate_post_new_tags,
+ None if anonymous else ctx.user)
ctx.session.commit()
return _serialize_post(ctx, post)
+def create_snapshots_for_post(
+ post: model.Post,
+ new_tags: List[model.Tag],
+ user: Optional[model.User]):
+ snapshots.create(post, user)
+ for tag in new_tags:
+ snapshots.create(tag, user)
+
+
@rest.routes.get('/post/(?P<post_id>[^/]+)/?')
def get_post(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
auth.verify_privilege(ctx.user, 'posts:view')
diff --git a/server/szurubooru/func/images.py b/server/szurubooru/func/images.py
index 9e62aef..b3df55e 100644
--- a/server/szurubooru/func/images.py
+++ b/server/szurubooru/func/images.py
@@ -79,6 +79,68 @@ class Image:
'-',
])
+ def to_webm(self) -> bytes:
+ with util.create_temp_file_path(suffix='.log') as phase_log_path:
+ # Pass 1
+ self._execute([
+ '-i', '{path}',
+ '-pass', '1',
+ '-passlogfile', phase_log_path,
+ '-vcodec', 'libvpx-vp9',
+ '-crf', '4',
+ '-b:v', '2500K',
+ '-acodec', 'libvorbis',
+ '-f', 'webm',
+ '-y', '/dev/null'
+ ])
+
+ # Pass 2
+ return self._execute([
+ '-i', '{path}',
+ '-pass', '2',
+ '-passlogfile', phase_log_path,
+ '-vcodec', 'libvpx-vp9',
+ '-crf', '4',
+ '-b:v', '2500K',
+ '-acodec', 'libvorbis',
+ '-f', 'webm',
+ '-'
+ ])
+
+ def to_mp4(self) -> bytes:
+ with util.create_temp_file_path(suffix='.dat') as mp4_temp_path:
+ width = self.width
+ height = self.height
+ altered_dimensions = False
+
+ if self.width % 2 != 0:
+ width = self.width - 1
+ altered_dimensions = True
+
+ if self.height % 2 != 0:
+ height = self.height - 1
+ altered_dimensions = True
+
+ args = [
+ '-i', '{path}',
+ '-vcodec', 'libx264',
+ '-preset', 'slow',
+ '-crf', '22',
+ '-b:v', '200K',
+ '-profile:v', 'main',
+ '-pix_fmt', 'yuv420p',
+ '-acodec', 'aac',
+ '-f', 'mp4'
+ ]
+
+ if altered_dimensions:
+ args += ['-filter:v', 'scale=\'%d:%d\'' % (width, height)]
+
+ self._execute(args + ['-y', mp4_temp_path])
+
+ with open(mp4_temp_path, 'rb') as mp4_temp:
+ return mp4_temp.read()
+
def _execute(
self,
cli: List[str],
diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py
index 406f6e1..219c832 100644
--- a/server/szurubooru/func/posts.py
+++ b/server/szurubooru/func/posts.py
@@ -5,7 +5,7 @@ import sqlalchemy as sa
from szurubooru import config, db, model, errors, rest
from szurubooru.func import (
users, scores, comments, tags, util,
- mime, images, files, image_hash, serialization)
+ mime, images, files, image_hash, serialization, snapshots)
EMPTY_PIXEL = (
@@ -364,7 +364,7 @@ def create_post(
update_post_content(post, content)
new_tags = update_post_tags(post, tag_names)
- return (post, new_tags)
+ return post, new_tags
def update_post_safety(post: model.Post, safety: str) -> None:
@@ -429,6 +429,47 @@ def _sync_post_content(post: model.Post) -> None:
generate_post_thumbnail(post)
+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_name.name
+ for tag_name in [tag.names 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
+
+
def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
assert post
if not content:
diff --git a/server/szurubooru/func/util.py b/server/szurubooru/func/util.py
index 61e975b..ba2d4dc 100644
--- a/server/szurubooru/func/util.py
+++ b/server/szurubooru/func/util.py
@@ -41,6 +41,16 @@ def create_temp_file(**kwargs: Any) -> Generator:
os.remove(path)
+@contextmanager
+def create_temp_file_path(**kwargs: Any) -> Generator:
+ (descriptor, path) = tempfile.mkstemp(**kwargs)
+ os.close(descriptor)
+ try:
+ yield path
+ finally:
+ os.remove(path)
+
+
def unalias_dict(source: List[Tuple[List[str], T]]) -> Dict[str, T]:
output_dict = {} # type: Dict[str, T]
for aliases, value in source:

© 2015 - 2026 Jakob L. Kreuze