about summary refs log tree commit diff
diff options
context:
space:
mode:
authormultiple creatures <dev@multiple-creature.party>2019-04-12 13:58:30 -0500
committermultiple creatures <dev@multiple-creature.party>2019-05-21 03:16:21 -0500
commit2cc20895349b2668be4f09beae1b92e8b2254079 (patch)
tree88644e8ffc4ecae2a5c8a1cc911ef5f6cecbb104
parentcd042a4ee30c46b117d74a182e14846a1d62540b (diff)
Add support for standard GIFs (under 200 KB)
-rw-r--r--app/javascript/flavours/glitch/components/media_gallery.js84
-rw-r--r--app/models/media_attachment.rb28
-rw-r--r--lib/paperclip/lazy_thumbnail.rb2
3 files changed, 89 insertions, 25 deletions
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index 3478766d2..62ef1da5e 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -58,6 +58,9 @@ class Item extends React.PureComponent {
   handleMouseEnter = (e) => {
     if (this.hoverToPlay()) {
       e.target.play();
+    } else if (this.hoverToPlayClassicGif()) {
+      const { attachment } = this.props;
+      e.target.src = attachment.get('url');
     }
   }
 
@@ -65,6 +68,9 @@ class Item extends React.PureComponent {
     if (this.hoverToPlay()) {
       e.target.pause();
       e.target.currentTime = 0;
+    } else if (this.hoverToPlayClassicGif()) {
+      const { attachment } = this.props;
+      e.target.src = attachment.get('preview_url');
     }
   }
 
@@ -73,6 +79,14 @@ class Item extends React.PureComponent {
     return !autoPlayGif && attachment.get('type') === 'gifv';
   }
 
+  hoverToPlayClassicGif () {
+    const { attachment } = this.props;
+    return !autoPlayGif && (
+      attachment.get('type') === 'image' &&
+      attachment.get('url').split('.').pop().startsWith('gif')
+    );
+  }
+
   handleClick = (e) => {
     const { index, onClick } = this.props;
 
@@ -80,6 +94,9 @@ class Item extends React.PureComponent {
       if (this.hoverToPlay()) {
         e.target.pause();
         e.target.currentTime = 0;
+      } else if (this.hoverToPlayClassicGif()) {
+        const { attachment } = this.props;
+        e.target.src = attachment.get('preview_url');
       }
       e.preventDefault();
       onClick(index);
@@ -199,25 +216,54 @@ class Item extends React.PureComponent {
       const x      = ((focusX /  2) + .5) * 100;
       const y      = ((focusY / -2) + .5) * 100;
 
-      thumbnail = (
-        <a
-          className='media-gallery__item-thumbnail'
-          href={attachment.get('remote_url') || originalUrl}
-          onClick={this.handleClick}
-          target='_blank'
-        >
-          <img
-            className={letterbox ? 'letterbox' : null}
-            src={previewUrl}
-            srcSet={srcSet}
-            sizes={sizes}
-            alt={attachment.get('description')}
-            title={attachment.get('description')}
-            style={{ objectPosition: letterbox ? null : `${x}% ${y}%` }}
-            onLoad={this.handleImageLoad}
-          />
-        </a>
-      );
+      const isGif  = originalUrl.split('.').pop().startsWith('gif');
+      const autoPlay = !isIOS() && autoPlayGif;
+
+      if (isGif && !autoPlay) {
+        thumbnail = (
+          <a
+            className='media-gallery__item-thumbnail'
+            href={attachment.get('remote_url') || originalUrl}
+            onClick={this.handleClick}
+            target='_blank'
+          >
+            <img
+              className={letterbox ? 'letterbox' : null}
+              src={previewUrl}
+              sizes={sizes}
+              alt={attachment.get('description')}
+              title={attachment.get('description')}
+              style={{ objectPosition: letterbox ? null : `${x}% ${y}%` }}
+              onMouseEnter={this.handleMouseEnter}
+              onMouseLeave={this.handleMouseLeave}
+              onMouseDown={this.handleMouseDown}
+              onLoad={this.handleImageLoad}
+            />
+
+            <span className='media-gallery__gifv__label'>GIF</span>
+          </a>
+        );
+      } else {
+        thumbnail = (
+          <a
+            className='media-gallery__item-thumbnail'
+            href={attachment.get('remote_url') || originalUrl}
+            onClick={this.handleClick}
+            target='_blank'
+          >
+            <img
+              className={letterbox ? 'letterbox' : null}
+              src={previewUrl}
+              srcSet={srcSet}
+              sizes={sizes}
+              alt={attachment.get('description')}
+              title={attachment.get('description')}
+              style={{ objectPosition: letterbox ? null : `${x}% ${y}%` }}
+              onLoad={this.handleImageLoad}
+            />
+          </a>
+        );
+      }
     } else if (attachment.get('type') === 'gifv') {
       const autoPlay = !isIOS() && autoPlayGif;
 
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index 8d3a656ae..2bc81dc6f 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -54,6 +54,12 @@ class MediaAttachment < ApplicationRecord
     },
   }.freeze
 
+  GIF_THUMB_FORMAT = {
+    format: 'png',
+    pixels: 160_000, # 400x400px
+    file_geometry_parser: FastGeometryParser,
+  }.freeze
+
   AUDIO_STYLES = {
     small: {
       format: 'png',
@@ -121,6 +127,7 @@ class MediaAttachment < ApplicationRecord
 
   IMAGE_LIMIT = 8.megabytes
   VIDEO_LIMIT = 40.megabytes
+  GIF_LIMIT = ENV.fetch('MAX_GIF_SIZE', 200).to_i.kilobytes
 
   belongs_to :account,          inverse_of: :media_attachments, optional: true
   belongs_to :status,           inverse_of: :media_attachments, optional: true
@@ -193,10 +200,17 @@ class MediaAttachment < ApplicationRecord
 
     def file_styles(f)
       if f.instance.file_content_type == 'image/gif'
-        {
-          small: IMAGE_STYLES[:small],
-          original: VIDEO_FORMAT,
-        }
+        if f.instance.file_file_size > GIF_LIMIT
+          {
+            small: IMAGE_STYLES[:small],
+            original: VIDEO_FORMAT,
+          }
+        else
+          {
+            small: GIF_THUMB_FORMAT,
+            original: IMAGE_STYLES[:original],
+          }
+        end
       elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type
         IMAGE_STYLES
       elsif AUDIO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)
@@ -218,7 +232,11 @@ class MediaAttachment < ApplicationRecord
 
     def file_processors(f)
       if f.file_content_type == 'image/gif'
-        [:gif_transcoder, :blurhash_transcoder]
+        if f.file_file_size > GIF_LIMIT
+          [:gif_transcoder, :blurhash_transcoder]
+        else
+          [:lazy_thumbnail, :blurhash_transcoder]
+        end
       elsif VIDEO_MIME_TYPES.include? f.file_content_type
         [:video_transcoder, :blurhash_transcoder]
       elsif AUDIO_MIME_TYPES.include? f.file_content_type
diff --git a/lib/paperclip/lazy_thumbnail.rb b/lib/paperclip/lazy_thumbnail.rb
index 542c17fb2..5992e76d8 100644
--- a/lib/paperclip/lazy_thumbnail.rb
+++ b/lib/paperclip/lazy_thumbnail.rb
@@ -20,7 +20,7 @@ module Paperclip
     private
 
     def needs_convert?
-      needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
+      options[:force_convert] == true || needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
     end
 
     def needs_different_geometry?