Browse Source

Video autoplay

master
morethanwords 4 years ago
parent
commit
8ea5c3a283
  1. 54
      src/components/wrappers.ts
  2. 76
      src/lib/mediaPlayer.ts
  3. 23
      src/scss/partials/_chatBubble.scss

54
src/components/wrappers.ts

@ -22,6 +22,8 @@ import { renderImageFromUrl } from './misc';
import PollElement from './poll'; import PollElement from './poll';
import ProgressivePreloader from './preloader'; import ProgressivePreloader from './preloader';
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: { export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
doc: MyDocument, doc: MyDocument,
container?: HTMLDivElement, container?: HTMLDivElement,
@ -35,22 +37,28 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
noInfo?: true, noInfo?: true,
group?: string, group?: string,
}) { }) {
const isAlbumItem = !(boxWidth && boxHeight);
const canAutoplay = doc.type != 'video' || (doc.size <= MAX_VIDEO_AUTOPLAY_SIZE && !isAlbumItem);
let spanTime: HTMLElement;
if(!noInfo) { if(!noInfo) {
if(doc.type != 'round') { if(doc.type != 'round') {
let span: HTMLSpanElement, spanPlay: HTMLSpanElement; spanTime = document.createElement('span');
spanTime.classList.add('video-time');
span = document.createElement('span'); container.append(spanTime);
span.classList.add('video-time');
container.append(span);
if(doc.type != 'gif') { if(doc.type != 'gif') {
span.innerText = (doc.duration + '').toHHMMSS(false); spanTime.innerText = (doc.duration + '').toHHMMSS(false);
spanPlay = document.createElement('span'); if(canAutoplay) {
spanTime.classList.add('tgico', 'can-autoplay');
} else {
const spanPlay = document.createElement('span');
spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center'); spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center');
container.append(spanPlay); container.append(spanPlay);
}
} else { } else {
span.innerText = 'GIF'; spanTime.innerText = 'GIF';
} }
} }
} }
@ -132,7 +140,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
let img: HTMLImageElement; let img: HTMLImageElement;
if(message) { if(message) {
if(doc.type == 'video' && doc.thumbs?.length) { if(!canAutoplay && doc.thumbs?.length) {
return wrapPhoto(doc, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware); return wrapPhoto(doc, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware);
} }
@ -199,18 +207,18 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
}, {once: true}); */ }, {once: true}); */
await promise; await promise;
if(middleware && !middleware()) {
return;
}
} else if(doc.supportsStreaming) { } else if(doc.supportsStreaming) {
preloader = new ProgressivePreloader(null, false, false, 'prepend'); preloader = new ProgressivePreloader(null, false, false, 'prepend');
preloader.attach(container, false, null); preloader.attach(container, false, null);
video.addEventListener('canplay', () => { video.addEventListener(isSafari ? 'timeupdate' : 'canplay', () => {
preloader.detach(); preloader.detach();
}, {once: true}); }, {once: true});
} }
if(middleware && !middleware()) {
return;
}
//console.log('loaded doc:', doc, doc.url, container); //console.log('loaded doc:', doc, doc.url, container);
const deferred = deferredPromise<void>(); const deferred = deferredPromise<void>();
@ -224,7 +232,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
/* if(!video.paused) { /* if(!video.paused) {
video.pause(); video.pause();
} */ } */
if(doc.type == 'gif' && group) { if(doc.type != 'round' && group) {
animationIntersector.addAnimation(video, group); animationIntersector.addAnimation(video, group);
} }
@ -235,6 +243,12 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
}, {once: true}); }, {once: true});
//} //}
if(doc.type == 'video') {
video.addEventListener('timeupdate', () => {
spanTime.innerText = (video.duration - video.currentTime + '').toHHMMSS(false);
});
}
video.addEventListener('error', (e) => { video.addEventListener('error', (e) => {
deferred.resolve(); deferred.resolve();
/* console.error('video error', e, video.src); /* console.error('video error', e, video.src);
@ -253,15 +267,15 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
container.append(video); container.append(video);
} */ } */
if(doc.type == 'gif'/* || true */) { if(doc.type == 'round') {
video.dataset.ckin = 'circle';
video.dataset.overlay = '1';
new VideoPlayer(video);
} else {
video.muted = true; video.muted = true;
video.loop = true; video.loop = true;
//video.play(); //video.play();
video.autoplay = true; video.autoplay = true;
} else if(doc.type == 'round') {
video.dataset.ckin = 'circle';
video.dataset.overlay = '1';
new VideoPlayer(video);
} }
return deferred; return deferred;

76
src/lib/mediaPlayer.ts

@ -318,15 +318,15 @@ export default class VideoPlayer {
const html = this.buildControls(); const html = this.buildControls();
player.insertAdjacentHTML('beforeend', html); player.insertAdjacentHTML('beforeend', html);
let updateInterval = 0;
let elapsed = 0; let elapsed = 0;
let prevTime = 0; let prevTime = 0;
let timeDuration: HTMLElement;
if(skin === 'default') { if(skin === 'default') {
const toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>; const toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;
const fullScreenButton = player.querySelector('.fullscreen') as HTMLElement; const fullScreenButton = player.querySelector('.fullscreen') as HTMLElement;
var timeElapsed = player.querySelector('#time-elapsed'); const timeElapsed = player.querySelector('#time-elapsed');
var timeDuration = player.querySelector('#time-duration') as HTMLElement; timeDuration = player.querySelector('#time-duration') as HTMLElement;
timeDuration.innerHTML = String(video.duration | 0).toHHMMSS(); timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();
const volumeDiv = document.createElement('div'); const volumeDiv = document.createElement('div');
@ -451,10 +451,6 @@ export default class VideoPlayer {
/* video.addEventListener('play', () => { /* video.addEventListener('play', () => {
}); */ }); */
video.addEventListener('pause', () => {
clearInterval(updateInterval);
});
video.addEventListener('dblclick', () => { video.addEventListener('dblclick', () => {
if(isTouchSupported) { if(isTouchSupported) {
return; return;
@ -470,16 +466,20 @@ export default class VideoPlayer {
'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => { 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => {
player.addEventListener(eventName, this.onFullScreen, false); player.addEventListener(eventName, this.onFullScreen, false);
}); });
video.addEventListener('timeupdate', () => {
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();
});
} else if(skin === 'circle') { } else if(skin === 'circle') {
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
wrapper.classList.add('circle-time-left'); wrapper.classList.add('circle-time-left');
video.parentNode.insertBefore(wrapper, video); video.parentNode.insertBefore(wrapper, video);
wrapper.innerHTML = '<div class="circle-time"></div><div class="iconVolume tgico-nosound"></div>'; wrapper.innerHTML = '<div class="circle-time"></div><div class="iconVolume tgico-nosound"></div>';
var circle = player.querySelector('.progress-ring__circle') as SVGCircleElement; const circle = player.querySelector('.progress-ring__circle') as SVGCircleElement;
const radius = circle.r.baseVal.value; const radius = circle.r.baseVal.value;
var circumference = 2 * Math.PI * radius; const circumference = 2 * Math.PI * radius;
var timeDuration = player.querySelector('.circle-time') as HTMLElement; timeDuration = player.querySelector('.circle-time') as HTMLElement;
const iconVolume = player.querySelector('.iconVolume') as HTMLDivElement; const iconVolume = player.querySelector('.iconVolume') as HTMLDivElement;
circle.style.strokeDasharray = circumference + ' ' + circumference; circle.style.strokeDasharray = circumference + ' ' + circumference;
circle.style.strokeDashoffset = '' + circumference; circle.style.strokeDashoffset = '' + circumference;
@ -505,6 +505,28 @@ export default class VideoPlayer {
video.addEventListener('pause', () => { video.addEventListener('pause', () => {
iconVolume.style.display = ''; iconVolume.style.display = '';
}); });
let updateInterval = 0;
video.addEventListener('timeupdate', () => {
clearInterval(updateInterval);
let elapsed = 0;
let prevTime = 0;
updateInterval = window.setInterval(() => {
if(video.currentTime != prevTime) {
elapsed = video.currentTime; // Update if getCurrentTime was changed
prevTime = video.currentTime;
}
const offset = circumference - elapsed / video.duration * circumference;
circle.style.strokeDashoffset = '' + offset;
if(video.paused) clearInterval(updateInterval);
}, 20);
const timeLeft = String((video.duration - video.currentTime) | 0).toHHMMSS();
if(timeLeft != '0') timeDuration.innerHTML = timeLeft;
});
} }
video.addEventListener('play', () => { video.addEventListener('play', () => {
@ -522,14 +544,6 @@ export default class VideoPlayer {
timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS(); timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();
}); });
} }
video.addEventListener('timeupdate', () => {
if(skin == 'default') {
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();
}
updateInterval = this.handleProgress(timeDuration, circumference, circle, updateInterval);
});
} }
public togglePlay(stop?: boolean) { public togglePlay(stop?: boolean) {
@ -547,32 +561,6 @@ export default class VideoPlayer {
//this.wrapper.classList.toggle('is-playing', !this.video.paused); //this.wrapper.classList.toggle('is-playing', !this.video.paused);
} }
private handleProgress(timeDuration: HTMLElement, circumference: number, circle: SVGCircleElement, updateInterval: number) {
const {video, skin} = this;
clearInterval(updateInterval);
let elapsed = 0;
let prevTime = 0;
if(skin === 'circle') {
updateInterval = window.setInterval(() => {
if(video.currentTime != prevTime) {
elapsed = video.currentTime; // Update if getCurrentTime was changed
prevTime = video.currentTime;
}
const offset = circumference - elapsed / video.duration * circumference;
circle.style.strokeDashoffset = '' + offset;
if(video.paused) clearInterval(updateInterval);
}, 20);
const timeLeft = String((video.duration - video.currentTime) | 0).toHHMMSS();
if(timeLeft != '0') timeDuration.innerHTML = timeLeft;
return updateInterval;
}
}
private buildControls() { private buildControls() {
const skin = this.skin; const skin = this.skin;
if(skin === 'default') { if(skin === 'default') {

23
src/scss/partials/_chatBubble.scss

@ -519,6 +519,10 @@ $bubble-margin: .25rem;
display: none; display: none;
} }
} }
.preloader-container {
z-index: 1;
}
} }
&:not(.sticker) { &:not(.sticker) {
@ -537,6 +541,12 @@ $bubble-margin: .25rem;
height: 100%; height: 100%;
} }
html.is-safari &:not(.round) {
img:not(.emoji), video {
border-radius: inherit;
}
}
&.is-album { &.is-album {
.attachment { .attachment {
max-width: unquote('min(451px, 100%)'); max-width: unquote('min(451px, 100%)');
@ -1000,7 +1010,7 @@ $bubble-margin: .25rem;
} }
} }
span.video-time { .video-time {
position: absolute; position: absolute;
top: 3px; top: 3px;
left: 3px; left: 3px;
@ -1014,9 +1024,18 @@ $bubble-margin: .25rem;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
&.can-autoplay:after {
content: $tgico-nosound;
// * same as .iconVolume
padding: 0 1px 0 3px;
font-size: 1.25rem;
color: #fff;
}
} }
span.video-play { .video-play {
background-color: var(--message-time-background); background-color: var(--message-time-background);
color: #fff; color: #fff;
text-align: center; text-align: center;

Loading…
Cancel
Save