Compare commits

..

1 Commits

Author SHA1 Message Date
Blake Erickson
a875df7c49 DEV: Generate video thumbnails from the File object instead of the DOM
In order to avoid built in browser CORS issues and sites that are using
CDNs this change allows us to generate thumbnail images from videos
directly from the File uploaded instead of reading the already uploaded
file via the `video` tag.

Follow-up to: f144c64e13
2023-03-17 16:30:24 -06:00
7 changed files with 25 additions and 57 deletions

View File

@ -937,8 +937,6 @@ export default Component.extend(
// Short upload urls need resolution
resolveAllShortUrls(ajax, this.siteSettings, preview);
this._generateVideoThumbnail();
preview.addEventListener("click", this._handleImageScaleButtonClick);
this._registerImageAltTextButtonClick(preview);

View File

@ -325,6 +325,11 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
cacheShortUploadUrl(upload.short_url, upload);
// video/mp4, video/webm, video/quicktime, etc.
if (file.type.split("/")[0] === "video") {
this._generateVideoThumbnail(file, upload.url);
}
if (this.useUploadPlaceholders) {
this.appEvents.trigger(
`${this.composerEventPrefix}:replace-text`,

View File

@ -17,30 +17,12 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
useUploadPlaceholders: true,
@bind
_generateVideoThumbnail() {
if (!this.siteSettings.enable_diffhtml_preview) {
return;
}
_generateVideoThumbnail(videoFile, uploadUrl) {
let video = document.createElement("video");
video.src = URL.createObjectURL(videoFile.data);
let videos = document.getElementsByClassName("video-container");
if (!videos) {
return;
}
// Only generate a topic thumbnail for the first video
let video_container = videos[0];
if (!video_container) {
return;
}
let video = video_container.querySelector("video:first-of-type");
if (!video) {
return;
}
let video_src = video.getElementsByTagName("source")[0].src;
let video_sha1 = video_src
.substring(video_src.lastIndexOf("/") + 1)
let videoSha1 = uploadUrl
.substring(uploadUrl.lastIndexOf("/") + 1)
.split(".")[0];
// Wait for the video element to load, otherwise the canvas will be empty
@ -58,10 +40,10 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
// upload video thumbnail
canvas.toBlob((blob) => {
this._uppyInstance = new Uppy({
id: `screenshot-placeholder`,
id: "video-thumbnail",
meta: {
upload_type: `thumbnail`,
video_sha1,
videoSha1,
},
autoProceed: true,
});
@ -99,7 +81,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
try {
this._uppyInstance.addFile({
source: `${this.id} thumbnail`,
name: video_sha1,
name: `${videoSha1}`,
type: blob.type,
data: blob,
});

View File

@ -613,7 +613,6 @@ export default class ChatLivePane extends Component {
const message = ChatMessage.create(this.args.channel, data.chat_message);
this.args.channel.addMessages([message]);
this.scrollToLatestMessage();
this.updateLastReadMessage();
} else {
// If we are almost at the bottom, we append the message and notice the user
const message = ChatMessage.create(this.args.channel, data.chat_message);
@ -896,19 +895,16 @@ export default class ChatLivePane extends Component {
@action
editLastMessageRequested() {
const lastUserMessage = this.args.channel.messages.findLast(
(message) => message.user.id === this.currentUser.id
(message) =>
message.user.id === this.currentUser.id &&
!message.staged &&
!message.error
);
if (!lastUserMessage) {
return;
if (lastUserMessage) {
this.editingMessage = lastUserMessage;
this._focusComposer();
}
if (lastUserMessage.staged || lastUserMessage.error) {
return;
}
this.editingMessage = lastUserMessage;
this._focusComposer();
}
@action

View File

@ -384,7 +384,6 @@ $float-height: 530px;
.d-icon {
color: var(--secondary);
margin-left: 1px; // "fixes" the 1px svg shift
}
}

View File

@ -56,9 +56,7 @@
}
.chat-message-separator__text-container {
align-items: center;
display: flex;
height: 40px;
padding-top: 7px;
position: sticky;
top: -1px;
@ -100,7 +98,11 @@
.chat-message-separator__line {
border-top: 1px solid var(--secondary-high);
left: 0;
margin: 0 0 -1px;
position: relative;
right: 0;
top: -1px;
}
}
}

View File

@ -70,19 +70,5 @@ RSpec.describe "Shortcuts | chat composer", type: :system, js: true do
expect(page.find(".chat-composer-message-details")).to have_content(message_1.message)
end
context "when last message is not editable" do
after { page.driver.browser.network_conditions = { offline: false } }
it "does not edit a message" do
chat.visit_channel(channel_1)
page.driver.browser.network_conditions = { offline: true }
channel_page.send_message("Hello world")
find(".chat-composer-input").send_keys(:arrow_up)
expect(page).to have_no_css(".chat-composer-message-details")
end
end
end
end