288 lines
7.8 KiB
TypeScript

import { Api as GramJs } from '../../../lib/gramjs';
import { strippedPhotoToJpg } from '../../../lib/gramjs/Utils';
import type { ApiPrivacySettings, PrivacyVisibility } from '../../../types';
import type {
ApiFormattedText,
ApiMessageEntity,
ApiMessageEntityDefault,
ApiPhoto,
ApiPhotoSize,
ApiThumbnail,
ApiUsername,
ApiVideoSize,
} from '../../types';
import {
ApiMessageEntityTypes,
} from '../../types';
import { compact } from '../../../util/iteratees';
import localDb from '../localDb';
import { bytesToDataUri } from './helpers';
import { pathBytesToSvg } from './pathBytesToSvg';
import { buildApiPeerId } from './peers';
const DEFAULT_THUMB_SIZE = { w: 100, h: 100 };
export function buildApiThumbnailFromStripped(
sizes?: GramJs.TypePhotoSize[], mimeType?: string,
): ApiThumbnail | undefined {
if (!sizes || !sizes.length) {
return undefined;
}
const thumb = sizes.find((s: any): s is GramJs.PhotoStrippedSize => s instanceof GramJs.PhotoStrippedSize);
if (!thumb) {
return undefined;
}
const realSizes = sizes.filter((s): s is GramJs.PhotoSize => s instanceof GramJs.PhotoSize);
const { w, h } = realSizes.length ? realSizes[realSizes.length - 1] : DEFAULT_THUMB_SIZE;
const { bytes } = thumb;
const dataUri = bytesToDataUri(
!mimeType || mimeType === 'image/jpeg' ? strippedPhotoToJpg(bytes) : bytes,
undefined,
mimeType,
);
return {
dataUri,
width: w,
height: h,
};
}
export function buildApiThumbnailFromCached(photoSize: GramJs.PhotoCachedSize): ApiThumbnail | undefined {
const { w, h, bytes } = photoSize;
const dataUri = bytesToDataUri(bytes, undefined, 'image/webp');
return {
dataUri,
width: w,
height: h,
};
}
export function buildApiThumbnailFromPath(
photoSize: GramJs.PhotoPathSize,
sizeAttribute: GramJs.DocumentAttributeImageSize | GramJs.DocumentAttributeVideo,
): ApiThumbnail | undefined {
const { w, h } = sizeAttribute;
const dataUri = `data:image/svg+xml;utf8,${pathBytesToSvg(photoSize.bytes, w, h)}`;
return {
dataUri,
width: w,
height: h,
};
}
export function buildApiPhoto(photo: GramJs.Photo, isSpoiler?: boolean): ApiPhoto {
const sizes = photo.sizes
.filter((s: any): s is GramJs.PhotoSize => {
return s instanceof GramJs.PhotoSize || s instanceof GramJs.PhotoSizeProgressive;
})
.map(buildApiPhotoSize);
return {
mediaType: 'photo',
id: String(photo.id),
thumbnail: buildApiThumbnailFromStripped(photo.sizes),
sizes,
isSpoiler,
date: photo.date,
...(photo.videoSizes && { videoSizes: compact(photo.videoSizes.map(buildApiVideoSize)), isVideo: true }),
};
}
export function buildApiVideoSize(videoSize: GramJs.TypeVideoSize): ApiVideoSize | undefined {
if (!(videoSize instanceof GramJs.VideoSize)) return undefined;
const {
videoStartTs, size, h, w, type,
} = videoSize;
return {
videoStartTs,
size,
height: h,
width: w,
type: type as ('u' | 'v'),
};
}
export function buildApiPhotoSize(photoSize: GramJs.PhotoSize): ApiPhotoSize {
const { w, h, type } = photoSize;
return {
width: w,
height: h,
type: type as ('s' | 'm' | 'x' | 'y' | 'w'),
};
}
export function buildApiUsernames(mtpPeer: GramJs.User | GramJs.Channel | GramJs.UpdateUserName) {
if (!mtpPeer.usernames && !('username' in mtpPeer && mtpPeer.username)) {
return undefined;
}
const usernames: ApiUsername[] = [];
if ('username' in mtpPeer && mtpPeer.username) {
usernames.push({
username: mtpPeer.username,
isActive: true,
isEditable: true,
});
}
if (mtpPeer.usernames) {
mtpPeer.usernames.forEach(({ username, active, editable }) => {
usernames.push({
username,
...(active && { isActive: true }),
...(editable && { isEditable: true }),
});
});
}
return usernames;
}
export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySettings {
let visibility: PrivacyVisibility | undefined;
let isUnspecified: boolean | undefined;
let allowUserIds: string[] | undefined;
let allowChatIds: string[] | undefined;
let blockUserIds: string[] | undefined;
let blockChatIds: string[] | undefined;
let shouldAllowPremium: true | undefined;
const localChats = localDb.chats;
rules.forEach((rule) => {
if (rule instanceof GramJs.PrivacyValueAllowAll) {
visibility ||= 'everybody';
} else if (rule instanceof GramJs.PrivacyValueAllowContacts) {
visibility ||= 'contacts';
} else if (rule instanceof GramJs.PrivacyValueAllowCloseFriends) {
visibility ||= 'closeFriends';
} else if (rule instanceof GramJs.PrivacyValueDisallowContacts) {
visibility ||= 'nonContacts';
} else if (rule instanceof GramJs.PrivacyValueDisallowAll) {
visibility ||= 'nobody';
} else if (rule instanceof GramJs.PrivacyValueAllowUsers) {
allowUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueDisallowUsers) {
blockUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueAllowChatParticipants) {
// Server allows channel ids here, so we need to check
allowChatIds = rule.chats.map((chatId) => {
const dialogId = buildApiPeerId(chatId, 'chat');
const channelId = buildApiPeerId(chatId, 'channel');
if (localChats[dialogId]) return dialogId;
return channelId;
});
} else if (rule instanceof GramJs.PrivacyValueDisallowChatParticipants) {
blockChatIds = rule.chats.map((chatId) => {
const dialogId = buildApiPeerId(chatId, 'chat');
const channelId = buildApiPeerId(chatId, 'channel');
if (localChats[dialogId]) return dialogId;
return channelId;
});
} else if (rule instanceof GramJs.PrivacyValueAllowPremium) {
shouldAllowPremium = true;
}
});
if (!visibility) {
// Disallow by default
visibility = 'nobody';
isUnspecified = true;
}
return {
visibility,
isUnspecified,
allowUserIds: allowUserIds || [],
allowChatIds: allowChatIds || [],
blockUserIds: blockUserIds || [],
blockChatIds: blockChatIds || [],
shouldAllowPremium,
};
}
export function buildApiFormattedText(textWithEntities: GramJs.TextWithEntities): ApiFormattedText {
const { text, entities } = textWithEntities;
return {
text,
entities: entities.map(buildApiMessageEntity),
};
}
export function buildApiMessageEntity(entity: GramJs.TypeMessageEntity): ApiMessageEntity {
const {
className: type, offset, length,
} = entity;
if (entity instanceof GramJs.MessageEntityMentionName) {
return {
type: ApiMessageEntityTypes.MentionName,
offset,
length,
userId: buildApiPeerId(entity.userId, 'user'),
};
}
if (entity instanceof GramJs.MessageEntityTextUrl) {
return {
type: ApiMessageEntityTypes.TextUrl,
offset,
length,
url: entity.url,
};
}
if (entity instanceof GramJs.MessageEntityPre) {
return {
type: ApiMessageEntityTypes.Pre,
offset,
length,
language: entity.language,
};
}
if (entity instanceof GramJs.MessageEntityCustomEmoji) {
return {
type: ApiMessageEntityTypes.CustomEmoji,
offset,
length,
documentId: entity.documentId.toString(),
};
}
if (entity instanceof GramJs.MessageEntityBlockquote) {
return {
type: ApiMessageEntityTypes.Blockquote,
canCollapse: entity.collapsed,
offset,
length,
};
}
return {
type: type as `${ApiMessageEntityDefault['type']}`,
offset,
length,
};
}
export function buildAvatarPhotoId(photo: GramJs.TypeUserProfilePhoto | GramJs.TypeChatPhoto) {
if ('photoId' in photo) {
return photo.photoId.toString();
}
return undefined;
}