Populate info.duration for audio & video file uploads (#11225)
* Improve m.file m.image m.audio m.video types * Populate `info.duration` for audio & video file uploads * Fix tests * Iterate types * Improve coverage * Fix test * Add small delay to stabilise cypress test * Fix test idempotency * Improve coverage * Slow down * iterate
This commit is contained in:
parent
8b8ca425d7
commit
f04a0e2860
17 changed files with 556 additions and 85 deletions
|
@ -198,7 +198,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
const isEncrypted = this.props.mediaEventHelper?.media.isEncrypted;
|
||||
const contentUrl = this.getContentUrl();
|
||||
const contentFileSize = this.content.info ? this.content.info.size : null;
|
||||
const fileType = this.content.info ? this.content.info.mimetype : "application/octet-stream";
|
||||
const fileType = this.content.info?.mimetype ?? "application/octet-stream";
|
||||
|
||||
let placeholder: React.ReactNode = null;
|
||||
if (this.props.showGenericPlaceholder) {
|
||||
|
|
|
@ -29,7 +29,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
|||
import Spinner from "../elements/Spinner";
|
||||
import { Media, mediaFromContent } from "../../../customisations/Media";
|
||||
import { BLURHASH_FIELD, createThumbnail } from "../../../utils/image-media";
|
||||
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
|
||||
import { ImageContent } from "../../../customisations/models/IMediaEventContent";
|
||||
import ImageView from "../elements/ImageView";
|
||||
import { IBodyProps } from "./IBodyProps";
|
||||
import { ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";
|
||||
|
@ -102,7 +102,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const content = this.props.mxEvent.getContent<IMediaEventContent>();
|
||||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
const httpUrl = this.state.contentUrl;
|
||||
if (!httpUrl) return;
|
||||
const params: Omit<ComponentProps<typeof ImageView>, "onFinished"> = {
|
||||
|
@ -212,7 +212,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
const thumbWidth = 800;
|
||||
const thumbHeight = 600;
|
||||
|
||||
const content = this.props.mxEvent.getContent<IMediaEventContent>();
|
||||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
const media = mediaFromContent(content);
|
||||
const info = content.info;
|
||||
|
||||
|
@ -287,7 +287,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
contentUrl = this.getContentUrl();
|
||||
}
|
||||
|
||||
const content = this.props.mxEvent.getContent<IMediaEventContent>();
|
||||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
let isAnimated = mayBeAnimated(content.info?.mimetype);
|
||||
|
||||
// If there is no included non-animated thumbnail then we will generate our own, we can't depend on the server
|
||||
|
@ -317,7 +317,13 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
}
|
||||
|
||||
if (isAnimated) {
|
||||
const thumb = await createThumbnail(img, img.width, img.height, content.info!.mimetype, false);
|
||||
const thumb = await createThumbnail(
|
||||
img,
|
||||
img.width,
|
||||
img.height,
|
||||
content.info?.mimetype ?? "image/jpeg",
|
||||
false,
|
||||
);
|
||||
thumbUrl = URL.createObjectURL(thumb.thumbnail);
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -381,7 +387,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
protected getBanner(content: IMediaEventContent): ReactNode {
|
||||
protected getBanner(content: ImageContent): ReactNode {
|
||||
// Hide it for the threads list & the file panel where we show it as text anyway.
|
||||
if (
|
||||
[TimelineRenderingType.ThreadsList, TimelineRenderingType.File].includes(this.context.timelineRenderingType)
|
||||
|
@ -395,7 +401,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
protected messageContent(
|
||||
contentUrl: string | null,
|
||||
thumbUrl: string | null,
|
||||
content: IMediaEventContent,
|
||||
content: ImageContent,
|
||||
forcedHeight?: number,
|
||||
): ReactNode {
|
||||
if (!thumbUrl) thumbUrl = contentUrl; // fallback
|
||||
|
@ -591,7 +597,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const content = this.props.mxEvent.getContent<IMediaEventContent>();
|
||||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
|
||||
if (this.state.error) {
|
||||
let errorText = _t("Unable to show image due to error");
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import React from "react";
|
||||
|
||||
import MImageBody from "./MImageBody";
|
||||
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
|
||||
import { ImageContent } from "../../../customisations/models/IMediaEventContent";
|
||||
|
||||
const FORCED_IMAGE_HEIGHT = 44;
|
||||
|
||||
|
@ -35,7 +35,7 @@ export default class MImageReplyBody extends MImageBody {
|
|||
return super.render();
|
||||
}
|
||||
|
||||
const content = this.props.mxEvent.getContent<IMediaEventContent>();
|
||||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
const thumbnail = this.state.contentUrl
|
||||
? this.messageContent(this.state.contentUrl, this.state.thumbUrl, content, FORCED_IMAGE_HEIGHT)
|
||||
: undefined;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue