Add wide emoji support
Co-authored-by: Kei IWASAKI <laughk@users.noreply.github.com>
This commit is contained in:
parent
2029200420
commit
fa82ec15d5
|
@ -98,6 +98,8 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_content_emoji_reaction_size,
|
||||
:setting_emoji_scale,
|
||||
:setting_picker_emoji_size,
|
||||
:setting_enable_wide_emoji,
|
||||
:setting_enable_wide_emoji_reaction,
|
||||
:setting_hide_bot_on_public_timeline,
|
||||
:setting_confirm_follow_from_bot,
|
||||
:setting_default_search_searchability,
|
||||
|
|
|
@ -123,12 +123,35 @@ module AccountsHelper
|
|||
|
||||
return if user.nil?
|
||||
|
||||
":root {
|
||||
css = []
|
||||
|
||||
css << <<-EOS
|
||||
:root {
|
||||
--content-font-size: #{h(user.setting_content_font_size)}px;
|
||||
--info-font-size: #{h(user.setting_info_font_size)}px;
|
||||
--content-emoji-reaction-size: #{h(user.setting_content_emoji_reaction_size)}px;
|
||||
--emoji-scale: #{h(user.setting_emoji_scale)};
|
||||
}"
|
||||
}
|
||||
EOS
|
||||
|
||||
css << <<-EOS if user.setting_enable_wide_emoji
|
||||
img.emojione.custom-emoji:not(.reaction) {
|
||||
width: unset !important;
|
||||
max-width: min(100%, 10em);
|
||||
}
|
||||
EOS
|
||||
|
||||
css << <<-EOS if user.setting_enable_wide_emoji_reaction
|
||||
span.reactions-bar__item__emoji {
|
||||
width: unset !important;
|
||||
}
|
||||
span.reactions-bar__item__emoji img.emojione.custom-emoji {
|
||||
width: unset !important;
|
||||
max-width: 8em;
|
||||
}
|
||||
EOS
|
||||
|
||||
css.join("\n")
|
||||
end
|
||||
|
||||
def svg_logo
|
||||
|
|
|
@ -139,7 +139,7 @@ module ApplicationHelper
|
|||
elsif animate
|
||||
image_tag(reaction['url'], class: 'emojione', alt: ":#{reaction['name']}:")
|
||||
else
|
||||
image_tag(reaction['static_url'], class: 'emojione custom-emoji', alt: ":#{reaction['name']}", 'data-original' => full_asset_url(reaction['url']), 'data-static' => full_asset_url(reaction['static_url']))
|
||||
image_tag(reaction['static_url'], class: 'emojione custom-emoji reaction', alt: ":#{reaction['name']}", 'data-original' => full_asset_url(reaction['url']), 'data-static' => full_asset_url(reaction['static_url']))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import { autoPlayGif } from 'mastodon/initial_state';
|
||||
import { assetHost } from 'mastodon/utils/config';
|
||||
import unicodeMapping from 'mastodon/features/emoji/emoji_unicode_mapping_light';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class Emoji extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
emoji: PropTypes.string.isRequired,
|
||||
emojiMap: ImmutablePropTypes.map.isRequired,
|
||||
className: PropTypes.string,
|
||||
hovered: PropTypes.bool.isRequired,
|
||||
url: PropTypes.string,
|
||||
static_url: PropTypes.string,
|
||||
|
@ -21,11 +23,12 @@ export default class Emoji extends React.PureComponent {
|
|||
if (unicodeMapping[emoji]) {
|
||||
const { filename, shortCode } = unicodeMapping[emoji];
|
||||
const title = shortCode ? `:${shortCode}:` : '';
|
||||
const className = classNames('emojione', this.props.className);
|
||||
|
||||
return (
|
||||
<img
|
||||
draggable='false'
|
||||
className='emojione'
|
||||
className={className}
|
||||
alt={emoji}
|
||||
title={title}
|
||||
src={`${assetHost}/emoji/${filename}.svg`}
|
||||
|
@ -34,11 +37,12 @@ export default class Emoji extends React.PureComponent {
|
|||
} else if (emojiMap.get(emoji)) {
|
||||
const filename = (autoPlayGif || hovered) ? emojiMap.getIn([emoji, 'url']) : emojiMap.getIn([emoji, 'static_url']);
|
||||
const shortCode = `:${emoji}:`;
|
||||
const className = classNames('emojione custom-emoji', this.props.className);
|
||||
|
||||
return (
|
||||
<img
|
||||
draggable='false'
|
||||
className='emojione custom-emoji'
|
||||
className={className}
|
||||
alt={shortCode}
|
||||
title={shortCode}
|
||||
src={filename}
|
||||
|
@ -47,11 +51,12 @@ export default class Emoji extends React.PureComponent {
|
|||
} else if (url || static_url) {
|
||||
const filename = (autoPlayGif || hovered) && url ? url : static_url;
|
||||
const shortCode = `:${emoji}:`;
|
||||
const className = classNames('emojione custom-emoji', this.props.className);
|
||||
|
||||
return (
|
||||
<img
|
||||
draggable='false'
|
||||
className='emojione custom-emoji'
|
||||
className={className}
|
||||
alt={shortCode}
|
||||
title={shortCode}
|
||||
src={filename}
|
||||
|
|
|
@ -123,7 +123,7 @@ class EmojiReaction extends ImmutablePureComponent {
|
|||
<Fragment>
|
||||
<div className='reactions-bar__item-wrapper' ref={this.setTargetRef}>
|
||||
<button className={classNames('reactions-bar__item', { active: myReaction })} disabled={disableReactions || status.get('emoji_reactioned') && !myReaction} onClick={this.handleClick} title={`:${shortCode}:`} style={this.props.style}>
|
||||
<span className='reactions-bar__item__emoji'><Emoji hovered={this.state.hovered} emoji={emojiReaction.get('name')} emojiMap={this.props.emojiMap} url={emojiReaction.get('url')} static_url={emojiReaction.get('static_url')} /></span>
|
||||
<span className='reactions-bar__item__emoji'><Emoji className='reaction' hovered={this.state.hovered} emoji={emojiReaction.get('name')} emojiMap={this.props.emojiMap} url={emojiReaction.get('url')} static_url={emojiReaction.get('static_url')} /></span>
|
||||
<span className='reactions-bar__item__count'><AnimatedNumber value={emojiReaction.get('count')} /></span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -61,7 +61,7 @@ class Reaction extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<div className='account__emoji_reaction' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
<Emoji hovered={this.state.hovered} emoji={emojiReaction.get('name')} emojiMap={emojiMap} url={emojiReaction.get('url')} static_url={emojiReaction.get('static_url')} />
|
||||
<Emoji className='reaction' hovered={this.state.hovered} emoji={emojiReaction.get('name')} emojiMap={emojiMap} url={emojiReaction.get('url')} static_url={emojiReaction.get('static_url')} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -352,18 +352,20 @@ class Notification extends ImmutablePureComponent {
|
|||
const { intl, unread, emojiMap } = this.props;
|
||||
|
||||
if (!notification.get('emoji_reaction')) {
|
||||
return <Fragment></Fragment>
|
||||
return <Fragment />;
|
||||
}
|
||||
|
||||
const wide = notification.getIn(['emoji_reaction', 'width'], 1) / notification.getIn(['emoji_reaction', 'height'], 1) >= 1.4;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={this.getHandlers()}>
|
||||
<div className={classNames('notification notification-reaction focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.emoji_reaction, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||
<div className='notification__message'>
|
||||
<div className='notification__favourite-icon-wrapper'>
|
||||
<div className={classNames('notification__reaction-icon-wrapper', { wide })}>
|
||||
<Emoji hovered={false} emoji={notification.getIn(['emoji_reaction', 'name'])} emojiMap={emojiMap} url={notification.getIn(['emoji_reaction', 'url'])} static_url={notification.getIn(['emoji_reaction', 'static_url'])} />
|
||||
</div>
|
||||
|
||||
<span title={notification.get('created_at')}>
|
||||
<span title={notification.get('created_at')} className={classNames('notification__reaction-message-wrapper', { wide })}>
|
||||
<FormattedMessage id='notification.emoji_reaction' defaultMessage='{name} reactioned your post' values={{ name: link }} />
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -60,6 +60,8 @@ export const enableEmptyColumn = getMeta('enable_empty_column');
|
|||
export const showReloadButton = getMeta('show_reload_button');
|
||||
export const defaultColumnWidth = getMeta('default_column_width');
|
||||
export const pickerEmojiSize = getMeta('picker_emoji_size');
|
||||
export const enableWideEmoji = getMeta('enable_wide_emoji');
|
||||
export const enableWideEmojiReaction = getMeta('enable_wide_emoji_reaction');
|
||||
export const disablePost = getMeta('disable_post');
|
||||
export const disableReactions = getMeta('disable_reactions');
|
||||
export const disableFollow = getMeta('disable_follow');
|
||||
|
|
|
@ -1946,7 +1946,8 @@ a.account__display-name {
|
|||
}
|
||||
}
|
||||
|
||||
.notification__favourite-icon-wrapper {
|
||||
.notification__favourite-icon-wrapper,
|
||||
.notification__reaction-icon-wrapper {
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
|
||||
|
@ -1955,6 +1956,11 @@ a.account__display-name {
|
|||
}
|
||||
}
|
||||
|
||||
.notification__reaction-message-wrapper.wide {
|
||||
display: block;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.icon-button.star-icon.active {
|
||||
color: $gold-star;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ class UserSettingsDecorator
|
|||
hide_link_preview
|
||||
hide_photo_preview
|
||||
hide_video_preview
|
||||
enable_wide_emoji
|
||||
enable_wide_emoji_reaction
|
||||
).freeze
|
||||
|
||||
STRING_KEYS = %w(
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
# visible_in_picker :boolean default(TRUE), not null
|
||||
# category_id :bigint(8)
|
||||
# image_storage_schema_version :integer
|
||||
# width :integer
|
||||
# height :integer
|
||||
#
|
||||
|
||||
class CustomEmoji < ApplicationRecord
|
||||
include Attachmentable
|
||||
|
||||
LOCAL_LIMIT = (ENV['MAX_EMOJI_SIZE'] || 50.kilobytes).to_i
|
||||
LIMIT = [LOCAL_LIMIT, (ENV['MAX_REMOTE_EMOJI_SIZE'] || 200.kilobytes).to_i].max
|
||||
LOCAL_LIMIT = (ENV['MAX_EMOJI_SIZE'] || 256.kilobytes).to_i
|
||||
LIMIT = [LOCAL_LIMIT, (ENV['MAX_REMOTE_EMOJI_SIZE'] || 256.kilobytes).to_i].max
|
||||
|
||||
SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'
|
||||
|
||||
|
@ -37,7 +39,7 @@ class CustomEmoji < ApplicationRecord
|
|||
belongs_to :category, class_name: 'CustomEmojiCategory', optional: true
|
||||
has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode
|
||||
|
||||
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile exif' } }, validate_media_type: false
|
||||
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile exif', file_geometry_parser: FastGeometryParser } }, processors: [:dimension_extractor], validate_media_type: false
|
||||
|
||||
before_validation :downcase_domain
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ class User < ApplicationRecord
|
|||
:post_reference_modal, :add_reference_modal, :unselect_reference_modal, :delete_scheduled_status_modal,
|
||||
:hexagon_avatar, :enable_empty_column,
|
||||
:content_font_size, :info_font_size, :content_emoji_reaction_size, :emoji_scale, :picker_emoji_size,
|
||||
:enable_wide_emoji, :enable_wide_emoji_reaction,
|
||||
:hide_bot_on_public_timeline, :confirm_follow_from_bot,
|
||||
:default_search_searchability, :default_expires_in, :default_expires_action,
|
||||
:show_reload_button, :default_column_width,
|
||||
|
|
|
@ -78,6 +78,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:content_emoji_reaction_size] = object.current_account.user.setting_content_emoji_reaction_size
|
||||
store[:emoji_scale] = object.current_account.user.setting_emoji_scale
|
||||
store[:picker_emoji_size] = object.current_account.user.setting_picker_emoji_size
|
||||
store[:enable_wide_emoji] = object.current_account.user.setting_enable_wide_emoji
|
||||
store[:enable_wide_emoji_reaction] = object.current_account.user.setting_enable_wide_emoji_reaction
|
||||
store[:hide_bot_on_public_timeline] = object.current_account.user.setting_hide_bot_on_public_timeline
|
||||
store[:confirm_follow_from_bot] = object.current_account.user.setting_confirm_follow_from_bot
|
||||
store[:show_reload_button] = object.current_account.user.setting_show_reload_button
|
||||
|
|
|
@ -6,6 +6,8 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer
|
|||
attributes :shortcode, :url, :static_url, :visible_in_picker
|
||||
|
||||
attribute :category, if: :category_loaded?
|
||||
attribute :width, if: :width?
|
||||
attribute :height, if: :height?
|
||||
|
||||
def url
|
||||
full_asset_url(object.image.url)
|
||||
|
@ -22,4 +24,20 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer
|
|||
def category_loaded?
|
||||
object.association(:category).loaded? && object.category.present?
|
||||
end
|
||||
|
||||
def width
|
||||
object.width
|
||||
end
|
||||
|
||||
def height
|
||||
object.height
|
||||
end
|
||||
|
||||
def width?
|
||||
!object.width.nil?
|
||||
end
|
||||
|
||||
def height?
|
||||
!object.height.nil?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,6 +8,8 @@ class REST::EmojiReactionSerializer < ActiveModel::Serializer
|
|||
attribute :url, if: :custom_emoji?
|
||||
attribute :static_url, if: :custom_emoji?
|
||||
attribute :domain, if: :custom_emoji?
|
||||
attribute :width, if: :width?
|
||||
attribute :height, if: :height?
|
||||
|
||||
belongs_to :account, serializer: REST::AccountSerializer
|
||||
|
||||
|
@ -26,4 +28,20 @@ class REST::EmojiReactionSerializer < ActiveModel::Serializer
|
|||
def domain
|
||||
object.custom_emoji.domain
|
||||
end
|
||||
|
||||
def width
|
||||
object.custom_emoji.width
|
||||
end
|
||||
|
||||
def height
|
||||
object.custom_emoji.height
|
||||
end
|
||||
|
||||
def width?
|
||||
custom_emoji? && object.custom_emoji.width
|
||||
end
|
||||
|
||||
def height?
|
||||
custom_emoji? && object.custom_emoji.height
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,8 @@ class REST::GroupedEmojiReactionSerializer < ActiveModel::Serializer
|
|||
attribute :url, if: :custom_emoji?
|
||||
attribute :static_url, if: :custom_emoji?
|
||||
attribute :domain, if: :custom_emoji?
|
||||
attribute :width, if: :width?
|
||||
attribute :height, if: :height?
|
||||
attribute :account_ids, if: :has_account_ids?
|
||||
|
||||
def count
|
||||
|
@ -38,4 +40,20 @@ class REST::GroupedEmojiReactionSerializer < ActiveModel::Serializer
|
|||
def domain
|
||||
object.custom_emoji.domain
|
||||
end
|
||||
|
||||
def width
|
||||
object.custom_emoji.width
|
||||
end
|
||||
|
||||
def height
|
||||
object.custom_emoji.height
|
||||
end
|
||||
|
||||
def width?
|
||||
custom_emoji? && object.custom_emoji.width
|
||||
end
|
||||
|
||||
def height?
|
||||
custom_emoji? && object.custom_emoji.height
|
||||
end
|
||||
end
|
||||
|
|
|
@ -148,6 +148,8 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
:searchability,
|
||||
:status_compact_mode,
|
||||
:account_conversations,
|
||||
:enable_wide_emoji,
|
||||
:enable_wide_emoji_reaction,
|
||||
]
|
||||
|
||||
capabilities << :profile_search unless Chewy.enabled?
|
||||
|
|
|
@ -33,6 +33,12 @@
|
|||
= f.input :setting_content_emoji_reaction_size, as: :range, input_html: { min: 10, max: 48, list: 'emoji_reaction_size_label' }, wrapper: :with_label, false: true, fedibird_features: true
|
||||
= f.input :setting_picker_emoji_size, as: :range, input_html: { min: 22, max: 48, list: 'picker_emoji_size_label' }, wrapper: :with_label, false: true, fedibird_features: true
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_enable_wide_emoji, as: :boolean, wrapper: :with_label, hint: true, fedibird_features: true
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_enable_wide_emoji_reaction, as: :boolean, wrapper: :with_label, hint: true, fedibird_features: true
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_theme_public, as: :boolean, wrapper: :with_label, hint: true, fedibird_features: true
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ require_relative '../lib/sanitize_ext/sanitize_config'
|
|||
require_relative '../lib/redis/namespace_extensions'
|
||||
require_relative '../lib/paperclip/url_generator_extensions'
|
||||
require_relative '../lib/paperclip/attachment_extensions'
|
||||
require_relative '../lib/paperclip/dimension_extractor'
|
||||
require_relative '../lib/paperclip/lazy_thumbnail'
|
||||
require_relative '../lib/paperclip/gif_transcoder'
|
||||
require_relative '../lib/paperclip/transcoder'
|
||||
|
|
|
@ -91,6 +91,8 @@ en:
|
|||
setting_enable_personal_timeline: Enable a personal home to display personal post
|
||||
setting_enable_reaction: Enable the reaction display on the timeline and display the reaction button
|
||||
setting_enable_status_reference: Enable the feature where a post references another post
|
||||
setting_enable_wide_emoji: Displays wide emoji derived from Misskey in their original proportions (for content)
|
||||
setting_enable_wide_emoji_reaction: Displays wide emoji derived from Misskey in their original proportions (for reaction)
|
||||
setting_follow_button_to_list_adder: Change the behavior of the Follow / Subscribe button, open a dialog where you can select a list to follow / subscribe, or opt out of receiving at home
|
||||
setting_hexagon_avatar: Display everyone's avatar icon as a hollowed out hexagon (joke feature)
|
||||
setting_hide_bot_on_public_timeline: Disable Bot accounts from appearing on federation & hashtag & domain & group timelines (overridden by column setting)
|
||||
|
@ -288,6 +290,8 @@ en:
|
|||
setting_enable_personal_timeline: Enable personal timeline
|
||||
setting_enable_reaction: Enable reaction
|
||||
setting_enable_status_reference: Enable reference
|
||||
setting_enable_wide_emoji: Enable wide emoji (for content)
|
||||
setting_enable_wide_emoji_reaction: Enable wide emoji (for reaction)
|
||||
setting_expand_spoilers: Always expand posts marked with content warnings
|
||||
setting_follow_button_to_list_adder: Open list add dialog with follow button
|
||||
setting_hexagon_avatar: Experience NFT Avatar
|
||||
|
|
|
@ -87,6 +87,8 @@ ja:
|
|||
setting_enable_personal_timeline: 自分限定を表示する自分限定ホームを有効にします
|
||||
setting_enable_reaction: タイムラインでリアクションの表示を有効にし、リアクションボタンを表示する
|
||||
setting_enable_status_reference: 投稿が別の投稿を参照する機能を有効にします
|
||||
setting_enable_wide_emoji: Misskey由来の横幅の広い絵文字を元の比率で表示します(本文)
|
||||
setting_enable_wide_emoji_reaction: Misskey由来の横幅の広い絵文字を元の比率で表示します(リアクション)
|
||||
setting_follow_button_to_list_adder: フォロー・購読ボタンの動作を変更し、フォロー・購読するリストを選択したり、ホームで受け取らないよう設定するダイアログを開きます
|
||||
setting_hexagon_avatar: 全員のアバターアイコンを6角形にくりぬいて表示します(ジョーク機能)
|
||||
setting_hide_bot_on_public_timeline: 連合・ハッシュタグ・ドメイン・グループタイムライン上にBotアカウントが表示されないようにします(※カラム設定を優先)
|
||||
|
@ -284,6 +286,8 @@ ja:
|
|||
setting_enable_personal_timeline: 自分限定ホームを有効にする
|
||||
setting_enable_reaction: リアクションを有効にする
|
||||
setting_enable_status_reference: 参照を有効にする
|
||||
setting_enable_wide_emoji: ワイド絵文字を有効にする(本文)
|
||||
setting_enable_wide_emoji_reaction: ワイド絵文字を有効にする(リアクション)
|
||||
setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する
|
||||
setting_follow_button_to_list_adder: フォローボタンでリスト追加ダイアログを開く
|
||||
setting_hexagon_avatar: NFTアイコンを体験する
|
||||
|
|
|
@ -73,6 +73,8 @@ defaults: &defaults
|
|||
content_emoji_reaction_size: 16
|
||||
emoji_scale: 1,
|
||||
picker_emoji_size: 22,
|
||||
enable_wide_emoji: true
|
||||
enable_wide_emoji_reaction: true
|
||||
notification_emails:
|
||||
follow: false
|
||||
reblog: false
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class AddWidthHeightToCustomEmoji < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :custom_emojis, :width, :integer, null: true, default: nil
|
||||
add_column :custom_emojis, :height, :integer, null: true, default: nil
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2023_02_15_062659) do
|
||||
ActiveRecord::Schema.define(version: 2023_02_21_031206) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -371,6 +371,8 @@ ActiveRecord::Schema.define(version: 2023_02_15_062659) do
|
|||
t.boolean "visible_in_picker", default: true, null: false
|
||||
t.bigint "category_id"
|
||||
t.integer "image_storage_schema_version"
|
||||
t.integer "width"
|
||||
t.integer "height"
|
||||
t.index ["shortcode", "domain"], name: "index_custom_emojis_on_shortcode_and_domain", unique: true
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ require_relative 'cli_helper'
|
|||
|
||||
module Mastodon
|
||||
class EmojiCLI < Thor
|
||||
include CLIHelper
|
||||
|
||||
def self.exit_on_failure?
|
||||
true
|
||||
end
|
||||
|
@ -132,6 +134,38 @@ module Mastodon
|
|||
say('OK', :green)
|
||||
end
|
||||
|
||||
option :local_only, type: :boolean
|
||||
option :remote_only, type: :boolean
|
||||
option :all, type: :boolean
|
||||
option :concurrency, type: :numeric, default: 5, aliases: [:c]
|
||||
option :verbose, type: :boolean, aliases: [:v]
|
||||
desc 'fix-dimension', 'Fix dimension all custom emoji'
|
||||
long_desc <<-LONG_DESC
|
||||
Fix dimension all custom emoji.
|
||||
|
||||
With the --local-only option, only local emoji will be fixed.
|
||||
With the --remote-only option, only remote emoji will be fixed.
|
||||
With the --all option, fix dimension of all emojis.
|
||||
LONG_DESC
|
||||
def fix_dimension
|
||||
scope = CustomEmoji
|
||||
scope = scope.local if options[:local_only]
|
||||
scope = scope.remote if options[:remote_only]
|
||||
scope = scope.where(width: nil) unless options[:all]
|
||||
|
||||
processed, fixed = parallelize_with_progress(scope) do |emoji|
|
||||
width, height = FastImage.size(emoji.image.url)
|
||||
next if width.nil?
|
||||
|
||||
emoji.update!(width: width, height: height)
|
||||
1
|
||||
rescue
|
||||
next
|
||||
end
|
||||
|
||||
say("Checked #{processed} emojis, fixed #{fixed}", :green, true)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def color(green, _yellow, red)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Paperclip
|
||||
class DimensionExtractor < Paperclip::Processor
|
||||
def make
|
||||
geometry = options.fetch(:file_geometry_parser).from_file(@file)
|
||||
|
||||
attachment.instance.width = geometry.width if attachment.instance.respond_to?(:width)
|
||||
attachment.instance.height = geometry.height if attachment.instance.respond_to?(:height)
|
||||
|
||||
File.open(@file.path)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue