Skip to content
Extraits de code Groupes Projets
Valider 80c44ed9 rédigé par Eugen Rochko's avatar Eugen Rochko
Parcourir les fichiers

Do not autoplay videos, display play button instead. Use expiring links when...

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)
parent 290ffb63
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de
avec 34 ajouts et 27 suppressions
...@@ -53,7 +53,8 @@ const VideoPlayer = React.createClass({ ...@@ -53,7 +53,8 @@ const VideoPlayer = React.createClass({
propTypes: { propTypes: {
media: ImmutablePropTypes.map.isRequired, media: ImmutablePropTypes.map.isRequired,
width: React.PropTypes.number, width: React.PropTypes.number,
height: React.PropTypes.number height: React.PropTypes.number,
sensitive: React.PropTypes.bool
}, },
getDefaultProps () { getDefaultProps () {
...@@ -102,6 +103,12 @@ const VideoPlayer = React.createClass({ ...@@ -102,6 +103,12 @@ const VideoPlayer = React.createClass({
<span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span> <span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
</div> </div>
); );
} else if (!sensitive && !this.state.visible) {
return (
<div style={{ cursor: 'pointer', position: 'relative', marginTop: '8px', width: `${width}px`, height: `${height}px`, background: `url(${media.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }} onClick={this.handleOpen}>
<div style={{ position: 'absolute', top: '50%', left: '50%', fontSize: '36px', transform: 'translate(-50%, -50%)', padding: '5px', borderRadius: '100px', color: 'rgba(255, 255, 255, 0.8)' }}><i className='fa fa-play' /></div>
</div>
);
} }
return ( return (
......
...@@ -112,13 +112,11 @@ module AtomBuilderHelper ...@@ -112,13 +112,11 @@ module AtomBuilderHelper
end end
def link_enclosure(xml, media) 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 end
def link_avatar(xml, account) def link_avatar(xml, account)
single_link_avatar(xml, account, :large, 300) single_link_avatar(xml, account, :original, 120)
# single_link_avatar(xml, account, :medium, 96)
# single_link_avatar(xml, account, :small, 48)
end end
def logo(xml, url) def logo(xml, url)
......
...@@ -6,7 +6,7 @@ module StreamEntriesHelper ...@@ -6,7 +6,7 @@ module StreamEntriesHelper
end end
def avatar_for_status_url(status) 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 end
def entry_classes(status, is_predecessor, is_successor, include_threads) def entry_classes(status, is_predecessor, is_successor, include_threads)
......
...@@ -13,12 +13,12 @@ class Account < ApplicationRecord ...@@ -13,12 +13,12 @@ class Account < ApplicationRecord
validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?' validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?'
# Avatar upload # 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_content_type :avatar, content_type: IMAGE_MIME_TYPES
validates_attachment_size :avatar, less_than: 2.megabytes validates_attachment_size :avatar, less_than: 2.megabytes
# Header upload # 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_content_type :header, content_type: IMAGE_MIME_TYPES
validates_attachment_size :header, less_than: 2.megabytes validates_attachment_size :header, less_than: 2.megabytes
......
...@@ -10,7 +10,7 @@ class MediaAttachment < ApplicationRecord ...@@ -10,7 +10,7 @@ class MediaAttachment < ApplicationRecord
has_attached_file :file, has_attached_file :file,
styles: -> (f) { file_styles f }, styles: -> (f) { file_styles f },
processors: -> (f) { f.video? ? [:transcoder] : [:thumbnail] }, 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_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
validates_attachment_size :file, less_than: 4.megabytes validates_attachment_size :file, less_than: 4.megabytes
......
.account-grid-card .account-grid-card
.account-grid-card__header .account-grid-card__header
.avatar= image_tag account.avatar.url(:medium) .avatar= image_tag account.avatar.expiring_url(3600, :original)
.name .name
= link_to TagManager.instance.url_for(account) do = link_to TagManager.instance.url_for(account) do
%span.display_name= display_name(account) %span.display_name= display_name(account)
......
.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 - if user_signed_in? && current_account.id != @account.id
.controls .controls
- if current_account.following?(@account) - if current_account.following?(@account)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- else - else
= link_to t('accounts.follow'), follow_account_path(@account), data: { method: :post }, class: 'button' = 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 %h1.name
= display_name(@account) = display_name(@account)
%small= "@#{@account.username}" %small= "@#{@account.username}"
......
...@@ -6,7 +6,7 @@ Nokogiri::XML::Builder.new do |xml| ...@@ -6,7 +6,7 @@ Nokogiri::XML::Builder.new do |xml|
title xml, @account.display_name title xml, @account.display_name
subtitle xml, @account.note subtitle xml, @account.note
updated_at xml, stream_updated_at 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 author(xml) do
include_author xml, @account include_author xml, @account
......
...@@ -4,8 +4,8 @@ attributes :id, :username, :acct, :display_name ...@@ -4,8 +4,8 @@ attributes :id, :username, :acct, :display_name
node(:note) { |account| Formatter.instance.simplified_format(account) } node(:note) { |account| Formatter.instance.simplified_format(account) }
node(:url) { |account| TagManager.instance.url_for(account) } node(:url) { |account| TagManager.instance.url_for(account) }
node(:avatar) { |account| full_asset_url(account.avatar.url(:large, false)) } node(:avatar) { |account| full_asset_url(account.avatar.expiring_url(3600, :original)) }
node(:header) { |account| full_asset_url(account.header.url(:medium, false)) } 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(: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(: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) } node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : (account.try(:statuses_count) || account.statuses.count) }
object @media object @media
attribute :id, :type attribute :id, :type
node(:url) { |media| full_asset_url(media.file.url) } node(:url) { |media| full_asset_url(media.file.expiring_url(3600, :original)) }
node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } node(:preview_url) { |media| full_asset_url(media.file.expiring_url(3600, :small)) }
node(:text_url) { |media| medium_url(media) } node(:text_url) { |media| medium_url(media) }
attributes :id, :remote_url, :type attributes :id, :remote_url, :type
node(:url) { |media| full_asset_url(media.file.url) } node(:url) { |media| full_asset_url(media.file.expiring_url(3600, :original)) }
node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } node(:preview_url) { |media| full_asset_url(media.file.expiring_url(3600, :small)) }
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
- if (status.reblog? ? status.reblog : status).media_attachments.size > 0 - if (status.reblog? ? status.reblog : status).media_attachments.size > 0
%ul.media-attachments %ul.media-attachments
- (status.reblog? ? status.reblog : status).media_attachments.each do |media| - (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 - if include_threads
= render partial: 'status', collection: @descendants, as: :status, locals: { is_successor: true } = render partial: 'status', collection: @descendants, as: :status, locals: { is_successor: true }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%meta{ name: 'og:title', content: "#{@account.username} on #{Rails.configuration.x.local_domain}" }/ %meta{ name: 'og:title', content: "#{@account.username} on #{Rails.configuration.x.local_domain}" }/
%meta{ name: 'og:article:author', content: @account.username }/ %meta{ name: 'og:article:author', content: @account.username }/
%meta{ name: 'og:description', content: @stream_entry.activity.content }/ %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 .activity-stream.activity-stream-headless
= render partial: @type, locals: { @type.to_sym => @stream_entry.activity, include_threads: true } = render partial: @type, locals: { @type.to_sym => @stream_entry.activity, include_threads: true }
if ENV['S3_ENABLED'] == 'true' if ENV['S3_ENABLED'] == 'true'
Aws.eager_autoload!(services: %w(S3)) Aws.eager_autoload!(services: %w(S3))
Paperclip::Attachment.default_options[:storage] = :s3 Paperclip::Attachment.default_options[:storage] = :s3
Paperclip::Attachment.default_options[:s3_protocol] = 'https' Paperclip::Attachment.default_options[:s3_protocol] = 'https'
Paperclip::Attachment.default_options[:url] = ':s3_domain_url' 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[: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[: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? unless ENV['S3_CLOUDFRONT_HOST'].blank?
Paperclip::Attachment.default_options[:url] = ':s3_alias_url' Paperclip::Attachment.default_options[:url] = ':s3_alias_url'
......
public/avatars/medium/missing.png

1,03 ko

Fichier déplacé
public/avatars/small/missing.png

681 octets

...@@ -162,7 +162,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do ...@@ -162,7 +162,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
let(:account) { Fabricate(:account, username: 'alice') } let(:account) { Fabricate(:account, username: 'alice') }
it 'creates a link' do it 'creates a link' do
expect(used_with_namespaces { |xml| helper.link_avatar(xml, account) }).to match '<link rel="avatar" type="" media:width="300" media:height="300" href="http://test.host/avatars/large/missing.png"/>' expect(used_with_namespaces { |xml| helper.link_avatar(xml, account) }).to match '<link rel="avatar" type="" media:width="120" media:height="120" href="http://test.host/avatars/original/missing.png"/>'
end end
end end
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter