Video: Display .mov as document when playing not supported (#1455)
This commit is contained in:
parent
135db2345b
commit
2de5600602
@ -23,7 +23,14 @@ import {
|
|||||||
ApiInvoice,
|
ApiInvoice,
|
||||||
} from '../../types';
|
} 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 { pick } from '../../../util/iteratees';
|
||||||
import { getApiChatIdFromMtpPeer } from './chats';
|
import { getApiChatIdFromMtpPeer } from './chats';
|
||||||
import { buildStickerFromDocument } from './symbols';
|
import { buildStickerFromDocument } from './symbols';
|
||||||
@ -286,6 +293,11 @@ export function buildVideoFromDocument(document: GramJs.Document): ApiVideo | un
|
|||||||
id, mimeType, thumbs, size, attributes,
|
id, mimeType, thumbs, size, attributes,
|
||||||
} = document;
|
} = document;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-globals
|
||||||
|
if (mimeType === VIDEO_MOV_TYPE && !(self as any).isMovSupported) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const videoAttr = attributes
|
const videoAttr = attributes
|
||||||
.find((a: any): a is GramJs.DocumentAttributeVideo => a instanceof GramJs.DocumentAttributeVideo);
|
.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,
|
height: photoSize.h,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mimeType.startsWith('image/')) {
|
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
|
||||||
mediaType = 'photo';
|
mediaType = 'photo';
|
||||||
|
|
||||||
const imageAttribute = attributes
|
const imageAttribute = attributes
|
||||||
@ -432,7 +444,7 @@ export function buildApiDocument(document: GramJs.TypeDocument): ApiDocument | u
|
|||||||
height,
|
height,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (mimeType.startsWith('video/')) {
|
} else if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
|
||||||
mediaType = 'video';
|
mediaType = 'video';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,9 +44,14 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
|
|||||||
|
|
||||||
onUpdate = _onUpdate;
|
onUpdate = _onUpdate;
|
||||||
|
|
||||||
const { userAgent, platform, sessionData } = initialArgs;
|
const {
|
||||||
|
userAgent, platform, sessionData, isMovSupported,
|
||||||
|
} = initialArgs;
|
||||||
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
|
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-globals
|
||||||
|
(self as any).isMovSupported = isMovSupported;
|
||||||
|
|
||||||
client = new TelegramClient(
|
client = new TelegramClient(
|
||||||
session,
|
session,
|
||||||
process.env.TELEGRAM_T_API_ID,
|
process.env.TELEGRAM_T_API_ID,
|
||||||
|
|||||||
@ -18,7 +18,13 @@ import {
|
|||||||
ApiReportReason,
|
ApiReportReason,
|
||||||
} from '../../types';
|
} 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 { invokeRequest, uploadFile } from './client';
|
||||||
import {
|
import {
|
||||||
buildApiMessage,
|
buildApiMessage,
|
||||||
@ -506,9 +512,11 @@ async function uploadMedia(localMessage: ApiMessage, attachment: ApiAttachment,
|
|||||||
|
|
||||||
const attributes: GramJs.TypeDocumentAttribute[] = [new GramJs.DocumentAttributeFilename({ fileName: filename })];
|
const attributes: GramJs.TypeDocumentAttribute[] = [new GramJs.DocumentAttributeFilename({ fileName: filename })];
|
||||||
if (quick) {
|
if (quick) {
|
||||||
if (mimeType.startsWith('image/')) {
|
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
|
||||||
return new GramJs.InputMediaUploadedPhoto({ file: inputFile });
|
return new GramJs.InputMediaUploadedPhoto({ file: inputFile });
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
|
||||||
const { width, height, duration } = quick;
|
const { width, height, duration } = quick;
|
||||||
if (duration !== undefined) {
|
if (duration !== undefined) {
|
||||||
attributes.push(new GramJs.DocumentAttributeVideo({
|
attributes.push(new GramJs.DocumentAttributeVideo({
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export interface ApiInitialArgs {
|
|||||||
userAgent: string;
|
userAgent: string;
|
||||||
platform?: string;
|
platform?: string;
|
||||||
sessionData?: ApiSessionData;
|
sessionData?: ApiSessionData;
|
||||||
|
isMovSupported?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiOnProgress {
|
export interface ApiOnProgress {
|
||||||
|
|||||||
@ -13,12 +13,12 @@ import {
|
|||||||
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
||||||
SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
||||||
SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,
|
SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,
|
||||||
CONTENT_TYPES_FOR_QUICK_UPLOAD,
|
|
||||||
ANIMATION_LEVEL_MAX,
|
ANIMATION_LEVEL_MAX,
|
||||||
ANIMATION_END_DELAY,
|
ANIMATION_END_DELAY,
|
||||||
DARK_THEME_BG_COLOR,
|
DARK_THEME_BG_COLOR,
|
||||||
LIGHT_THEME_BG_COLOR,
|
LIGHT_THEME_BG_COLOR,
|
||||||
ANIMATION_LEVEL_MIN,
|
ANIMATION_LEVEL_MIN,
|
||||||
|
SUPPORTED_IMAGE_CONTENT_TYPES,
|
||||||
} from '../../config';
|
} from '../../config';
|
||||||
import {
|
import {
|
||||||
IS_SINGLE_COLUMN_LAYOUT,
|
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;
|
const CLOSE_ANIMATION_DURATION = IS_SINGLE_COLUMN_LAYOUT ? 450 + ANIMATION_END_DELAY : undefined;
|
||||||
|
|
||||||
function canBeQuicklyUploaded(item: DataTransferItem) {
|
function isImage(item: DataTransferItem) {
|
||||||
return item.kind === 'file' && item.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.has(item.type);
|
return item.kind === 'file' && item.type && SUPPORTED_IMAGE_CONTENT_TYPES.has(item.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
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)
|
// 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
|
// 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')
|
.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);
|
setDropAreaState(shouldDrawQuick ? DropAreaState.QuickFile : DropAreaState.Document);
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { FC, memo, useCallback } from '../../../lib/teact/teact';
|
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 { IS_TOUCH_ENV } from '../../../util/environment';
|
||||||
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
||||||
import { IAllowedAttachmentOptions } from '../../../modules/helpers';
|
import { IAllowedAttachmentOptions } from '../../../modules/helpers';
|
||||||
@ -35,7 +35,7 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const handleQuickSelect = useCallback(() => {
|
const handleQuickSelect = useCallback(() => {
|
||||||
openSystemFilesDialog(
|
openSystemFilesDialog(
|
||||||
Array.from(CONTENT_TYPES_FOR_QUICK_UPLOAD).join(','),
|
Array.from(CONTENT_TYPES_WITH_PREVIEW).join(','),
|
||||||
(e) => handleFileSelect(e, true),
|
(e) => handleFileSelect(e, true),
|
||||||
);
|
);
|
||||||
}, [handleFileSelect]);
|
}, [handleFileSelect]);
|
||||||
|
|||||||
@ -4,7 +4,12 @@ import React, {
|
|||||||
|
|
||||||
import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types';
|
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 { getFileExtension } from '../../common/helpers/documentInfo';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
import usePrevious from '../../../hooks/usePrevious';
|
import usePrevious from '../../../hooks/usePrevious';
|
||||||
@ -128,7 +133,7 @@ const AttachmentModal: FC<OwnProps> = ({
|
|||||||
if (files?.length) {
|
if (files?.length) {
|
||||||
const newFiles = isQuick
|
const newFiles = isQuick
|
||||||
? Array.from(files).filter((file) => {
|
? 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);
|
: Array.from(files);
|
||||||
|
|
||||||
@ -149,8 +154,8 @@ const AttachmentModal: FC<OwnProps> = ({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const areAllPhotos = renderingAttachments.every((a) => a.mimeType.startsWith('image/'));
|
const areAllPhotos = renderingAttachments.every((a) => SUPPORTED_IMAGE_CONTENT_TYPES.has(a.mimeType));
|
||||||
const areAllVideos = renderingAttachments.every((a) => a.mimeType.startsWith('video/'));
|
const areAllVideos = renderingAttachments.every((a) => SUPPORTED_VIDEO_CONTENT_TYPES.has(a.mimeType));
|
||||||
const areAllAudios = renderingAttachments.every((a) => a.mimeType.startsWith('audio/'));
|
const areAllAudios = renderingAttachments.every((a) => a.mimeType.startsWith('audio/'));
|
||||||
|
|
||||||
let title = '';
|
let title = '';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { ApiAttachment } from '../../../../api/types';
|
import { ApiAttachment } from '../../../../api/types';
|
||||||
|
import { SUPPORTED_IMAGE_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES } from '../../../../config';
|
||||||
import {
|
import {
|
||||||
preloadImage,
|
preloadImage,
|
||||||
preloadVideo,
|
preloadVideo,
|
||||||
@ -17,7 +18,7 @@ export default async function buildAttachment(
|
|||||||
let quick;
|
let quick;
|
||||||
let previewBlobUrl;
|
let previewBlobUrl;
|
||||||
|
|
||||||
if (mimeType.startsWith('image/')) {
|
if (SUPPORTED_IMAGE_CONTENT_TYPES.has(mimeType)) {
|
||||||
if (isQuick) {
|
if (isQuick) {
|
||||||
const img = await preloadImage(blobUrl);
|
const img = await preloadImage(blobUrl);
|
||||||
const { width, height } = img;
|
const { width, height } = img;
|
||||||
@ -33,7 +34,7 @@ export default async function buildAttachment(
|
|||||||
} else {
|
} else {
|
||||||
previewBlobUrl = blobUrl;
|
previewBlobUrl = blobUrl;
|
||||||
}
|
}
|
||||||
} else if (mimeType.startsWith('video/')) {
|
} else if (SUPPORTED_VIDEO_CONTENT_TYPES.has(mimeType)) {
|
||||||
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
|
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
|
||||||
quick = { width, height, duration };
|
quick = { width, height, duration };
|
||||||
|
|
||||||
|
|||||||
@ -121,8 +121,19 @@ export const BASE_EMOJI_KEYWORD_LANG = 'en';
|
|||||||
export const MENU_TRANSITION_DURATION = 200;
|
export const MENU_TRANSITION_DURATION = 200;
|
||||||
export const SLIDE_TRANSITION_DURATION = 450;
|
export const SLIDE_TRANSITION_DURATION = 450;
|
||||||
|
|
||||||
export const CONTENT_TYPES_FOR_QUICK_UPLOAD = new Set([
|
export const VIDEO_MOV_TYPE = 'video/quicktime';
|
||||||
'image/png', 'image/gif', 'image/jpeg', 'video/mp4', 'video/avi', '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
|
// eslint-disable-next-line max-len
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
MEDIA_PROGRESSIVE_CACHE_NAME,
|
MEDIA_PROGRESSIVE_CACHE_NAME,
|
||||||
IS_TEST,
|
IS_TEST,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import { PLATFORM_ENV } from '../../../util/environment';
|
import { IS_MOV_SUPPORTED, PLATFORM_ENV } from '../../../util/environment';
|
||||||
import { unsubscribe } from '../../../util/notifications';
|
import { unsubscribe } from '../../../util/notifications';
|
||||||
import * as cacheApi from '../../../util/cacheApi';
|
import * as cacheApi from '../../../util/cacheApi';
|
||||||
import { updateAppBadge } from '../../../util/appBadge';
|
import { updateAppBadge } from '../../../util/appBadge';
|
||||||
@ -37,6 +37,7 @@ addReducer('initApi', (global: GlobalState, actions) => {
|
|||||||
userAgent: navigator.userAgent,
|
userAgent: navigator.userAgent,
|
||||||
platform: PLATFORM_ENV,
|
platform: PLATFORM_ENV,
|
||||||
sessionData: loadStoredSession(),
|
sessionData: loadStoredSession(),
|
||||||
|
isMovSupported: IS_MOV_SUPPORTED,
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import {
|
|||||||
MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT,
|
MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT,
|
||||||
MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH,
|
MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH,
|
||||||
IS_TEST,
|
IS_TEST,
|
||||||
|
SUPPORTED_VIDEO_CONTENT_TYPES,
|
||||||
|
VIDEO_MOV_TYPE,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
|
|
||||||
export * from './environmentWebp';
|
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';
|
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 DPR = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
export const MASK_IMAGE_DISABLED = true;
|
export const MASK_IMAGE_DISABLED = true;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user