Web Page: Support media repair (#6321)

This commit is contained in:
zubiden 2025-10-08 12:33:22 +02:00 committed by Alexander Zinchuk
parent cccde14f59
commit f0f9993ebd
9 changed files with 91 additions and 26 deletions

View File

@ -25,14 +25,14 @@ export function addMessageToLocalDb(message: GramJs.TypeMessage | GramJs.TypeSpo
} }
} }
export function addWebPageMediaToLocalDb(webPage: GramJs.TypeWebPage, context?: MediaRepairContext) { export function addWebPageMediaToLocalDb(webPage: GramJs.TypeWebPage) {
if (webPage instanceof GramJs.WebPage) { if (webPage instanceof GramJs.WebPage) {
if (webPage.document) { if (webPage.document) {
const document = addMessageRepairInfo(webPage.document, context); const document = addWebPageRepairInfo(webPage.document, webPage);
addDocumentToLocalDb(document); addDocumentToLocalDb(document);
} }
if (webPage.photo) { if (webPage.photo) {
const photo = addMessageRepairInfo(webPage.photo, context); const photo = addWebPageRepairInfo(webPage.photo, webPage);
addPhotoToLocalDb(photo); addPhotoToLocalDb(photo);
} }
} }
@ -146,6 +146,22 @@ export function addMessageRepairInfo<T extends GramJs.TypeDocument | GramJs.Type
return repairableMedia; return repairableMedia;
} }
export function addWebPageRepairInfo<T extends GramJs.TypeDocument | GramJs.TypeWebDocument | GramJs.TypePhoto>(
media: T, webPage?: GramJs.TypeWebPage,
): T & RepairInfo {
if (!(webPage instanceof GramJs.WebPage)) return media;
if (!(media instanceof GramJs.Document || media instanceof GramJs.Photo || media instanceof GramJs.WebDocument)) {
return media;
}
const repairableMedia = media as T & RepairInfo;
repairableMedia.localRepairInfo = {
type: 'webPage',
url: webPage.url,
};
return repairableMedia;
}
export function addChatToLocalDb(chat: GramJs.Chat | GramJs.Channel) { export function addChatToLocalDb(chat: GramJs.Chat | GramJs.Channel) {
const id = buildApiPeerId(chat.id, chat instanceof GramJs.Chat ? 'chat' : 'channel'); const id = buildApiPeerId(chat.id, chat instanceof GramJs.Chat ? 'chat' : 'channel');
const storedChat = localDb.chats[id]; const storedChat = localDb.chats[id];

View File

@ -18,8 +18,13 @@ export type MessageRepairInfo = {
id: number; id: number;
}; };
export type WebPageRepairInfo = {
type: 'webPage';
url: string;
};
export type RepairInfo = { export type RepairInfo = {
localRepairInfo?: StoryRepairInfo | MessageRepairInfo; localRepairInfo?: StoryRepairInfo | MessageRepairInfo | WebPageRepairInfo;
}; };
export interface LocalDb { export interface LocalDb {

View File

@ -21,6 +21,7 @@ import {
DEBUG, DEBUG_GRAMJS, IS_TEST, LANG_PACK, UPLOAD_WORKERS, DEBUG, DEBUG_GRAMJS, IS_TEST, LANG_PACK, UPLOAD_WORKERS,
} from '../../../config'; } from '../../../config';
import { pause } from '../../../util/schedulers'; import { pause } from '../../../util/schedulers';
import { buildWebPage } from '../apiBuilders/messageContent';
import { import {
buildApiMessage, buildApiMessage,
setMessageBuilderCurrentUserId, setMessageBuilderCurrentUserId,
@ -28,9 +29,15 @@ import {
import { buildApiPeerId } from '../apiBuilders/peers'; import { buildApiPeerId } from '../apiBuilders/peers';
import { buildApiStory } from '../apiBuilders/stories'; import { buildApiStory } from '../apiBuilders/stories';
import { buildApiUser, buildApiUserFullInfo } from '../apiBuilders/users'; import { buildApiUser, buildApiUserFullInfo } from '../apiBuilders/users';
import { buildInputChannelFromLocalDb, buildInputPeerFromLocalDb, getEntityTypeById } from '../gramjsBuilders'; import {
buildInputChannelFromLocalDb,
buildInputPeerFromLocalDb,
DEFAULT_PRIMITIVES,
getEntityTypeById,
} from '../gramjsBuilders';
import { import {
addStoryToLocalDb, addUserToLocalDb, addStoryToLocalDb, addUserToLocalDb,
addWebPageMediaToLocalDb,
} from '../helpers/localDb'; } from '../helpers/localDb';
import { import {
isResponseUpdate, log, isResponseUpdate, log,
@ -522,6 +529,11 @@ export async function repairFileReference({
const result = await repairMessageMedia(localRepairInfo.peerId, localRepairInfo.id); const result = await repairMessageMedia(localRepairInfo.peerId, localRepairInfo.id);
return result; return result;
} }
if (localRepairInfo.type === 'webPage') {
const result = await repairWebPageMedia(localRepairInfo.url);
return result;
}
} }
return false; return false;
@ -599,6 +611,27 @@ async function repairStoryMedia(peerId: string, storyId: number) {
return true; return true;
} }
export async function repairWebPageMedia(url: string) {
const result = await invokeRequest(new GramJs.messages.GetWebPage({
url,
hash: DEFAULT_PRIMITIVES.INT,
}), {
shouldIgnoreErrors: true,
});
if (!result?.webpage) return false;
const webPage = buildWebPage(result.webpage);
if (!webPage) return false;
addWebPageMediaToLocalDb(result.webpage);
sendApiUpdate({
'@type': 'updateWebPage',
webPage,
});
return webPage.webpageType === 'full';
}
export function setForceHttpTransport(forceHttpTransport: boolean) { export function setForceHttpTransport(forceHttpTransport: boolean) {
client.setForceHttpTransport(forceHttpTransport); client.setForceHttpTransport(forceHttpTransport);
} }

View File

@ -574,7 +574,8 @@
"MemberRequestsRequestToJoinDescriptionChannel" = "This channel accepts new subscribers only after they are approved by its admins."; "MemberRequestsRequestToJoinDescriptionChannel" = "This channel accepts new subscribers only after they are approved by its admins.";
"MemberRequestsRequestToJoinDescriptionGroup" = "This group accepts new members only after they are approved by its admins."; "MemberRequestsRequestToJoinDescriptionGroup" = "This group accepts new members only after they are approved by its admins.";
"ShareYouPhoneNumberTitle" = "Share your phone number?"; "ShareYouPhoneNumberTitle" = "Share your phone number?";
"AreYouSureShareMyContactInfoBot" = "The bot will know your phone number. This can be useful for integration with other services."; "AreYouSureShareMyContactInfoBot" = "The bot will know your phone number. This can be useful for integration with other services.\n\n⚠ Warning! Never enter your Telegram login codes in mini apps.";
"ContactShare" = "Share Contact";
"OK" = "OK"; "OK" = "OK";
"ForwardTo" = "Forward to..."; "ForwardTo" = "Forward to...";
"AttachGame" = "Game"; "AttachGame" = "Game";
@ -752,7 +753,6 @@
"PollsStopSure" = "Stop"; "PollsStopSure" = "Stop";
"PaymentTestInvoice" = "TEST INVOICE"; "PaymentTestInvoice" = "TEST INVOICE";
"PaymentInvoiceNotFound" = "Invoice not found"; "PaymentInvoiceNotFound" = "Invoice not found";
"AttachLiveLocation" = "Live Location";
"NoWordsRecognized" = "No words recognized."; "NoWordsRecognized" = "No words recognized.";
"ViaBot" = "via"; "ViaBot" = "via";
"DiscussChannel" = "channel"; "DiscussChannel" = "channel";
@ -1117,6 +1117,7 @@
"AttachStory" = "Story"; "AttachStory" = "Story";
"AttachInvoice" = "Invoice: {description}"; "AttachInvoice" = "Invoice: {description}";
"AttachLocation" = "Location"; "AttachLocation" = "Location";
"AttachLiveLocation" = "Live Location";
"AttachGiveaway" = "Giveaway"; "AttachGiveaway" = "Giveaway";
"AttachGiveawayResults" = "Giveaway Results"; "AttachGiveawayResults" = "Giveaway Results";
"AttachTodo" = "Checklist"; "AttachTodo" = "Checklist";
@ -1478,9 +1479,9 @@
"GiftInfoDescriptionConverted_other" = "You converted this gift to **{amount}** Stars."; "GiftInfoDescriptionConverted_other" = "You converted this gift to **{amount}** Stars.";
"GiftInfoPeerDescriptionOutConverted_one" = "{peer} converted this gift to **{amount}** Star."; "GiftInfoPeerDescriptionOutConverted_one" = "{peer} converted this gift to **{amount}** Star.";
"GiftInfoPeerDescriptionOutConverted_other" = "{peer} converted this gift to **{amount}** Stars."; "GiftInfoPeerDescriptionOutConverted_other" = "{peer} converted this gift to **{amount}** Stars.";
"GiftInfoDescriptionFreeUpgrade" = "Upgrade this gift for free to turn it to a unique collectible."; "GiftInfoDescriptionFreeUpgrade" = "Upgrade this gift for free to turn it into a unique collectible.";
"GiftInfoDescriptionUpgrade2" = "Upgrade this gift to turn it to a unique collectible."; "GiftInfoDescriptionUpgrade2" = "Upgrade this gift to turn it to a unique collectible.";
"GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift to a unique collectible"; "GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift into a unique collectible";
"GiftInfoDescriptionUpgraded" = "This gift was turned into a unique collectible."; "GiftInfoDescriptionUpgraded" = "This gift was turned into a unique collectible.";
"GiftInfoFrom" = "From"; "GiftInfoFrom" = "From";
"GiftInfoDate" = "Date"; "GiftInfoDate" = "Date";
@ -1877,8 +1878,8 @@
"ActionStarGiftChannelText" = "Add this gift to your channel's profile or convert it to {amount}."; "ActionStarGiftChannelText" = "Add this gift to your channel's profile or convert it to {amount}.";
"ActionStarGiftDisplaying" = "You added this gift to your profile."; "ActionStarGiftDisplaying" = "You added this gift to your profile.";
"ActionStarGiftChannelDisplaying" = "This gift is displayed to visitors of your channel."; "ActionStarGiftChannelDisplaying" = "This gift is displayed to visitors of your channel.";
"ActionStarGiftUpgradeText" = "{peer} can turn this gift to a unique collectible."; "ActionStarGiftUpgradeText" = "{peer} can turn this gift into a unique collectible.";
"ActionStarGiftUpgradeTextYou" = "Tap “Unpack” to turn this gift to a unique collectible."; "ActionStarGiftUpgradeTextYou" = "Tap “Unpack” to turn this gift into a unique collectible.";
"ActionStarGiftUpgraded" = "This gift was upgraded."; "ActionStarGiftUpgraded" = "This gift was upgraded.";
"ActionStarGiftUnpack" = "Unpack"; "ActionStarGiftUnpack" = "Unpack";
"ActionStarGiftLimitedRibbon" = "1 of {total}"; "ActionStarGiftLimitedRibbon" = "1 of {total}";
@ -1973,7 +1974,7 @@
"GiftPremiumDescriptionYourBalance" = "Your balance is **{stars}**. {link}"; "GiftPremiumDescriptionYourBalance" = "Your balance is **{stars}**. {link}";
"StarsGiftCompleted" = "Gift sent!"; "StarsGiftCompleted" = "Gift sent!";
"GiftSent" = "Gift sent!"; "GiftSent" = "Gift sent!";
"PrivacyDescriptionMessagesContactsAndPremium" = "You can restrict messages from users who are not in your contacts and don't have Premium."; "PrivacyDescriptionMessagesContactsAndPremium" = "You can restrict messages from users who are not in your contacts and whom you haven't messaged first.";
"PrivacyChargeForMessages" = "Charge for Messages"; "PrivacyChargeForMessages" = "Charge for Messages";
"PrivacyDescriptionChargeForMessages" = "Charge a fee for messages from people outside your contacts or those you haven't messaged first."; "PrivacyDescriptionChargeForMessages" = "Charge a fee for messages from people outside your contacts or those you haven't messaged first.";
"RemoveFeeTitle" = "Remove Fee"; "RemoveFeeTitle" = "Remove Fee";
@ -2201,7 +2202,7 @@
"DescriptionAboutTon" = "Offer TON to submit post suggestions to channels on Telegram."; "DescriptionAboutTon" = "Offer TON to submit post suggestions to channels on Telegram.";
"ButtonTopUpViaFragment" = "Top Up Via Fragment"; "ButtonTopUpViaFragment" = "Top Up Via Fragment";
"TonModalHint" = "You can top up your TON using Fragment."; "TonModalHint" = "You can top up your TON using Fragment.";
"TonGiftReceived" = "TON Top Up"; "TonGiftReceived" = "TON Top-Up";
"MediaSpoilerSensitive" = "18+"; "MediaSpoilerSensitive" = "18+";
"TitleSensitiveModal" = "{years}+ content"; "TitleSensitiveModal" = "{years}+ content";
"TextSensitiveModal" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?"; "TextSensitiveModal" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?";
@ -2215,8 +2216,8 @@
"TitleAgeCheckSuccess" = "Age Check Success"; "TitleAgeCheckSuccess" = "Age Check Success";
"ButtonAgeVerification" = "Verify My Age"; "ButtonAgeVerification" = "Verify My Age";
"GiftRibbonPremium" = "premium"; "GiftRibbonPremium" = "premium";
"NotificationGiftsLimit2_one" = "You've already sent **one** of these gifts, and it's the limit."; "NotificationGiftsLimit2_one" = "You already sent **one** of these gifts, which is the limit.";
"NotificationGiftsLimit2_other" = "You've already sent {count} of these gifts, and it's the limit."; "NotificationGiftsLimit2_other" = "You already sent **{count}** of these gifts, which is the limit.";
"PremiumGiftHeader" = "Premium Gift"; "PremiumGiftHeader" = "Premium Gift";
"DescriptionGiftPremiumRequired2_one" = "Subscribe to **Telegram Premium** to send **one** of these gifts and unlock powerful features."; "DescriptionGiftPremiumRequired2_one" = "Subscribe to **Telegram Premium** to send **one** of these gifts and unlock powerful features.";
"DescriptionGiftPremiumRequired2_other" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock powerful features."; "DescriptionGiftPremiumRequired2_other" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock powerful features.";
@ -2257,7 +2258,7 @@
"PostsSearchTransaction" = "Posts Search"; "PostsSearchTransaction" = "Posts Search";
"AllStoriesCategory" = "All stories"; "AllStoriesCategory" = "All stories";
"TitleRating" = "Rating"; "TitleRating" = "Rating";
"RatingReflectsActivity" = "This rating reflects {name}'s activity on Telegram. It is based on:"; "RatingReflectsActivity" = "This rating reflects **{name}'s** activity on Telegram. It is based on:";
"RatingYourReflectsActivity" = "This rating reflects your activity on Telegram. It is based on:"; "RatingYourReflectsActivity" = "This rating reflects your activity on Telegram. It is based on:";
"RatingGiftsFromTelegram" = "Gifts from Telegram"; "RatingGiftsFromTelegram" = "Gifts from Telegram";
"RatingGiftsFromTelegramDesc" = "100% of the Stars spent on gifts purchased from Telegram."; "RatingGiftsFromTelegramDesc" = "100% of the Stars spent on gifts purchased from Telegram.";

View File

@ -12,7 +12,7 @@ import getReadableErrorText from '../../util/getReadableErrorText';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import useOldLang from '../../hooks/useOldLang'; import useLang from '../../hooks/useLang';
import Button from '../ui/Button'; import Button from '../ui/Button';
import Modal from '../ui/Modal'; import Modal from '../ui/Modal';
@ -29,7 +29,7 @@ const Dialogs: FC<StateProps> = ({ dialogs, currentMessageList }) => {
} = getActions(); } = getActions();
const [isModalOpen, openModal, closeModal] = useFlag(); const [isModalOpen, openModal, closeModal] = useFlag();
const lang = useOldLang(); const lang = useLang();
useEffect(() => { useEffect(() => {
if (dialogs.length > 0) { if (dialogs.length > 0) {
@ -62,7 +62,11 @@ const Dialogs: FC<StateProps> = ({ dialogs, currentMessageList }) => {
title={lang('ShareYouPhoneNumberTitle')} title={lang('ShareYouPhoneNumberTitle')}
onCloseAnimationEnd={dismissDialog} onCloseAnimationEnd={dismissDialog}
> >
{lang('AreYouSureShareMyContactInfoBot')} {lang(
'AreYouSureShareMyContactInfoBot',
undefined,
{ withNodes: true, withMarkdown: true, renderTextFilters: ['br', 'emoji'],
})}
<div className="dialog-buttons mt-2"> <div className="dialog-buttons mt-2">
<Button <Button
className="confirm-dialog-button" className="confirm-dialog-button"

View File

@ -1138,10 +1138,14 @@ const WebAppModalTabContent: FC<OwnProps & StateProps> = ({
<ConfirmDialog <ConfirmDialog
isOpen={isRequestingPhone} isOpen={isRequestingPhone}
onClose={handleRejectPhone} onClose={handleRejectPhone}
title={oldLang('ShareYouPhoneNumberTitle')} title={lang('ShareYouPhoneNumberTitle')}
text={oldLang('AreYouSureShareMyContactInfoBot')} textParts={lang(
'AreYouSureShareMyContactInfoBot',
undefined,
{ withNodes: true, withMarkdown: true, renderTextFilters: ['br', 'emoji'],
})}
confirmHandler={handleAcceptPhone} confirmHandler={handleAcceptPhone}
confirmLabel={oldLang('ContactShare')} confirmLabel={lang('ContactShare')}
/> />
<ConfirmDialog <ConfirmDialog
isOpen={isRequestingWriteAccess} isOpen={isRequestingWriteAccess}

View File

@ -26,7 +26,7 @@ export const DEBUG = process.env.APP_ENV !== 'production';
export const DEBUG_MORE = false; export const DEBUG_MORE = false;
export const DEBUG_LOG_FILENAME = 'tt-log.json'; export const DEBUG_LOG_FILENAME = 'tt-log.json';
export const STRICTERDOM_ENABLED = DEBUG; export const STRICTERDOM_ENABLED = DEBUG;
export const BOT_VERIFICATION_PEERS_LIMIT = 20; export const FORCE_FALLBACK_LANG = false;
export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebA-Beta-03-20'; export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebA-Beta-03-20';
@ -364,6 +364,7 @@ export const GIVEAWAY_MAX_ADDITIONAL_COUNTRIES = 10;
export const BOOST_PER_SENT_GIFT = 3; export const BOOST_PER_SENT_GIFT = 3;
export const FRAGMENT_PHONE_CODE = '888'; export const FRAGMENT_PHONE_CODE = '888';
export const FRAGMENT_PHONE_LENGTH = 11; export const FRAGMENT_PHONE_LENGTH = 11;
export const BOT_VERIFICATION_PEERS_LIMIT = 20;
export const LIGHT_THEME_BG_COLOR = '#99BA92'; export const LIGHT_THEME_BG_COLOR = '#99BA92';
export const DARK_THEME_BG_COLOR = '#0F0F0F'; export const DARK_THEME_BG_COLOR = '#0F0F0F';

View File

@ -516,6 +516,7 @@ export interface LangPair {
'MemberRequestsRequestToJoinDescriptionGroup': undefined; 'MemberRequestsRequestToJoinDescriptionGroup': undefined;
'ShareYouPhoneNumberTitle': undefined; 'ShareYouPhoneNumberTitle': undefined;
'AreYouSureShareMyContactInfoBot': undefined; 'AreYouSureShareMyContactInfoBot': undefined;
'ContactShare': undefined;
'OK': undefined; 'OK': undefined;
'ForwardTo': undefined; 'ForwardTo': undefined;
'AttachGame': undefined; 'AttachGame': undefined;
@ -664,7 +665,6 @@ export interface LangPair {
'PollsStopSure': undefined; 'PollsStopSure': undefined;
'PaymentTestInvoice': undefined; 'PaymentTestInvoice': undefined;
'PaymentInvoiceNotFound': undefined; 'PaymentInvoiceNotFound': undefined;
'AttachLiveLocation': undefined;
'NoWordsRecognized': undefined; 'NoWordsRecognized': undefined;
'ViaBot': undefined; 'ViaBot': undefined;
'DiscussChannel': undefined; 'DiscussChannel': undefined;
@ -964,6 +964,7 @@ export interface LangPair {
'AttachContact': undefined; 'AttachContact': undefined;
'AttachStory': undefined; 'AttachStory': undefined;
'AttachLocation': undefined; 'AttachLocation': undefined;
'AttachLiveLocation': undefined;
'AttachGiveaway': undefined; 'AttachGiveaway': undefined;
'AttachGiveawayResults': undefined; 'AttachGiveawayResults': undefined;
'AttachTodo': undefined; 'AttachTodo': undefined;

View File

@ -22,7 +22,7 @@ import {
type RegularLangFnParameters, type RegularLangFnParameters,
} from './types'; } from './types';
import { DEBUG, LANG_PACK } from '../../config'; import { DEBUG, FORCE_FALLBACK_LANG, LANG_PACK } from '../../config';
import { callApi } from '../../api/gramjs'; import { callApi } from '../../api/gramjs';
import renderText from '../../components/common/helpers/renderText'; import renderText from '../../components/common/helpers/renderText';
import { IS_INTL_LIST_FORMAT_SUPPORTED } from '../browser/globalEnvironment'; import { IS_INTL_LIST_FORMAT_SUPPORTED } from '../browser/globalEnvironment';
@ -344,7 +344,7 @@ export function getTranslationFn(): LangFn {
} }
function getString(langKey: LangKey, count: number) { function getString(langKey: LangKey, count: number) {
let langPackStringValue = langPack?.strings[langKey]; let langPackStringValue = !FORCE_FALLBACK_LANG ? langPack?.strings[langKey] : undefined;
if (!langPackStringValue && !fallbackLangPack) { if (!langPackStringValue && !fallbackLangPack) {
loadFallbackPack(); loadFallbackPack();