mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-02 05:06:51 +08:00
Updates supported file types for theme and component screenshots. ### Reasoning Switching to `.webp` makes themes lighter. In official themes we measured: - ~60% smaller compared to `.png` - ~35% smaller compared to `.jpg` `.png`, `.jpg`, and `.jpeg` remain supported. ### Changes * Dropped `.gif` support * Added `.webp` support (static + animated) --- More details: https://meta.discourse.org/t/adding-metadata-and-screenshots-to-a-theme/119205.
89 lines
3.1 KiB
Ruby
89 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ThemeScreenshotsHandler
|
|
MAX_THEME_SCREENSHOT_FILE_SIZE = 1.megabyte
|
|
MAX_THEME_SCREENSHOT_DIMENSIONS = [3840, 2160] # 4K resolution
|
|
MAX_THEME_SCREENSHOT_COUNT = 2
|
|
THEME_SCREENSHOT_ALLOWED_FILE_TYPES = %w[.jpeg .jpg .png .webp].freeze
|
|
|
|
class ThemeScreenshotError < StandardError
|
|
end
|
|
|
|
def initialize(theme)
|
|
@theme = theme
|
|
end
|
|
|
|
# Screenshots here come from RemoteTheme.extract_theme_info, which
|
|
# in turn parses the theme about.json file, which is where screenshots
|
|
# are defined.
|
|
def parse_screenshots_as_theme_fields!(screenshots, theme_importer)
|
|
updated_theme_fields = []
|
|
screenshots = Array.wrap(screenshots).take(MAX_THEME_SCREENSHOT_COUNT)
|
|
screenshots.each do |relative_path|
|
|
path = theme_importer.real_path(relative_path)
|
|
next if !path.present?
|
|
|
|
screenshot_filename = File.basename(path)
|
|
screenshot_extension = File.extname(path)
|
|
|
|
if !THEME_SCREENSHOT_ALLOWED_FILE_TYPES.include?(screenshot_extension)
|
|
raise ThemeScreenshotError,
|
|
I18n.t(
|
|
"themes.import_error.screenshot_invalid_type",
|
|
file_name: screenshot_filename,
|
|
accepted_formats: THEME_SCREENSHOT_ALLOWED_FILE_TYPES.join(","),
|
|
)
|
|
end
|
|
|
|
if File.size(path) > MAX_THEME_SCREENSHOT_FILE_SIZE
|
|
raise ThemeScreenshotError,
|
|
I18n.t(
|
|
"themes.import_error.screenshot_invalid_size",
|
|
file_name: screenshot_filename,
|
|
max_size:
|
|
ActiveSupport::NumberHelper.number_to_human_size(MAX_THEME_SCREENSHOT_FILE_SIZE),
|
|
)
|
|
end
|
|
|
|
screenshot_width, screenshot_height = FastImage.size(path)
|
|
if (screenshot_width.nil? || screenshot_height.nil?) ||
|
|
screenshot_width > MAX_THEME_SCREENSHOT_DIMENSIONS[0] ||
|
|
screenshot_height > MAX_THEME_SCREENSHOT_DIMENSIONS[1]
|
|
raise ThemeScreenshotError,
|
|
I18n.t(
|
|
"themes.import_error.screenshot_invalid_dimensions",
|
|
file_name: screenshot_filename,
|
|
width: screenshot_width.to_i,
|
|
height: screenshot_height.to_i,
|
|
max_width: MAX_THEME_SCREENSHOT_DIMENSIONS[0],
|
|
max_height: MAX_THEME_SCREENSHOT_DIMENSIONS[1],
|
|
)
|
|
end
|
|
|
|
upload =
|
|
RemoteTheme.create_upload(
|
|
theme: @theme,
|
|
path: path,
|
|
relative_path: relative_path,
|
|
skip_validations: true,
|
|
)
|
|
if !upload.errors.empty?
|
|
raise ThemeScreenshotError,
|
|
I18n.t(
|
|
"themes.import_error.screenshot",
|
|
errors: upload.errors.full_messages.join(","),
|
|
)
|
|
end
|
|
|
|
screenshot_filename_clean =
|
|
FileHelper.sanitize_filename(screenshot_filename.gsub(screenshot_extension, ""))
|
|
updated_theme_fields << @theme.set_field(
|
|
target: :common,
|
|
name: "screenshot_#{screenshot_filename_clean}",
|
|
type: :theme_screenshot_upload_var,
|
|
upload_id: upload.id,
|
|
)
|
|
end
|
|
updated_theme_fields
|
|
end
|
|
end
|