mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 12:32:30 +08:00
### What problem does this PR solve? Fix: Add video preview ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -2,7 +2,7 @@ import message from '@/components/ui/message';
|
|||||||
import { Spin } from '@/components/ui/spin';
|
import { Spin } from '@/components/ui/spin';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
interface ImagePreviewerProps {
|
interface ImagePreviewerProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -17,7 +17,7 @@ export const ImagePreviewer: React.FC<ImagePreviewerProps> = ({
|
|||||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
const fetchImage = async () => {
|
const fetchImage = useCallback(async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const res = await request(url, {
|
const res = await request(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@ -30,12 +30,13 @@ export const ImagePreviewer: React.FC<ImagePreviewerProps> = ({
|
|||||||
const objectUrl = URL.createObjectURL(res.data);
|
const objectUrl = URL.createObjectURL(res.data);
|
||||||
setImageSrc(objectUrl);
|
setImageSrc(objectUrl);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
}, [url]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (url) {
|
if (url) {
|
||||||
fetchImage();
|
fetchImage();
|
||||||
}
|
}
|
||||||
}, [url]);
|
}, [url, fetchImage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import styles from './index.less';
|
|||||||
import PdfPreviewer, { IProps } from './pdf-preview';
|
import PdfPreviewer, { IProps } from './pdf-preview';
|
||||||
import { PptPreviewer } from './ppt-preview';
|
import { PptPreviewer } from './ppt-preview';
|
||||||
import { TxtPreviewer } from './txt-preview';
|
import { TxtPreviewer } from './txt-preview';
|
||||||
|
import { VideoPreviewer } from './video-preview';
|
||||||
|
|
||||||
type PreviewProps = {
|
type PreviewProps = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
@ -42,11 +43,30 @@ const Preview = ({
|
|||||||
<TxtPreviewer className={className} url={url} />
|
<TxtPreviewer className={className} url={url} />
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
{['visual'].indexOf(fileType) > -1 && (
|
{['jpg', 'png', 'gif', 'jpeg', 'svg', 'bmp', 'ico', 'tif'].indexOf(
|
||||||
|
fileType,
|
||||||
|
) > -1 && (
|
||||||
<section>
|
<section>
|
||||||
<ImagePreviewer className={className} url={url} />
|
<ImagePreviewer className={className} url={url} />
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
{[
|
||||||
|
'mp4',
|
||||||
|
'avi',
|
||||||
|
'mov',
|
||||||
|
'mkv',
|
||||||
|
'wmv',
|
||||||
|
'flv',
|
||||||
|
'mpeg',
|
||||||
|
'mpg',
|
||||||
|
'asf',
|
||||||
|
'rm',
|
||||||
|
'rmvb',
|
||||||
|
].indexOf(fileType) > -1 && (
|
||||||
|
<section>
|
||||||
|
<VideoPreviewer className={className} url={url} />
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
{['pptx'].indexOf(fileType) > -1 && (
|
{['pptx'].indexOf(fileType) > -1 && (
|
||||||
<section>
|
<section>
|
||||||
<PptPreviewer className={className} url={url} />
|
<PptPreviewer className={className} url={url} />
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
import message from '@/components/ui/message';
|
||||||
|
import { Spin } from '@/components/ui/spin';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
interface VideoPreviewerProps {
|
||||||
|
className?: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VideoPreviewer: React.FC<VideoPreviewerProps> = ({
|
||||||
|
className,
|
||||||
|
url,
|
||||||
|
}) => {
|
||||||
|
// const url = useGetDocumentUrl();
|
||||||
|
const [videoSrc, setVideoSrc] = useState<string | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const fetchVideo = useCallback(async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const res = await request(url, {
|
||||||
|
method: 'GET',
|
||||||
|
responseType: 'blob',
|
||||||
|
onError: () => {
|
||||||
|
message.error('Failed to load video');
|
||||||
|
setIsLoading(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const objectUrl = URL.createObjectURL(res.data);
|
||||||
|
setVideoSrc(objectUrl);
|
||||||
|
setIsLoading(false);
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (url) {
|
||||||
|
fetchVideo();
|
||||||
|
}
|
||||||
|
}, [url, fetchVideo]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (videoSrc) {
|
||||||
|
URL.revokeObjectURL(videoSrc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [videoSrc]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'relative w-full h-full p-4 bg-background-paper border border-border-normal rounded-md video-previewer',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{isLoading && (
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<Spin />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isLoading && videoSrc && (
|
||||||
|
<div className="max-h-[80vh] overflow-auto p-2">
|
||||||
|
<video
|
||||||
|
src={videoSrc}
|
||||||
|
controls
|
||||||
|
className="w-full h-auto max-w-full object-contain"
|
||||||
|
onLoadedData={() => URL.revokeObjectURL(videoSrc!)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -166,6 +166,7 @@ const Chunk = () => {
|
|||||||
case 'doc':
|
case 'doc':
|
||||||
return documentInfo?.name.split('.').pop() || 'doc';
|
return documentInfo?.name.split('.').pop() || 'doc';
|
||||||
case 'visual':
|
case 'visual':
|
||||||
|
return documentInfo?.name.split('.').pop() || 'visual';
|
||||||
case 'docx':
|
case 'docx':
|
||||||
case 'txt':
|
case 'txt':
|
||||||
case 'md':
|
case 'md':
|
||||||
|
|||||||
Reference in New Issue
Block a user