diff --git a/app/controllers/api/v1/statuses/translations_controller.rb b/app/controllers/api/v1/statuses/translations_controller.rb
index 540b17d009..ec5ea5b85b 100644
--- a/app/controllers/api/v1/statuses/translations_controller.rb
+++ b/app/controllers/api/v1/statuses/translations_controller.rb
@@ -8,7 +8,15 @@ class Api::V1::Statuses::TranslationsController < Api::BaseController
before_action :set_translation
rescue_from TranslationService::NotConfiguredError, with: :not_found
- rescue_from TranslationService::UnexpectedResponseError, TranslationService::QuotaExceededError, TranslationService::TooManyRequestsError, with: :service_unavailable
+ rescue_from TranslationService::UnexpectedResponseError, with: :service_unavailable
+
+ rescue_from TranslationService::QuotaExceededError do
+ render json: { error: I18n.t('translation.errors.quota_exceeded') }, status: 503
+ end
+
+ rescue_from TranslationService::TooManyRequestsError do
+ render json: { error: I18n.t('translation.errors.too_many_requests') }, status: 503
+ end
def create
render json: @translation, serializer: REST::TranslationSerializer
diff --git a/app/javascript/mastodon/components/hashtag_bar.tsx b/app/javascript/mastodon/components/hashtag_bar.tsx
index 674c481b81..d45a6e20eb 100644
--- a/app/javascript/mastodon/components/hashtag_bar.tsx
+++ b/app/javascript/mastodon/components/hashtag_bar.tsx
@@ -10,8 +10,8 @@ import { groupBy, minBy } from 'lodash';
import { getStatusContent } from './status_content';
-// About two lines on desktop
-const VISIBLE_HASHTAGS = 7;
+// Fit on a single line on desktop
+const VISIBLE_HASHTAGS = 3;
// Those types are not correct, they need to be replaced once this part of the state is typed
export type TagLike = Record<{ name: string }>;
@@ -210,7 +210,7 @@ const HashtagBar: React.FC<{
const revealedHashtags = expanded
? hashtags
- : hashtags.slice(0, VISIBLE_HASHTAGS - 1);
+ : hashtags.slice(0, VISIBLE_HASHTAGS);
return (
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 9ef8e4d083..d53dced95a 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -9308,19 +9308,24 @@ noscript {
display: flex;
flex-wrap: wrap;
font-size: 14px;
+ line-height: 18px;
gap: 4px;
+ color: $darker-text-color;
a {
display: inline-flex;
- color: $dark-text-color;
+ color: inherit;
text-decoration: none;
- &:hover {
- text-decoration: none;
-
- span {
- text-decoration: underline;
- }
+ &:hover span {
+ text-decoration: underline;
}
}
+
+ .link-button {
+ color: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ padding: 0;
+ }
}
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index 02b61bd512..23d2a33048 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -44,6 +44,7 @@ class MediaAttachment < ApplicationRecord
MAX_VIDEO_MATRIX_LIMIT = 8_294_400 # 3840x2160px
MAX_VIDEO_FRAME_RATE = 120
+ MAX_VIDEO_FRAMES = 36_000 # Approx. 5 minutes at 120 fps
IMAGE_FILE_EXTENSIONS = %w(.jpg .jpeg .png .gif .webp .heic .heif .avif).freeze
VIDEO_FILE_EXTENSIONS = %w(.webm .mp4 .m4v .mov).freeze
@@ -98,17 +99,12 @@ class MediaAttachment < ApplicationRecord
convert_options: {
output: {
'loglevel' => 'fatal',
- 'movflags' => 'faststart',
- 'pix_fmt' => 'yuv420p',
- 'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'',
- 'vsync' => 'cfr',
+ 'preset' => 'veryfast',
'c:v' => 'h264',
- 'maxrate' => '1300K',
- 'bufsize' => '1300K',
- 'b:v' => '1300K',
- 'frames:v' => 60 * 60 * 3,
- 'crf' => 18,
+ 'c:a' => 'aac',
+ 'b:a' => '192k',
'map_metadata' => '-1',
+ 'frames:v' => MAX_VIDEO_FRAMES,
}.freeze,
}.freeze,
}.freeze
@@ -135,7 +131,7 @@ class MediaAttachment < ApplicationRecord
convert_options: {
output: {
'loglevel' => 'fatal',
- :vf => 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease',
+ :vf => 'scale=\'min(640\, iw):min(640\, ih)\':force_original_aspect_ratio=decrease',
}.freeze,
}.freeze,
format: 'png',
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 71121bb2e2..8bdfd1ec91 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1709,6 +1709,10 @@ en:
default: "%b %d, %Y, %H:%M"
month: "%b %Y"
time: "%H:%M"
+ translation:
+ errors:
+ quota_exceeded: The server-wide usage quota for the translation service has been exceeded.
+ too_many_requests: There have been too many requests to the translation service recently.
two_factor_authentication:
add: Add
disable: Disable 2FA
diff --git a/lib/paperclip/transcoder.rb b/lib/paperclip/transcoder.rb
index 0f2e30f7d5..b88cf662c2 100644
--- a/lib/paperclip/transcoder.rb
+++ b/lib/paperclip/transcoder.rb
@@ -4,6 +4,9 @@ module Paperclip
# This transcoder is only to be used for the MediaAttachment model
# to check when uploaded videos are actually gifv's
class Transcoder < Paperclip::Processor
+ # This is the H.264 "High" value taken from https://www.dr-lex.be/info-stuff/videocalc.html
+ BITS_PER_PIXEL = 0.11
+
def initialize(file, options = {}, attachment = nil)
super
@@ -38,8 +41,11 @@ module Paperclip
@output_options['vframes'] = 1
when 'mp4'
unless eligible_to_passthrough?(metadata)
- @output_options['acodec'] = 'aac'
- @output_options['strict'] = 'experimental'
+ bitrate = (metadata.width * metadata.height * 30 * BITS_PER_PIXEL) / 1_000
+
+ @output_options['b:v'] = "#{bitrate}k"
+ @output_options['maxrate'] = "#{bitrate + 192}k"
+ @output_options['bufsize'] = "#{bitrate * 5}k"
if high_vfr?(metadata)
@output_options['vsync'] = 'vfr'