mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-23 20:37:42 +00:00
Feature/video player in details (#8115)
* details support video player * optimize * pause when moving out of player --------- Co-authored-by: zhouwenxuan <aries@Mac.local>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
.detail-body .detail-image {
|
||||
height: 144px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -54,3 +55,8 @@
|
||||
position: absolute;
|
||||
transform: translateY(-50px);
|
||||
}
|
||||
|
||||
.detail-body .video-js {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { siteRoot, thumbnailSizeForGrid, enableSeafileAI } from '../../../utils/constants';
|
||||
import { siteRoot, thumbnailSizeForGrid, enableSeafileAI, fileServerRoot, MimetypesKind } from '../../../utils/constants';
|
||||
import { seafileAPI } from '../../../utils/seafile-api';
|
||||
import { Utils } from '../../../utils/utils';
|
||||
import toaster from '../../toast';
|
||||
@@ -13,6 +13,7 @@ import AIIcon from '../../../metadata/components/metadata-details/ai-icon';
|
||||
import SettingsIcon from '../../../metadata/components/metadata-details/settings-icon';
|
||||
import { eventBus } from '../../common/event-bus';
|
||||
import { EVENT_BUS_TYPE } from '../../../metadata/constants';
|
||||
import VideoPlayer from '../../video-player';
|
||||
|
||||
import './index.css';
|
||||
|
||||
@@ -22,7 +23,9 @@ class DirentDetails extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
direntDetail: '',
|
||||
isHovering: false,
|
||||
};
|
||||
this.videoPlayerRef = React.createRef();
|
||||
}
|
||||
|
||||
updateDetail = (repoID, dirent, direntPath) => {
|
||||
@@ -57,21 +60,78 @@ class DirentDetails extends React.Component {
|
||||
eventBus.dispatch(EVENT_BUS_TYPE.CLEAR_MAP_INSTANCE);
|
||||
}
|
||||
|
||||
renderImage = () => {
|
||||
handleVideoHover = (isHovering) => {
|
||||
this.setState({ isHovering }, () => {
|
||||
if (this.videoPlayerRef.current) {
|
||||
const player = this.videoPlayerRef.current.player;
|
||||
if (isHovering) {
|
||||
player.play();
|
||||
} else {
|
||||
player.pause();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
getImageSrc = () => {
|
||||
const { repoID, path, dirent, currentRepoInfo } = this.props;
|
||||
return currentRepoInfo.encrypted
|
||||
? `${siteRoot}repo/${repoID}/raw${Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`)}`
|
||||
: `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForGrid}${Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`)}?mtime=${this.state.direntDetail.mtime}`;
|
||||
};
|
||||
|
||||
getVideoSrc = () => {
|
||||
const { repoID, path, dirent } = this.props;
|
||||
const encodedPath = Utils.encodePath(Utils.joinPath(path, dirent.name));
|
||||
return `${fileServerRoot}repos/${repoID}/files${encodedPath}?op=download`;
|
||||
};
|
||||
|
||||
renderMedia = () => {
|
||||
const { dirent } = this.props;
|
||||
if (!dirent) return null;
|
||||
const isImg = Utils.imageCheck(dirent.name);
|
||||
if (!isImg) return null;
|
||||
const { repoID, path, currentRepoInfo } = this.props;
|
||||
let src = '';
|
||||
if (currentRepoInfo.encrypted) {
|
||||
src = `${siteRoot}repo/${repoID}/raw` + Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`);
|
||||
} else {
|
||||
src = `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForGrid}` + Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`) + '?mtime=' + this.state.direntDetail.mtime;
|
||||
}
|
||||
|
||||
const isImage = Utils.imageCheck(dirent.name);
|
||||
const isVideo = Utils.videoCheck(dirent.name);
|
||||
if (!isImage && !isVideo) return null;
|
||||
|
||||
const src = this.getImageSrc();
|
||||
const videoSrc = this.getVideoSrc();
|
||||
const mimetype = MimetypesKind[dirent.name.split('.').pop().toLowerCase()] || 'video/mp4';
|
||||
|
||||
let options = {
|
||||
autoplay: false,
|
||||
preload: 'auto',
|
||||
muted: true,
|
||||
sources: [{
|
||||
src: videoSrc,
|
||||
type: mimetype
|
||||
}],
|
||||
controls: true,
|
||||
bigPlayButton: false,
|
||||
controlBar: {
|
||||
playToggle: false,
|
||||
volumnPanel: false,
|
||||
fullscreenToggle: false,
|
||||
pictureInPictureToggle: false,
|
||||
children: ['progressControl', 'remainingTimeDisplay']
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="detail-image">
|
||||
<img src={src} alt="" />
|
||||
<div
|
||||
className="detail-image"
|
||||
onMouseEnter={() => this.handleVideoHover(true)}
|
||||
onMouseLeave={() => this.handleVideoHover(false)}
|
||||
>
|
||||
{isVideo ? (
|
||||
<VideoPlayer
|
||||
id={`video-player-${dirent.id}`}
|
||||
ref={this.videoPlayerRef}
|
||||
{...options}
|
||||
/>
|
||||
) : (
|
||||
<img src={src} alt="" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -84,7 +144,7 @@ class DirentDetails extends React.Component {
|
||||
<Detail>
|
||||
<Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={this.props.onClose} />
|
||||
<Body>
|
||||
{this.renderImage()}
|
||||
{this.renderMedia()}
|
||||
</Body>
|
||||
</Detail>
|
||||
);
|
||||
@@ -106,7 +166,7 @@ class DirentDetails extends React.Component {
|
||||
<SettingsIcon />
|
||||
</Header>
|
||||
<Body>
|
||||
{this.renderImage()}
|
||||
{this.renderMedia()}
|
||||
{dirent && direntDetail && (
|
||||
<div className="detail-content">
|
||||
{dirent.type !== 'file' ? (
|
||||
|
@@ -23,6 +23,13 @@ class VideoPlayer extends React.Component {
|
||||
this.player.el().focus();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// Update sources if changed
|
||||
if (JSON.stringify(this.props.sources) !== JSON.stringify(prevProps.sources)) {
|
||||
this.player.src(this.props.sources[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// destroy player on unmount
|
||||
componentWillUnmount() {
|
||||
if (this.player) {
|
||||
|
@@ -60,7 +60,7 @@ class Dirent {
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
const json = {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
mtime: this.mtime,
|
||||
@@ -71,6 +71,10 @@ class Dirent {
|
||||
modifier_email: this.modifier_email,
|
||||
modifier_contact_email: this.modifier_contact_email,
|
||||
};
|
||||
if (this.encoded_thumbnail_src) {
|
||||
json.encoded_thumbnail_src = this.encoded_thumbnail_src;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user