uploads: show videos and ugoiras on upload page.

* On the upload page, show the video when uploading a video or ugoira.
* On the upload page, show the filesize and resolution beneath the
  image, instead of above it.
* On the media asset show page, show the full video or ugoira instead of
  just the thumbnail.
This commit is contained in:
evazion
2022-01-30 22:27:07 -06:00
parent 5d2996d0c2
commit 4ad554e28b
12 changed files with 161 additions and 86 deletions

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
# A component for showing a full-sized image or video for a media asset.
class MediaAssetComponent < ApplicationComponent
attr_reader :media_asset
delegate :image_width, :image_height, :variant, :is_image?, :is_video?, :is_ugoira?, :is_flash?, to: :media_asset
def initialize(media_asset:)
super
@media_asset = media_asset
end
end

View File

@@ -0,0 +1,15 @@
<div class="media-asset-component relative fit-screen">
<div class="media-asset-zoom-level hidden absolute top-0.5 left-0.5 p-1 m-0.5 leading-none rounded text-xs font-arial font-bold pointer-events-none">
100%
</div>
<% if is_image? %>
<%= tag.img src: variant(:original).file_url, width: image_width, height: image_height, draggable: "false", class: "media-asset-image select-none" -%>
<% elsif is_video? %>
<%= tag.video src: variant(:original).file_url, width: image_width, height: image_height, autoplay: true, loop: true, controls: "controls" %>
<% elsif is_ugoira? %>
<%= tag.video src: variant(:sample).file_url, width: image_width, height: image_height, autoplay: true, loop: true, controls: "controls" %>
<% elsif is_flash? %>
<%= tag.div class: "ruffle-container", "data-swf": variant(:original).file_url %>
<% end %>
</div>

View File

@@ -0,0 +1,56 @@
export default class MediaAssetComponent {
static initialize() {
$(".media-asset-component").toArray().forEach(element => {
new MediaAssetComponent(element);
});
}
constructor(element) {
this.$component = $(element);
if (this.$image.length) {
this.$image.on("click.danbooru", e => this.toggleFit());
new ResizeObserver(() => this.updateZoom()).observe(this.$image.get(0));
this.updateZoom();
}
}
toggleFit() {
this.$component.toggleClass("fit-screen");
this.updateZoom();
}
updateZoom() {
this.$image.removeClass("cursor-zoom-in cursor-zoom-out");
this.$zoomLevel.addClass("hidden").text(`${Math.round(100 * this.zoomLevel)}%`);
if (this.isDownscaled) {
this.$image.addClass("cursor-zoom-out");
this.$zoomLevel.removeClass("hidden");
} else if (this.isTooBig) {
this.$image.addClass("cursor-zoom-in");
}
}
get zoomLevel() {
return this.$image.width() / Number(this.$image.attr("width"));
}
get isDownscaled() {
return this.$image.width() < Number(this.$image.attr("width"));
}
get isTooBig() {
return this.$image.width() > this.$component.width();
}
get $image() {
return this.$component.find(".media-asset-image");
}
get $zoomLevel() {
return this.$component.find(".media-asset-zoom-level");
}
}
$(MediaAssetComponent.initialize);

View File

@@ -0,0 +1,11 @@
.media-asset-component.fit-screen img, .media-asset-component.fit-screen video {
max-width: 100%;
max-height: 90vh;
width: auto;
height: auto;
}
.media-asset-zoom-level {
color: var(--preview-icon-color);
background: var(--preview-icon-background);
}

View File

@@ -43,6 +43,7 @@ import FileUploadComponent from "../../components/file_upload_component/file_upl
import ForumPostComponent from "../../components/forum_post_component/forum_post_component.js";
import IqdbQuery from "../src/javascripts/iqdb_queries.js";
import Note from "../src/javascripts/notes.js";
import MediaAssetComponent from "../../components/media_asset_component/media_asset_component.js";
import PopupMenuComponent from "../../components/popup_menu_component/popup_menu_component.js";
import Post from "../src/javascripts/posts.js";
import PostModeMenu from "../src/javascripts/post_mode_menu.js";
@@ -68,6 +69,7 @@ Danbooru.FavoritesTooltipComponent = FavoritesTooltipComponent;
Danbooru.FileUploadComponent = FileUploadComponent;
Danbooru.ForumPostComponent = ForumPostComponent;
Danbooru.IqdbQuery = IqdbQuery;
Danbooru.MediaAssetComponent = MediaAssetComponent;
Danbooru.Note = Note;
Danbooru.PopupMenuComponent = PopupMenuComponent;
Danbooru.Post = Post;

View File

@@ -6,7 +6,6 @@ Upload.IQDB_HIGH_SIMILARITY = 70;
Upload.initialize_all = function() {
if ($("#c-uploads #a-show").length) {
this.initialize_image();
this.initialize_similar();
$("#toggle-artist-commentary").on("click.danbooru", function(e) {
@@ -38,47 +37,6 @@ Upload.initialize_similar = function() {
});
}
Upload.initialize_image = function() {
$(document).on("click.danbooru", "#image", Upload.toggle_size);
$(document).on("click.danbooru", "#upload-image-view-small", Upload.view_small);
$(document).on("click.danbooru", "#upload-image-view-large", Upload.view_large);
$(document).on("click.danbooru", "#upload-image-view-full", Upload.view_full);
}
Upload.view_small = function(e) {
$("#image").addClass("fit-width fit-height");
$("#a-show").attr("data-image-size", "small");
e.preventDefault();
}
Upload.view_large = function(e) {
$("#image").removeClass("fit-height").addClass("fit-width");
$("#a-show").attr("data-image-size", "large");
e.preventDefault();
}
Upload.view_full = function(e) {
$("#image").removeClass("fit-width fit-height");
$("#a-show").attr("data-image-size", "full");
e.preventDefault();
}
Upload.toggle_size = function(e) {
let window_aspect_ratio = $(window).width() / $(window).height();
let image_aspect_ratio = $("#image").width() / $("#image").height();
let image_size = $("#a-show").attr("data-image-size");
if (image_size === "small" && image_aspect_ratio >= window_aspect_ratio) {
Upload.view_full(e);
} else if (image_size === "small" && image_aspect_ratio < window_aspect_ratio) {
Upload.view_large(e);
} else if (image_size === "large") {
Upload.view_small(e);
} else if (image_size === "full") {
Upload.view_small(e);
}
}
Upload.toggle_commentary = function() {
if ($(".artist-commentary").is(":visible")) {
$("#toggle-artist-commentary").text("show »");

View File

@@ -13,6 +13,8 @@ $spacer: 0.25rem; /* 4px */
.font-bold { font-weight: bold; }
.cursor-pointer { cursor: pointer; }
.cursor-zoom-in { cursor: zoom-in; }
.cursor-zoom-out { cursor: zoom-out; }
.hidden { display: none !important; }
.inline-block { display: inline-block; }
@@ -36,6 +38,8 @@ $spacer: 0.25rem; /* 4px */
.break-all { word-break: break-all; }
.whitespace-nowrap { white-space: nowrap; }
.pointer-events-none { pointer-events: none; }
.select-none { user-select: none; }
.leading-none { line-height: 1; }
.absolute { position: absolute; }
@@ -83,6 +87,7 @@ $spacer: 0.25rem; /* 4px */
.p-0 { padding: 0; }
.p-px { padding: 1px; }
.p-0\.5 { padding: 0.5 * $spacer; }
.p-1 { padding: 1 * $spacer; }
.p-4 { padding: 4 * $spacer; }
.px-4 { padding-left: 4 * $spacer; padding-right: 4 * $spacer; }
@@ -116,6 +121,7 @@ $spacer: 0.25rem; /* 4px */
.max-h-270px { max-height: 270px; }
.max-h-360px { max-height: 360px; }
.max-h-720px { max-height: 720px; }
.max-h-screen { max-height: 100vh; }
.space-x-1 > * + * { margin-left: 1 * $spacer; }
.space-x-2 > * + * { margin-left: 2 * $spacer; }

View File

@@ -1,35 +1,5 @@
div#c-uploads {
div#a-show {
&[data-image-size="small"] {
#image {
cursor: zoom-in;
}
a#upload-image-view-small {
font-weight: bold;
}
}
&[data-image-size="large"] {
#image {
cursor: zoom-out;
}
a#upload-image-view-large {
font-weight: bold;
}
}
&[data-image-size="full"] {
#image {
cursor: zoom-out;
}
a#upload-image-view-full {
font-weight: bold;
}
}
.artist-commentary {
margin-top: 1em;
}
@@ -42,7 +12,7 @@ div#c-uploads {
margin-bottom: 2em;
}
ul#upload-image-metadata, ul#links {
ul#links {
margin-bottom: 1em;
}

View File

@@ -2,7 +2,7 @@
<div id="a-show" class="fixed-width-container">
<h1 class="mb-4">Media Asset</h1>
<%= render MediaAssetPreviewComponent.new(media_asset: @media_asset, link_target: @media_asset.variant("original").file_url, save_data: CurrentUser.save_data) %>
<%= render MediaAssetComponent.new(media_asset: @media_asset) %>
<table class="striped aligned-vertical">
<% if @post.present? %>

View File

@@ -1,5 +1,5 @@
<div id="c-uploads">
<div id="a-new" data-image-size="small">
<div id="a-new">
<h1 class="text-center mb-4">Upload</h1>
<div class="flex items-center justify-center">

View File

@@ -1,5 +1,5 @@
<div id="c-uploads">
<div id="a-show" data-image-size="small">
<div id="a-show">
<h1>Upload</h1>
<% if @upload.is_pending? || @upload.is_processing? %>
@@ -32,17 +32,16 @@
<% @upload_media_asset = @upload.upload_media_assets.first %>
<% @media_asset = @upload_media_asset.media_asset %>
<p id="upload-image-metadata">
<strong>Size</strong>
<span id="upload-image-metadata-filesize"><%= number_to_human_size(@media_asset.file_size) %></span>
<span id="upload-image-metadata-resolution"><%= @media_asset.image_width %>x<%= @media_asset.image_height %></span>
<span id="upload-image-metadata-size-links">
(<a id="upload-image-view-small" href="">small</a> | <a id="upload-image-view-large" href="">large</a> | <a id="upload-image-view-full" href="">full</a>)
</span>
</p>
<div id="upload-image">
<%= tag.img src: @media_asset.variant("original").file_url, title: "Preview", id: "image", class: "fit-width fit-height", "data-shortcut": "z" %>
<%= render MediaAssetComponent.new(media_asset: @media_asset) %>
<p>
<strong>Size</strong>
<%= link_to @media_asset.variant(:original).file_url do %>
<%= number_to_human_size(@media_asset.file_size) %> .<%= @media_asset.file_ext %>
<% end %>
(<%= @media_asset.image_width %>x<%= @media_asset.image_height %>)
</p>
</div>
<%= render "uploads/related_posts", source: @upload.source_strategy %>

View File

@@ -0,0 +1,45 @@
require "test_helper"
class MediaAssetComponentTest < ViewComponent::TestCase
def render_component(media_asset, **options)
render_inline(MediaAssetComponent.new(media_asset: media_asset, **options))
end
context "The MediaAssetComponent" do
context "for an image" do
should "render the image" do
media_asset = create(:media_asset, file_ext: "jpg")
node = render_component(media_asset)
assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component img").attr("src").value)
end
end
context "for a video" do
should "render the video" do
media_asset = create(:media_asset, file_ext: "mp4", duration: 30)
node = render_component(media_asset)
assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component video").attr("src").value)
end
end
context "for a ugoira" do
should "render the ugoira" do
media_asset = create(:media_asset, file_ext: "zip")
node = render_component(media_asset)
assert_equal(media_asset.variant(:sample).file_url, node.css(".media-asset-component video").attr("src").value)
end
end
context "for a flash file" do
should "render the flash" do
media_asset = create(:media_asset, file_ext: "swf")
node = render_component(media_asset)
assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component div.ruffle-container").attr("data-swf").value)
end
end
end
end