This commit is contained in:
recordcrash
2025-04-28 19:14:41 +00:00
committed by GitHub
13 changed files with 82 additions and 24 deletions

6
.gitignore vendored
View File

@ -13,3 +13,9 @@ server/**/lib/
server/**/bin/
server/**/pyvenv.cfg
__pycache__/
# Developer Tools
.vscode/
.idea/
*.sublime-project
*.sublime-workspace

View File

@ -7,7 +7,7 @@ scrubbing](https://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*.
## Features
- Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations
- Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations, project files (PSD)
- Ability to retrieve web video content using [yt-dlp](https://github.com/yt-dlp/yt-dlp)
- Post comments
- Post notes / annotations, including arbitrary polygons

View File

@ -1,7 +1,11 @@
<div class='post-content post-type-<%- ctx.post.type %>'>
<% if (['image', 'animation'].includes(ctx.post.type)) { %>
<% if (ctx.post.mimeType === 'image/vnd.adobe.photoshop') { %>
<img class='resize-listener' alt='' src='<%- ctx.post.thumbnailUrl %>'/>
<% } else { %>
<img class='resize-listener' alt='' src='<%- ctx.post.contentUrl %>'/>
<% } %>
<% } else if (ctx.post.type === 'flash') { %>

View File

@ -13,6 +13,7 @@
'image/avif': 'AVIF',
'image/heif': 'HEIF',
'image/heic': 'HEIC',
'image/vnd.adobe.photoshop': 'PSD',
'video/webm': 'WEBM',
'video/mp4': 'MPEG-4',
'video/quicktime': 'MOV',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -20,6 +20,7 @@ function _mimeTypeToPostType(mimeType) {
"image/avif": "image",
"image/heif": "image",
"image/heic": "image",
"image/vnd.adobe.photoshop": "image",
"video/mp4": "video",
"video/webm": "video",
"video/quicktime": "video",
@ -165,7 +166,7 @@ class PostUploadView extends events.EventTarget {
this._contentInputNode,
{
extraText:
"Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf, .avif, .heif, .heic",
"Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf, .avif, .heif, .heic, .psd",
allowUrls: true,
allowMultiple: true,
lock: false,

View File

@ -5,7 +5,7 @@
services:
server:
image: szurubooru/server:latest
build: server
depends_on:
- sql
environment:
@ -23,9 +23,10 @@ services:
volumes:
- "${MOUNT_DATA}:/data"
- "./server/config.yaml:/opt/app/config.yaml"
restart: unless-stopped
client:
image: szurubooru/client:latest
build: client
depends_on:
- server
environment:
@ -35,6 +36,7 @@ services:
- "${MOUNT_DATA}:/data:ro"
ports:
- "${PORT}:80"
restart: unless-stopped
sql:
image: postgres:11-alpine

View File

@ -1,9 +1,12 @@
ARG ALPINE_VERSION=3.13
ARG ALPINE_VERSION=3.16
FROM alpine:$ALPINE_VERSION as prereqs
#######################################
# Base Stage (prereqs)
#######################################
FROM alpine:$ALPINE_VERSION AS prereqs
WORKDIR /opt/app
# Install system dependencies (Python, development packages, and runtime libraries)
RUN apk --no-cache add \
python3 \
python3-dev \
@ -13,31 +16,47 @@ RUN apk --no-cache add \
libheif-dev \
libavif \
libavif-dev \
freetype-dev \
ffmpeg \
lapack \
lapack-dev \
# from requirements.txt:
py3-yaml \
py3-psycopg2 \
py3-sqlalchemy \
py3-certifi \
py3-numpy \
py3-pillow \
py3-pynacl \
py3-tz \
py3-pyrfc3339
# Install pip-only packages, using a wheel to avoid building scikit-image
RUN pip3 install --no-cache-dir wheel
RUN pip3 install --no-cache-dir --disable-pip-version-check \
--extra-index-url https://alpine-wheels.github.io/index \
"aggdraw==1.3.12" \
"alembic>=0.8.5" \
"attrs==25.1.0" \
"coloredlogs==5.0" \
"pyheif==0.6.1" \
"heif-image-plugin>=0.3.2" \
yt-dlp \
"pillow-avif-plugin~=1.1.0"
"pillow>=6.1.0" \
"pillow-avif-plugin~=1.1.0" \
"psd-tools==1.10.4" \
"numpy==1.21.6" \
"scikit-image==0.19.3" \
"scipy==1.8.0" \
"sqlalchemy==1.3.21"
RUN apk --no-cache del py3-pip
COPY ./ /opt/app/
RUN rm -rf /opt/app/szurubooru/tests
FROM --platform=$BUILDPLATFORM prereqs as testing
#######################################
# Testing Stage
#######################################
FROM --platform=$BUILDPLATFORM prereqs AS testing
WORKDIR /opt/app
RUN apk --no-cache add \
@ -60,8 +79,10 @@ USER app
ENTRYPOINT ["pytest", "--tb=short"]
CMD ["szurubooru/"]
FROM prereqs as release
#######################################
# Release Stage
#######################################
FROM prereqs AS release
WORKDIR /opt/app
ARG PUID=1000

View File

@ -1,15 +1,20 @@
aggdraw==1.3.12
alembic>=0.8.5
attrs==25.1.0
certifi>=2017.11.5
coloredlogs==5.0
heif-image-plugin==0.3.2
numpy>=1.8.2
heif-image-plugin>=0.3.2
numpy>=1.21.6
pillow-avif-plugin~=1.1.0
pillow>=4.3.0
pillow>=6.1.0
psd-tools==1.10.4
psycopg2-binary>=2.6.1
pyheif==0.6.1
pynacl>=1.2.1
pyRFC3339>=1.0
pytz>=2018.3
pyyaml>=3.11
SQLAlchemy>=1.0.12, <1.4
scikit-image==0.19.3
scipy==1.8.0
SQLAlchemy==1.3.21
yt-dlp

View File

@ -7,13 +7,14 @@ import subprocess
from io import BytesIO
from typing import List
import HeifImagePlugin
import pillow_avif
from PIL import Image as PILImage
from psd_tools import PSDImage
from szurubooru import errors
from szurubooru.func import mime, util
logger = logging.getLogger(__name__)
@ -24,6 +25,15 @@ def convert_heif_to_png(content: bytes) -> bytes:
return img_byte_arr.getvalue()
def convert_psd_to_png(content: bytes) -> bytes:
psd_object = PSDImage.open(BytesIO(content))
img = psd_object.composite()
img_byte_arr = BytesIO()
img.save(img_byte_arr, format="PNG")
return img_byte_arr.getvalue()
class Image:
def __init__(self, content: bytes) -> None:
self.content = content
@ -265,10 +275,13 @@ class Image:
get_logs: bool = False,
) -> bytes:
mime_type = mime.get_mime_type(self.content)
if mime.is_heif(mime_type):
# FFmpeg does not support HEIF.
# FFmpeg does not support HEIF or PSD.
# https://trac.ffmpeg.org/ticket/6521
# https://ffmpeg.org/pipermail/ffmpeg-devel/2016-July/196477.html
if mime.is_heif(mime_type):
self.content = convert_heif_to_png(self.content)
elif mime_type == "image/vnd.adobe.photoshop":
self.content = convert_psd_to_png(self.content)
extension = mime.get_extension(mime_type)
assert extension
with util.create_temp_file(suffix="." + extension) as handle:

View File

@ -33,6 +33,9 @@ def get_mime_type(content: bytes) -> str:
if content[4:12] in (b"ftypheic", b"ftypheix"):
return "image/heic"
if content[0:4] == b"8BPS":
return "image/vnd.adobe.photoshop"
if content[0:4] == b"\x1A\x45\xDF\xA3":
return "video/webm"
@ -56,6 +59,7 @@ def get_extension(mime_type: str) -> Optional[str]:
"image/avif": "avif",
"image/heif": "heif",
"image/heic": "heic",
"image/vnd.adobe.photoshop": "psd",
"video/mp4": "mp4",
"video/quicktime": "mov",
"video/webm": "webm",
@ -87,6 +91,7 @@ def is_image(mime_type: str) -> bool:
"image/avif",
"image/heif",
"image/heic",
"image/vnd.adobe.photoshop",
)