2022-03-21 22:42:23 +01:00
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
2022-03-22 13:32:10 +01:00
|
|
|
import { useLocation, useNavigate } from 'react-router-dom';
|
2022-03-22 14:03:50 +01:00
|
|
|
import { Helmet } from 'react-helmet';
|
2022-03-21 22:42:23 +01:00
|
|
|
import '../css/Media.css';
|
|
|
|
|
2022-03-22 14:03:50 +01:00
|
|
|
const thumbnailBase = '/api/thumbnails/';
|
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
const ClipEntry = ({ name, filename, uploader, thumbnail, duration, clickHandler }) => {
|
|
|
|
|
|
|
|
const _uploader = `${ uploader.tag } (${ uploader.id })`;
|
2022-03-20 16:36:58 +01:00
|
|
|
|
|
|
|
return (
|
2022-03-22 13:32:10 +01:00
|
|
|
<div className='clip-listing shadow' onClick={clickHandler}>
|
2022-03-21 22:42:23 +01:00
|
|
|
<div className='flex-container'>
|
|
|
|
<div title={name} id='title' className='listing-element'>
|
|
|
|
<p><strong>Title</strong>: {name}</p>
|
|
|
|
</div>
|
|
|
|
<div title={_uploader} id='uploader' className='listing-element'>
|
|
|
|
<p> <strong>Uploader</strong>: {_uploader }</p>
|
|
|
|
</div>
|
|
|
|
<div title={filename} id='filename' className='listing-element'>
|
|
|
|
<p> <strong>Filename</strong>: {filename}</p>
|
|
|
|
</div>
|
|
|
|
<div title={duration} id='duration' className='listing-element'>
|
|
|
|
<p> <strong>Length</strong>: {duration}</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-03-22 14:03:50 +01:00
|
|
|
<img className='thumbnail shadow' alt='Thumbnail' src={`${thumbnailBase}${thumbnail}`}/>
|
2022-03-21 22:42:23 +01:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const VideoPlayer = ({ refF, video }) => {
|
|
|
|
|
2022-03-22 14:16:28 +01:00
|
|
|
const { filename, name, thumbnail, uploader } = video;
|
2022-03-21 22:42:23 +01:00
|
|
|
const source = `/api/clips/${filename}`;
|
|
|
|
|
|
|
|
return (
|
2022-03-22 13:32:10 +01:00
|
|
|
<div ref={refF} className='video-popup shadow'>
|
2022-03-22 14:03:50 +01:00
|
|
|
|
|
|
|
<Helmet>
|
2022-03-22 14:16:28 +01:00
|
|
|
<title>{name}</title>
|
|
|
|
<meta name='author' content={uploader.name} />
|
2022-03-22 14:03:50 +01:00
|
|
|
<meta property='og:url' content={window.location.href} />
|
2022-03-22 14:07:51 +01:00
|
|
|
<meta property='og:image' content={`${window.location.origin}${thumbnailBase}${thumbnail}`} />
|
2022-03-22 14:03:50 +01:00
|
|
|
<meta property='og:video:type' content='text/html' />
|
2022-03-22 14:07:51 +01:00
|
|
|
<meta property='og:video:url' content={`${window.location.origin}${source}`} />
|
2022-03-22 14:03:50 +01:00
|
|
|
<meta property='og:type' content='video.other' />
|
|
|
|
</Helmet>
|
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
<div>
|
|
|
|
<h1 className='no-margin no-padding'>
|
|
|
|
{name}
|
|
|
|
</h1>
|
|
|
|
</div>
|
|
|
|
<video className='video-player center' controls >
|
|
|
|
<source src={source} type='video/mp4' />
|
2022-03-20 16:36:58 +01:00
|
|
|
</video>
|
|
|
|
</div>
|
2022-03-21 22:42:23 +01:00
|
|
|
);
|
2022-03-20 16:36:58 +01:00
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
};
|
2022-03-20 16:36:58 +01:00
|
|
|
|
|
|
|
const Media = () => {
|
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
const [index, updateIndex] = useState([]);
|
|
|
|
const [video, setVideo] = useState();
|
|
|
|
const ref = useRef(null);
|
|
|
|
|
2022-03-22 13:32:10 +01:00
|
|
|
const location = useLocation();
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
document.addEventListener('mousedown', (event) => {
|
2022-03-22 13:32:10 +01:00
|
|
|
if (ref.current && !ref.current.contains(event.target)) {
|
|
|
|
setVideo(null);
|
|
|
|
navigate('/media');
|
|
|
|
}
|
2022-03-21 22:42:23 +01:00
|
|
|
});
|
2022-03-20 16:36:58 +01:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
(async () => {
|
2022-03-21 22:42:23 +01:00
|
|
|
const response = await fetch(`/api/clips`);
|
2022-03-20 16:36:58 +01:00
|
|
|
if (response.status !== 200) return console.error('Failed to get clip index');
|
2022-03-22 13:32:10 +01:00
|
|
|
const data = await response.json();
|
|
|
|
updateIndex(data);
|
|
|
|
if (location.hash) {
|
|
|
|
const video = data.find(vid => `#${vid.name.toLowerCase()}` === location.hash.toLowerCase());
|
|
|
|
if (video) setVideo(video);
|
|
|
|
}
|
2022-03-21 22:42:23 +01:00
|
|
|
})();
|
2022-03-20 16:36:58 +01:00
|
|
|
|
|
|
|
}, []);
|
|
|
|
|
2022-03-22 13:32:10 +01:00
|
|
|
const clickHandler = (video) => {
|
|
|
|
setVideo(video);
|
|
|
|
navigate(`#${video.name}`);
|
|
|
|
};
|
|
|
|
|
2022-03-21 22:42:23 +01:00
|
|
|
let i = 0;
|
2022-03-20 16:36:58 +01:00
|
|
|
return (
|
2022-03-21 22:42:23 +01:00
|
|
|
<div className='media-page'>
|
2022-03-22 13:32:10 +01:00
|
|
|
{index.map(entry => <ClipEntry clickHandler={() => clickHandler(entry)} key={i++} {...entry} />)}
|
2022-03-21 22:42:23 +01:00
|
|
|
{video ? <VideoPlayer refF={ref} video={video} />:''}
|
2022-03-20 16:36:58 +01:00
|
|
|
</div>
|
2022-03-21 22:42:23 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
};
|
2022-03-20 16:36:58 +01:00
|
|
|
|
|
|
|
export default Media;
|