Finished implementing video support
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -15,7 +15,7 @@
|
||||
"@angular/forms": "^21.2.0",
|
||||
"@angular/platform-browser": "^21.2.0",
|
||||
"@angular/router": "^21.2.0",
|
||||
"@chatenium/chatenium-sdk": "^1.1.2",
|
||||
"@chatenium/chatenium-sdk": "^1.1.3",
|
||||
"@ngx-translate/core": "^17.0.0",
|
||||
"@ngx-translate/http-loader": "^17.0.0",
|
||||
"@taiga-ui/addon-charts": "^5.1.0",
|
||||
@@ -988,9 +988,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@chatenium/chatenium-sdk": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.1.2.tgz",
|
||||
"integrity": "sha512-MYUdi1zxcsSUlf1JADU7HNU6zxPejNuspbt+9P3iUBI2ecHWzhqSdcQRR+OMEe0UThl7QNIlZrt0yl15/4fjYQ==",
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.1.3.tgz",
|
||||
"integrity": "sha512-y1+ls4MnMu9/t0vWtQEjIw1QPwk0peQbdEx738xu8OgxD/0nEBn6SGhhnesPHcQmdnkhZe/xiRVrIlDmZxGUHg==",
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "^10.4.0",
|
||||
"axios": "^1.14.0",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"@angular/forms": "^21.2.0",
|
||||
"@angular/platform-browser": "^21.2.0",
|
||||
"@angular/router": "^21.2.0",
|
||||
"@chatenium/chatenium-sdk": "^1.1.2",
|
||||
"@chatenium/chatenium-sdk": "^1.1.3",
|
||||
"@ngx-translate/core": "^17.0.0",
|
||||
"@ngx-translate/http-loader": "^17.0.0",
|
||||
"@taiga-ui/addon-charts": "^5.1.0",
|
||||
|
||||
@@ -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
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -110,4 +110,6 @@ export class Messages {
|
||||
// last message is always end
|
||||
return i + 1 === this.messages().length;
|
||||
}
|
||||
|
||||
protected readonly Object = Object;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user