From caf5b8e9757679b93b9a34b0c55f43cb47910201 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 4 Mar 2017 22:17:10 +0100 Subject: Fix #431 - convert gif to webm during upload. Web UI treats them like it did before. In the API, attachments now can be either image, video or gifv. Gifv is to be treated like images in terms of behaviour, but are videos by file type. --- app/models/media_attachment.rb | 69 +++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 6925f9b0d..620a92dbc 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -1,15 +1,32 @@ # frozen_string_literal: true class MediaAttachment < ApplicationRecord + self.inheritance_column = nil + + enum type: [:image, :gifv, :video] + IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze VIDEO_MIME_TYPES = ['video/webm', 'video/mp4'].freeze + IMAGE_STYLES = { original: '1280x1280>', small: '400x400>' }.freeze + VIDEO_STYLES = { + small: { + convert_options: { + output: { + vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease', + }, + }, + format: 'png', + time: 0, + }, + }.freeze + belongs_to :account, inverse_of: :media_attachments belongs_to :status, inverse_of: :media_attachments has_attached_file :file, - styles: -> (f) { file_styles f }, - processors: -> (f) { f.video? ? [:transcoder] : [:thumbnail] }, + styles: ->(f) { file_styles f }, + processors: ->(f) { file_processors f }, convert_options: { all: '-quality 90 -strip' } validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES validates_attachment_size :file, less_than: 8.megabytes @@ -27,45 +44,45 @@ class MediaAttachment < ApplicationRecord self.file = URI.parse(url) end - def image? - IMAGE_MIME_TYPES.include? file_content_type - end - - def video? - VIDEO_MIME_TYPES.include? file_content_type - end - - def type - image? ? 'image' : 'video' - end - def to_param shortcode end before_create :set_shortcode + before_post_process :set_type class << self private def file_styles(f) - if f.instance.image? + if f.instance.file_content_type == 'image/gif' { - original: '1280x1280>', - small: '400x400>', - } - else - { - small: { + small: IMAGE_STYLES[:small], + original: { + format: 'webm', convert_options: { output: { - vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease', + 'c:v' => 'libvpx', + 'crf' => 6, + 'b:v' => '500K', }, }, - format: 'png', - time: 1, }, } + elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type + IMAGE_STYLES + else + VIDEO_STYLES + end + end + + def file_processors(f) + if f.file_content_type == 'image/gif' + [:gif_transcoder] + elsif VIDEO_MIME_TYPES.include? f.file_content_type + [:transcoder] + else + [:thumbnail] end end end @@ -80,4 +97,8 @@ class MediaAttachment < ApplicationRecord break if MediaAttachment.find_by(shortcode: shortcode).nil? end end + + def set_type + self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image + end end -- cgit From 85fce04d1b4353c3645c15967d222cdcdb488dfd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 Mar 2017 22:55:24 +0100 Subject: Detect videos with no sound, handle them like gifv --- app/models/media_attachment.rb | 2 +- config/application.rb | 1 + lib/paperclip/video_transcoder.rb | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 lib/paperclip/video_transcoder.rb (limited to 'app/models/media_attachment.rb') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 620a92dbc..d560bd673 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -80,7 +80,7 @@ class MediaAttachment < ApplicationRecord if f.file_content_type == 'image/gif' [:gif_transcoder] elsif VIDEO_MIME_TYPES.include? f.file_content_type - [:transcoder] + [:video_transcoder] else [:thumbnail] end diff --git a/config/application.rb b/config/application.rb index 30ed608c5..cb009b24c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -8,6 +8,7 @@ Bundler.require(*Rails.groups) require_relative '../app/lib/exceptions' require_relative '../lib/paperclip/gif_transcoder' +require_relative '../lib/paperclip/video_transcoder' Dotenv::Railtie.load diff --git a/lib/paperclip/video_transcoder.rb b/lib/paperclip/video_transcoder.rb new file mode 100644 index 000000000..c3504c17c --- /dev/null +++ b/lib/paperclip/video_transcoder.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Paperclip + # This transcoder is only to be used for the MediaAttachment model + # to check when uploaded videos are actually gifv's + class VideoTranscoder < Paperclip::Processor + def make + meta = ::Av.cli.identify(@file.path) + attachment.instance.type = MediaAttachment.types[:gifv] unless meta[:audio_encode] + + Paperclip::Transcoder.make(file, options, attachment) + end + end +end -- cgit From 79b08c5f0a05844d2465e1e99c5cde4d7b4f6d0e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 Mar 2017 23:13:21 +0100 Subject: Higher quality webms? Might improve conversation of some types of gifs --- app/models/media_attachment.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index d560bd673..f300c127c 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -63,7 +63,7 @@ class MediaAttachment < ApplicationRecord convert_options: { output: { 'c:v' => 'libvpx', - 'crf' => 6, + 'crf' => 4, 'b:v' => '500K', }, }, -- cgit From 6382ef2bc6f54f01a107fc921a8f29ec2eb9878c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 Mar 2017 23:27:25 +0100 Subject: Add vsync -cfr option when converting gif to webm --- app/models/media_attachment.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index f300c127c..30a76f3ec 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -62,9 +62,10 @@ class MediaAttachment < ApplicationRecord format: 'webm', convert_options: { output: { - 'c:v' => 'libvpx', - 'crf' => 4, - 'b:v' => '500K', + 'c:v' => 'libvpx', + 'crf' => 4, + 'b:v' => '500K', + 'vsync' => 'cfr', }, }, }, -- cgit From 8d93f0ca563322764ee4b5395598af542eb678e7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 Mar 2017 23:43:58 +0100 Subject: Increase max bitrate of converted webms, slightly optimized counter queries (Because postgres can tell that count(*) needs no extra checks, but counting a specific column requires them) --- app/controllers/api_controller.rb | 10 +++++----- app/models/media_attachment.rb | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index db16f82e5..c43011754 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -102,14 +102,14 @@ class ApiController < ApplicationController def set_counters_maps(statuses) # rubocop:disable Style/AccessorMethodName status_ids = statuses.compact.map { |s| s.reblog? ? s.reblog_of_id : s.id }.uniq - @favourites_counts_map = Favourite.select('status_id, COUNT(id) AS favourites_count').group('status_id').where(status_id: status_ids).map { |f| [f.status_id, f.favourites_count] }.to_h - @reblogs_counts_map = Status.select('statuses.id, COUNT(reblogs.id) AS reblogs_count').joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.id = reblogs.reblog_of_id').where(id: status_ids).group('statuses.id').map { |r| [r.id, r.reblogs_count] }.to_h + @favourites_counts_map = Favourite.select('status_id, COUNT(*) AS favourites_count').group('status_id').where(status_id: status_ids).map { |f| [f.status_id, f.favourites_count] }.to_h + @reblogs_counts_map = Status.select('statuses.id, COUNT(*) AS reblogs_count').joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.id = reblogs.reblog_of_id').where(id: status_ids).group('statuses.id').map { |r| [r.id, r.reblogs_count] }.to_h end def set_account_counters_maps(accounts) # rubocop:disable Style/AccessorMethodName account_ids = accounts.compact.map(&:id).uniq - @followers_counts_map = Follow.unscoped.select('target_account_id, COUNT(account_id) AS followers_count').group('target_account_id').where(target_account_id: account_ids).map { |f| [f.target_account_id, f.followers_count] }.to_h - @following_counts_map = Follow.unscoped.select('account_id, COUNT(target_account_id) AS following_count').group('account_id').where(account_id: account_ids).map { |f| [f.account_id, f.following_count] }.to_h - @statuses_counts_map = Status.unscoped.select('account_id, COUNT(id) AS statuses_count').group('account_id').where(account_id: account_ids).map { |s| [s.account_id, s.statuses_count] }.to_h + @followers_counts_map = Follow.unscoped.select('target_account_id, COUNT(*) AS followers_count').group('target_account_id').where(target_account_id: account_ids).map { |f| [f.target_account_id, f.followers_count] }.to_h + @following_counts_map = Follow.unscoped.select('account_id, COUNT(*) AS following_count').group('account_id').where(account_id: account_ids).map { |f| [f.account_id, f.following_count] }.to_h + @statuses_counts_map = Status.unscoped.select('account_id, COUNT(*) AS statuses_count').group('account_id').where(account_id: account_ids).map { |s| [s.account_id, s.statuses_count] }.to_h end end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 30a76f3ec..5241d9515 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -64,7 +64,7 @@ class MediaAttachment < ApplicationRecord output: { 'c:v' => 'libvpx', 'crf' => 4, - 'b:v' => '500K', + 'b:v' => '1300K', 'vsync' => 'cfr', }, }, -- cgit From 03a857f59a773483924a942ac3bda1b290f82a2e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 6 Mar 2017 00:30:03 +0100 Subject: Use more widely supported MP4 format for gifv's --- app/models/media_attachment.rb | 12 +++++++----- lib/paperclip/gif_transcoder.rb | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 5241d9515..1090f1b39 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -59,13 +59,15 @@ class MediaAttachment < ApplicationRecord { small: IMAGE_STYLES[:small], original: { - format: 'webm', + format: 'mp4', convert_options: { output: { - 'c:v' => 'libvpx', - 'crf' => 4, - 'b:v' => '1300K', - 'vsync' => 'cfr', + 'movflags' => 'faststart', + 'pix_fmt' => 'yuv420p', + 'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'', + 'vsync' => 'cfr', + 'b:v' => '1300K', + 'crf' => 4, }, }, }, diff --git a/lib/paperclip/gif_transcoder.rb b/lib/paperclip/gif_transcoder.rb index 33d2c4a01..8337448b2 100644 --- a/lib/paperclip/gif_transcoder.rb +++ b/lib/paperclip/gif_transcoder.rb @@ -11,8 +11,8 @@ module Paperclip final_file = Paperclip::Transcoder.make(file, options, attachment) - attachment.instance.file_file_name = 'media.webm' - attachment.instance.file_content_type = 'video/webm' + attachment.instance.file_file_name = 'media.mp4' + attachment.instance.file_content_type = 'video/mp4' attachment.instance.type = MediaAttachment.types[:gifv] final_file -- cgit From d6cb4bbe99f16b40c5962130d19ca3336124af1b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 6 Mar 2017 01:50:35 +0100 Subject: Performance improvement for profiles --- app/controllers/api/v1/accounts_controller.rb | 1 + app/models/media_attachment.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'app/models/media_attachment.rb') diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index c666651b4..9c84e0a1b 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -53,6 +53,7 @@ class Api::V1::AccountsController < ApiController set_maps(@statuses) set_counters_maps(@statuses) + set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq) next_path = statuses_api_v1_account_url(max_id: @statuses.last.id) unless @statuses.empty? prev_path = statuses_api_v1_account_url(since_id: @statuses.first.id) unless @statuses.empty? diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 1090f1b39..818190214 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -67,7 +67,8 @@ class MediaAttachment < ApplicationRecord 'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'', 'vsync' => 'cfr', 'b:v' => '1300K', - 'crf' => 4, + 'maxrate' => '500K', + 'crf' => 6, }, }, }, -- cgit