Fix stickers border
Stickers are now uncompress in SW
This commit is contained in:
parent
c33748eb5c
commit
99203abe01
@ -355,34 +355,27 @@ class StickersTab implements EmoticonsTab {
|
|||||||
//console.log('got stickerSet', stickerSet, li);
|
//console.log('got stickerSet', stickerSet, li);
|
||||||
|
|
||||||
if(stickerSet.set.thumb) {
|
if(stickerSet.set.thumb) {
|
||||||
appStickersManager.getStickerSetThumb(stickerSet.set).then((blob) => {
|
const thumbURL = appStickersManager.getStickerSetThumbURL(stickerSet.set);
|
||||||
//console.log('setting thumb', stickerSet, blob);
|
|
||||||
if(stickerSet.set.pFlags.animated) { // means animated
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.addEventListener('loadend', async(e) => {
|
|
||||||
// @ts-ignore
|
|
||||||
const text = e.srcElement.result;
|
|
||||||
let json = await apiManager.gzipUncompress<string>(text, true);
|
|
||||||
|
|
||||||
let animation = await lottieLoader.loadAnimationWorker({
|
|
||||||
container: li,
|
|
||||||
loop: true,
|
|
||||||
autoplay: false,
|
|
||||||
animationData: JSON.parse(json),
|
|
||||||
width: 32,
|
|
||||||
height: 32
|
|
||||||
}, EMOTICONSSTICKERGROUP);
|
|
||||||
});
|
|
||||||
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
} else {
|
|
||||||
let image = new Image();
|
|
||||||
renderImageFromUrl(image, URL.createObjectURL(blob));
|
|
||||||
|
|
||||||
|
if(stickerSet.set.pFlags.animated) {
|
||||||
|
fetch(thumbURL)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(json => {
|
||||||
|
lottieLoader.loadAnimationWorker({
|
||||||
|
container: li,
|
||||||
|
loop: true,
|
||||||
|
autoplay: false,
|
||||||
|
animationData: json,
|
||||||
|
width: 32,
|
||||||
|
height: 32
|
||||||
|
}, EMOTICONSSTICKERGROUP);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const image = new Image();
|
||||||
|
renderImageFromUrl(image, thumbURL).then(() => {
|
||||||
li.append(image);
|
li.append(image);
|
||||||
}
|
})
|
||||||
});
|
}
|
||||||
} else { // as thumb will be used first sticker
|
} else { // as thumb will be used first sticker
|
||||||
wrapSticker({
|
wrapSticker({
|
||||||
doc: stickerSet.documents[0],
|
doc: stickerSet.documents[0],
|
||||||
|
@ -165,29 +165,29 @@ let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceEl
|
|||||||
else elem.style.backgroundImage = 'url(' + url + ')';
|
else elem.style.backgroundImage = 'url(' + url + ')';
|
||||||
};
|
};
|
||||||
|
|
||||||
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string): Promise<boolean> {
|
export async function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string): Promise<boolean> {
|
||||||
if(loadedURLs[url]) {
|
if(loadedURLs[url]) {
|
||||||
set(elem, url);
|
set(elem, url);
|
||||||
return Promise.resolve(true);
|
} else {
|
||||||
|
if(elem instanceof HTMLSourceElement) {
|
||||||
|
elem.src = url;
|
||||||
|
} else {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
let loader = new Image();
|
||||||
|
loader.src = url;
|
||||||
|
//let perf = performance.now();
|
||||||
|
loader.addEventListener('load', () => {
|
||||||
|
set(elem, url);
|
||||||
|
loadedURLs[url] = true;
|
||||||
|
//console.log('onload:', url, performance.now() - perf);
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
loader.addEventListener('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(elem instanceof HTMLSourceElement) {
|
return !!loadedURLs[url];
|
||||||
elem.src = url;
|
|
||||||
return Promise.resolve(false);
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let loader = new Image();
|
|
||||||
loader.src = url;
|
|
||||||
//let perf = performance.now();
|
|
||||||
loader.addEventListener('load', () => {
|
|
||||||
set(elem, url);
|
|
||||||
loadedURLs[url] = true;
|
|
||||||
//console.log('onload:', url, performance.now() - perf);
|
|
||||||
resolve(false);
|
|
||||||
});
|
|
||||||
loader.addEventListener('error', reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function putPreloader(elem: Element, returnDiv = false) {
|
export function putPreloader(elem: Element, returnDiv = false) {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import appPhotosManager from '../lib/appManagers/appPhotosManager';
|
import appPhotosManager from '../lib/appManagers/appPhotosManager';
|
||||||
//import CryptoWorker from '../lib/crypto/cryptoworker';
|
|
||||||
import apiManager from '../lib/mtproto/mtprotoworker';
|
|
||||||
import LottieLoader from '../lib/lottieLoader';
|
import LottieLoader from '../lib/lottieLoader';
|
||||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||||
import { formatBytes, getEmojiToneIndex } from "../lib/utils";
|
import { formatBytes, getEmojiToneIndex } from "../lib/utils";
|
||||||
@ -416,13 +414,18 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
|
|
||||||
//console.log('wrap sticker', thumb, div);
|
//console.log('wrap sticker', thumb, div);
|
||||||
|
|
||||||
|
let img: HTMLImageElement;
|
||||||
|
const afterRender = () => {
|
||||||
|
if(!div.childElementCount) {
|
||||||
|
div.append(img);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if(thumb.bytes) {
|
if(thumb.bytes) {
|
||||||
let img = new Image();
|
img = new Image();
|
||||||
|
|
||||||
if((!isSafari || doc.stickerThumbConverted)/* && false */) {
|
if((!isSafari || doc.stickerThumbConverted)/* && false */) {
|
||||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true));
|
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true)).then(afterRender);
|
||||||
|
|
||||||
div.append(img);
|
|
||||||
} else {
|
} else {
|
||||||
webpWorkerController.convert(doc.id, thumb.bytes).then(bytes => {
|
webpWorkerController.convert(doc.id, thumb.bytes).then(bytes => {
|
||||||
if(middleware && !middleware()) return;
|
if(middleware && !middleware()) return;
|
||||||
@ -431,11 +434,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
doc.stickerThumbConverted = true;
|
doc.stickerThumbConverted = true;
|
||||||
|
|
||||||
if(!div.childElementCount) {
|
if(!div.childElementCount) {
|
||||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true)).then(() => {
|
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true)).then(afterRender);
|
||||||
if(!div.childElementCount) {
|
|
||||||
div.append(img);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -444,26 +443,24 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
} else if(!onlyThumb && stickerType == 2 && withThumb && toneIndex <= 0) {
|
} else if(!onlyThumb && stickerType == 2 && withThumb && toneIndex <= 0) {
|
||||||
let img = new Image();
|
img = new Image();
|
||||||
let load = () => appDocsManager.downloadDocThumb(doc, thumb.type).then(url => {
|
|
||||||
if(div.childElementCount || (middleware && !middleware())) return;
|
|
||||||
let promise = renderImageFromUrl(img, url);
|
|
||||||
|
|
||||||
if(!downloaded) {
|
const load = () => appDocsManager.downloadDocThumb(doc, thumb.type).then(url => {
|
||||||
promise.then(() => {
|
if(div.childElementCount || (middleware && !middleware())) return;
|
||||||
if(!div.childElementCount) {
|
const promise = renderImageFromUrl(img, url);
|
||||||
div.append(img);
|
|
||||||
}
|
//if(!downloaded) {
|
||||||
});
|
promise.then(afterRender);
|
||||||
}
|
//}
|
||||||
});
|
});
|
||||||
|
|
||||||
let downloaded = appDocsManager.hasDownloadedThumb(doc.id, thumb.type);
|
/* let downloaded = appDocsManager.hasDownloadedThumb(doc.id, thumb.type);
|
||||||
if(downloaded) {
|
if(downloaded) {
|
||||||
div.append(img);
|
div.append(img);
|
||||||
}
|
} */
|
||||||
|
|
||||||
lazyLoadQueue && !downloaded ? lazyLoadQueue.push({div, load, wasSeen: group == 'chat'}) : load();
|
//lazyLoadQueue && !downloaded ? lazyLoadQueue.push({div, load, wasSeen: group == 'chat'}) : load();
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,33 +479,27 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
let downloaded = doc.downloaded;
|
let downloaded = doc.downloaded;
|
||||||
let load = () => appDocsManager.downloadDocNew(doc.id).promise.then(blob => {
|
let load = async() => {
|
||||||
//console.log('loaded sticker:', doc, div);
|
|
||||||
if(middleware && !middleware()) return;
|
if(middleware && !middleware()) return;
|
||||||
|
|
||||||
//return;
|
|
||||||
|
|
||||||
if(stickerType == 2) {
|
if(stickerType == 2) {
|
||||||
const reader = new FileReader();
|
/* if(doc.id == '1860749763008266301') {
|
||||||
|
console.log('loaded sticker:', doc, div);
|
||||||
|
} */
|
||||||
|
|
||||||
reader.addEventListener('loadend', async(e) => {
|
//console.time('download sticker' + doc.id);
|
||||||
//console.time('decompress sticker' + doc.id);
|
|
||||||
//console.time('render sticker' + doc.id);
|
|
||||||
// @ts-ignore
|
|
||||||
const text = e.srcElement.result;
|
|
||||||
let json = await apiManager.gzipUncompress<string>(text, true);
|
|
||||||
|
|
||||||
//console.timeEnd('decompress sticker' + doc.id);
|
//appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {
|
||||||
|
fetch(doc.url).then(res => res.json()).then(async(json) => {
|
||||||
/* if(doc.id == '1860749763008266301') {
|
//console.timeEnd('download sticker' + doc.id);
|
||||||
console.log('loaded sticker:', doc, div);
|
//console.log('loaded sticker:', doc, div);
|
||||||
} */
|
if(middleware && !middleware()) return;
|
||||||
|
|
||||||
let animation = await LottieLoader.loadAnimationWorker/* loadAnimation */({
|
let animation = await LottieLoader.loadAnimationWorker/* loadAnimation */({
|
||||||
container: div,
|
container: div,
|
||||||
loop: loop && !emoji,
|
loop: loop && !emoji,
|
||||||
autoplay: play,
|
autoplay: play,
|
||||||
animationData: JSON.parse(json),
|
animationData: json,
|
||||||
width,
|
width,
|
||||||
height
|
height
|
||||||
}, group, toneIndex);
|
}, group, toneIndex);
|
||||||
@ -530,11 +521,9 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.timeEnd('render sticker' + doc.id);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
reader.readAsArrayBuffer(blob);
|
//console.timeEnd('render sticker' + doc.id);
|
||||||
} else if(stickerType == 1) {
|
} else if(stickerType == 1) {
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
|
|
||||||
@ -543,6 +532,8 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
img.style.opacity = '0';
|
img.style.opacity = '0';
|
||||||
|
|
||||||
img.addEventListener('load', () => {
|
img.addEventListener('load', () => {
|
||||||
|
doc.downloaded = true;
|
||||||
|
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
img.style.opacity = '';
|
img.style.opacity = '';
|
||||||
});
|
});
|
||||||
@ -557,7 +548,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
div.append(img);
|
div.append(img);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat' && stickerType != 2}), Promise.resolve()) : load();
|
return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat' && stickerType != 2}), Promise.resolve()) : load();
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { isObject, getFileURL } from '../utils';
|
|||||||
import opusDecodeController from '../opusDecodeController';
|
import opusDecodeController from '../opusDecodeController';
|
||||||
import { MTDocument, inputDocumentFileLocation } from '../../types';
|
import { MTDocument, inputDocumentFileLocation } from '../../types';
|
||||||
import { getFileNameByLocation } from '../bin_utils';
|
import { getFileNameByLocation } from '../bin_utils';
|
||||||
import appDownloadManager, { Download } from './appDownloadManager';
|
import appDownloadManager, { Download, ResponseMethod } from './appDownloadManager';
|
||||||
|
|
||||||
class AppDocsManager {
|
class AppDocsManager {
|
||||||
private docs: {[docID: string]: MTDocument} = {};
|
private docs: {[docID: string]: MTDocument} = {};
|
||||||
@ -273,7 +273,7 @@ class AppDocsManager {
|
|||||||
return this.downloadPromises[doc.id] = deferred;
|
return this.downloadPromises[doc.id] = deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
public downloadDocNew(docID: string | MTDocument, toFileEntry?: any): Download {
|
public downloadDocNew(docID: string | MTDocument/* , method: ResponseMethod = 'blob' */): Download {
|
||||||
const doc = this.getDoc(docID);
|
const doc = this.getDoc(docID);
|
||||||
|
|
||||||
if(doc._ == 'documentEmpty') {
|
if(doc._ == 'documentEmpty') {
|
||||||
@ -287,39 +287,39 @@ class AppDocsManager {
|
|||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
download = appDownloadManager.download(fileName, doc.url);
|
download = appDownloadManager.download(fileName, doc.url/* , method */);
|
||||||
//const _download: Download = {...download};
|
|
||||||
|
|
||||||
//_download.promise = _download.promise.then(async(blob) => {
|
const originalPromise = download.promise;
|
||||||
download.promise = download.promise.then(async(blob) => {
|
originalPromise.then(() => {
|
||||||
if(blob) {
|
doc.downloaded = true;
|
||||||
doc.downloaded = true;
|
|
||||||
|
|
||||||
if(doc.type == 'voice' && !opusDecodeController.isPlaySupported()) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
reader.onloadend = (e) => {
|
|
||||||
let uint8 = new Uint8Array(e.target.result as ArrayBuffer);
|
|
||||||
//console.log('sending uint8 to decoder:', uint8);
|
|
||||||
opusDecodeController.decode(uint8).then(result => {
|
|
||||||
doc.url = result.url;
|
|
||||||
resolve();
|
|
||||||
}, (err) => {
|
|
||||||
delete doc.downloaded;
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return blob;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//return this.downloadPromisesNew[doc.id] = _download;
|
if(doc.type == 'voice' && !opusDecodeController.isPlaySupported()) {
|
||||||
|
download.promise = originalPromise.then(async(blob) => {
|
||||||
|
let reader = new FileReader();
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
reader.onloadend = (e) => {
|
||||||
|
let uint8 = new Uint8Array(e.target.result as ArrayBuffer);
|
||||||
|
//console.log('sending uint8 to decoder:', uint8);
|
||||||
|
opusDecodeController.decode(uint8).then(result => {
|
||||||
|
doc.url = result.url;
|
||||||
|
resolve();
|
||||||
|
}, (err) => {
|
||||||
|
delete doc.downloaded;
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
});
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
//return originalPromise;
|
||||||
|
//return new Response(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import { $rootScope } from "../utils";
|
import { $rootScope } from "../utils";
|
||||||
import apiManager from "../mtproto/mtprotoworker";
|
import apiManager from "../mtproto/mtprotoworker";
|
||||||
|
|
||||||
export type Download = {promise: Promise<Blob>, controller: AbortController};
|
export type ResponseMethodBlob = 'blob';
|
||||||
|
export type ResponseMethodJson = 'json';
|
||||||
|
export type ResponseMethod = ResponseMethodBlob | ResponseMethodJson;
|
||||||
|
|
||||||
|
export type DownloadBlob = {promise: Promise<Blob>, controller: AbortController};
|
||||||
|
export type DownloadJson = {promise: Promise<any>, controller: AbortController};
|
||||||
|
export type Download = DownloadBlob/* | DownloadJson */;
|
||||||
|
|
||||||
export type Progress = {done: number, fileName: string, total: number, offset: number};
|
export type Progress = {done: number, fileName: string, total: number, offset: number};
|
||||||
export type ProgressCallback = (details: Progress) => void;
|
export type ProgressCallback = (details: Progress) => void;
|
||||||
|
|
||||||
@ -22,12 +29,14 @@ export class AppDownloadManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public download(fileName: string, url: string) {
|
public download(fileName: string, url: string, responseMethod?: ResponseMethodBlob): DownloadBlob;
|
||||||
|
public download(fileName: string, url: string, responseMethod?: ResponseMethodJson): DownloadJson;
|
||||||
|
public download(fileName: string, url: string, responseMethod: ResponseMethod = 'blob'): Download {
|
||||||
if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];
|
if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const promise = fetch(url, {signal: controller.signal})
|
const promise = fetch(url, {signal: controller.signal})
|
||||||
.then(res => res.blob())
|
.then(res => res[responseMethod]())
|
||||||
.catch(err => { // Только потому что event.request.signal не работает в SW, либо я кривой?
|
.catch(err => { // Только потому что event.request.signal не работает в SW, либо я кривой?
|
||||||
if(err.name === 'AbortError') {
|
if(err.name === 'AbortError') {
|
||||||
//console.log('Fetch aborted');
|
//console.log('Fetch aborted');
|
||||||
|
@ -217,7 +217,7 @@ class AppStickersManager {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStickerSetThumb(stickerSet: MTStickerSet) {
|
public getStickerSetThumbURL(stickerSet: MTStickerSet) {
|
||||||
const thumb = stickerSet.thumb;
|
const thumb = stickerSet.thumb;
|
||||||
const dcID = stickerSet.thumb_dc_id;
|
const dcID = stickerSet.thumb_dc_id;
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ class AppStickersManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const url = getFileURL('document', {dcID, location: input, size: thumb.size, mimeType: isAnimated ? "application/x-tgsticker" : 'image/webp'});
|
const url = getFileURL('document', {dcID, location: input, size: thumb.size, mimeType: isAnimated ? "application/x-tgsticker" : 'image/webp'});
|
||||||
return fetch(url).then(res => res.blob());
|
return url;
|
||||||
|
|
||||||
//return promise;
|
//return promise;
|
||||||
}
|
}
|
||||||
|
@ -134,15 +134,15 @@ export function dataUrlToBlob(url: string) {
|
|||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function blobConstruct(blobParts: any, mimeType: string = '') {
|
export function blobConstruct(blobParts: any, mimeType: string = ''): Blob {
|
||||||
var blob;
|
let blob;
|
||||||
var safeMimeType = blobSafeMimeType(mimeType);
|
const safeMimeType = blobSafeMimeType(mimeType);
|
||||||
try {
|
try {
|
||||||
blob = new Blob(blobParts, {type: safeMimeType});
|
blob = new Blob(blobParts, {type: safeMimeType});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
var bb = new BlobBuilder;
|
let bb = new BlobBuilder;
|
||||||
blobParts.forEach(function(blobPart: any) {
|
blobParts.forEach((blobPart: any) => {
|
||||||
bb.append(blobPart);
|
bb.append(blobPart);
|
||||||
});
|
});
|
||||||
blob = bb.getBlob(safeMimeType);
|
blob = bb.getBlob(safeMimeType);
|
||||||
@ -163,6 +163,7 @@ export function blobSafeMimeType(mimeType: string) {
|
|||||||
'audio/ogg',
|
'audio/ogg',
|
||||||
'audio/mpeg',
|
'audio/mpeg',
|
||||||
'audio/mp4',
|
'audio/mp4',
|
||||||
|
'application/json'
|
||||||
].indexOf(mimeType) === -1) {
|
].indexOf(mimeType) === -1) {
|
||||||
return 'application/octet-stream';
|
return 'application/octet-stream';
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,8 @@ export class FileManager {
|
|||||||
return this.blobSupported;
|
return this.blobSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | {file: any}): Promise<void> {
|
public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | string): Promise<void> {
|
||||||
if('file' in bytes) {
|
if(bytes instanceof Blob) { // is file bytes
|
||||||
return bytes.file((file: any) => {
|
|
||||||
return fileWriter.write(file);
|
|
||||||
});
|
|
||||||
} else if(bytes instanceof Blob) { // is file bytes
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let fileReader = new FileReader();
|
let fileReader = new FileReader();
|
||||||
fileReader.onload = function(event) {
|
fileReader.onload = function(event) {
|
||||||
@ -39,20 +35,20 @@ export class FileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getFakeFileWriter(mimeType: string, saveFileCallback: (blob: Blob) => Promise<Blob>) {
|
public getFakeFileWriter(mimeType: string, saveFileCallback: (blob: Blob) => Promise<Blob>) {
|
||||||
let blobParts: Array<Uint8Array> = [];
|
const blobParts: Array<Uint8Array | string> = [];
|
||||||
const fakeFileWriter = {
|
const fakeFileWriter = {
|
||||||
write: async(blob: Uint8Array) => {
|
write: async(part: Uint8Array | string) => {
|
||||||
if(!this.blobSupported) {
|
if(!this.blobSupported) {
|
||||||
throw false;
|
throw false;
|
||||||
}
|
}
|
||||||
|
|
||||||
blobParts.push(blob);
|
blobParts.push(part);
|
||||||
},
|
},
|
||||||
truncate: () => {
|
truncate: () => {
|
||||||
blobParts = [];
|
blobParts.length = 0;
|
||||||
},
|
},
|
||||||
finalize: () => {
|
finalize: () => {
|
||||||
const blob = blobConstruct(blobParts, mimeType) as Blob;
|
const blob = blobConstruct(blobParts, mimeType);
|
||||||
if(saveFileCallback) {
|
if(saveFileCallback) {
|
||||||
saveFileCallback(blob);
|
saveFileCallback(blob);
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,10 @@ import cacheStorage from "../cacheStorage";
|
|||||||
import FileManager from "../filemanager";
|
import FileManager from "../filemanager";
|
||||||
import apiManager from "./apiManager";
|
import apiManager from "./apiManager";
|
||||||
import { deferredPromise, CancellablePromise } from "../polyfill";
|
import { deferredPromise, CancellablePromise } from "../polyfill";
|
||||||
import { logger } from "../logger";
|
import { logger, LogLevels } from "../logger";
|
||||||
import { InputFileLocation, FileLocation, UploadFile } from "../../types";
|
import { InputFileLocation, FileLocation, UploadFile } from "../../types";
|
||||||
import { isSafari } from "../../helpers/userAgent";
|
import { isSafari } from "../../helpers/userAgent";
|
||||||
|
import cryptoWorker from "../crypto/cryptoworker";
|
||||||
|
|
||||||
type Delayed = {
|
type Delayed = {
|
||||||
offset: number,
|
offset: number,
|
||||||
@ -43,7 +44,7 @@ export class ApiFileManager {
|
|||||||
|
|
||||||
public webpConvertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
|
public webpConvertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
|
||||||
|
|
||||||
private log: ReturnType<typeof logger> = logger('AFM');
|
private log: ReturnType<typeof logger> = logger('AFM', LogLevels.error);
|
||||||
|
|
||||||
public downloadRequest(dcID: 'upload', cb: () => Promise<void>, activeDelta: number): Promise<void>;
|
public downloadRequest(dcID: 'upload', cb: () => Promise<void>, activeDelta: number): Promise<void>;
|
||||||
public downloadRequest(dcID: number, cb: () => Promise<UploadFile>, activeDelta: number): Promise<UploadFile>;
|
public downloadRequest(dcID: number, cb: () => Promise<UploadFile>, activeDelta: number): Promise<UploadFile>;
|
||||||
@ -144,6 +145,29 @@ export class ApiFileManager {
|
|||||||
return bytes * 1024;
|
return bytes * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uncompressTGS = (bytes: Uint8Array, fileName: string) => {
|
||||||
|
//this.log('uncompressTGS', bytes, bytes.slice().buffer);
|
||||||
|
// slice нужен потому что в uint8array - 5053 length, в arraybuffer - 5084
|
||||||
|
return cryptoWorker.gzipUncompress<string>(bytes.slice().buffer, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
convertWebp = (bytes: Uint8Array, fileName: string) => {
|
||||||
|
const convertPromise = deferredPromise<Uint8Array>();
|
||||||
|
|
||||||
|
(self as any as ServiceWorkerGlobalScope)
|
||||||
|
.clients
|
||||||
|
.matchAll({includeUncontrolled: false, type: 'window'})
|
||||||
|
.then((listeners) => {
|
||||||
|
if(!listeners.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners[0].postMessage({type: 'convertWebp', payload: {fileName, bytes}});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.webpConvertPromises[fileName] = convertPromise;
|
||||||
|
};
|
||||||
|
|
||||||
public downloadFile(options: DownloadOptions): CancellablePromise<Blob> {
|
public downloadFile(options: DownloadOptions): CancellablePromise<Blob> {
|
||||||
if(!FileManager.isAvailable()) {
|
if(!FileManager.isAvailable()) {
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
||||||
@ -152,18 +176,21 @@ export class ApiFileManager {
|
|||||||
let size = options.size ?? 0;
|
let size = options.size ?? 0;
|
||||||
let {dcID, location} = options;
|
let {dcID, location} = options;
|
||||||
|
|
||||||
let processWebp = false;
|
let process: ApiFileManager['uncompressTGS'] | ApiFileManager['convertWebp'];
|
||||||
|
|
||||||
if(options.mimeType == 'image/webp' && isSafari) {
|
if(options.mimeType == 'image/webp' && isSafari) {
|
||||||
processWebp = true;
|
process = this.convertWebp;
|
||||||
options.mimeType = 'image/png';
|
options.mimeType = 'image/png';
|
||||||
|
} else if(options.mimeType == 'application/x-tgsticker') {
|
||||||
|
process = this.uncompressTGS;
|
||||||
|
options.mimeType = 'application/json';
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.log('Dload file', dcID, location, size)
|
|
||||||
const fileName = getFileNameByLocation(location);
|
const fileName = getFileNameByLocation(location);
|
||||||
const cachedPromise = this.cachedDownloadPromises[fileName];
|
const cachedPromise = this.cachedDownloadPromises[fileName];
|
||||||
const fileStorage = this.getFileStorage();
|
const fileStorage = this.getFileStorage();
|
||||||
|
|
||||||
//this.log('downloadFile', fileName, fileName.length, location, arguments);
|
//this.log('downloadFile', fileName, size, location, options.mimeType, process);
|
||||||
|
|
||||||
if(cachedPromise) {
|
if(cachedPromise) {
|
||||||
if(options.processPart) {
|
if(options.processPart) {
|
||||||
@ -266,22 +293,11 @@ export class ApiFileManager {
|
|||||||
await options.processPart(bytes, offset, delayed);
|
await options.processPart(bytes, offset, delayed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(processWebp) {
|
if(process) {
|
||||||
const convertPromise = deferredPromise<Uint8Array>();
|
//const perf = performance.now();
|
||||||
|
const processed = await process(bytes, fileName);
|
||||||
(self as any as ServiceWorkerGlobalScope)
|
//this.log('downloadFile process downloaded time', performance.now() - perf, mimeType, process);
|
||||||
.clients
|
return processed;
|
||||||
.matchAll({includeUncontrolled: false, type: 'window'})
|
|
||||||
.then((listeners) => {
|
|
||||||
if(!listeners.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
listeners[0].postMessage({type: 'convertWebp', payload: {fileName, bytes}});
|
|
||||||
});
|
|
||||||
|
|
||||||
return await (this.webpConvertPromises[fileName] = convertPromise);
|
|
||||||
//return appWebpManager.convertToPng(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -318,12 +334,12 @@ export class ApiFileManager {
|
|||||||
superpuper();
|
superpuper();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//done += limit;
|
||||||
|
done += result.bytes.byteLength;
|
||||||
|
|
||||||
const processedResult = await processDownloaded(result.bytes, offset);
|
const processedResult = await processDownloaded(result.bytes, offset);
|
||||||
checkCancel();
|
checkCancel();
|
||||||
|
|
||||||
//done += limit;
|
|
||||||
done += processedResult.byteLength;
|
|
||||||
const isFinal = offset + limit >= size;
|
const isFinal = offset + limit >= size;
|
||||||
//if(!isFinal) {
|
//if(!isFinal) {
|
||||||
////this.log('deferred notify 2:', {done: offset + limit, total: size}, deferred);
|
////this.log('deferred notify 2:', {done: offset + limit, total: size}, deferred);
|
||||||
|
@ -11,7 +11,7 @@ import { getFileNameByLocation } from '../bin_utils';
|
|||||||
import { logger, LogLevels } from '../logger';
|
import { logger, LogLevels } from '../logger';
|
||||||
import { isSafari } from '../../helpers/userAgent';
|
import { isSafari } from '../../helpers/userAgent';
|
||||||
|
|
||||||
const log = logger('SW'/* , LogLevels.error */);
|
const log = logger('SW', LogLevels.error);
|
||||||
|
|
||||||
const ctx = self as any as ServiceWorkerGlobalScope;
|
const ctx = self as any as ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
// "outDir": "./dist/", /* Redirect output structure to the directory. */
|
// "outDir": "./dist/", /* Redirect output structure to the directory. */
|
||||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
//"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
@ -65,8 +65,9 @@
|
|||||||
"node_modules",
|
"node_modules",
|
||||||
"public",
|
"public",
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"./public/*.js",
|
||||||
"./src/lib/crypto/crypto.worker.js",
|
"./src/lib/crypto/crypto.worker.js",
|
||||||
"src/vendor/StackBlur.js",
|
"./src/vendor/StackBlur.js",
|
||||||
"./src/lib/*.js",
|
"./src/lib/*.js",
|
||||||
"./src/*.js",
|
"./src/*.js",
|
||||||
"*.js",
|
"*.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user