mirror of
https://github.com/danog/telegram-tt.git
synced 2024-11-26 20:34:44 +01:00
Properly handle FILE_REFERENCE_EXPIRED
(#1772)
This commit is contained in:
parent
6e0f8de4fc
commit
20f710b345
@ -21,7 +21,7 @@ type GramJsAppConfig = {
|
|||||||
|
|
||||||
function buildEmojiSounds(appConfig: GramJsAppConfig) {
|
function buildEmojiSounds(appConfig: GramJsAppConfig) {
|
||||||
const { emojies_sounds } = appConfig;
|
const { emojies_sounds } = appConfig;
|
||||||
return Object.keys(emojies_sounds).reduce((acc: Record<string, string>, key) => {
|
return emojies_sounds ? Object.keys(emojies_sounds).reduce((acc: Record<string, string>, key) => {
|
||||||
const l = emojies_sounds[key];
|
const l = emojies_sounds[key];
|
||||||
localDb.documents[l.id] = new GramJs.Document({
|
localDb.documents[l.id] = new GramJs.Document({
|
||||||
id: BigInt(l.id),
|
id: BigInt(l.id),
|
||||||
@ -35,7 +35,7 @@ function buildEmojiSounds(appConfig: GramJsAppConfig) {
|
|||||||
|
|
||||||
acc[key] = l.id;
|
acc[key] = l.id;
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {}) : {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildApiConfig(json: GramJs.TypeJSONValue): ApiAppConfig {
|
export function buildApiConfig(json: GramJs.TypeJSONValue): ApiAppConfig {
|
||||||
|
@ -21,10 +21,11 @@ import {
|
|||||||
} from './auth';
|
} from './auth';
|
||||||
import { updater } from '../updater';
|
import { updater } from '../updater';
|
||||||
import { setMessageBuilderCurrentUserId } from '../apiBuilders/messages';
|
import { setMessageBuilderCurrentUserId } from '../apiBuilders/messages';
|
||||||
import downloadMediaWithClient from './media';
|
import downloadMediaWithClient, { parseMediaUrl } from './media';
|
||||||
import { buildApiUserFromFull } from '../apiBuilders/users';
|
import { buildApiUserFromFull } from '../apiBuilders/users';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { buildApiPeerId } from '../apiBuilders/peers';
|
import { buildApiPeerId } from '../apiBuilders/peers';
|
||||||
|
import { addMessageToLocalDb } from '../helpers';
|
||||||
|
|
||||||
const DEFAULT_USER_AGENT = 'Unknown UserAgent';
|
const DEFAULT_USER_AGENT = 'Unknown UserAgent';
|
||||||
const DEFAULT_PLATFORM = 'Unknown platform';
|
const DEFAULT_PLATFORM = 'Unknown platform';
|
||||||
@ -265,7 +266,21 @@ export function downloadMedia(
|
|||||||
args: { url: string; mediaFormat: ApiMediaFormat; start?: number; end?: number; isHtmlAllowed?: boolean },
|
args: { url: string; mediaFormat: ApiMediaFormat; start?: number; end?: number; isHtmlAllowed?: boolean },
|
||||||
onProgress?: ApiOnProgress,
|
onProgress?: ApiOnProgress,
|
||||||
) {
|
) {
|
||||||
return downloadMediaWithClient(args, client, isConnected, onProgress);
|
return downloadMediaWithClient(args, client, isConnected, onProgress).catch(async (err) => {
|
||||||
|
if (err.message.startsWith('FILE_REFERENCE')) {
|
||||||
|
const isFileReferenceRepaired = await repairFileReference({ url: args.url });
|
||||||
|
if (!isFileReferenceRepaired) {
|
||||||
|
if (DEBUG) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('Failed to repair file reference', args.url);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return downloadMediaWithClient(args, client, isConnected, onProgress);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uploadFile(file: File, onProgress?: ApiOnProgress) {
|
export function uploadFile(file: File, onProgress?: ApiOnProgress) {
|
||||||
@ -338,3 +353,50 @@ async function handleTerminatedSession() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function repairFileReference({
|
||||||
|
url,
|
||||||
|
}: {
|
||||||
|
url: string;
|
||||||
|
}) {
|
||||||
|
const parsed = parseMediaUrl(url);
|
||||||
|
|
||||||
|
if (!parsed) return undefined;
|
||||||
|
|
||||||
|
const {
|
||||||
|
entityType, entityId, mediaMatchType,
|
||||||
|
} = parsed;
|
||||||
|
|
||||||
|
if (mediaMatchType === 'file') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityType === 'msg') {
|
||||||
|
const entity = localDb.messages[entityId]!;
|
||||||
|
const messageId = entity.id;
|
||||||
|
|
||||||
|
const peer = 'channelId' in entity.peerId ? new GramJs.InputChannel({
|
||||||
|
channelId: entity.peerId.channelId,
|
||||||
|
accessHash: (localDb.chats[buildApiPeerId(entity.peerId.channelId, 'channel')] as GramJs.Channel).accessHash!,
|
||||||
|
}) : undefined;
|
||||||
|
const result = await invokeRequest(
|
||||||
|
peer
|
||||||
|
? new GramJs.channels.GetMessages({
|
||||||
|
channel: peer,
|
||||||
|
id: [new GramJs.InputMessageID({ id: messageId })],
|
||||||
|
})
|
||||||
|
: new GramJs.messages.GetMessages({
|
||||||
|
id: [new GramJs.InputMessageID({ id: messageId })],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result || result instanceof GramJs.messages.MessagesNotModified) return false;
|
||||||
|
|
||||||
|
const message = result.messages[0];
|
||||||
|
if (message instanceof GramJs.MessageEmpty) return false;
|
||||||
|
addMessageToLocalDb(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export {
|
export {
|
||||||
destroy, disconnect, downloadMedia, fetchCurrentUser,
|
destroy, disconnect, downloadMedia, fetchCurrentUser, repairFileReference,
|
||||||
} from './client';
|
} from './client';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -11,13 +11,8 @@ import {
|
|||||||
MEDIA_CACHE_NAME_AVATARS,
|
MEDIA_CACHE_NAME_AVATARS,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { getEntityTypeById } from '../gramjsBuilders';
|
|
||||||
import * as cacheApi from '../../../util/cacheApi';
|
import * as cacheApi from '../../../util/cacheApi';
|
||||||
|
import { getEntityTypeById } from '../gramjsBuilders';
|
||||||
type EntityType = (
|
|
||||||
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'channel' | 'chat' | 'user' | 'photo' | 'stickerSet' | 'webDocument' |
|
|
||||||
'document'
|
|
||||||
);
|
|
||||||
|
|
||||||
const MEDIA_ENTITY_TYPES = new Set(['msg', 'sticker', 'gif', 'wallpaper', 'photo', 'webDocument', 'document']);
|
const MEDIA_ENTITY_TYPES = new Set(['msg', 'sticker', 'gif', 'wallpaper', 'photo', 'webDocument', 'document']);
|
||||||
const TGS_MIME_TYPE = 'application/x-tgsticker';
|
const TGS_MIME_TYPE = 'application/x-tgsticker';
|
||||||
@ -64,6 +59,11 @@ export default async function downloadMedia(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EntityType = (
|
||||||
|
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'channel' | 'chat' | 'user' | 'photo' | 'stickerSet' | 'webDocument' |
|
||||||
|
'document'
|
||||||
|
);
|
||||||
|
|
||||||
async function download(
|
async function download(
|
||||||
url: string,
|
url: string,
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
@ -74,19 +74,16 @@ async function download(
|
|||||||
mediaFormat?: ApiMediaFormat,
|
mediaFormat?: ApiMediaFormat,
|
||||||
isHtmlAllowed?: boolean,
|
isHtmlAllowed?: boolean,
|
||||||
) {
|
) {
|
||||||
const mediaMatch = url.startsWith('staticMap')
|
const parsed = parseMediaUrl(url);
|
||||||
? url.match(/(staticMap):([0-9-]+)(\?.+)/)
|
|
||||||
: url.startsWith('webDocument')
|
|
||||||
? url.match(/(webDocument):(.+)/)
|
|
||||||
: url.match(
|
|
||||||
/(avatar|profile|photo|msg|stickerSet|sticker|wallpaper|gif|file|document)([-\d\w./]+)(?::\d+)?(\?size=\w+)?/,
|
|
||||||
);
|
|
||||||
if (!mediaMatch) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaMatch[1] === 'file') {
|
if (!parsed) return undefined;
|
||||||
const response = await fetch(mediaMatch[2]);
|
|
||||||
|
const {
|
||||||
|
entityType, entityId, sizeType, params, mediaMatchType,
|
||||||
|
} = parsed;
|
||||||
|
|
||||||
|
if (entityType === 'file') {
|
||||||
|
const response = await fetch(entityId);
|
||||||
const data = await response.arrayBuffer();
|
const data = await response.arrayBuffer();
|
||||||
return { data };
|
return { data };
|
||||||
}
|
}
|
||||||
@ -95,18 +92,8 @@ async function download(
|
|||||||
return Promise.reject(new Error('ERROR: Client is not connected'));
|
return Promise.reject(new Error('ERROR: Client is not connected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
let entityType: EntityType;
|
if (entityType === 'staticMap') {
|
||||||
const entityId: string | number = mediaMatch[2];
|
const accessHash = entityId;
|
||||||
const sizeType = mediaMatch[3] ? mediaMatch[3].replace('?size=', '') : undefined;
|
|
||||||
let entity: (
|
|
||||||
GramJs.User | GramJs.Chat | GramJs.Channel | GramJs.Photo |
|
|
||||||
GramJs.Message | GramJs.MessageService |
|
|
||||||
GramJs.Document | GramJs.StickerSet | GramJs.TypeWebDocument | undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mediaMatch[1] === 'staticMap') {
|
|
||||||
const accessHash = mediaMatch[2];
|
|
||||||
const params = mediaMatch[3];
|
|
||||||
const parsedParams = new URLSearchParams(params);
|
const parsedParams = new URLSearchParams(params);
|
||||||
const long = parsedParams.get('long');
|
const long = parsedParams.get('long');
|
||||||
const lat = parsedParams.get('lat');
|
const lat = parsedParams.get('lat');
|
||||||
@ -123,13 +110,11 @@ async function download(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaMatch[1] === 'avatar' || mediaMatch[1] === 'profile') {
|
let entity: (
|
||||||
entityType = getEntityTypeById(entityId);
|
GramJs.User | GramJs.Chat | GramJs.Channel | GramJs.Photo |
|
||||||
} else {
|
GramJs.Message | GramJs.MessageService |
|
||||||
entityType = mediaMatch[1] as (
|
GramJs.Document | GramJs.StickerSet | GramJs.TypeWebDocument | undefined
|
||||||
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'stickerSet' | 'photo' | 'webDocument' | 'document'
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (entityType) {
|
switch (entityType) {
|
||||||
case 'channel':
|
case 'channel':
|
||||||
@ -209,7 +194,7 @@ async function download(
|
|||||||
|
|
||||||
return { mimeType, data };
|
return { mimeType, data };
|
||||||
} else {
|
} else {
|
||||||
const data = await client.downloadProfilePhoto(entity, mediaMatch[1] === 'profile');
|
const data = await client.downloadProfilePhoto(entity, mediaMatchType === 'profile');
|
||||||
const mimeType = getMimeType(data);
|
const mimeType = getMimeType(data);
|
||||||
|
|
||||||
return { mimeType, data };
|
return { mimeType, data };
|
||||||
@ -310,3 +295,47 @@ function getMimeType(data: Uint8Array, fallbackMimeType = 'image/jpeg') {
|
|||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseMediaUrl(url: string) {
|
||||||
|
const mediaMatch = url.startsWith('staticMap')
|
||||||
|
? url.match(/(staticMap):([0-9-]+)(\?.+)/)
|
||||||
|
: url.startsWith('webDocument')
|
||||||
|
? url.match(/(webDocument):(.+)/)
|
||||||
|
: url.match(
|
||||||
|
/(avatar|profile|photo|msg|stickerSet|sticker|wallpaper|gif|file|document)([-\d\w./]+)(?::\d+)?(\?size=\w+)?/,
|
||||||
|
);
|
||||||
|
if (!mediaMatch) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mediaMatchType = mediaMatch[1];
|
||||||
|
const entityId: string | number = mediaMatch[2];
|
||||||
|
|
||||||
|
if (mediaMatchType === 'file') {
|
||||||
|
return {
|
||||||
|
mediaMatchType,
|
||||||
|
entityType: 'file',
|
||||||
|
entityId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let entityType: EntityType;
|
||||||
|
const params = mediaMatch[3];
|
||||||
|
const sizeType = params?.replace('?size=', '') || undefined;
|
||||||
|
|
||||||
|
if (mediaMatch[1] === 'avatar' || mediaMatch[1] === 'profile') {
|
||||||
|
entityType = getEntityTypeById(entityId);
|
||||||
|
} else {
|
||||||
|
entityType = mediaMatch[1] as (
|
||||||
|
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'stickerSet' | 'photo' | 'webDocument' | 'document'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mediaMatchType,
|
||||||
|
entityType,
|
||||||
|
entityId,
|
||||||
|
sizeType,
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user