commit
5ea9e27e48
21 changed files with 229 additions and 11 deletions
|
@ -37,6 +37,9 @@
|
||||||
'image/png': 'PNG',
|
'image/png': 'PNG',
|
||||||
'image/webp': 'WEBP',
|
'image/webp': 'WEBP',
|
||||||
'image/bmp': 'BMP',
|
'image/bmp': 'BMP',
|
||||||
|
'image/avif': 'AVIF',
|
||||||
|
'image/heif': 'HEIF',
|
||||||
|
'image/heic': 'HEIC',
|
||||||
'video/webm': 'WEBM',
|
'video/webm': 'WEBM',
|
||||||
'video/mp4': 'MPEG-4',
|
'video/mp4': 'MPEG-4',
|
||||||
'application/x-shockwave-flash': 'SWF',
|
'application/x-shockwave-flash': 'SWF',
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
'image/png': 'PNG',
|
'image/png': 'PNG',
|
||||||
'image/webp': 'WEBP',
|
'image/webp': 'WEBP',
|
||||||
'image/bmp': 'BMP',
|
'image/bmp': 'BMP',
|
||||||
|
'image/avif': 'AVIF',
|
||||||
|
'image/heif': 'HEIF',
|
||||||
|
'image/heic': 'HEIC',
|
||||||
'video/webm': 'WEBM',
|
'video/webm': 'WEBM',
|
||||||
'video/mp4': 'MPEG-4',
|
'video/mp4': 'MPEG-4',
|
||||||
'application/x-shockwave-flash': 'SWF',
|
'application/x-shockwave-flash': 'SWF',
|
||||||
|
|
|
@ -16,6 +16,9 @@ function _mimeTypeToPostType(mimeType) {
|
||||||
"image/png": "image",
|
"image/png": "image",
|
||||||
"image/webp": "image",
|
"image/webp": "image",
|
||||||
"image/bmp": "image",
|
"image/bmp": "image",
|
||||||
|
"image/avif": "image",
|
||||||
|
"image/heif": "image",
|
||||||
|
"image/heic": "image",
|
||||||
"video/mp4": "video",
|
"video/mp4": "video",
|
||||||
"video/webm": "video",
|
"video/webm": "video",
|
||||||
}[mimeType] || "unknown"
|
}[mimeType] || "unknown"
|
||||||
|
@ -111,6 +114,9 @@ class Url extends Uploadable {
|
||||||
gif: "image/gif",
|
gif: "image/gif",
|
||||||
webp: "image/webp",
|
webp: "image/webp",
|
||||||
bmp: "image/bmp",
|
bmp: "image/bmp",
|
||||||
|
avif: "image/avif",
|
||||||
|
heif: "image/heif",
|
||||||
|
heic: "image/heic",
|
||||||
mp4: "video/mp4",
|
mp4: "video/mp4",
|
||||||
webm: "video/webm",
|
webm: "video/webm",
|
||||||
};
|
};
|
||||||
|
@ -155,7 +161,7 @@ class PostUploadView extends events.EventTarget {
|
||||||
this._contentInputNode,
|
this._contentInputNode,
|
||||||
{
|
{
|
||||||
extraText:
|
extraText:
|
||||||
"Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf",
|
"Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf, .avif, .heif, .heic",
|
||||||
allowUrls: true,
|
allowUrls: true,
|
||||||
allowMultiple: true,
|
allowMultiple: true,
|
||||||
lock: false,
|
lock: false,
|
||||||
|
|
14
client/package-lock.json
generated
14
client/package-lock.json
generated
|
@ -31,7 +31,7 @@
|
||||||
"terser": "^3.7.7",
|
"terser": "^3.7.7",
|
||||||
"underscore": "^1.12.1",
|
"underscore": "^1.12.1",
|
||||||
"watchify": "^4.0.0",
|
"watchify": "^4.0.0",
|
||||||
"ws": "^7.4.5"
|
"ws": "^7.4.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
|
@ -4467,9 +4467,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "7.4.5",
|
"version": "7.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
|
||||||
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==",
|
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.3.0"
|
"node": ">=8.3.0"
|
||||||
|
@ -8481,9 +8481,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "7.4.5",
|
"version": "7.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
|
||||||
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==",
|
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,6 +31,6 @@
|
||||||
"terser": "^3.7.7",
|
"terser": "^3.7.7",
|
||||||
"underscore": "^1.12.1",
|
"underscore": "^1.12.1",
|
||||||
"watchify": "^4.0.0",
|
"watchify": "^4.0.0",
|
||||||
"ws": "^7.4.5"
|
"ws": "^7.4.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ WORKDIR /opt/app
|
||||||
|
|
||||||
RUN apk --no-cache add \
|
RUN apk --no-cache add \
|
||||||
python3 \
|
python3 \
|
||||||
|
python3-dev \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
py3-pip \
|
py3-pip \
|
||||||
# from requirements.txt:
|
# from requirements.txt:
|
||||||
|
@ -18,10 +19,18 @@ RUN apk --no-cache add \
|
||||||
py3-pynacl \
|
py3-pynacl \
|
||||||
py3-tz \
|
py3-tz \
|
||||||
py3-pyrfc3339 \
|
py3-pyrfc3339 \
|
||||||
|
build-base \
|
||||||
|
&& apk --no-cache add --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community \
|
||||||
|
libheif \
|
||||||
|
libavif \
|
||||||
|
libheif-dev \
|
||||||
|
libavif-dev \
|
||||||
&& pip3 install --no-cache-dir --disable-pip-version-check \
|
&& pip3 install --no-cache-dir --disable-pip-version-check \
|
||||||
alembic \
|
alembic \
|
||||||
"coloredlogs==5.0" \
|
"coloredlogs==5.0" \
|
||||||
youtube_dl \
|
youtube_dl \
|
||||||
|
pillow-avif-plugin \
|
||||||
|
pyheif-pillow-opener \
|
||||||
&& apk --no-cache del py3-pip
|
&& apk --no-cache del py3-pip
|
||||||
|
|
||||||
COPY ./ /opt/app/
|
COPY ./ /opt/app/
|
||||||
|
|
|
@ -9,4 +9,6 @@ pillow>=4.3.0
|
||||||
pynacl>=1.2.1
|
pynacl>=1.2.1
|
||||||
pytz>=2018.3
|
pytz>=2018.3
|
||||||
pyRFC3339>=1.0
|
pyRFC3339>=1.0
|
||||||
|
pillow-avif-plugin>=1.1.0
|
||||||
|
pyheif-pillow-opener>=0.1.0
|
||||||
youtube_dl
|
youtube_dl
|
||||||
|
|
|
@ -6,6 +6,10 @@ from typing import Any, Callable, List, Optional, Set, Tuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
import pillow_avif
|
||||||
|
import pyheif
|
||||||
|
from pyheif_pillow_opener import register_heif_opener
|
||||||
|
register_heif_opener()
|
||||||
|
|
||||||
from szurubooru import config, errors
|
from szurubooru import config, errors
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@ import math
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from io import BytesIO
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
from szurubooru import errors
|
from szurubooru import errors
|
||||||
from szurubooru.func import mime, util
|
from szurubooru.func import mime, util
|
||||||
|
@ -12,6 +14,13 @@ from szurubooru.func import mime, util
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_heif_to_png(content: bytes) -> bytes:
|
||||||
|
img = PILImage.open(BytesIO(content))
|
||||||
|
img_byte_arr = BytesIO()
|
||||||
|
img.save(img_byte_arr, format='PNG')
|
||||||
|
return img_byte_arr.getvalue()
|
||||||
|
|
||||||
|
|
||||||
class Image:
|
class Image:
|
||||||
def __init__(self, content: bytes) -> None:
|
def __init__(self, content: bytes) -> None:
|
||||||
self.content = content
|
self.content = content
|
||||||
|
@ -252,7 +261,12 @@ class Image:
|
||||||
ignore_error_if_data: bool = False,
|
ignore_error_if_data: bool = False,
|
||||||
get_logs: bool = False,
|
get_logs: bool = False,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
extension = mime.get_extension(mime.get_mime_type(self.content))
|
mime_type = mime.get_mime_type(self.content)
|
||||||
|
if mime.is_heif(mime_type):
|
||||||
|
# FFmpeg does not support HEIF.
|
||||||
|
# https://trac.ffmpeg.org/ticket/6521
|
||||||
|
self.content = convert_heif_to_png(self.content)
|
||||||
|
extension = mime.get_extension(mime_type)
|
||||||
assert extension
|
assert extension
|
||||||
with util.create_temp_file(suffix="." + extension) as handle:
|
with util.create_temp_file(suffix="." + extension) as handle:
|
||||||
handle.write(self.content)
|
handle.write(self.content)
|
||||||
|
|
|
@ -24,6 +24,15 @@ def get_mime_type(content: bytes) -> str:
|
||||||
if content[0:2] == b"BM":
|
if content[0:2] == b"BM":
|
||||||
return "image/bmp"
|
return "image/bmp"
|
||||||
|
|
||||||
|
if content[4:12] in (b"ftypavif", b"ftypavis"):
|
||||||
|
return "image/avif"
|
||||||
|
|
||||||
|
if content[4:12] == b"ftypmif1":
|
||||||
|
return "image/heif"
|
||||||
|
|
||||||
|
if content[4:12] in (b"ftypheic", b"ftypheix"):
|
||||||
|
return "image/heic"
|
||||||
|
|
||||||
if content[0:4] == b"\x1A\x45\xDF\xA3":
|
if content[0:4] == b"\x1A\x45\xDF\xA3":
|
||||||
return "video/webm"
|
return "video/webm"
|
||||||
|
|
||||||
|
@ -41,6 +50,9 @@ def get_extension(mime_type: str) -> Optional[str]:
|
||||||
"image/png": "png",
|
"image/png": "png",
|
||||||
"image/webp": "webp",
|
"image/webp": "webp",
|
||||||
"image/bmp": "bmp",
|
"image/bmp": "bmp",
|
||||||
|
"image/avif": "avif",
|
||||||
|
"image/heif": "heif",
|
||||||
|
"image/heic": "heic",
|
||||||
"video/mp4": "mp4",
|
"video/mp4": "mp4",
|
||||||
"video/webm": "webm",
|
"video/webm": "webm",
|
||||||
"application/octet-stream": "dat",
|
"application/octet-stream": "dat",
|
||||||
|
@ -63,6 +75,9 @@ def is_image(mime_type: str) -> bool:
|
||||||
"image/gif",
|
"image/gif",
|
||||||
"image/webp",
|
"image/webp",
|
||||||
"image/bmp",
|
"image/bmp",
|
||||||
|
"image/avif",
|
||||||
|
"image/heif",
|
||||||
|
"image/heic",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,3 +87,10 @@ def is_animated_gif(content: bytes) -> bool:
|
||||||
get_mime_type(content) == "image/gif"
|
get_mime_type(content) == "image/gif"
|
||||||
and len(re.findall(pattern, content)) > 1
|
and len(re.findall(pattern, content)) > 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_heif(mime_type: str) -> bool:
|
||||||
|
return mime_type.lower() in (
|
||||||
|
"image/heif",
|
||||||
|
"image/heic",
|
||||||
|
"image/avif",
|
||||||
|
)
|
||||||
|
|
|
@ -650,7 +650,8 @@ def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
|
||||||
image = images.Image(content)
|
image = images.Image(content)
|
||||||
post.canvas_width = image.width
|
post.canvas_width = image.width
|
||||||
post.canvas_height = image.height
|
post.canvas_height = image.height
|
||||||
except errors.ProcessingError:
|
except errors.ProcessingError as ex:
|
||||||
|
logger.exception(ex)
|
||||||
if not config.config["allow_broken_uploads"]:
|
if not config.config["allow_broken_uploads"]:
|
||||||
raise InvalidPostContentError("Unable to process image metadata")
|
raise InvalidPostContentError("Unable to process image metadata")
|
||||||
else:
|
else:
|
||||||
|
|
BIN
server/szurubooru/tests/assets/avif-avis.avif
Normal file
BIN
server/szurubooru/tests/assets/avif-avis.avif
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/avif-similar.avif
Normal file
BIN
server/szurubooru/tests/assets/avif-similar.avif
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/avif.avif
Normal file
BIN
server/szurubooru/tests/assets/avif.avif
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/heic-heix.heic
Normal file
BIN
server/szurubooru/tests/assets/heic-heix.heic
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/heic.heic
Normal file
BIN
server/szurubooru/tests/assets/heic.heic
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/heif-similar.heif
Normal file
BIN
server/szurubooru/tests/assets/heif-similar.heif
Normal file
Binary file not shown.
BIN
server/szurubooru/tests/assets/heif.heif
Normal file
BIN
server/szurubooru/tests/assets/heif.heif
Normal file
Binary file not shown.
|
@ -27,3 +27,53 @@ def test_signature_functions(read_asset, config_injector):
|
||||||
words2 = image_hash.generate_words(sig2)
|
words2 = image_hash.generate_words(sig2)
|
||||||
words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
|
words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
|
||||||
assert words_match == 18
|
assert words_match == 18
|
||||||
|
|
||||||
|
|
||||||
|
def test_signature_heif(read_asset, config_injector):
|
||||||
|
sig1 = image_hash.generate_signature(read_asset("heif.heif"))
|
||||||
|
sig2 = image_hash.generate_signature(read_asset("heif-similar.heif"))
|
||||||
|
|
||||||
|
sig1_repacked = image_hash.unpack_signature(
|
||||||
|
image_hash.pack_signature(sig1)
|
||||||
|
)
|
||||||
|
sig2_repacked = image_hash.unpack_signature(
|
||||||
|
image_hash.pack_signature(sig2)
|
||||||
|
)
|
||||||
|
assert array_equal(sig1, sig1_repacked)
|
||||||
|
assert array_equal(sig2, sig2_repacked)
|
||||||
|
|
||||||
|
dist1 = image_hash.normalized_distance([sig1], sig2)
|
||||||
|
assert abs(dist1[0] - 0.136777724290135) < 1e-8
|
||||||
|
|
||||||
|
dist2 = image_hash.normalized_distance([sig2], sig2)
|
||||||
|
assert abs(dist2[0]) < 1e-8
|
||||||
|
|
||||||
|
words1 = image_hash.generate_words(sig1)
|
||||||
|
words2 = image_hash.generate_words(sig2)
|
||||||
|
words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
|
||||||
|
assert words_match == 43
|
||||||
|
|
||||||
|
|
||||||
|
def test_signature_avif(read_asset, config_injector):
|
||||||
|
sig1 = image_hash.generate_signature(read_asset("avif.avif"))
|
||||||
|
sig2 = image_hash.generate_signature(read_asset("avif-similar.avif"))
|
||||||
|
|
||||||
|
sig1_repacked = image_hash.unpack_signature(
|
||||||
|
image_hash.pack_signature(sig1)
|
||||||
|
)
|
||||||
|
sig2_repacked = image_hash.unpack_signature(
|
||||||
|
image_hash.pack_signature(sig2)
|
||||||
|
)
|
||||||
|
assert array_equal(sig1, sig1_repacked)
|
||||||
|
assert array_equal(sig2, sig2_repacked)
|
||||||
|
|
||||||
|
dist1 = image_hash.normalized_distance([sig1], sig2)
|
||||||
|
assert abs(dist1[0] - 0.22628712858355998) < 1e-8
|
||||||
|
|
||||||
|
dist2 = image_hash.normalized_distance([sig2], sig2)
|
||||||
|
assert abs(dist2[0]) < 1e-8
|
||||||
|
|
||||||
|
words1 = image_hash.generate_words(sig1)
|
||||||
|
words2 = image_hash.generate_words(sig2)
|
||||||
|
words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
|
||||||
|
assert words_match == 12
|
||||||
|
|
|
@ -14,6 +14,11 @@ from szurubooru.func import mime
|
||||||
("gif.gif", "image/gif"),
|
("gif.gif", "image/gif"),
|
||||||
("webp.webp", "image/webp"),
|
("webp.webp", "image/webp"),
|
||||||
("bmp.bmp", "image/bmp"),
|
("bmp.bmp", "image/bmp"),
|
||||||
|
("avif.avif", "image/avif"),
|
||||||
|
("avif-avis.avif", "image/avif"),
|
||||||
|
("heif.heif", "image/heif"),
|
||||||
|
("heic.heic", "image/heic"),
|
||||||
|
("heic-heix.heic", "image/heic"),
|
||||||
("text.txt", "application/octet-stream"),
|
("text.txt", "application/octet-stream"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -36,6 +41,9 @@ def test_get_mime_type_for_empty_file():
|
||||||
("image/gif", "gif"),
|
("image/gif", "gif"),
|
||||||
("image/webp", "webp"),
|
("image/webp", "webp"),
|
||||||
("image/bmp", "bmp"),
|
("image/bmp", "bmp"),
|
||||||
|
("image/avif", "avif"),
|
||||||
|
("image/heif", "heif"),
|
||||||
|
("image/heic", "heic"),
|
||||||
("application/octet-stream", "dat"),
|
("application/octet-stream", "dat"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -78,10 +86,16 @@ def test_is_video(input_mime_type, expected_state):
|
||||||
("image/png", True),
|
("image/png", True),
|
||||||
("image/jpeg", True),
|
("image/jpeg", True),
|
||||||
("image/bmp", True),
|
("image/bmp", True),
|
||||||
|
("image/avif", True),
|
||||||
|
("image/heic", True),
|
||||||
|
("image/heif", True),
|
||||||
("IMAGE/GIF", True),
|
("IMAGE/GIF", True),
|
||||||
("IMAGE/PNG", True),
|
("IMAGE/PNG", True),
|
||||||
("IMAGE/JPEG", True),
|
("IMAGE/JPEG", True),
|
||||||
("IMAGE/BMP", True),
|
("IMAGE/BMP", True),
|
||||||
|
("IMAGE/AVIF", True),
|
||||||
|
("IMAGE/HEIC", True),
|
||||||
|
("IMAGE/HEIF", True),
|
||||||
("image/anything_else", False),
|
("image/anything_else", False),
|
||||||
("not an image", False),
|
("not an image", False),
|
||||||
],
|
],
|
||||||
|
@ -99,3 +113,26 @@ def test_is_image(input_mime_type, expected_state):
|
||||||
)
|
)
|
||||||
def test_is_animated_gif(read_asset, input_path, expected_state):
|
def test_is_animated_gif(read_asset, input_path, expected_state):
|
||||||
assert mime.is_animated_gif(read_asset(input_path)) == expected_state
|
assert mime.is_animated_gif(read_asset(input_path)) == expected_state
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"input_mime_type,expected_state",
|
||||||
|
[
|
||||||
|
("image/gif", False),
|
||||||
|
("image/png", False),
|
||||||
|
("image/jpeg", False),
|
||||||
|
("image/avif", True),
|
||||||
|
("image/heic", True),
|
||||||
|
("image/heif", True),
|
||||||
|
("IMAGE/GIF", False),
|
||||||
|
("IMAGE/PNG", False),
|
||||||
|
("IMAGE/JPEG", False),
|
||||||
|
("IMAGE/AVIF", True),
|
||||||
|
("IMAGE/HEIC", True),
|
||||||
|
("IMAGE/HEIF", True),
|
||||||
|
("image/anything_else", False),
|
||||||
|
("not an image", False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_is_heif(input_mime_type, expected_state):
|
||||||
|
assert mime.is_heif(input_mime_type) == expected_state
|
||||||
|
|
|
@ -399,6 +399,41 @@ def test_update_post_source_with_too_long_string():
|
||||||
model.Post.TYPE_IMAGE,
|
model.Post.TYPE_IMAGE,
|
||||||
"1_244c8840887984c4.bmp",
|
"1_244c8840887984c4.bmp",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
"avif.avif",
|
||||||
|
"image/avif",
|
||||||
|
model.Post.TYPE_IMAGE,
|
||||||
|
"1_244c8840887984c4.avif",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
"avif-avis.avif",
|
||||||
|
"image/avif",
|
||||||
|
model.Post.TYPE_IMAGE,
|
||||||
|
"1_244c8840887984c4.avif",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
"heic.heic",
|
||||||
|
"image/heic",
|
||||||
|
model.Post.TYPE_IMAGE,
|
||||||
|
"1_244c8840887984c4.heic",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
"heic-heix.heic",
|
||||||
|
"image/heic",
|
||||||
|
model.Post.TYPE_IMAGE,
|
||||||
|
"1_244c8840887984c4.heic",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
"heif.heif",
|
||||||
|
"image/heif",
|
||||||
|
model.Post.TYPE_IMAGE,
|
||||||
|
"1_244c8840887984c4.heif",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
False,
|
False,
|
||||||
"gif-animated.gif",
|
"gif-animated.gif",
|
||||||
|
@ -706,6 +741,38 @@ def test_update_post_content_leaving_custom_thumbnail(
|
||||||
assert os.path.exists(generated_path)
|
assert os.path.exists(generated_path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filename", ("avif.avif", "heic.heic", "heif.heif"))
|
||||||
|
def test_update_post_content_convert_heif_to_png_when_processing(
|
||||||
|
tmpdir, config_injector, read_asset, post_factory, filename
|
||||||
|
):
|
||||||
|
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)
|
||||||
|
posts.update_post_content(post, read_asset(filename))
|
||||||
|
posts.update_post_thumbnail(post, read_asset(filename))
|
||||||
|
db.session.flush()
|
||||||
|
generated_path = (
|
||||||
|
"{}/data/generated-thumbnails/".format(tmpdir)
|
||||||
|
+ "1_244c8840887984c4.jpg"
|
||||||
|
)
|
||||||
|
source_path = (
|
||||||
|
"{}/data/posts/custom-thumbnails/".format(tmpdir)
|
||||||
|
+ "1_244c8840887984c4.dat"
|
||||||
|
)
|
||||||
|
assert os.path.exists(source_path)
|
||||||
|
assert os.path.exists(generated_path)
|
||||||
|
|
||||||
|
|
||||||
def test_update_post_tags(tag_factory):
|
def test_update_post_tags(tag_factory):
|
||||||
post = model.Post()
|
post = model.Post()
|
||||||
with patch("szurubooru.func.tags.get_or_create_tags_by_names"):
|
with patch("szurubooru.func.tags.get_or_create_tags_by_names"):
|
||||||
|
|
Loading…
Reference in a new issue