webk 2.1.0.1
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
VITE_API_ID=1025907
|
||||
VITE_API_HASH=452b0359b988148995f22ff0f4229750
|
||||
VITE_VERSION=2.1.0
|
||||
VITE_VERSION_FULL=2.1.0 (520)
|
||||
VITE_BUILD=520
|
||||
VITE_VERSION=2.1.0.1
|
||||
VITE_VERSION_FULL=2.1.0.1 (521)
|
||||
VITE_BUILD=521
|
||||
VITE_MTPROTO_WORKER=1
|
||||
VITE_MTPROTO_SW=
|
||||
VITE_MTPROTO_HTTP=
|
||||
|
6494
webk/pnpm-lock.yaml
generated
6494
webk/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
2.1.0 (520)
|
||||
2.1.0.1 (521)
|
@ -27,6 +27,7 @@ import EventListenerBase from '../helpers/eventListenerBase';
|
||||
import animationIntersector from './animationIntersector';
|
||||
import apiManagerProxy from '../lib/mtproto/mtprotoworker';
|
||||
import setCurrentTime from '../helpers/dom/setCurrentTime';
|
||||
import stealthMode from '../helpers/stealthMode';
|
||||
|
||||
// TODO: Safari: проверить стрим, включить его и сразу попробовать включить видео или другую песню
|
||||
// TODO: Safari: попробовать замаскировать подгрузку последнего чанка
|
||||
@ -294,7 +295,7 @@ export class AppMediaPlaybackController extends EventListenerBase<{
|
||||
|
||||
if(doc.type !== 'audio' && message?.pFlags.media_unread && message.fromId !== rootScope.myId) {
|
||||
media.addEventListener('timeupdate', () => {
|
||||
this.managers.appMessagesManager.readMessages(peerId, [mid]);
|
||||
this.managers.appMessagesManager.readMessages(peerId, [mid], stealthMode.isEnabled());
|
||||
}, {once: true});
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,7 @@ import safeWindowOpen from '../../helpers/dom/safeWindowOpen';
|
||||
import findAndSplice from '../../helpers/array/findAndSplice';
|
||||
import generatePhotoForExtendedMediaPreview from '../../lib/appManagers/utils/photos/generatePhotoForExtendedMediaPreview';
|
||||
import icon from '../icon';
|
||||
import stealthMode from '../../helpers/stealthMode';
|
||||
|
||||
export const USER_REACTIONS_INLINE = false;
|
||||
export const TEST_BUBBLES_DELETION = false;
|
||||
@ -2136,7 +2137,7 @@ export default class ChatBubbles {
|
||||
this.log('will readHistory by maxId:', maxId);
|
||||
}
|
||||
|
||||
callback = () => this.managers.appMessagesManager.readHistory(peerId, maxId, threadId);
|
||||
callback = () => this.managers.appMessagesManager.readHistory(peerId, maxId, threadId, undefined, stealthMode.isEnabled());
|
||||
} else {
|
||||
const readContents: number[] = [];
|
||||
for(const mid of this.unreadedContentSeen) {
|
||||
@ -2150,7 +2151,7 @@ export default class ChatBubbles {
|
||||
this.log('will readMessages', readContents);
|
||||
}
|
||||
|
||||
callback = () => this.managers.appMessagesManager.readMessages(peerId, readContents);
|
||||
callback = () => this.managers.appMessagesManager.readMessages(peerId, readContents, stealthMode.isEnabled());
|
||||
}
|
||||
|
||||
this[unreadedSeenKey].clear();
|
||||
@ -4599,7 +4600,7 @@ export default class ChatBubbles {
|
||||
if(this.chat.type === ChatType.Chat || this.chat.type === ChatType.Discussion) {
|
||||
const {peerId, threadId} = this.chat;
|
||||
const historyMaxId = await this.chat.getHistoryMaxId();
|
||||
this.managers.appMessagesManager.readHistory(peerId, historyMaxId, threadId, true);
|
||||
this.managers.appMessagesManager.readHistory(peerId, historyMaxId, threadId, true, stealthMode.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,7 @@ import createContextMenu from '../../helpers/dom/createContextMenu';
|
||||
import {Accessor, createEffect, createRoot, createSignal, Setter} from 'solid-js';
|
||||
import SelectedEffect from './selectedEffect';
|
||||
import windowSize from '../../helpers/windowSize';
|
||||
import stealthMode from '../../helpers/stealthMode';
|
||||
|
||||
// console.log('Recorder', Recorder);
|
||||
|
||||
@ -713,7 +714,7 @@ export default class ChatInput {
|
||||
icon: 'readchats',
|
||||
text: isReaction ? 'ReadAllReactions' : 'ReadAllMentions',
|
||||
onClick: () => {
|
||||
this.managers.appMessagesManager.readMentions(this.chat.peerId, this.chat.threadId, isReaction);
|
||||
this.managers.appMessagesManager.readMentions(this.chat.peerId, this.chat.threadId, isReaction, stealthMode.isEnabled());
|
||||
}
|
||||
}],
|
||||
listenTo: btn,
|
||||
|
@ -135,8 +135,8 @@ export default class ChatTranslation extends PinnedContainer {
|
||||
]});
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
this.toggle(!peerTranslation().shouldShow());
|
||||
createEffect(() => { // octt: force show translation menu on all chats, to curb some issues
|
||||
this.toggle(false); // (!peerTranslation().shouldShow());
|
||||
});
|
||||
|
||||
const listenerSetter = new ListenerSetter();
|
||||
@ -160,11 +160,11 @@ export default class ChatTranslation extends PinnedContainer {
|
||||
},
|
||||
verify: isPremium,
|
||||
separatorDown: true
|
||||
}, {
|
||||
}, { // octt: make the disable translation button into a toggle button
|
||||
icon: 'crossround',
|
||||
text: 'Hide',
|
||||
text: 'Toggle', // 'Hide',
|
||||
onClick: () => {
|
||||
this.managers.appTranslationsManager.togglePeerTranslations(peerId(), true);
|
||||
this.managers.appTranslationsManager.togglePeerTranslations(peerId(), peerTranslation().shouldShow()); // true);
|
||||
}
|
||||
}],
|
||||
listenerSetter
|
||||
|
@ -301,7 +301,7 @@ export default class DialogsContextMenu {
|
||||
if(!this.threadId) {
|
||||
this.managers.appMessagesManager.markDialogUnread(peerId, true);
|
||||
} else {
|
||||
this.managers.appMessagesManager.readHistory(peerId, dialog.top_message, this.threadId);
|
||||
this.managers.appMessagesManager.readHistory(peerId, dialog.top_message, this.threadId, undefined, false);
|
||||
}
|
||||
} else if(!this.threadId) {
|
||||
this.managers.appMessagesManager.markDialogUnread(peerId);
|
||||
|
@ -52,6 +52,7 @@ import mediaSizes from '../../helpers/mediaSizes';
|
||||
import {fastRaf} from '../../helpers/schedulers';
|
||||
import {getInstallPrompt} from '../../helpers/dom/installPrompt';
|
||||
import liteMode from '../../helpers/liteMode';
|
||||
import stealthMode from '../../helpers/stealthMode';
|
||||
import AppPowerSavingTab from './tabs/powerSaving';
|
||||
import AppMyStoriesTab from './tabs/myStories';
|
||||
import {joinDeepPath} from '../../helpers/object/setDeepProperty';
|
||||
@ -156,6 +157,14 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
themeCheckboxField.setValueSilently(themeController.getTheme().name === 'night');
|
||||
});
|
||||
|
||||
const stealthCheckboxField = new CheckboxField({ // octt: //
|
||||
toggle: true,
|
||||
checked: stealthMode.isEnabled()
|
||||
});
|
||||
stealthCheckboxField.input.addEventListener('change', () => {
|
||||
stealthMode.setState(stealthCheckboxField.checked);
|
||||
});
|
||||
|
||||
const menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean | Promise<boolean>})[] = [{
|
||||
icon: 'savedmessages',
|
||||
text: 'SavedMessages',
|
||||
@ -216,6 +225,17 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.createTab(AppPowerSavingTab).open();
|
||||
},
|
||||
verify: () => liteMode.isEnabled()
|
||||
}, { // octt: stealth mode
|
||||
icon: 'deletedaccount',
|
||||
text: 'PremiumStoriesStealth',
|
||||
onClick: () => {},
|
||||
checkboxField: stealthCheckboxField
|
||||
}, { // octt: Spaccogram Channel
|
||||
icon: 'help',
|
||||
text: 'SpaccogramNewsInfo',
|
||||
onClick: () => {
|
||||
appImManager.openUrl('https://t.me/+ujaob63Vy705Mzgx');
|
||||
}
|
||||
}, {
|
||||
icon: 'help',
|
||||
text: 'TelegramFeatures',
|
||||
@ -223,7 +243,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
const url = I18n.format('TelegramFeaturesUrl', true);
|
||||
appImManager.openUrl(url);
|
||||
}
|
||||
}, {
|
||||
}, /* { // octt: disable this, official devs must not get bug reports from noobs using my broken code
|
||||
icon: 'bug',
|
||||
text: 'ReportBug',
|
||||
onClick: () => {
|
||||
@ -236,7 +256,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
a.remove();
|
||||
}, 0);
|
||||
}
|
||||
}, {
|
||||
}, */ /* { // octt: disable switch to WebA
|
||||
icon: 'char' as Icon,
|
||||
className: 'a',
|
||||
text: 'ChatList.Menu.SwitchTo.A',
|
||||
@ -249,7 +269,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
});
|
||||
},
|
||||
verify: () => App.isMainDomain
|
||||
}, /* {
|
||||
}, */ /* {
|
||||
icon: 'char w',
|
||||
text: 'ChatList.Menu.SwitchTo.Webogram',
|
||||
onClick: () => {
|
||||
@ -300,9 +320,9 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
buttons.splice(3, 0, ...attachMenuBotsButtons);
|
||||
filteredButtons.splice(0, filteredButtons.length, ...buttons);
|
||||
},
|
||||
onOpen: (e, btnMenu) => {
|
||||
onOpen: (e, btnMenu) => { // octt: branding
|
||||
const btnMenuFooter = document.createElement('a');
|
||||
btnMenuFooter.href = 'https://github.com/morethanwords/tweb/blob/master/CHANGELOG.md';
|
||||
// btnMenuFooter.href = 'https://github.com/morethanwords/tweb/blob/master/CHANGELOG.md';
|
||||
setBlankToAnchor(btnMenuFooter);
|
||||
btnMenuFooter.classList.add('btn-menu-footer');
|
||||
btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => {
|
||||
@ -311,7 +331,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
});
|
||||
const t = document.createElement('span');
|
||||
t.classList.add('btn-menu-footer-text');
|
||||
t.textContent = 'Telegram Web' + App.suffix + ' '/* ' alpha ' */ + App.versionFull;
|
||||
t.textContent = /* 'Telegram Web' */ 'Spaccogram Web' + App.suffix + ' '/* ' alpha ' */ + App.versionFull;
|
||||
btnMenuFooter.append(t);
|
||||
btnMenu.classList.add('has-footer');
|
||||
btnMenu.append(btnMenuFooter);
|
||||
|
@ -11,7 +11,10 @@
|
||||
|
||||
import type {TrueDcId} from '../types';
|
||||
|
||||
export const MAIN_DOMAINS = ['web.telegram.org', 'webk.telegram.org'];
|
||||
export const MAIN_DOMAINS = [
|
||||
'web.telegram.org', 'webk.telegram.org',
|
||||
'tweb.octt.eu.org' // octt: fork domain
|
||||
];
|
||||
export const DEFAULT_BACKGROUND_SLUG = 'pattern';
|
||||
|
||||
const threads = Math.min(4, navigator.hardwareConcurrency ?? 4);
|
||||
|
@ -109,7 +109,8 @@ export type State = {
|
||||
nightTheme?: boolean, // ! DEPRECATED
|
||||
timeFormat: 'h12' | 'h23',
|
||||
liteMode: {[key in LiteModeKey]: boolean},
|
||||
savedAsForum: boolean
|
||||
savedAsForum: boolean,
|
||||
stealthMode: boolean // octt: //
|
||||
},
|
||||
playbackParams: ReturnType<AppMediaPlaybackController['getPlaybackParams']>,
|
||||
keepSigned: boolean,
|
||||
@ -305,26 +306,27 @@ export const STATE_INIT: State = {
|
||||
sound: false
|
||||
},
|
||||
timeFormat: getTimeFormat(),
|
||||
liteMode: {
|
||||
liteMode: { // octt: many lite mode properties enabled by default
|
||||
all: false,
|
||||
animations: false,
|
||||
chat: false,
|
||||
chat_background: false,
|
||||
chat_spoilers: false,
|
||||
effects: false,
|
||||
effects_premiumstickers: false,
|
||||
effects_reactions: false,
|
||||
effects_emoji: false,
|
||||
emoji: false,
|
||||
emoji_messages: false,
|
||||
emoji_panel: false,
|
||||
animations: true,
|
||||
chat: true,
|
||||
chat_background: true,
|
||||
chat_spoilers: true,
|
||||
effects: true,
|
||||
effects_premiumstickers: true,
|
||||
effects_reactions: true,
|
||||
effects_emoji: true,
|
||||
emoji: true,
|
||||
emoji_messages: true,
|
||||
emoji_panel: true,
|
||||
gif: false,
|
||||
stickers: false,
|
||||
stickers_chat: false,
|
||||
stickers_panel: false,
|
||||
stickers_panel: true,
|
||||
video: false
|
||||
},
|
||||
savedAsForum: false
|
||||
savedAsForum: false,
|
||||
stealthMode: false // octt: //
|
||||
},
|
||||
playbackParams: {
|
||||
volume: 1,
|
||||
|
24
webk/src/helpers/stealthMode.ts
Normal file
24
webk/src/helpers/stealthMode.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* Copyright (C) 2024-2024 OctoSpacc, Spacc Inc.
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import {MOUNT_CLASS_TO} from '../config/debug';
|
||||
import rootScope from '../lib/rootScope';
|
||||
import {joinDeepPath} from './object/setDeepProperty';
|
||||
|
||||
export class StealthMode {
|
||||
public isEnabled() {
|
||||
return !!(rootScope.settings && rootScope.settings.stealthMode);
|
||||
}
|
||||
|
||||
public setState(state: boolean) {
|
||||
return rootScope.managers.appStateManager.setByKey(joinDeepPath('settings', 'stealthMode'), state);
|
||||
}
|
||||
}
|
||||
|
||||
const stealthMode = new StealthMode();
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.stealthMode = stealthMode);
|
||||
export default stealthMode;
|
@ -316,7 +316,7 @@ IMAGE_MIME_TYPES_SUPPORTED_PROMISE.then((mimeTypes) => {
|
||||
I18n.setTimeFormat(stateResult.state.settings.timeFormat);
|
||||
|
||||
rootScope.managers.rootScope.getPremium().then((isPremium) => {
|
||||
rootScope.premium = isPremium;
|
||||
rootScope.premium = true; // isPremium; // octt: force premium to be enabled
|
||||
});
|
||||
|
||||
themeController.setThemeListener();
|
||||
|
@ -1122,6 +1122,7 @@ const lang = {
|
||||
},
|
||||
'HidAccount': 'The account was hidden by the user',
|
||||
'TelegramFeatures': 'Telegram Features',
|
||||
'SpaccogramNewsInfo': 'Spaccogram News & Info',
|
||||
'SetColor': 'Set a color',
|
||||
'Open': 'Open',
|
||||
'OpenUrlTitle': 'Open Link',
|
||||
@ -1478,6 +1479,7 @@ const lang = {
|
||||
'UsernameDeactivateLinkChannelMessage': 'Do you want to hide this link from the channel info page?',
|
||||
'Hide': 'Hide',
|
||||
'Show': 'Show',
|
||||
'Toggle': 'Toggle', // octt
|
||||
'UsernameActivateErrorTitle': 'Too many active links',
|
||||
'UsernameActivateErrorMessage': 'Sorry, you have too many active public links already. Please hide one of your active public links first.',
|
||||
'ChannelSignMessages': 'Sign Messages',
|
||||
|
@ -1217,6 +1217,8 @@ export class AppImManager extends EventListenerBase<{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false; // octt: don't block copy
|
||||
|
||||
e.preventDefault();
|
||||
const peerId = bubble.dataset.peerId.toPeerId();
|
||||
const chat = apiManagerProxy.getChat(peerId.toChatId());
|
||||
|
@ -58,7 +58,7 @@ import getStickerEffectThumb from './utils/stickers/getStickerEffectThumb';
|
||||
import getDocumentInput from './utils/docs/getDocumentInput';
|
||||
import reactionsEqual from './utils/reactions/reactionsEqual';
|
||||
import getPeerActiveUsernames from './utils/peers/getPeerActiveUsernames';
|
||||
import {BroadcastEvents} from '../rootScope';
|
||||
import rootScope, {BroadcastEvents} from '../rootScope';
|
||||
import setBooleanFlag from '../../helpers/object/setBooleanFlag';
|
||||
import getMessageThreadId from './utils/messages/getMessageThreadId';
|
||||
import callbackify from '../../helpers/callbackify';
|
||||
@ -78,6 +78,7 @@ import getMainGroupedMessage from './utils/messages/getMainGroupedMessage';
|
||||
import getUnreadReactions from './utils/messages/getUnreadReactions';
|
||||
import isMentionUnread from './utils/messages/isMentionUnread';
|
||||
import canMessageHaveFactCheck from './utils/messages/canMessageHaveFactCheck';
|
||||
import stealthMode from '../../helpers/stealthMode';
|
||||
|
||||
// console.trace('include');
|
||||
// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках
|
||||
@ -5030,8 +5031,8 @@ export class AppMessagesManager extends AppManager {
|
||||
return Promise.all(promises).then(noop);
|
||||
}
|
||||
|
||||
public readHistory(peerId: PeerId, maxId = 0, threadId?: number, force = false) {
|
||||
if(DO_NOT_READ_HISTORY) {
|
||||
public readHistory(peerId: PeerId, maxId = 0, threadId?: number, force = false, stealthMode: boolean = false) {
|
||||
if(DO_NOT_READ_HISTORY || stealthMode) { // octt: //
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@ -5321,8 +5322,8 @@ export class AppMessagesManager extends AppManager {
|
||||
});
|
||||
}
|
||||
|
||||
public readMessages(peerId: PeerId, msgIds: number[]) {
|
||||
if(DO_NOT_READ_HISTORY) {
|
||||
public readMessages(peerId: PeerId, msgIds: number[], stealthMode: boolean = false) {
|
||||
if(DO_NOT_READ_HISTORY || stealthMode) { // octt: //
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@ -5367,8 +5368,8 @@ export class AppMessagesManager extends AppManager {
|
||||
return promise;
|
||||
}
|
||||
|
||||
public async readMentions(peerId: PeerId, threadId?: number, isReaction?: boolean): Promise<boolean> {
|
||||
if(DO_NOT_READ_HISTORY) {
|
||||
public async readMentions(peerId: PeerId, threadId?: number, isReaction?: boolean, stealthMode: boolean = false): Promise<boolean> {
|
||||
if(DO_NOT_READ_HISTORY || stealthMode) { // octt: //
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -304,6 +304,7 @@ export class AppPeersManager extends AppManager {
|
||||
}
|
||||
|
||||
public noForwards(peerId: PeerId) {
|
||||
return false; // octt: always allow forwards
|
||||
if(peerId.isUser()) return false;
|
||||
else {
|
||||
const chat = this.appChatsManager.getChat(peerId.toChatId());
|
||||
|
@ -2,5 +2,6 @@ import {isRestricted} from '../../../../helpers/restrictions';
|
||||
import {Message} from '../../../../layer';
|
||||
|
||||
export default function isMessageRestricted(message: Message.message) {
|
||||
return false; // octt: make no message appear restricted
|
||||
return !!(message.restriction_reason && isRestricted(message.restriction_reason));
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import {isRestricted} from '../../../../helpers/restrictions';
|
||||
import {Chat, User} from '../../../../layer';
|
||||
|
||||
export default function isPeerRestricted(peer: Chat | User) {
|
||||
return false; // octt: make no chat appear restricted
|
||||
const restrictionReasons = (peer as Chat.channel)?.restriction_reason;
|
||||
return !!(restrictionReasons && (peer as Chat.channel).pFlags.restricted && isRestricted(restrictionReasons));
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ export class RootScope extends EventListenerBase<BroadcastEventsListeners> {
|
||||
}
|
||||
|
||||
public getPremium() {
|
||||
return this.premium;
|
||||
return true; // this.premium; // octt: force premium enabled
|
||||
}
|
||||
|
||||
public dispatchEventSingle(...args: any[]) {
|
||||
|
@ -966,6 +966,7 @@
|
||||
"Stickers_other" = "%1$d stickers";
|
||||
"HidAccount" = "The account was hidden by the user";
|
||||
"TelegramFeatures" = "Telegram Features";
|
||||
"SpaccogramNewsInfo" = "Spaccogram News & Info";
|
||||
"SetColor" = "Set a color";
|
||||
"Open" = "Open";
|
||||
"OpenUrlTitle" = "Open Link";
|
||||
@ -1296,6 +1297,7 @@
|
||||
"UsernameDeactivateLinkChannelMessage" = "Do you want to hide this link from the channel info page?";
|
||||
"Hide" = "Hide";
|
||||
"Show" = "Show";
|
||||
"Toggle" = "Toggle";
|
||||
"UsernameActivateErrorTitle" = "Too many active links";
|
||||
"UsernameActivateErrorMessage" = "Sorry, you have too many active public links already. Please hide one of your active public links first.";
|
||||
"ChannelSignMessages" = "Sign Messages";
|
||||
|
@ -127,14 +127,18 @@ export default function usePeerLanguage(peerId: () => PeerId, onlyIfForeign?: bo
|
||||
return;
|
||||
}
|
||||
|
||||
// octt: fallback translation language, useful for reading restricted chats
|
||||
// TODO add source language selection menu
|
||||
const languageFallback = ('it' as TranslatableLanguageISO);
|
||||
|
||||
_createStore?.();
|
||||
const current = state[_peerId];
|
||||
if(current && current.total < MIN_TOTAL_PROCESSED_MESSAGES && !current.isFull) {
|
||||
return;
|
||||
return languageFallback;
|
||||
}
|
||||
|
||||
if(onlyIfForeign && current && (current.totalForeign / current.total) < MIN_FOREIGN_PERCENTAGE) {
|
||||
return;
|
||||
return languageFallback;
|
||||
}
|
||||
|
||||
return current?.language;
|
||||
|
@ -12,12 +12,12 @@ import {ServerOptions} from 'vite';
|
||||
|
||||
const rootDir = resolve(__dirname);
|
||||
|
||||
const handlebarsPlugin = handlebars({
|
||||
const handlebarsPlugin = handlebars({ // octt: fork branding
|
||||
context: {
|
||||
title: 'Telegram Web',
|
||||
description: 'Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.',
|
||||
url: 'https://web.telegram.org/k/',
|
||||
origin: 'https://web.telegram.org/'
|
||||
title: 'Spaccogram Web', // 'Telegram Web',
|
||||
description: 'Spaccogram Web is an unofficial fork of Telegram Web made for advanced users and developers.', // 'Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.',
|
||||
url: 'https://tweb.octt.eu.org/', // 'https://web.telegram.org/k/',
|
||||
origin: 'https://tweb.octt.eu.org/', // 'https://web.telegram.org/'
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user