Finished implementing video support

This commit is contained in:
2026-04-10 09:39:39 +02:00
parent 2bcb6adbb3
commit 67918644e0
7 changed files with 41 additions and 24 deletions

View File

@@ -44,6 +44,9 @@ export class Dm implements OnInit {
if (session != null) {
let attachments: Attachment[] = []
files?.forEach(file => {
const extraMetaData: Record<string, string> = {}
extraMetaData["thumbnailMetaData"] = file.videoThumbnail ?? ""
attachments.push({
fileName: file.name,
fileId: file.fileId,
@@ -52,7 +55,7 @@ export class Dm implements OnInit {
path: file.blob,
height: file.height,
width: file.width,
localVideoThumbnail: file.videoThumbnail
extraMetaData: extraMetaData
})
})

View File

@@ -127,7 +127,6 @@ export class MessageBox {
width = videoData.width
}
console.log("push")
this.viewModel().files().push({
fileId: uuidv4(),
data: file,
@@ -169,30 +168,39 @@ export class MessageBox {
const objectUrl = URL.createObjectURL(file);
const video = document.createElement('video');
video.src = objectUrl;
video.crossOrigin = 'anonymous';
video.preload = 'metadata'; // Ensure metadata is loaded
video.muted = true;
video.playsInline = true;
return new Promise((resolve) => {
video.addEventListener('loadeddata', async () => {
video.currentTime = 0;
video.addEventListener('loadeddata', () => {
// Step 1: Seek to a tiny bit past 0 to ensure a frame is available
video.currentTime = 0.1;
});
video.addEventListener('seeked', async () => {
// Step 2: Now that the seek is done, the frame is ready
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const ctx = canvas.getContext('2d');
ctx!.drawImage(video, 0, 0, canvas.width, canvas.height);
const thumbnail = canvas.toDataURL('image/jpeg')
const thumbnailResp = await fetch(thumbnail);
const thumbnailBlob = await thumbnailResp.blob();
const thumbnailBlobUrl = URL.createObjectURL(thumbnailBlob);
resolve({
thumbnailBlob: thumbnailBlobUrl,
height: video.videoHeight,
width: video.videoWidth,
});
});
// Clean up: Convert directly to blob to avoid double-processing
canvas.toBlob((blob) => {
const thumbnailBlobUrl = URL.createObjectURL(blob!);
// Revoke the original video URL to save memory
URL.revokeObjectURL(objectUrl);
resolve({
thumbnailBlob: thumbnailBlobUrl,
height: video.videoHeight,
width: video.videoWidth,
});
}, 'image/jpeg', 0.8);
}, { once: true }); // Only trigger once
});
}
}

View File

@@ -17,7 +17,11 @@
@if (file.type == "image") {
<img [src]="file.path" style="width: 100%; height: 100%; max-height: 300px; object-fit: cover; border-radius: 25px"/>
} @else if (file.type == "video") {
<video-player [src]="file.path"></video-player>
@if (file.extraMetaData && Object.keys(file.extraMetaData).length > 0) {
<video-player maxHeight="250px" maxWidth="250px" [src]="file.path" [thumbnailOverwrite]="file.extraMetaData['thumbnailMetaData']"></video-player>
} @else {
<video-player maxHeight="250px" maxWidth="250px" [src]="file.path"></video-player>
}
}
}
</masonry>

View File

@@ -110,4 +110,6 @@ export class Messages {
// last message is always end
return i + 1 === this.messages().length;
}
protected readonly Object = Object;
}

View File

@@ -2,7 +2,7 @@
<div id="player" [style]="'max-width:'+maxWidth+';max-height:'+maxHeight" (mouseover)="controlShowed = true"
(mouseleave)="controlShowed = false" #player>
<video (mouseout)="showVolRange = false" [class.upScale]="videoFullscreen"
[style]="'max-width:'+maxWidth+';height:'+maxHeight" (pause)="videoPlaying = false"
[style]="'max-width:'+maxWidth+';height:'+maxHeight+';border-radius: 15px'" (pause)="videoPlaying = false"
(play)="videoPlaying = true" #video (timeupdate)="watched = videoHMSFormat(video.currentTime)"
(loadedmetadata)="videoPlayer = video; video.style.display = 'block'; videoLoaded = true"
(click)="videoPlaying ? video.pause() : video.play(); videoPlaying = !videoPlaying"
@@ -77,9 +77,9 @@
} @else {
<div class="player_preview">
@if (thumbnailOverwrite) {
<img [src]="thumbnailOverwrite" />
<img [style]="'max-width:'+maxWidth+';max-height:'+maxHeight+';border-radius: 15px'" [src]="thumbnailOverwrite" />
} @else {
<oimg [src]="src+'_thumbnail.png'"></oimg>
<oimg [height]="maxHeight" [width]="maxWidth" style="border-radius: 15px" [src]="src+'_thumbnail.png'"></oimg>
}
<button tuiButton (click)="playVideo()">
<tui-icon icon="@tui.play"></tui-icon>