Refactor animated stickers a bit
This commit is contained in:
parent
d885a85e40
commit
c70369e4e9
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
import type Chat from './chat/chat';
|
import type Chat from './chat/chat';
|
||||||
import { getEmojiToneIndex } from '../vendor/emoji';
|
import { getEmojiToneIndex } from '../vendor/emoji';
|
||||||
import { readBlobAsText } from '../helpers/blob';
|
|
||||||
import { deferredPromise } from '../helpers/cancellablePromise';
|
import { deferredPromise } from '../helpers/cancellablePromise';
|
||||||
import { formatFullSentTime } from '../helpers/date';
|
import { formatFullSentTime } from '../helpers/date';
|
||||||
import mediaSizes, { ScreenSize } from '../helpers/mediaSizes';
|
import mediaSizes, { ScreenSize } from '../helpers/mediaSizes';
|
||||||
@ -1277,9 +1276,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
//appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {
|
//appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {
|
||||||
//fetch(doc.url).then(res => res.json()).then(async(json) => {
|
//fetch(doc.url).then(res => res.json()).then(async(json) => {
|
||||||
return await appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId)
|
return await appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId)
|
||||||
.then(readBlobAsText)
|
.then(async(blob) => {
|
||||||
//.then(JSON.parse)
|
|
||||||
.then(async(json) => {
|
|
||||||
//console.timeEnd('download sticker' + doc.id);
|
//console.timeEnd('download sticker' + doc.id);
|
||||||
//console.log('loaded sticker:', doc, div/* , blob */);
|
//console.log('loaded sticker:', doc, div/* , blob */);
|
||||||
if(middleware && !middleware()) {
|
if(middleware && !middleware()) {
|
||||||
@ -1290,13 +1287,14 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
container: div,
|
container: div,
|
||||||
loop: loop && !emoji,
|
loop: loop && !emoji,
|
||||||
autoplay: play,
|
autoplay: play,
|
||||||
animationData: json,
|
animationData: blob,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
name: 'doc' + doc.id,
|
name: 'doc' + doc.id,
|
||||||
needUpscale,
|
needUpscale,
|
||||||
skipRatio
|
skipRatio,
|
||||||
}, group, toneIndex, middleware);
|
toneIndex
|
||||||
|
}, group, middleware);
|
||||||
|
|
||||||
//const deferred = deferredPromise<void>();
|
//const deferred = deferredPromise<void>();
|
||||||
|
|
||||||
@ -1596,14 +1594,12 @@ export async function wrapStickerSetThumb({set, lazyLoadQueue, container, group,
|
|||||||
|
|
||||||
if(set.pFlags.animated) {
|
if(set.pFlags.animated) {
|
||||||
return promise
|
return promise
|
||||||
.then(readBlobAsText)
|
.then((blob) => {
|
||||||
//.then(JSON.parse)
|
|
||||||
.then(json => {
|
|
||||||
lottieLoader.loadAnimationWorker({
|
lottieLoader.loadAnimationWorker({
|
||||||
container,
|
container,
|
||||||
loop: true,
|
loop: true,
|
||||||
autoplay,
|
autoplay,
|
||||||
animationData: json,
|
animationData: blob,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
needUpscale: true,
|
needUpscale: true,
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* https://github.com/morethanwords/tweb
|
|
||||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
||||||
*
|
|
||||||
* Originally from:
|
|
||||||
* https://github.com/zhukov/webogram
|
|
||||||
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
|
||||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function readBlobAs(blob: Blob, method: 'readAsText'): Promise<string>;
|
|
||||||
export function readBlobAs(blob: Blob, method: 'readAsDataURL'): Promise<string>;
|
|
||||||
export function readBlobAs(blob: Blob, method: 'readAsArrayBuffer'): Promise<ArrayBuffer>;
|
|
||||||
export function readBlobAs(blob: Blob, method: 'readAsArrayBuffer' | 'readAsText' | 'readAsDataURL'): Promise<any> {
|
|
||||||
// const perf = performance.now();
|
|
||||||
return new Promise<any>((resolve) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.addEventListener('loadend', (e) => {
|
|
||||||
// console.log('readBlobAs time:', method, performance.now() - perf);
|
|
||||||
resolve(e.target.result);
|
|
||||||
});
|
|
||||||
reader[method](blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readBlobAsText(blob: Blob) {
|
|
||||||
return readBlobAs(blob, 'readAsText');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readBlobAsDataURL(blob: Blob) {
|
|
||||||
return readBlobAs(blob, 'readAsDataURL');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readBlobAsArrayBuffer(blob: Blob) {
|
|
||||||
return readBlobAs(blob, 'readAsArrayBuffer');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readBlobAsUint8Array(blob: Blob) {
|
|
||||||
return readBlobAsArrayBuffer(blob).then(buffer => new Uint8Array(buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blobConstruct(blobParts: any, mimeType: string = ''): Blob {
|
|
||||||
let blob;
|
|
||||||
const safeMimeType = blobSafeMimeType(mimeType);
|
|
||||||
try {
|
|
||||||
blob = new Blob(blobParts, {type: safeMimeType});
|
|
||||||
} catch(e) {
|
|
||||||
// @ts-ignore
|
|
||||||
let bb = new BlobBuilder;
|
|
||||||
blobParts.forEach((blobPart: any) => {
|
|
||||||
bb.append(blobPart);
|
|
||||||
});
|
|
||||||
blob = bb.getBlob(safeMimeType);
|
|
||||||
}
|
|
||||||
return blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.iana.org/assignments/media-types/media-types.xhtml
|
|
||||||
export function blobSafeMimeType(mimeType: string) {
|
|
||||||
if([
|
|
||||||
'image/jpeg',
|
|
||||||
'image/png',
|
|
||||||
'image/gif',
|
|
||||||
'image/webp',
|
|
||||||
'image/bmp',
|
|
||||||
'video/mp4',
|
|
||||||
'video/webm',
|
|
||||||
'video/quicktime',
|
|
||||||
'audio/ogg',
|
|
||||||
'audio/mpeg',
|
|
||||||
'audio/mp4',
|
|
||||||
'application/json',
|
|
||||||
'application/pdf'
|
|
||||||
].indexOf(mimeType) === -1) {
|
|
||||||
return 'application/octet-stream';
|
|
||||||
}
|
|
||||||
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
28
src/helpers/blob/blobConstruct.ts
Normal file
28
src/helpers/blob/blobConstruct.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*
|
||||||
|
* Originally from:
|
||||||
|
* https://github.com/zhukov/webogram
|
||||||
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
||||||
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import blobSafeMimeType from "./blobSafeMimeType";
|
||||||
|
|
||||||
|
export default function blobConstruct(blobParts: any, mimeType: string = ''): Blob {
|
||||||
|
let blob;
|
||||||
|
const safeMimeType = blobSafeMimeType(mimeType);
|
||||||
|
try {
|
||||||
|
blob = new Blob(blobParts, {type: safeMimeType});
|
||||||
|
} catch(e) {
|
||||||
|
// @ts-ignore
|
||||||
|
let bb = new BlobBuilder;
|
||||||
|
blobParts.forEach((blobPart: any) => {
|
||||||
|
bb.append(blobPart);
|
||||||
|
});
|
||||||
|
blob = bb.getBlob(safeMimeType);
|
||||||
|
}
|
||||||
|
return blob;
|
||||||
|
}
|
33
src/helpers/blob/blobSafeMimeType.ts
Normal file
33
src/helpers/blob/blobSafeMimeType.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*
|
||||||
|
* Originally from:
|
||||||
|
* https://github.com/zhukov/webogram
|
||||||
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
||||||
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||||
|
export default function blobSafeMimeType(mimeType: string) {
|
||||||
|
if([
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'image/webp',
|
||||||
|
'image/bmp',
|
||||||
|
'video/mp4',
|
||||||
|
'video/webm',
|
||||||
|
'video/quicktime',
|
||||||
|
'audio/ogg',
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/mp4',
|
||||||
|
'application/json',
|
||||||
|
'application/pdf'
|
||||||
|
].indexOf(mimeType) === -1) {
|
||||||
|
return 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
|
return mimeType;
|
||||||
|
}
|
23
src/helpers/blob/readBlobAs.ts
Normal file
23
src/helpers/blob/readBlobAs.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
// import { IS_WEB_WORKER } from "../context";
|
||||||
|
|
||||||
|
// const id = IS_WEB_WORKER ? Math.random() * 0x1000 | 0 : 0;
|
||||||
|
export default function readBlobAs(blob: Blob, method: 'readAsText'): Promise<string>;
|
||||||
|
export default function readBlobAs(blob: Blob, method: 'readAsDataURL'): Promise<string>;
|
||||||
|
export default function readBlobAs(blob: Blob, method: 'readAsArrayBuffer'): Promise<ArrayBuffer>;
|
||||||
|
export default function readBlobAs(blob: Blob, method: 'readAsArrayBuffer' | 'readAsText' | 'readAsDataURL'): Promise<any> {
|
||||||
|
// const perf = performance.now();
|
||||||
|
return new Promise<any>((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('loadend', (e) => {
|
||||||
|
// console.log(`readBlobAs [${id}] ${method} time ${performance.now() - perf}`);
|
||||||
|
resolve(e.target.result);
|
||||||
|
});
|
||||||
|
reader[method](blob);
|
||||||
|
});
|
||||||
|
}
|
11
src/helpers/blob/readBlobAsArrayBuffer.ts
Normal file
11
src/helpers/blob/readBlobAsArrayBuffer.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import readBlobAs from "./readBlobAs";
|
||||||
|
|
||||||
|
export default function readBlobAsArrayBuffer(blob: Blob) {
|
||||||
|
return readBlobAs(blob, 'readAsArrayBuffer');
|
||||||
|
}
|
11
src/helpers/blob/readBlobAsDataURL.ts
Normal file
11
src/helpers/blob/readBlobAsDataURL.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import readBlobAs from "./readBlobAs";
|
||||||
|
|
||||||
|
export default function readBlobAsDataURL(blob: Blob) {
|
||||||
|
return readBlobAs(blob, 'readAsDataURL');
|
||||||
|
}
|
11
src/helpers/blob/readBlobAsText.ts
Normal file
11
src/helpers/blob/readBlobAsText.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import readBlobAs from "./readBlobAs";
|
||||||
|
|
||||||
|
export default function readBlobAsText(blob: Blob) {
|
||||||
|
return readBlobAs(blob, 'readAsText');
|
||||||
|
}
|
11
src/helpers/blob/readBlobAsUint8Array.ts
Normal file
11
src/helpers/blob/readBlobAsUint8Array.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import readBlobAsArrayBuffer from "./readBlobAsArrayBuffer";
|
||||||
|
|
||||||
|
export default function readBlobAsUint8Array(blob: Blob) {
|
||||||
|
return readBlobAsArrayBuffer(blob).then(buffer => new Uint8Array(buffer));
|
||||||
|
}
|
@ -13,7 +13,6 @@ import AppStorage from '../storage';
|
|||||||
import { MOUNT_CLASS_TO } from '../../config/debug';
|
import { MOUNT_CLASS_TO } from '../../config/debug';
|
||||||
import { forEachReverse } from '../../helpers/array';
|
import { forEachReverse } from '../../helpers/array';
|
||||||
import DATABASE_STATE from '../../config/databases/state';
|
import DATABASE_STATE from '../../config/databases/state';
|
||||||
import { readBlobAsText } from '../../helpers/blob';
|
|
||||||
import lottieLoader from '../rlottie/lottieLoader';
|
import lottieLoader from '../rlottie/lottieLoader';
|
||||||
import mediaSizes from '../../helpers/mediaSizes';
|
import mediaSizes from '../../helpers/mediaSizes';
|
||||||
import { getEmojiToneIndex } from '../../vendor/emoji';
|
import { getEmojiToneIndex } from '../../vendor/emoji';
|
||||||
@ -162,7 +161,7 @@ export class AppStickersManager {
|
|||||||
|
|
||||||
public getAnimatedEmojiSounds(overwrite?: boolean) {
|
public getAnimatedEmojiSounds(overwrite?: boolean) {
|
||||||
if(this.getAnimatedEmojiSoundsPromise && !overwrite) return this.getAnimatedEmojiSoundsPromise;
|
if(this.getAnimatedEmojiSoundsPromise && !overwrite) return this.getAnimatedEmojiSoundsPromise;
|
||||||
const promise = this.getAnimatedEmojiSoundsPromise = apiManager.getAppConfig(overwrite).then(appConfig => {
|
const promise = this.getAnimatedEmojiSoundsPromise = Promise.resolve(apiManager.getAppConfig(overwrite)).then(appConfig => {
|
||||||
if(this.getAnimatedEmojiSoundsPromise !== promise) {
|
if(this.getAnimatedEmojiSoundsPromise !== promise) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -257,19 +256,19 @@ export class AppStickersManager {
|
|||||||
const doc = this.getAnimatedEmojiSticker(emoji);
|
const doc = this.getAnimatedEmojiSticker(emoji);
|
||||||
if(doc) {
|
if(doc) {
|
||||||
return appDocsManager.downloadDoc(doc)
|
return appDocsManager.downloadDoc(doc)
|
||||||
.then(readBlobAsText)
|
.then(async(blob) => {
|
||||||
.then(async(json) => {
|
|
||||||
const mediaSize = mediaSizes.active.emojiSticker;
|
const mediaSize = mediaSizes.active.emojiSticker;
|
||||||
const toneIndex = getEmojiToneIndex(emoji);
|
const toneIndex = getEmojiToneIndex(emoji);
|
||||||
const animation = await lottieLoader.loadAnimationWorker({
|
const animation = await lottieLoader.loadAnimationWorker({
|
||||||
container: undefined,
|
container: undefined,
|
||||||
animationData: json,
|
animationData: blob,
|
||||||
width: width ?? mediaSize.width,
|
width: width ?? mediaSize.width,
|
||||||
height: height ?? mediaSize.height,
|
height: height ?? mediaSize.height,
|
||||||
name: 'doc' + doc.id,
|
name: 'doc' + doc.id,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
loop: false
|
loop: false,
|
||||||
}, 'none', toneIndex);
|
toneIndex
|
||||||
|
}, 'none');
|
||||||
|
|
||||||
animation.addEventListener('firstFrame', () => {
|
animation.addEventListener('firstFrame', () => {
|
||||||
appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);
|
appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Modes from '../config/modes';
|
import Modes from '../config/modes';
|
||||||
import { blobConstruct } from '../helpers/blob';
|
import blobConstruct from '../helpers/blob/blobConstruct';
|
||||||
import FileManager from './filemanager';
|
import FileManager from './fileManager';
|
||||||
//import { MOUNT_CLASS_TO } from './mtproto/mtproto_config';
|
//import { MOUNT_CLASS_TO } from './mtproto/mtproto_config';
|
||||||
//import { logger } from './polyfill';
|
//import { logger } from './polyfill';
|
||||||
|
|
||||||
|
@ -9,10 +9,11 @@
|
|||||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { blobConstruct, readBlobAsUint8Array } from "../helpers/blob";
|
import blobConstruct from "../helpers/blob/blobConstruct";
|
||||||
|
import readBlobAsUint8Array from "../helpers/blob/readBlobAsUint8Array";
|
||||||
|
|
||||||
export class FileManager {
|
export class FileManager {
|
||||||
public blobSupported = true;
|
private blobSupported = true;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
try {
|
try {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import { Database } from '../config/databases';
|
import { Database } from '../config/databases';
|
||||||
import Modes from '../config/modes';
|
import Modes from '../config/modes';
|
||||||
import { blobConstruct } from '../helpers/blob';
|
import blobConstruct from '../helpers/blob/blobConstruct';
|
||||||
import { safeAssign } from '../helpers/object';
|
import { safeAssign } from '../helpers/object';
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
import type { ReferenceBytes } from "./referenceDatabase";
|
import type { ReferenceBytes } from "./referenceDatabase";
|
||||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||||
import Modes from "../../config/modes";
|
import Modes from "../../config/modes";
|
||||||
import { readBlobAsArrayBuffer } from "../../helpers/blob";
|
|
||||||
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
||||||
import { notifyAll, notifySomeone } from "../../helpers/context";
|
import { notifyAll, notifySomeone } from "../../helpers/context";
|
||||||
import { getFileNameByLocation } from "../../helpers/fileName";
|
import { getFileNameByLocation } from "../../helpers/fileName";
|
||||||
@ -21,7 +20,7 @@ import { InputFile, InputFileLocation, InputWebFileLocation, UploadFile, UploadW
|
|||||||
import { DcId, WorkerTaskVoidTemplate } from "../../types";
|
import { DcId, WorkerTaskVoidTemplate } from "../../types";
|
||||||
import CacheStorageController from "../cacheStorage";
|
import CacheStorageController from "../cacheStorage";
|
||||||
import cryptoWorker from "../crypto/cryptoworker";
|
import cryptoWorker from "../crypto/cryptoworker";
|
||||||
import FileManager from "../filemanager";
|
import fileManager from "../fileManager";
|
||||||
import { logger, LogTypes } from "../logger";
|
import { logger, LogTypes } from "../logger";
|
||||||
import apiManager from "./apiManager";
|
import apiManager from "./apiManager";
|
||||||
import { isWebpSupported } from "./mtproto.worker";
|
import { isWebpSupported } from "./mtproto.worker";
|
||||||
@ -29,6 +28,7 @@ import { bytesToHex } from "../../helpers/bytes";
|
|||||||
import assumeType from "../../helpers/assumeType";
|
import assumeType from "../../helpers/assumeType";
|
||||||
import ctx from "../../environment/ctx";
|
import ctx from "../../environment/ctx";
|
||||||
import noop from "../../helpers/noop";
|
import noop from "../../helpers/noop";
|
||||||
|
import readBlobAsArrayBuffer from "../../helpers/blob/readBlobAsArrayBuffer";
|
||||||
|
|
||||||
type Delayed = {
|
type Delayed = {
|
||||||
offset: number,
|
offset: number,
|
||||||
@ -45,8 +45,11 @@ export type DownloadOptions = {
|
|||||||
limitPart?: number,
|
limitPart?: number,
|
||||||
queueId?: number,
|
queueId?: number,
|
||||||
onlyCache?: boolean,
|
onlyCache?: boolean,
|
||||||
|
// getFileMethod: Parameters<CacheStorageController['getFile']>[1]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type DownloadPromise = CancellablePromise<Blob>;
|
||||||
|
|
||||||
export type MyUploadFile = UploadFile.uploadFile | UploadWebFile.uploadWebFile;
|
export type MyUploadFile = UploadFile.uploadFile | UploadWebFile.uploadWebFile;
|
||||||
|
|
||||||
export interface RefreshReferenceTask extends WorkerTaskVoidTemplate {
|
export interface RefreshReferenceTask extends WorkerTaskVoidTemplate {
|
||||||
@ -66,7 +69,7 @@ export class ApiFileManager {
|
|||||||
private cacheStorage = new CacheStorageController('cachedFiles');
|
private cacheStorage = new CacheStorageController('cachedFiles');
|
||||||
|
|
||||||
private cachedDownloadPromises: {
|
private cachedDownloadPromises: {
|
||||||
[fileName: string]: CancellablePromise<Blob>
|
[fileName: string]: DownloadPromise
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
private uploadPromises: {
|
private uploadPromises: {
|
||||||
@ -311,8 +314,8 @@ export class ApiFileManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public downloadFile(options: DownloadOptions): CancellablePromise<Blob> {
|
public downloadFile(options: DownloadOptions): DownloadPromise {
|
||||||
if(!FileManager.isAvailable()) {
|
if(!fileManager.isAvailable()) {
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +346,8 @@ export class ApiFileManager {
|
|||||||
//this.log('downloadFile cachedPromise');
|
//this.log('downloadFile cachedPromise');
|
||||||
|
|
||||||
if(size) {
|
if(size) {
|
||||||
return cachedPromise.then((blob: Blob) => {
|
return cachedPromise.then((blob) => {
|
||||||
if(blob.size < size) {
|
if(blob instanceof Blob && blob.size < size) {
|
||||||
this.debug && this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
this.debug && this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
||||||
|
|
||||||
return this.deleteFile(fileName).then(() => {
|
return this.deleteFile(fileName).then(() => {
|
||||||
@ -361,12 +364,12 @@ export class ApiFileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deferred = deferredPromise<Blob>();
|
const deferred: DownloadPromise = deferredPromise();
|
||||||
const mimeType = options.mimeType || 'image/jpeg';
|
const mimeType = options.mimeType || 'image/jpeg';
|
||||||
|
|
||||||
let error: Error;
|
let error: Error;
|
||||||
let resolved = false;
|
let resolved = false;
|
||||||
let cacheFileWriter: ReturnType<typeof FileManager['getFakeFileWriter']>;
|
let cacheFileWriter: ReturnType<typeof fileManager['getFakeFileWriter']>;
|
||||||
let errorHandler = (_error: Error) => {
|
let errorHandler = (_error: Error) => {
|
||||||
error = _error;
|
error = _error;
|
||||||
delete this.cachedDownloadPromises[fileName];
|
delete this.cachedDownloadPromises[fileName];
|
||||||
@ -464,7 +467,7 @@ export class ApiFileManager {
|
|||||||
await writeFilePromise;
|
await writeFilePromise;
|
||||||
checkCancel();
|
checkCancel();
|
||||||
|
|
||||||
await FileManager.write(fileWriter, processedResult);
|
await fileManager.write(fileWriter, processedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFileDeferred.resolve();
|
writeFileDeferred.resolve();
|
||||||
|
@ -12,7 +12,7 @@ import { logger, LogTypes } from "../logger";
|
|||||||
import apiManager from "../mtproto/mtprotoworker";
|
import apiManager from "../mtproto/mtprotoworker";
|
||||||
import RLottiePlayer, { RLottieOptions } from './rlottiePlayer';
|
import RLottiePlayer, { RLottieOptions } from './rlottiePlayer';
|
||||||
import QueryableWorker from './queryableWorker';
|
import QueryableWorker from './queryableWorker';
|
||||||
import applyReplacements from './applyReplacements';
|
import blobConstruct from '../../helpers/blob/blobConstruct';
|
||||||
|
|
||||||
export type LottieAssetName = 'EmptyFolder' | 'Folders_1' | 'Folders_2' |
|
export type LottieAssetName = 'EmptyFolder' | 'Folders_1' | 'Folders_2' |
|
||||||
'TwoFactorSetupMonkeyClose' | 'TwoFactorSetupMonkeyCloseAndPeek' |
|
'TwoFactorSetupMonkeyClose' | 'TwoFactorSetupMonkeyCloseAndPeek' |
|
||||||
@ -101,16 +101,16 @@ export class LottieLoader {
|
|||||||
return fetch(url)
|
return fetch(url)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if(!res.headers || res.headers.get('content-type') === 'application/octet-stream') {
|
if(!res.headers || res.headers.get('content-type') === 'application/octet-stream') {
|
||||||
return res.arrayBuffer().then(data => apiManager.invokeCrypto('gzipUncompress', data, true))
|
return res.arrayBuffer().then(data => apiManager.invokeCrypto('gzipUncompress', data)).then(arr => blobConstruct([arr], ''))
|
||||||
} else {
|
} else {
|
||||||
return res.text();
|
return res.blob();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/* .then(str => {
|
/* .then(str => {
|
||||||
return new Promise<string>((resolve) => setTimeout(() => resolve(str), 2e3));
|
return new Promise<string>((resolve) => setTimeout(() => resolve(str), 2e3));
|
||||||
}) */
|
}) */
|
||||||
.then(str => {
|
.then(blob => {
|
||||||
const newParams = Object.assign(params, {animationData: str as string/* JSON.parse(str) */, needUpscale: true});
|
const newParams = Object.assign(params, {animationData: blob, needUpscale: true});
|
||||||
if(!newParams.name) newParams.name = url;
|
if(!newParams.name) newParams.name = url;
|
||||||
return this.loadAnimationWorker(newParams);
|
return this.loadAnimationWorker(newParams);
|
||||||
});
|
});
|
||||||
@ -130,22 +130,12 @@ export class LottieLoader {
|
|||||||
]).then(() => player);
|
]).then(() => player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async loadAnimationWorker(params: RLottieOptions, group = params.group || '', toneIndex = -1, middleware?: () => boolean): Promise<RLottiePlayer> {
|
public async loadAnimationWorker(params: RLottieOptions, group = params.group || '', middleware?: () => boolean): Promise<RLottiePlayer> {
|
||||||
if(!this.isWebAssemblySupported) {
|
if(!this.isWebAssemblySupported) {
|
||||||
return this.loadPromise as any;
|
return this.loadPromise as any;
|
||||||
}
|
}
|
||||||
//params.autoplay = true;
|
//params.autoplay = true;
|
||||||
|
|
||||||
if(toneIndex >= 1 && toneIndex <= 5) {
|
|
||||||
/* params.animationData = copy(params.animationData);
|
|
||||||
this.applyReplacements(params.animationData, toneIndex); */
|
|
||||||
|
|
||||||
params.toneIndex = toneIndex;
|
|
||||||
const newAnimationData = JSON.parse(params.animationData);
|
|
||||||
applyReplacements(newAnimationData, toneIndex);
|
|
||||||
params.animationData = JSON.stringify(newAnimationData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.loaded) {
|
if(!this.loaded) {
|
||||||
await this.loadLottieWorkers();
|
await this.loadLottieWorkers();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export default class QueryableWorker extends EventListenerBase<{
|
|||||||
transfer.push(arg);
|
transfer.push(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(arg.buffer && arg.buffer instanceof ArrayBuffer) {
|
if(typeof(arg) === 'object' && arg.buffer instanceof ArrayBuffer) {
|
||||||
transfer.push(arg.buffer);
|
transfer.push(arg.buffer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import readBlobAsText from "../../helpers/blob/readBlobAsText";
|
||||||
|
import applyReplacements from "./applyReplacements";
|
||||||
|
|
||||||
importScripts('rlottie-wasm.js');
|
importScripts('rlottie-wasm.js');
|
||||||
//import Module, { allocate, intArrayFromString } from './rlottie-wasm';
|
//import Module, { allocate, intArrayFromString } from './rlottie-wasm';
|
||||||
|
|
||||||
@ -19,46 +22,46 @@ export class RLottieItem {
|
|||||||
private stringOnWasmHeap: number;
|
private stringOnWasmHeap: number;
|
||||||
private handle: LottieHandlePointer;
|
private handle: LottieHandlePointer;
|
||||||
private frameCount: number;
|
private frameCount: number;
|
||||||
|
private fps: number;
|
||||||
|
|
||||||
private dead: boolean;
|
private dead: boolean;
|
||||||
//private context: OffscreenCanvasRenderingContext2D;
|
//private context: OffscreenCanvasRenderingContext2D;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private reqId: number,
|
private reqId: number,
|
||||||
jsString: string,
|
|
||||||
private width: number,
|
private width: number,
|
||||||
private height: number,
|
private height: number/* ,
|
||||||
private fps: number/* ,
|
|
||||||
private canvas: OffscreenCanvas */
|
private canvas: OffscreenCanvas */
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(json: string, fps: number) {
|
||||||
|
if(this.dead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.fps = Math.max(1, Math.min(60, fps || DEFAULT_FPS));
|
this.fps = Math.max(1, Math.min(60, fps || DEFAULT_FPS));
|
||||||
|
|
||||||
this.frameCount = 0;
|
|
||||||
|
|
||||||
//this.context = canvas.getContext('2d');
|
//this.context = canvas.getContext('2d');
|
||||||
|
|
||||||
this.init(jsString);
|
|
||||||
|
|
||||||
reply('loaded', this.reqId, this.frameCount, this.fps);
|
|
||||||
|
|
||||||
/* let frame = 0;
|
/* let frame = 0;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if(frame >= this.frameCount) frame = 0;
|
if(frame >= this.frameCount) frame = 0;
|
||||||
let _frame = frame++;
|
let _frame = frame++;
|
||||||
this.render(_frame, null);
|
this.render(_frame, null);
|
||||||
}, 1000 / this.fps); */
|
}, 1000 / this.fps); */
|
||||||
}
|
|
||||||
|
|
||||||
private init(jsString: string) {
|
|
||||||
try {
|
try {
|
||||||
this.handle = worker.Api.init();
|
this.handle = worker.Api.init();
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.stringOnWasmHeap = allocate(intArrayFromString(jsString), 'i8', 0);
|
this.stringOnWasmHeap = allocate(intArrayFromString(json), 'i8', 0);
|
||||||
|
|
||||||
this.frameCount = worker.Api.loadFromData(this.handle, this.stringOnWasmHeap);
|
this.frameCount = worker.Api.loadFromData(this.handle, this.stringOnWasmHeap);
|
||||||
|
|
||||||
worker.Api.resize(this.handle, this.width, this.height);
|
worker.Api.resize(this.handle, this.width, this.height);
|
||||||
|
|
||||||
|
reply('loaded', this.reqId, this.frameCount, this.fps);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error('init RLottieItem error:', e);
|
console.error('init RLottieItem error:', e);
|
||||||
reply('error', this.reqId, e);
|
reply('error', this.reqId, e);
|
||||||
@ -66,7 +69,7 @@ export class RLottieItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render(frameNo: number, clamped?: Uint8ClampedArray) {
|
public render(frameNo: number, clamped?: Uint8ClampedArray) {
|
||||||
if(this.dead) return;
|
if(this.dead || this.handle === undefined) return;
|
||||||
//return;
|
//return;
|
||||||
|
|
||||||
if(this.frameCount < frameNo || frameNo < 0) {
|
if(this.frameCount < frameNo || frameNo < 0) {
|
||||||
@ -99,7 +102,9 @@ export class RLottieItem {
|
|||||||
public destroy() {
|
public destroy() {
|
||||||
this.dead = true;
|
this.dead = true;
|
||||||
|
|
||||||
worker.Api.destroy(this.handle);
|
if(this.handle !== undefined) {
|
||||||
|
worker.Api.destroy(this.handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,27 +143,39 @@ _Module.onRuntimeInitialized = function() {
|
|||||||
|
|
||||||
const items: {[reqId: string]: RLottieItem} = {};
|
const items: {[reqId: string]: RLottieItem} = {};
|
||||||
const queryableFunctions = {
|
const queryableFunctions = {
|
||||||
loadFromData: function(reqId: number, jsString: string, width: number, height: number/* , canvas: OffscreenCanvas */) {
|
loadFromData: function(reqId: number, blob: Blob, width: number, height: number, toneIndex: number/* , canvas: OffscreenCanvas */) {
|
||||||
try {
|
const item = items[reqId] = new RLottieItem(reqId, width, height/* , canvas */);
|
||||||
// ! WARNING, с этой проверкой не все стикеры работают, например - ДУРКА
|
readBlobAsText(blob).then((json) => {
|
||||||
/* if(!/"tgs":\s*?1./.test(jsString)) {
|
try {
|
||||||
throw new Error('Invalid file');
|
if(typeof(toneIndex) === 'number' && toneIndex >= 1 && toneIndex <= 5) {
|
||||||
} */
|
/* params.animationData = copy(params.animationData);
|
||||||
|
this.applyReplacements(params.animationData, toneIndex); */
|
||||||
|
|
||||||
/* let perf = performance.now();
|
const newAnimationData = JSON.parse(json);
|
||||||
let json = JSON.parse(jsString);
|
applyReplacements(newAnimationData, toneIndex);
|
||||||
console.log('sticker decode:', performance.now() - perf); */
|
json = JSON.stringify(newAnimationData);
|
||||||
|
}
|
||||||
|
|
||||||
const match = jsString.match(/"fr":\s*?(\d+?),/);
|
// ! WARNING, с этой проверкой не все стикеры работают, например - ДУРКА
|
||||||
const frameRate = +match?.[1] || DEFAULT_FPS;
|
/* if(!/"tgs":\s*?1./.test(jsString)) {
|
||||||
|
throw new Error('Invalid file');
|
||||||
|
} */
|
||||||
|
|
||||||
//console.log('Rendering sticker:', reqId, frameRate, 'now rendered:', Object.keys(items).length);
|
/* let perf = performance.now();
|
||||||
|
let json = JSON.parse(jsString);
|
||||||
|
console.log('sticker decode:', performance.now() - perf); */
|
||||||
|
|
||||||
items[reqId] = new RLottieItem(reqId, jsString, width, height, frameRate/* , canvas */);
|
const match = json.match(/"fr":\s*?(\d+?),/);
|
||||||
} catch(e) {
|
const frameRate = +match?.[1] || DEFAULT_FPS;
|
||||||
console.error('Invalid file for sticker:', jsString);
|
|
||||||
reply('error', reqId, e);
|
//console.log('Rendering sticker:', reqId, frameRate, 'now rendered:', Object.keys(items).length);
|
||||||
}
|
|
||||||
|
item.init(json, frameRate);
|
||||||
|
} catch(err) {
|
||||||
|
console.error('Invalid file for sticker:', json);
|
||||||
|
reply('error', reqId, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
destroy: function(reqId: number) {
|
destroy: function(reqId: number) {
|
||||||
const item = items[reqId];
|
const item = items[reqId];
|
||||||
|
@ -15,7 +15,7 @@ export type RLottieOptions = {
|
|||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
canvas?: HTMLCanvasElement,
|
canvas?: HTMLCanvasElement,
|
||||||
autoplay?: boolean,
|
autoplay?: boolean,
|
||||||
animationData: string,
|
animationData: Blob,
|
||||||
loop?: boolean,
|
loop?: boolean,
|
||||||
width?: number,
|
width?: number,
|
||||||
height?: number,
|
height?: number,
|
||||||
@ -264,8 +264,8 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||||||
this.worker.sendQuery(methodName, this.reqId, ...args);
|
this.worker.sendQuery(methodName, this.reqId, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadFromData(jsonString: string) {
|
public loadFromData(data: RLottieOptions['animationData']) {
|
||||||
this.sendQuery('loadFromData', jsonString, this.width, this.height/* , this.canvas.transferControlToOffscreen() */);
|
this.sendQuery('loadFromData', data, this.width, this.height, this.toneIndex/* , this.canvas.transferControlToOffscreen() */);
|
||||||
}
|
}
|
||||||
|
|
||||||
public play() {
|
public play() {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { readBlobAsUint8Array } from "../../helpers/blob";
|
import readBlobAsUint8Array from "../../helpers/blob/readBlobAsUint8Array";
|
||||||
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
||||||
import { getWindowClients } from "../../helpers/context";
|
import { getWindowClients } from "../../helpers/context";
|
||||||
import debounce from "../../helpers/schedulers/debounce";
|
import debounce from "../../helpers/schedulers/debounce";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user