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) {
|
||||
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];
|
||||
localDb.documents[l.id] = new GramJs.Document({
|
||||
id: BigInt(l.id),
|
||||
@ -35,7 +35,7 @@ function buildEmojiSounds(appConfig: GramJsAppConfig) {
|
||||
|
||||
acc[key] = l.id;
|
||||
return acc;
|
||||
}, {});
|
||||
}, {}) : {};
|
||||
}
|
||||
|
||||
export function buildApiConfig(json: GramJs.TypeJSONValue): ApiAppConfig {
|
||||
|
@ -21,10 +21,11 @@ import {
|
||||
} from './auth';
|
||||
import { updater } from '../updater';
|
||||
import { setMessageBuilderCurrentUserId } from '../apiBuilders/messages';
|
||||
import downloadMediaWithClient from './media';
|
||||
import downloadMediaWithClient, { parseMediaUrl } from './media';
|
||||
import { buildApiUserFromFull } from '../apiBuilders/users';
|
||||
import localDb from '../localDb';
|
||||
import { buildApiPeerId } from '../apiBuilders/peers';
|
||||
import { addMessageToLocalDb } from '../helpers';
|
||||
|
||||
const DEFAULT_USER_AGENT = 'Unknown UserAgent';
|
||||
const DEFAULT_PLATFORM = 'Unknown platform';
|
||||
@ -265,7 +266,21 @@ export function downloadMedia(
|
||||
args: { url: string; mediaFormat: ApiMediaFormat; start?: number; end?: number; isHtmlAllowed?: boolean },
|
||||
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) {
|
||||
@ -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 {
|
||||
destroy, disconnect, downloadMedia, fetchCurrentUser,
|
||||
destroy, disconnect, downloadMedia, fetchCurrentUser, repairFileReference,
|
||||
} from './client';
|
||||
|
||||
export {
|
||||
|
@ -11,13 +11,8 @@ import {
|
||||
MEDIA_CACHE_NAME_AVATARS,
|
||||
} from '../../../config';
|
||||
import localDb from '../localDb';
|
||||
import { getEntityTypeById } from '../gramjsBuilders';
|
||||
import * as cacheApi from '../../../util/cacheApi';
|
||||
|
||||
type EntityType = (
|
||||
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'channel' | 'chat' | 'user' | 'photo' | 'stickerSet' | 'webDocument' |
|
||||
'document'
|
||||
);
|
||||
import { getEntityTypeById } from '../gramjsBuilders';
|
||||
|
||||
const MEDIA_ENTITY_TYPES = new Set(['msg', 'sticker', 'gif', 'wallpaper', 'photo', 'webDocument', 'document']);
|
||||
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(
|
||||
url: string,
|
||||
client: TelegramClient,
|
||||
@ -74,19 +74,16 @@ async function download(
|
||||
mediaFormat?: ApiMediaFormat,
|
||||
isHtmlAllowed?: boolean,
|
||||
) {
|
||||
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 parsed = parseMediaUrl(url);
|
||||
|
||||
if (mediaMatch[1] === 'file') {
|
||||
const response = await fetch(mediaMatch[2]);
|
||||
if (!parsed) return undefined;
|
||||
|
||||
const {
|
||||
entityType, entityId, sizeType, params, mediaMatchType,
|
||||
} = parsed;
|
||||
|
||||
if (entityType === 'file') {
|
||||
const response = await fetch(entityId);
|
||||
const data = await response.arrayBuffer();
|
||||
return { data };
|
||||
}
|
||||
@ -95,18 +92,8 @@ async function download(
|
||||
return Promise.reject(new Error('ERROR: Client is not connected'));
|
||||
}
|
||||
|
||||
let entityType: EntityType;
|
||||
const entityId: string | number = mediaMatch[2];
|
||||
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];
|
||||
if (entityType === 'staticMap') {
|
||||
const accessHash = entityId;
|
||||
const parsedParams = new URLSearchParams(params);
|
||||
const long = parsedParams.get('long');
|
||||
const lat = parsedParams.get('lat');
|
||||
@ -123,13 +110,11 @@ async function download(
|
||||
};
|
||||
}
|
||||
|
||||
if (mediaMatch[1] === 'avatar' || mediaMatch[1] === 'profile') {
|
||||
entityType = getEntityTypeById(entityId);
|
||||
} else {
|
||||
entityType = mediaMatch[1] as (
|
||||
'msg' | 'sticker' | 'wallpaper' | 'gif' | 'stickerSet' | 'photo' | 'webDocument' | 'document'
|
||||
);
|
||||
}
|
||||
let entity: (
|
||||
GramJs.User | GramJs.Chat | GramJs.Channel | GramJs.Photo |
|
||||
GramJs.Message | GramJs.MessageService |
|
||||
GramJs.Document | GramJs.StickerSet | GramJs.TypeWebDocument | undefined
|
||||
);
|
||||
|
||||
switch (entityType) {
|
||||
case 'channel':
|
||||
@ -209,7 +194,7 @@ async function download(
|
||||
|
||||
return { mimeType, data };
|
||||
} else {
|
||||
const data = await client.downloadProfilePhoto(entity, mediaMatch[1] === 'profile');
|
||||
const data = await client.downloadProfilePhoto(entity, mediaMatchType === 'profile');
|
||||
const mimeType = getMimeType(data);
|
||||
|
||||
return { mimeType, data };
|
||||
@ -310,3 +295,47 @@ function getMimeType(data: Uint8Array, fallbackMimeType = 'image/jpeg') {
|
||||
|
||||
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