diff --git a/app/blueprints/packages/packages.py b/app/blueprints/packages/packages.py
index 1328a3c0..67558950 100644
--- a/app/blueprints/packages/packages.py
+++ b/app/blueprints/packages/packages.py
@@ -426,7 +426,7 @@ def move_to_state(package):
if not package.approved_at:
post_discord_webhook.delay(package.author.display_name,
"New package {}".format(package.get_url("packages.view", absolute=True)), False,
- package.title, package.short_desc, package.get_thumb_url(2, True))
+ package.title, package.short_desc, package.get_thumb_url(2, True, "png"))
package.approved_at = datetime.datetime.now()
screenshots = PackageScreenshot.query.filter_by(package=package, approved=False).all()
@@ -437,7 +437,7 @@ def move_to_state(package):
elif state == PackageState.READY_FOR_REVIEW:
post_discord_webhook.delay(package.author.display_name,
"Ready for Review: {}".format(package.get_url("packages.view", absolute=True)), True,
- package.title, package.short_desc, package.get_thumb_url(2, True))
+ package.title, package.short_desc, package.get_thumb_url(2, True, "png"))
add_notification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.get_url("packages.view"), package)
severity = AuditSeverity.NORMAL if current_user in package.maintainers else AuditSeverity.EDITOR
@@ -480,7 +480,7 @@ def remove(package):
post_discord_webhook.delay(current_user.username,
f"Deleted package {package.author.username}/{package.name} with reason '{reason}'",
- True, package.title, package.short_desc, package.get_thumb_url(2, True))
+ True, package.title, package.short_desc, package.get_thumb_url(2, True, "png"))
flash(gettext("Deleted package"), "success")
@@ -500,7 +500,7 @@ def remove(package):
post_discord_webhook.delay(current_user.username,
"Unapproved package with reason {}\n\n{}".format(reason, package.get_url("packages.view", absolute=True)), True,
- package.title, package.short_desc, package.get_thumb_url(2, True))
+ package.title, package.short_desc, package.get_thumb_url(2, True, "png"))
flash(gettext("Unapproved package"), "success")
diff --git a/app/blueprints/thumbnails/__init__.py b/app/blueprints/thumbnails/__init__.py
index 309004cc..2722e35d 100644
--- a/app/blueprints/thumbnails/__init__.py
+++ b/app/blueprints/thumbnails/__init__.py
@@ -14,15 +14,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-
from flask import abort, send_file, Blueprint, current_app
+import os
+from PIL import Image
+
bp = Blueprint("thumbnails", __name__)
-import os
-from PIL import Image
-ALLOWED_RESOLUTIONS=[(100,67), (270,180), (350,233), (1100,520)]
+ALLOWED_RESOLUTIONS = [(100, 67), (270, 180), (350, 233), (1100, 520)]
+ALLOWED_EXTENSIONS = {"png", "webp"}
+
def mkdir(path):
assert path != "" and path is not None
@@ -34,10 +36,7 @@ def mkdir(path):
def resize_and_crop(img_path, modified_path, size):
- try:
- img = Image.open(img_path)
- except FileNotFoundError:
- abort(404)
+ img = Image.open(img_path)
# Get current and desired ratio for the images
img_ratio = img.size[0] / float(img.size[1])
@@ -64,21 +63,40 @@ def resize_and_crop(img_path, modified_path, size):
img.save(modified_path)
+def find_source_file(img):
+ upload_dir = current_app.config["UPLOAD_DIR"]
+ source_filepath = os.path.join(upload_dir, img)
+ if os.path.isfile(source_filepath):
+ return source_filepath
+
+ period = source_filepath.rfind(".")
+ start = source_filepath[:period]
+ ext = source_filepath[period + 1:]
+ if ext not in ALLOWED_EXTENSIONS:
+ abort(404)
+
+ for other_ext in ALLOWED_EXTENSIONS:
+ other_path = f"{start}.{other_ext}"
+ if ext != other_ext and os.path.isfile(other_path):
+ return other_path
+
+ abort(404)
+
+
@bp.route("/thumbnails//")
def make_thumbnail(img, level):
if level > len(ALLOWED_RESOLUTIONS) or level <= 0:
abort(403)
w, h = ALLOWED_RESOLUTIONS[level - 1]
- upload_dir = current_app.config["UPLOAD_DIR"]
thumbnail_dir = current_app.config["THUMBNAIL_DIR"]
mkdir(thumbnail_dir)
output_dir = os.path.join(thumbnail_dir, str(level))
mkdir(output_dir)
- cache_filepath = os.path.join(output_dir, img)
- source_filepath = os.path.join(upload_dir, img)
+ cache_filepath = os.path.join(output_dir, img)
+ source_filepath = find_source_file(img)
resize_and_crop(source_filepath, cache_filepath, (w, h))
return send_file(cache_filepath)
diff --git a/app/models/packages.py b/app/models/packages.py
index fb35aa34..c5327e91 100644
--- a/app/models/packages.py
+++ b/app/models/packages.py
@@ -528,7 +528,7 @@ def as_key_dict(self):
}
def as_short_dict(self, base_url, version=None, release_id=None, no_load=False):
- tnurl = self.get_thumb_url(1)
+ tnurl = self.get_thumb_url(1, format="png")
if release_id is None and no_load == False:
release = self.get_download_release(version=version)
@@ -555,7 +555,7 @@ def as_short_dict(self, base_url, version=None, release_id=None, no_load=False):
return ret
def as_dict(self, base_url, version=None):
- tnurl = self.get_thumb_url(1)
+ tnurl = self.get_thumb_url(1, format="png")
release = self.get_download_release(version=version)
return {
"author": self.author.username,
@@ -603,21 +603,21 @@ def as_dict(self, base_url, version=None):
]
}
- def get_thumb_or_placeholder(self, level=2):
- return self.get_thumb_url(level) or "/static/placeholder.png"
+ def get_thumb_or_placeholder(self, level=2, format="webp"):
+ return self.get_thumb_url(level, False, format) or "/static/placeholder.png"
- def get_thumb_url(self, level=2, abs=False):
+ def get_thumb_url(self, level=2, abs=False, format="webp"):
screenshot = self.main_screenshot
- url = screenshot.get_thumb_url(level) if screenshot is not None else None
+ url = screenshot.get_thumb_url(level, format) if screenshot is not None else None
if abs:
from app.utils import abs_url
return abs_url(url)
else:
return url
- def get_cover_image_url(self):
+ def get_cover_image_url(self, format="webp"):
screenshot = self.cover_image or self.main_screenshot
- return screenshot and screenshot.get_thumb_url(4)
+ return screenshot and screenshot.get_thumb_url(4, format)
def get_url(self, endpoint, absolute=False, **kwargs):
if absolute:
@@ -1101,8 +1101,12 @@ def get_delete_url(self):
name=self.package.name,
id=self.id)
- def get_thumb_url(self, level=2):
- return self.url.replace("/uploads/", "/thumbnails/{:d}/".format(level))
+ def get_thumb_url(self, level=2, format="webp"):
+ url = self.url.replace("/uploads/", "/thumbnails/{:d}/".format(level))
+ if format is not None:
+ start = url[:url.rfind(".")]
+ url = f"{start}.{format}"
+ return url
def as_dict(self, base_url=""):
return {
diff --git a/app/templates/collections/view.html b/app/templates/collections/view.html
index 6d9c389a..09fa6466 100644
--- a/app/templates/collections/view.html
+++ b/app/templates/collections/view.html
@@ -9,7 +9,7 @@
{%- endblock %}
{% block headextra %}
- {% set thumb_url = collection.packages and collection.packages[0].get_thumb_url(3, True) %}
+ {% set thumb_url = collection.packages and collection.packages[0].get_thumb_url(3, True, "png") %}
{% if thumb_url -%}
{%- endif %}
diff --git a/app/templates/macros/packagegridtile.html b/app/templates/macros/packagegridtile.html
index 9884e7c6..c041b100 100644
--- a/app/templates/macros/packagegridtile.html
+++ b/app/templates/macros/packagegridtile.html
@@ -1,6 +1,6 @@
{% macro render_pkgtile(package, show_author) -%}
-
+
diff --git a/app/templates/packages/game_hub.html b/app/templates/packages/game_hub.html
index 269a9189..68049ce1 100644
--- a/app/templates/packages/game_hub.html
+++ b/app/templates/packages/game_hub.html
@@ -10,8 +10,8 @@
{% endblock %}
{% block headextra %}
- {% if package.get_thumb_url(3, True) %}
-
+ {% if package.get_thumb_url(3, True, "png") %}
+
{% endif %}
{% endblock %}
diff --git a/app/templates/packages/gone.html b/app/templates/packages/gone.html
index 91bd6ee5..daa726d4 100644
--- a/app/templates/packages/gone.html
+++ b/app/templates/packages/gone.html
@@ -9,8 +9,8 @@
{% endblock %}
{% block headextra %}
- {% if package.get_thumb_url(3, True) -%}
-
+ {% if package.get_thumb_url(3, True, "png") -%}
+
{%- endif %}
{% endblock %}
diff --git a/app/templates/packages/view.html b/app/templates/packages/view.html
index ff7b49f0..3969a938 100644
--- a/app/templates/packages/view.html
+++ b/app/templates/packages/view.html
@@ -12,8 +12,8 @@
{% endblock %}
{% block headextra %}
- {% if package.get_thumb_url(3, True) -%}
-
+ {% if package.get_thumb_url(3, True, "png") -%}
+
{%- endif %}
{% endblock %}
@@ -261,7 +261,7 @@
{% if ss.approved or package.check_perm(current_user, "ADD_SCREENSHOTS") %}
{% endif %}