Video: Display .mov as document when playing not supported (#1455)

This commit is contained in:
Alexander Zinchuk 2021-09-24 14:37:23 +03:00
parent 135db2345b
commit 2de5600602
11 changed files with 77 additions and 22 deletions

View File

@ -23,7 +23,14 @@ import {
ApiInvoice,
} from '../../types';
import { DELETED_COMMENTS_CHANNEL_ID, LOCAL_MESSAGE_ID_BASE, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
import {
DELETED_COMMENTS_CHANNEL_ID,
LOCAL_MESSAGE_ID_BASE,
SERVICE_NOTIFICATIONS_USER_ID,
SUPPORTED_IMAGE_CONTENT_TYPES,
SUPPORTED_VIDEO_CONTENT_TYPES,
VIDEO_MOV_TYPE,
} from '../../../config';
import { pick } from '../../../util/iteratees';
import { getApiChatIdFromMtpPeer } from './chats';
import { buildStickerFromDocument } from './symbols';
@ -286,6 +293,11 @@ export function buildVideoFromDocument(document: GramJs.Document): ApiVideo | un
id, mimeType, thumbs, size, attributes,
} = document;
// eslint-disable-next-line no-restricted-globals
if (mimeType === VIDEO_MOV_TYPE && !(self as any).isMovSupported) {
return undefined;
}
const videoAttr = attributes
.find((a: any): a is GramJs.DocumentAttributeVideo => a instanceof GramJs.DocumentAttributeVideo);
@ -419,7 +431,7 @@ export function buildApiDocument(document: GramJs.TypeDocument): ApiDocument | u
height: photoSize.h,
};
if (mimeType.startsWith('image/')) {
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
mediaType = 'photo';
const imageAttribute = attributes
@ -432,7 +444,7 @@ export function buildApiDocument(document: GramJs.TypeDocument): ApiDocument | u
height,
};
}
} else if (mimeType.startsWith('video/')) {
} else if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
mediaType = 'video';
}
}

View File

@ -44,9 +44,14 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
onUpdate = _onUpdate;
const { userAgent, platform, sessionData } = initialArgs;
const {
userAgent, platform, sessionData, isMovSupported,
} = initialArgs;
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
// eslint-disable-next-line no-restricted-globals
(self as any).isMovSupported = isMovSupported;
client = new TelegramClient(
session,
process.env.TELEGRAM_T_API_ID,

View File

@ -18,7 +18,13 @@ import {
ApiReportReason,
} from '../../types';
import { ALL_FOLDER_ID, DEBUG, PINNED_MESSAGES_LIMIT } from '../../../config';
import {
ALL_FOLDER_ID,
DEBUG,
PINNED_MESSAGES_LIMIT,
SUPPORTED_IMAGE_CONTENT_TYPES,
SUPPORTED_VIDEO_CONTENT_TYPES,
} from '../../../config';
import { invokeRequest, uploadFile } from './client';
import {
buildApiMessage,
@ -506,9 +512,11 @@ async function uploadMedia(localMessage: ApiMessage, attachment: ApiAttachment,
const attributes: GramJs.TypeDocumentAttribute[] = [new GramJs.DocumentAttributeFilename({ fileName: filename })];
if (quick) {
if (mimeType.startsWith('image/')) {
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
return new GramJs.InputMediaUploadedPhoto({ file: inputFile });
} else {
}
if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
const { width, height, duration } = quick;
if (duration !== undefined) {
attributes.push(new GramJs.DocumentAttributeVideo({

View File

@ -4,6 +4,7 @@ export interface ApiInitialArgs {
userAgent: string;
platform?: string;
sessionData?: ApiSessionData;
isMovSupported?: boolean;
}
export interface ApiOnProgress {

View File

@ -13,12 +13,12 @@ import {
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,
CONTENT_TYPES_FOR_QUICK_UPLOAD,
ANIMATION_LEVEL_MAX,
ANIMATION_END_DELAY,
DARK_THEME_BG_COLOR,
LIGHT_THEME_BG_COLOR,
ANIMATION_LEVEL_MIN,
SUPPORTED_IMAGE_CONTENT_TYPES,
} from '../../config';
import {
IS_SINGLE_COLUMN_LAYOUT,
@ -99,8 +99,8 @@ type DispatchProps = Pick<GlobalActions, (
const CLOSE_ANIMATION_DURATION = IS_SINGLE_COLUMN_LAYOUT ? 450 + ANIMATION_END_DELAY : undefined;
function canBeQuicklyUploaded(item: DataTransferItem) {
return item.kind === 'file' && item.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.has(item.type);
function isImage(item: DataTransferItem) {
return item.kind === 'file' && item.type && SUPPORTED_IMAGE_CONTENT_TYPES.has(item.type);
}
const MiddleColumn: FC<StateProps & DispatchProps> = ({
@ -228,7 +228,8 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
// Filter unnecessary element for drag and drop images in Firefox (https://github.com/Ajaxy/telegram-tt/issues/49)
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#image
.filter((item) => item.type !== 'text/uri-list')
.every(canBeQuicklyUploaded);
// As of September 2021, native clients suggest "send quick, but compressed" only for images
.every(isImage);
setDropAreaState(shouldDrawQuick ? DropAreaState.QuickFile : DropAreaState.Document);
}, []);

View File

@ -1,6 +1,6 @@
import React, { FC, memo, useCallback } from '../../../lib/teact/teact';
import { CONTENT_TYPES_FOR_QUICK_UPLOAD } from '../../../config';
import { CONTENT_TYPES_WITH_PREVIEW } from '../../../config';
import { IS_TOUCH_ENV } from '../../../util/environment';
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
import { IAllowedAttachmentOptions } from '../../../modules/helpers';
@ -35,7 +35,7 @@ const AttachMenu: FC<OwnProps> = ({
const handleQuickSelect = useCallback(() => {
openSystemFilesDialog(
Array.from(CONTENT_TYPES_FOR_QUICK_UPLOAD).join(','),
Array.from(CONTENT_TYPES_WITH_PREVIEW).join(','),
(e) => handleFileSelect(e, true),
);
}, [handleFileSelect]);

View File

@ -4,7 +4,12 @@ import React, {
import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types';
import { CONTENT_TYPES_FOR_QUICK_UPLOAD, EDITABLE_INPUT_MODAL_ID } from '../../../config';
import {
CONTENT_TYPES_WITH_PREVIEW,
EDITABLE_INPUT_MODAL_ID,
SUPPORTED_IMAGE_CONTENT_TYPES,
SUPPORTED_VIDEO_CONTENT_TYPES,
} from '../../../config';
import { getFileExtension } from '../../common/helpers/documentInfo';
import captureEscKeyListener from '../../../util/captureEscKeyListener';
import usePrevious from '../../../hooks/usePrevious';
@ -128,7 +133,7 @@ const AttachmentModal: FC<OwnProps> = ({
if (files?.length) {
const newFiles = isQuick
? Array.from(files).filter((file) => {
return file.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.has(file.type);
return file.type && CONTENT_TYPES_WITH_PREVIEW.has(file.type);
})
: Array.from(files);
@ -149,8 +154,8 @@ const AttachmentModal: FC<OwnProps> = ({
return undefined;
}
const areAllPhotos = renderingAttachments.every((a) => a.mimeType.startsWith('image/'));
const areAllVideos = renderingAttachments.every((a) => a.mimeType.startsWith('video/'));
const areAllPhotos = renderingAttachments.every((a) => SUPPORTED_IMAGE_CONTENT_TYPES.has(a.mimeType));
const areAllVideos = renderingAttachments.every((a) => SUPPORTED_VIDEO_CONTENT_TYPES.has(a.mimeType));
const areAllAudios = renderingAttachments.every((a) => a.mimeType.startsWith('audio/'));
let title = '';

View File

@ -1,4 +1,5 @@
import { ApiAttachment } from '../../../../api/types';
import { SUPPORTED_IMAGE_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES } from '../../../../config';
import {
preloadImage,
preloadVideo,
@ -17,7 +18,7 @@ export default async function buildAttachment(
let quick;
let previewBlobUrl;
if (mimeType.startsWith('image/')) {
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
if (isQuick) {
const img = await preloadImage(blobUrl);
const { width, height } = img;
@ -33,7 +34,7 @@ export default async function buildAttachment(
} else {
previewBlobUrl = blobUrl;
}
} else if (mimeType.startsWith('video/')) {
} else if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
quick = { width, height, duration };

View File

@ -121,8 +121,19 @@ export const BASE_EMOJI_KEYWORD_LANG = 'en';
export const MENU_TRANSITION_DURATION = 200;
export const SLIDE_TRANSITION_DURATION = 450;
export const CONTENT_TYPES_FOR_QUICK_UPLOAD = new Set([
'image/png', 'image/gif', 'image/jpeg', 'video/mp4', 'video/avi', 'video/quicktime',
export const VIDEO_MOV_TYPE = 'video/quicktime';
export const SUPPORTED_IMAGE_CONTENT_TYPES = new Set([
'image/png', 'image/gif', 'image/jpeg',
]);
export const SUPPORTED_VIDEO_CONTENT_TYPES = new Set([
'video/mp4', // video/quicktime added dynamically in environment.ts
]);
export const CONTENT_TYPES_WITH_PREVIEW = new Set([
...SUPPORTED_IMAGE_CONTENT_TYPES,
...SUPPORTED_VIDEO_CONTENT_TYPES,
]);
// eslint-disable-next-line max-len

View File

@ -13,7 +13,7 @@ import {
MEDIA_PROGRESSIVE_CACHE_NAME,
IS_TEST,
} from '../../../config';
import { PLATFORM_ENV } from '../../../util/environment';
import { IS_MOV_SUPPORTED, PLATFORM_ENV } from '../../../util/environment';
import { unsubscribe } from '../../../util/notifications';
import * as cacheApi from '../../../util/cacheApi';
import { updateAppBadge } from '../../../util/appBadge';
@ -37,6 +37,7 @@ addReducer('initApi', (global: GlobalState, actions) => {
userAgent: navigator.userAgent,
platform: PLATFORM_ENV,
sessionData: loadStoredSession(),
isMovSupported: IS_MOV_SUPPORTED,
});
})();
});

View File

@ -4,6 +4,8 @@ import {
MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT,
MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH,
IS_TEST,
SUPPORTED_VIDEO_CONTENT_TYPES,
VIDEO_MOV_TYPE,
} from '../config';
export * from './environmentWebp';
@ -67,6 +69,14 @@ export const IS_CANVAS_FILTER_SUPPORTED = (
);
export const LAYERS_ANIMATION_NAME = IS_ANDROID ? 'slide-fade' : IS_IOS ? 'slide-layers' : 'push-slide';
const TEST_VIDEO = document.createElement('video');
export const IS_MOV_SUPPORTED = Boolean(
TEST_VIDEO.canPlayType(VIDEO_MOV_TYPE).replace('no', '')
|| IS_IOS, // IOS reports '', but still plays .mov files
);
if (IS_MOV_SUPPORTED) SUPPORTED_VIDEO_CONTENT_TYPES.add(VIDEO_MOV_TYPE);
export const DPR = window.devicePixelRatio || 1;
export const MASK_IMAGE_DISABLED = true;