Handle t.me/addstickers

This commit is contained in:
Eduard Kuzmenko 2021-06-29 16:17:10 +03:00
parent 43616c55fa
commit 3fdb9a81de
6 changed files with 89 additions and 61 deletions

View File

@ -5,7 +5,7 @@
*/
import PopupElement from ".";
import appStickersManager from "../../lib/appManagers/appStickersManager";
import appStickersManager, { AppStickersManager } from "../../lib/appManagers/appStickersManager";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import Scrollable from "../scrollable";
import { wrapSticker } from "../wrappers";
@ -29,11 +29,7 @@ export default class PopupStickers extends PopupElement {
private set: StickerSet.stickerSet;
constructor(private stickerSetInput: {
//_: 'inputStickerSetID',
id: string,
access_hash: string
}) {
constructor(private stickerSetInput: Parameters<AppStickersManager['getStickerSet']>[0]) {
super('popup-stickers', null, {closable: true, overlayClosable: true, body: true});
this.h6 = document.createElement('h6');

View File

@ -248,7 +248,7 @@ export class ApiUpdatesManager {
const promise = apiManager.invokeApi('updates.getDifference', {
pts: updatesState.pts,
pts_total_limit: first/* && false */ ? 50/* 1200 */ : undefined,
pts_total_limit: first && false ? 50/* 1200 */ : undefined,
date: updatesState.date,
qts: -1
}, {

View File

@ -59,6 +59,7 @@ import whichChild from '../../helpers/dom/whichChild';
import appEmojiManager from './appEmojiManager';
import PopupElement from '../../components/popups';
import singleInstance from '../mtproto/singleInstance';
import PopupStickers from '../../components/popups/stickers';
//console.log('appImManager included33!');
@ -223,9 +224,7 @@ export class AppImManager {
stateStorage.setToCache('chatPositions', c || {});
});
(window as any).showMaskedAlert = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
this.addAnchorListener('showMaskedAlert', (params, element) => {
const href = element.href;
const a = element.cloneNode(true) as HTMLAnchorElement;
@ -244,19 +243,9 @@ export class AppImManager {
},
}]
}).show();
}, false);
return false;
};
(window as any).execBotCommand = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
const params = this.parseUriParams(href);
if(!params) {
return;
}
this.addAnchorListener('execBotCommand', (params) => {
const {command, bot} = params;
/* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId);
@ -267,23 +256,35 @@ export class AppImManager {
appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : ''));
//console.log(command, bot);
});
return false;
};
(window as any).searchByHashtag = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
const params = this.parseUriParams(href);
this.addAnchorListener('searchByHashtag', (params) => {
if(!params) {
return;
}
const {hashtag} = params;
this.chat.initSearch('#' + hashtag + ' ');
});
return false;
this.addAnchorListener('addstickers', (params) => {
new PopupStickers({id: params[1]}).show();
}, true);
}
private addAnchorListener(name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers',
callback: (params: any, element: HTMLAnchorElement) => boolean | void, parseParams = true) {
(window as any)[name] = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
let params: any;
if(parseParams) {
params = !element.href.includes('#') ? new URL(element.href).pathname.split('/').slice(1) : this.parseUriParams(href);
}
const res = callback(params, element);
return res === undefined ? res : false;
};
}

View File

@ -16,6 +16,11 @@ import DATABASE_STATE from '../../config/databases/state';
const CACHE_TIME = 3600e3;
export type MyStickerSetInput = {
id: string,
access_hash?: string
};
export class AppStickersManager {
private storage = new AppStorage<Record<string, MessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets');
@ -23,7 +28,7 @@ export class AppStickersManager {
private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};
constructor() {
this.getStickerSet({id: 'emoji', access_hash: ''});
this.getStickerSet({id: 'emoji'}, {saveById: true});
rootScope.addMultipleEventsListeners({
updateNewStickerSet: (update) => {
@ -42,24 +47,23 @@ export class AppStickersManager {
});
}
public async getStickerSet(set: {
id: string,
access_hash: string
}, params: Partial<{
public async getStickerSet(set: MyStickerSetInput, params: Partial<{
overwrite: boolean,
useCache: boolean
useCache: boolean,
saveById: boolean
}> = {}): Promise<MessagesStickerSet> {
if(this.getStickerSetPromises[set.id]) {
return this.getStickerSetPromises[set.id];
const id = set.id;
if(this.getStickerSetPromises[id]) {
return this.getStickerSetPromises[id];
}
return this.getStickerSetPromises[set.id] = new Promise(async(resolve) => {
return this.getStickerSetPromises[id] = new Promise(async(resolve) => {
if(!params.overwrite) {
const cachedSet = await this.storage.get(set.id);
const cachedSet = await this.storage.get(id);
if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) {
this.saveStickers(cachedSet.documents);
resolve(cachedSet);
delete this.getStickerSetPromises[set.id];
delete this.getStickerSetPromises[id];
return;
}
}
@ -69,14 +73,15 @@ export class AppStickersManager {
stickerset: this.getStickerSetInput(set)
});
this.saveStickerSet(stickerSet, set.id);
const saveById = params.saveById ? id : stickerSet.set.id;
this.saveStickerSet(stickerSet, saveById);
resolve(stickerSet);
} catch(err) {
resolve(null);
}
delete this.getStickerSetPromises[set.id];
delete this.getStickerSetPromises[id];
});
}
@ -158,14 +163,23 @@ export class AppStickersManager {
//return promise;
} */
public getStickerSetInput(set: {id: string, access_hash: string}): InputStickerSet {
return set.id === 'emoji' ? {
_: 'inputStickerSetAnimatedEmoji'
} : {
_: 'inputStickerSetID',
id: set.id,
access_hash: set.access_hash
};
public getStickerSetInput(set: MyStickerSetInput): InputStickerSet {
if(set.id === 'emoji') {
return {
_: 'inputStickerSetAnimatedEmoji'
};
} else if(!set.access_hash) {
return {
_: 'inputStickerSetShortName',
short_name: set.id
};
} else {
return {
_: 'inputStickerSetID',
id: set.id,
access_hash: set.access_hash
};
}
}
public async getFeaturedStickers() {

View File

@ -354,6 +354,10 @@ export default class IDBStorage<T extends Database<any>> {
return this.openDatabase().then((db) => {
return new Promise<T>((resolve, reject) => {
/* if(mode === 'readwrite') {
return;
} */
const transaction = db.transaction([storeName], mode);
transaction.onerror = (e) => {

View File

@ -573,12 +573,15 @@ namespace RichTextProcessor {
const entityText = text.substr(entity.offset, entity.length);
// let inner: string;
let url: string;
let url: string = (entity as MessageEntity.messageEntityTextUrl).url || entityText;
let masked = false;
if(entity._ === 'messageEntityTextUrl') {
url = (entity as MessageEntity.messageEntityTextUrl).url;
url = wrapUrl(url, true);
let onclick: string;
const wrapped = wrapUrl(url, true);
url = wrapped.url;
onclick = wrapped.onclick;
if(entity._ === 'messageEntityTextUrl') {
const nextEntity = entities[i + 1];
if(nextEntity?._ === 'messageEntityUrl' &&
nextEntity.length === entity.length &&
@ -590,11 +593,13 @@ namespace RichTextProcessor {
masked = true;
}
} else {
url = wrapUrl(entityText, false);
//inner = encodeEntities(replaceUrlEncodings(entityText));
}
const currentContext = url[0] === '#';
if(!onclick && masked && !currentContext) {
onclick = 'showMaskedAlert';
}
const href = (currentContext || typeof electronHelpers === 'undefined')
? encodeEntities(url)
@ -603,7 +608,7 @@ namespace RichTextProcessor {
const target = (currentContext || typeof electronHelpers !== 'undefined')
? '' : ' target="_blank" rel="noopener noreferrer"';
insertPart(entity, `<a class="anchor-url" href="${href}"${target}${masked && !currentContext ? 'onclick="showMaskedAlert(this)"' : ''}>`, '</a>');
insertPart(entity, `<a class="anchor-url" href="${href}"${target}${onclick ? `onclick="${onclick}(this)"` : ''}>`, '</a>');
}
break;
@ -789,13 +794,14 @@ namespace RichTextProcessor {
return wrapRichText(text, {entities});
}
export function wrapUrl(url: string, unsafe?: number | boolean): string {
export function wrapUrl(url: string, unsafe?: number | boolean): {url: string, onclick: string} {
if(!matchUrlProtocol(url)) {
url = 'https://' + url;
}
let tgMeMatch;
let telescoPeMatch;
let onclick: string;
/* if(unsafe === 2) {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
@ -803,12 +809,19 @@ namespace RichTextProcessor {
const path = fullPath.split('/');
switch(path[0]) {
case 'joinchat':
case 'addstickers':
onclick = path[0];
break;
/* case 'joinchat':
onclick = 'joinchat';
url = 'tg://join?invite=' + path[1];
break;
case 'addstickers':
onclick = 'addstickers';
url = 'tg://addstickers?set=' + path[1];
break;
break; */
default:
if(path[1] && path[1].match(/^\d+$/)) { // https://t.me/.+/[0-9]+ (channel w/ username)
@ -846,7 +859,7 @@ namespace RichTextProcessor {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} */
return url;
return {url, onclick};
}
export function matchUrlProtocol(text: string) {