From 80c44ed9c19855d494ab26011dca0f6fbc644d0c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 4 Dec 2016 12:26:12 +0100 Subject: [PATCH] Do not autoplay videos, display play button instead. Use expiring links when using S3. Do not keep originals for avatars/headers, resize avatars down to 120x120 instead of 300x300. Set cache headers on S3 stuff, also make it private (aka only accessible via expiring links to prevent hotlinking) --- .../components/components/video_player.jsx | 9 ++++++++- app/helpers/atom_builder_helper.rb | 6 ++---- app/helpers/stream_entries_helper.rb | 2 +- app/models/account.rb | 4 ++-- app/models/media_attachment.rb | 2 +- app/views/accounts/_grid_card.html.haml | 2 +- app/views/accounts/_header.html.haml | 4 ++-- app/views/accounts/show.atom.ruby | 2 +- app/views/api/v1/accounts/show.rabl | 4 ++-- app/views/api/v1/media/create.rabl | 4 ++-- app/views/api/v1/statuses/_media.rabl | 4 ++-- app/views/stream_entries/_status.html.haml | 2 +- app/views/stream_entries/show.html.haml | 2 +- config/initializers/paperclip.rb | 12 +++++++----- public/avatars/medium/missing.png | Bin 1057 -> 0 bytes public/avatars/{large => original}/missing.png | Bin public/avatars/small/missing.png | Bin 681 -> 0 bytes spec/helpers/atom_builder_helper_spec.rb | 2 +- 18 files changed, 34 insertions(+), 27 deletions(-) delete mode 100644 public/avatars/medium/missing.png rename public/avatars/{large => original}/missing.png (100%) delete mode 100644 public/avatars/small/missing.png diff --git a/app/assets/javascripts/components/components/video_player.jsx b/app/assets/javascripts/components/components/video_player.jsx index 61c1995a782..8f64ad3cd32 100644 --- a/app/assets/javascripts/components/components/video_player.jsx +++ b/app/assets/javascripts/components/components/video_player.jsx @@ -53,7 +53,8 @@ const VideoPlayer = React.createClass({ propTypes: { media: ImmutablePropTypes.map.isRequired, width: React.PropTypes.number, - height: React.PropTypes.number + height: React.PropTypes.number, + sensitive: React.PropTypes.bool }, getDefaultProps () { @@ -102,6 +103,12 @@ const VideoPlayer = React.createClass({ ); + } else if (!sensitive && !this.state.visible) { + return ( +
+
+
+ ); } return ( diff --git a/app/helpers/atom_builder_helper.rb b/app/helpers/atom_builder_helper.rb index 40bbe0491ca..953ccd43884 100644 --- a/app/helpers/atom_builder_helper.rb +++ b/app/helpers/atom_builder_helper.rb @@ -112,13 +112,11 @@ module AtomBuilderHelper end def link_enclosure(xml, media) - xml.link(rel: 'enclosure', href: full_asset_url(media.file.url), type: media.file_content_type, length: media.file_file_size) + xml.link(rel: 'enclosure', href: full_asset_url(media.file.url(:original, false)), type: media.file_content_type, length: media.file_file_size) end def link_avatar(xml, account) - single_link_avatar(xml, account, :large, 300) - # single_link_avatar(xml, account, :medium, 96) - # single_link_avatar(xml, account, :small, 48) + single_link_avatar(xml, account, :original, 120) end def logo(xml, url) diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index 1eb2ed05861..4abb00b07d0 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -6,7 +6,7 @@ module StreamEntriesHelper end def avatar_for_status_url(status) - status.reblog? ? status.reblog.account.avatar.url(:large) : status.account.avatar.url(:large) + status.reblog? ? status.reblog.account.avatar.expiring_url(3600, :original) : status.account.avatar.expiring_url(3600, :original) end def entry_classes(status, is_predecessor, is_successor, include_threads) diff --git a/app/models/account.rb b/app/models/account.rb index 105b77e0440..b1cf34e9abe 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -13,12 +13,12 @@ class Account < ApplicationRecord validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?' # Avatar upload - has_attached_file :avatar, styles: { large: '300x300#' }, convert_options: { all: '-strip' } + has_attached_file :avatar, styles: { original: '120x120#' }, convert_options: { all: '-quality 80 -strip' } validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES validates_attachment_size :avatar, less_than: 2.megabytes # Header upload - has_attached_file :header, styles: { medium: '700x335#' }, convert_options: { all: '-strip' } + has_attached_file :header, styles: { original: '700x335#' }, convert_options: { all: '-quality 80 -strip' } validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES validates_attachment_size :header, less_than: 2.megabytes diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index f1b9b81121e..d37ef99a85b 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -10,7 +10,7 @@ class MediaAttachment < ApplicationRecord has_attached_file :file, styles: -> (f) { file_styles f }, processors: -> (f) { f.video? ? [:transcoder] : [:thumbnail] }, - convert_options: { all: '-strip' } + convert_options: { all: '-quality 80 -strip' } validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES validates_attachment_size :file, less_than: 4.megabytes diff --git a/app/views/accounts/_grid_card.html.haml b/app/views/accounts/_grid_card.html.haml index f65b78470c9..d91c184760c 100644 --- a/app/views/accounts/_grid_card.html.haml +++ b/app/views/accounts/_grid_card.html.haml @@ -1,6 +1,6 @@ .account-grid-card .account-grid-card__header - .avatar= image_tag account.avatar.url(:medium) + .avatar= image_tag account.avatar.expiring_url(3600, :original) .name = link_to TagManager.instance.url_for(account) do %span.display_name= display_name(account) diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 0063d9f1609..4c7d53678a1 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -1,4 +1,4 @@ -.card{ style: "background-image: url(#{@account.header.url(:medium)})" } +.card{ style: "background-image: url(#{@account.header.expiring_url(3600, :original)})" } - if user_signed_in? && current_account.id != @account.id .controls - if current_account.following?(@account) @@ -6,7 +6,7 @@ - else = link_to t('accounts.follow'), follow_account_path(@account), data: { method: :post }, class: 'button' - .avatar= image_tag @account.avatar.url(:large) + .avatar= image_tag @account.avatar.expiring_url(3600, :original) %h1.name = display_name(@account) %small= "@#{@account.username}" diff --git a/app/views/accounts/show.atom.ruby b/app/views/accounts/show.atom.ruby index 558c777f011..68b1c157dda 100644 --- a/app/views/accounts/show.atom.ruby +++ b/app/views/accounts/show.atom.ruby @@ -6,7 +6,7 @@ Nokogiri::XML::Builder.new do |xml| title xml, @account.display_name subtitle xml, @account.note updated_at xml, stream_updated_at - logo xml, full_asset_url(@account.avatar.url(:medium, false)) + logo xml, full_asset_url(@account.avatar.expiring_url(3600, :original)) author(xml) do include_author xml, @account diff --git a/app/views/api/v1/accounts/show.rabl b/app/views/api/v1/accounts/show.rabl index c01349ef23f..a58db29b6a4 100644 --- a/app/views/api/v1/accounts/show.rabl +++ b/app/views/api/v1/accounts/show.rabl @@ -4,8 +4,8 @@ attributes :id, :username, :acct, :display_name node(:note) { |account| Formatter.instance.simplified_format(account) } node(:url) { |account| TagManager.instance.url_for(account) } -node(:avatar) { |account| full_asset_url(account.avatar.url(:large, false)) } -node(:header) { |account| full_asset_url(account.header.url(:medium, false)) } +node(:avatar) { |account| full_asset_url(account.avatar.expiring_url(3600, :original)) } +node(:header) { |account| full_asset_url(account.header.expiring_url(3600, :original)) } node(:followers_count) { |account| defined?(@followers_counts_map) ? (@followers_counts_map[account.id] || 0) : (account.try(:followers_count) || account.followers.count) } node(:following_count) { |account| defined?(@following_counts_map) ? (@following_counts_map[account.id] || 0) : (account.try(:following_count) || account.following.count) } node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : (account.try(:statuses_count) || account.statuses.count) } diff --git a/app/views/api/v1/media/create.rabl b/app/views/api/v1/media/create.rabl index 803a9309443..2a4db7aaee0 100644 --- a/app/views/api/v1/media/create.rabl +++ b/app/views/api/v1/media/create.rabl @@ -1,5 +1,5 @@ object @media attribute :id, :type -node(:url) { |media| full_asset_url(media.file.url) } -node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } +node(:url) { |media| full_asset_url(media.file.expiring_url(3600, :original)) } +node(:preview_url) { |media| full_asset_url(media.file.expiring_url(3600, :small)) } node(:text_url) { |media| medium_url(media) } diff --git a/app/views/api/v1/statuses/_media.rabl b/app/views/api/v1/statuses/_media.rabl index e4ceef76301..76256ed2c77 100644 --- a/app/views/api/v1/statuses/_media.rabl +++ b/app/views/api/v1/statuses/_media.rabl @@ -1,4 +1,4 @@ attributes :id, :remote_url, :type -node(:url) { |media| full_asset_url(media.file.url) } -node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } +node(:url) { |media| full_asset_url(media.file.expiring_url(3600, :original)) } +node(:preview_url) { |media| full_asset_url(media.file.expiring_url(3600, :small)) } diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml index 2edc8bc3fce..42994abbdf0 100644 --- a/app/views/stream_entries/_status.html.haml +++ b/app/views/stream_entries/_status.html.haml @@ -34,7 +34,7 @@ - if (status.reblog? ? status.reblog : status).media_attachments.size > 0 %ul.media-attachments - (status.reblog? ? status.reblog : status).media_attachments.each do |media| - %li.transparent-background= link_to '', media.file.url, style: "background-image: url(#{media.file.url(:small)})", target: '_blank' + %li.transparent-background= link_to '', media.file.expiring_url(3600, :original), style: "background-image: url(#{media.file.expiring_url(3600, :small)})", target: '_blank' - if include_threads = render partial: 'status', collection: @descendants, as: :status, locals: { is_successor: true } diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml index a0e24887314..76dfa6dacd4 100644 --- a/app/views/stream_entries/show.html.haml +++ b/app/views/stream_entries/show.html.haml @@ -7,7 +7,7 @@ %meta{ name: 'og:title', content: "#{@account.username} on #{Rails.configuration.x.local_domain}" }/ %meta{ name: 'og:article:author', content: @account.username }/ %meta{ name: 'og:description', content: @stream_entry.activity.content }/ - %meta{ name: 'og:image', content: @stream_entry.activity.is_a?(Status) && @stream_entry.activity.media_attachments.size > 0 ? full_asset_url(@stream_entry.activity.media_attachments.first.file.url(:small)) : full_asset_url(@account.avatar.url(:large)) }/ + %meta{ name: 'og:image', content: @stream_entry.activity.is_a?(Status) && @stream_entry.activity.media_attachments.size > 0 ? full_asset_url(@stream_entry.activity.media_attachments.first.file.expiring_url(3600, :small)) : full_asset_url(@account.avatar.expiring_url(3600, :original)) }/ .activity-stream.activity-stream-headless = render partial: @type, locals: { @type.to_sym => @stream_entry.activity, include_threads: true } diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 4c2053e2cc8..704f7fe7375 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -1,11 +1,13 @@ if ENV['S3_ENABLED'] == 'true' Aws.eager_autoload!(services: %w(S3)) - Paperclip::Attachment.default_options[:storage] = :s3 - Paperclip::Attachment.default_options[:s3_protocol] = 'https' - Paperclip::Attachment.default_options[:url] = ':s3_domain_url' - Paperclip::Attachment.default_options[:s3_host_name] = "s3-#{ENV.fetch('S3_REGION')}.amazonaws.com" - Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename' + Paperclip::Attachment.default_options[:storage] = :s3 + Paperclip::Attachment.default_options[:s3_protocol] = 'https' + Paperclip::Attachment.default_options[:url] = ':s3_domain_url' + Paperclip::Attachment.default_options[:s3_host_name] = "s3-#{ENV.fetch('S3_REGION')}.amazonaws.com" + Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename' + Paperclip::Attachment.default_options[:s3_headers] = { 'Cache-Control' => 'max-age=315576000', 'Expires' => 10.years.from_now.httpdate } + Paperclip::Attachment.default_options[:s3_permissions] = :private unless ENV['S3_CLOUDFRONT_HOST'].blank? Paperclip::Attachment.default_options[:url] = ':s3_alias_url' diff --git a/public/avatars/medium/missing.png b/public/avatars/medium/missing.png deleted file mode 100644 index 98fffdae340a98f2630dd9c3439a31d678289ab5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1057 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPNr>w9k%enLJ(}6;gC9V-A&iT2ysd*&~&PAz-C8;S2 z<(VZJ3hti10pX2&;tUMTot`d^Ar-gY-Z|<2IE>-=$NBTOTa<~h%P5=)aV&`{-TUQ2 z^8fE%d$+FADvdJao;*|2Q-Rxa&(UiByR2szlRB2~e=pec`NZ+}m4Oacm9}~Zh zZ(v|aU{PRDW?+>PPYa&eO}3}$RhXFRI%j& z&yMpvv8_7XJZ;=_=EWAV*|_w7zda$fQ9M5_W2V)dzOA8;C;!v0UokiBr@Z@|J+YJP zR=Z7B(X6Yh>r**vW`8wxV`=`sy-YfH1nlSbOnCmY_x2o~w1Q@d%wHQOf4Z5__3=t= zJ;SuTj^+C2FBa$R6RNb1OL(~Uihsf~$vRn|!Yi*2yqsa4_q^56?*9hv)$9I0fBkkDW2DE9n6~i5 zy&REo3$kZR%Wh76_2bKpgWcPUSrTJ%8xCeP&eD2(AahUgZvVbr8Rk8!nMIiTa+7xP ztgFf2#*-i^^~yB&@#DN`wr}M+Huc7<-=$_udn(~?Q*-5hql)MDd;OOU4Xd6#`m){f z!}`BI&lvf>&sy61f5Yt~-}m!8Y&Z0AUVV?J0BC#Qg3GJ!XWHv}x3A(@v&XcBp@m_Q zhU28P7q`A%Iu>tkawYrJ*3;x3C_Wy5zE?Ut(&&X z<%$Wbqe!^0!ujGAr_$mMy_^y8Q*e>R-{QaDFXqnHunrBIkiJ5#L4e6~R(?vn?rOH! zV1szJ4~HdQYaGq%JbnJYd3z+6V)z%8oL5?pOq^#uEstwc@jSFH_IQq@(%B-DwNWom z^E0e@{N>i_&0c33+Lk(t2|c?W<8&`ea+9yl9n-YwigU_-y4MRFxAW z|8-&ZQ#;T2s_dS0xp_4gR(_kiVbO^nJKjIITF`g$j=SimKOFw?aSwhJF2Az)e;fnD zg1ZJEZhn+&n|#%Jep{aR;m+>G&eFEaBY$Ok{yD#sU)o;Ok%Tmkku&aYy3hFjwrrru Su{=-?XYh3Ob6Mw<&;$U-`NU8F diff --git a/public/avatars/large/missing.png b/public/avatars/original/missing.png similarity index 100% rename from public/avatars/large/missing.png rename to public/avatars/original/missing.png diff --git a/public/avatars/small/missing.png b/public/avatars/small/missing.png deleted file mode 100644 index 43fe8b741dfc4552522ea2d8b23548f86df30fa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&pIsQ&!kiOGwfy0w^R|;u=xnoS&PUnpeW$T$GwvlA5AW zo>`Ki;O^-g5Z=fq&cMJV=;`7Zl5y|tjokdn0V3=l?5A@t4$ufFh}>$n@pN3qpMUcY z9Wl?^_9Ni!t%(=Q0_2W8z8b#Eq|R{{ut))CaT0@1630#^@qAVZ{%HxlwGIYR|)WGhQp~n<@Wr0()btX<)W z+WQ%?I)_AhHqL$*d$hoJZK?P%XX)p09a*PmT-vSY;>qU48RGhHaguDS(?rdC^Qr_` z85so9Rpa)(*uvJKd4nbo8?$zwKh?(*b#<>odQY zNCr+am0!3jX@bY*M}2D*&vHk!buC&^E;WC?VxVB?$yv-Asv45nA!~{i8abFY?Qxlr zvY~qJT*lPUX0Iid4&kXTh4*$WNY0v3rMRnW%jX{q4l_h9m@Z{?2o4D2$qX~8=F{O7 zuj4r$RDQ1})Obx3%eu<%ds}kt%dZ!' + expect(used_with_namespaces { |xml| helper.link_avatar(xml, account) }).to match '' end end