Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.1 KiB

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { pause } from "./schedulers";
4 years ago
import { isAppleMobile } from "./userAgent";
export function preloadVideo(url: string): Promise<HTMLVideoElement> {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.volume = 0;
video.onloadedmetadata = () => resolve(video);
video.onerror = reject;
video.src = url;
});
}
export function createPosterFromVideo(video: HTMLVideoElement): Promise<Blob> {
return new Promise((resolve, reject) => {
video.onseeked = () => {
const canvas = document.createElement('canvas');
canvas.width = Math.min(1280, video.videoWidth);
canvas.height = Math.min(720, video.videoHeight);
const ctx = canvas.getContext('2d')!;
ctx.drawImage(video, 0, 0);
canvas.toBlob(blob => {
resolve(blob);
}, 'image/jpeg', 1);
};
video.onerror = reject;
video.currentTime = Math.min(video.duration, 1);
});
}
export async function createPosterForVideo(url: string): Promise<Blob | undefined> {
const video = await preloadVideo(url);
return Promise.race([
pause(2000) as Promise<undefined>,
createPosterFromVideo(video),
]);
4 years ago
}
export function onVideoLoad(video: HTMLVideoElement) {
return new Promise<void>((resolve) => {
if(video.readyState >= video.HAVE_METADATA) {
resolve();
return;
}
video.addEventListener(isAppleMobile ? 'loadeddata' : 'canplay', () => resolve(), {once: true});
});
4 years ago
}
export async function getFilesFromEvent(e: ClipboardEvent | DragEvent, onlyTypes = false): Promise<any[]> {
const files: any[] = [];
const scanFiles = async(entry: any, item: DataTransferItem) => {
if(entry.isDirectory) {
const directoryReader = entry.createReader();
await new Promise<void>((resolve, reject) => {
directoryReader.readEntries(async(entries: any) => {
for(const entry of entries) {
await scanFiles(entry, item);
}
resolve();
});
});
} else if(entry) {
if(onlyTypes) {
files.push(entry.type);
} else {
const itemFile = item.getAsFile(); // * Safari can't handle entry.file with pasting
const file = entry instanceof File ?
entry :
(
entry instanceof DataTransferItem ?
entry.getAsFile() :
await new Promise((resolve, reject) => entry.file(resolve, (err: any) => resolve(itemFile)))
);
/* if(!onlyTypes) {
console.log('getFilesFromEvent: got file', item, file);
} */
if(!file) return;
files.push(file);
}
}
};
if(e instanceof DragEvent && e.dataTransfer.files && !e.dataTransfer.items) {
for(let i = 0; i < e.dataTransfer.files.length; i++) {
const file = e.dataTransfer.files[i];
files.push(onlyTypes ? file.type : file);
}
} else {
// @ts-ignore
const items = (e.dataTransfer || e.clipboardData || e.originalEvent.clipboardData).items;
const promises: Promise<any>[] = [];
for(let i = 0; i < items.length; ++i) {
const item: DataTransferItem = items[i];
if(item.kind === 'file') {
const entry = (onlyTypes ? item : item.webkitGetAsEntry()) || item.getAsFile();
promises.push(scanFiles(entry, item));
}
}
await Promise.all(promises);
}
/* if(!onlyTypes) {
console.log('getFilesFromEvent: got files:', e, files);
} */
return files;
}
3 years ago
export function requestFile(accept?: string) {
const input = document.createElement('input');
input.type = 'file';
input.style.display = 'none';
if(accept) {
input.accept = accept;
}
document.body.append(input);
const promise = new Promise<File>((resolve, reject) => {
input.addEventListener('change', (e: any) => {
const file: File = e.target.files[0];
if(!file) {
reject('NO_FILE_SELECTED');
return;
}
resolve(file);
}, {once: true});
}).finally(() => {
input.remove();
});
input.click();
return promise;
}