mirror of
https://github.com/balzack/databag.git
synced 2025-02-15 04:59:16 +00:00
support multiple video qualities
This commit is contained in:
parent
b08438440e
commit
8f8cd6eb4d
@ -46,7 +46,7 @@ export function AudioAsset({ label, audioUrl }) {
|
|||||||
if (!active) {
|
if (!active) {
|
||||||
return (
|
return (
|
||||||
<div onClick={() => setActive(true)}>
|
<div onClick={() => setActive(true)}>
|
||||||
<SoundOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
|
<SoundOutlined style={{ fontSize: 32, color: '#eeeeee', cursor: 'pointer' }} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ export function AudioAsset({ label, audioUrl }) {
|
|||||||
if (height != dimension.height) {
|
if (height != dimension.height) {
|
||||||
setDimension({ height });
|
setDimension({ height });
|
||||||
}
|
}
|
||||||
return <div style={{ height: '100%', width: dimension.height, backgroundColor: '#444444' }} />
|
return <div style={{ height: '100%', borderRadius: 4, width: dimension.height, backgroundColor: '#444444' }} />
|
||||||
}}
|
}}
|
||||||
</ReactResizeDetector>
|
</ReactResizeDetector>
|
||||||
<div class="player" style={{ width: dimension.height, height: dimension.height }}>
|
<div class="player" style={{ width: dimension.height, height: dimension.height }}>
|
||||||
|
@ -24,7 +24,8 @@ export function TopicItem({ topic }) {
|
|||||||
return <img style={{ height: '100%', objectFit: 'contain' }} src={actions.getAssetUrl(asset.image.full)} alt="" />
|
return <img style={{ height: '100%', objectFit: 'contain' }} src={actions.getAssetUrl(asset.image.full)} alt="" />
|
||||||
}
|
}
|
||||||
if (asset.video) {
|
if (asset.video) {
|
||||||
return <VideoAsset thumbUrl={actions.getAssetUrl(asset.video.thumb)} videoUrl={actions.getAssetUrl(asset.video.full)} />
|
return <VideoAsset thumbUrl={actions.getAssetUrl(asset.video.thumb)}
|
||||||
|
lqUrl={actions.getAssetUrl(asset.video.lq)} hdUrl={actions.getAssetUrl(asset.video.hd)} />
|
||||||
}
|
}
|
||||||
if (asset.audio) {
|
if (asset.audio) {
|
||||||
return <AudioAsset label={asset.audio.label} audioUrl={actions.getAssetUrl(asset.audio.full)} />
|
return <AudioAsset label={asset.audio.label} audioUrl={actions.getAssetUrl(asset.audio.full)} />
|
||||||
|
@ -1,59 +1,84 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useRef, useEffect, useState } from 'react';
|
||||||
import { Button } from 'antd';
|
import { Button, Modal } from 'antd';
|
||||||
import ReactPlayer from 'react-player'
|
import ReactPlayer from 'react-player'
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import ReactResizeDetector from 'react-resize-detector';
|
||||||
import { PlayCircleOutlined } from '@ant-design/icons';
|
import { SelectOutlined, ExpandOutlined, MinusCircleOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
||||||
import { VideoAssetWrapper } from './VideoAsset.styled';
|
import { VideoAssetWrapper } from './VideoAsset.styled';
|
||||||
|
|
||||||
export function VideoAsset({ thumbUrl, videoUrl }) {
|
export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
|
||||||
|
|
||||||
const [active, setActive] = useState(false);
|
const [state, setState] = useState({});
|
||||||
const [dimension, setDimension] = useState({});
|
const player = useRef(null);
|
||||||
const [visibility, setVisibility] = useState('hidden');
|
|
||||||
const [playing, setPlaying] = useState(false);
|
const updateState = (value) => {
|
||||||
|
setState((s) => ({ ...s, ...value }));
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActive(false);
|
}, [thumbUrl, hdUrl, lqUrl]);
|
||||||
setVisibility('hidden');
|
|
||||||
setPlaying(false);
|
|
||||||
}, [thumbUrl, videoUrl]);
|
|
||||||
|
|
||||||
const onReady = () => {
|
const onFullScreen = () => {
|
||||||
setPlaying(true);
|
updateState({ fullscreen: true, modalUrl: hdUrl, playing: false, url: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPlay = () => {
|
const CenterButton = () => {
|
||||||
setVisibility('visible');
|
if (!state.loaded) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!thumbUrl) {
|
|
||||||
return <ReactPlayer height="100%" width="auto" controls="true" url={videoUrl} />
|
|
||||||
}
|
|
||||||
|
|
||||||
const Player = () => {
|
|
||||||
if (!active) {
|
|
||||||
return (
|
return (
|
||||||
<div onClick={() => setActive(true)}>
|
<div onClick={() => updateState({ loaded: true, url: lqUrl, controls: false, paused: true, playing: false })}>
|
||||||
|
<SelectOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state.playing) {
|
||||||
|
return (
|
||||||
|
<div onClick={() => updateState({ playing: false })}>
|
||||||
|
<MinusCircleOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (
|
||||||
|
<div onClick={() => updateState({ playing: true })}>
|
||||||
<PlayCircleOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
|
<PlayCircleOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <ReactPlayer style={{ visibility }} playing={playing} height="100%" width="100%" controls="true" url={videoUrl} onReady={onReady} onPlay={onPlay} />
|
}
|
||||||
|
|
||||||
|
const Controls = () => {
|
||||||
|
if (state.controls) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div class="control">
|
||||||
|
<CenterButton />
|
||||||
|
</div>
|
||||||
|
<div class="fullscreen" onClick={() => onFullScreen()}>
|
||||||
|
<ExpandOutlined style={{ fontSize: 24, color: '#eeeeee', cursor: 'pointer' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VideoAssetWrapper>
|
<VideoAssetWrapper>
|
||||||
<ReactResizeDetector handleWidth={true} handleHeight={true}>
|
<ReactResizeDetector handleWidth={true} handleHeight={true}>
|
||||||
{({ width, height }) => {
|
{({ width, height }) => {
|
||||||
if (width != dimension.width || height != dimension.height) {
|
if (width != state.width || height != state.height) {
|
||||||
setDimension({ width, height });
|
updateState({ width, height });
|
||||||
}
|
}
|
||||||
return <img style={{ height: '100%', objectFit: 'contain' }} src={thumbUrl} alt="" />
|
return <img style={{ height: '100%', objectFit: 'contain' }} src={thumbUrl} alt="" />
|
||||||
}}
|
}}
|
||||||
</ReactResizeDetector>
|
</ReactResizeDetector>
|
||||||
<div class="player" style={{ width: dimension.width, height: dimension.height }}>
|
<div class="player" style={{ width: state.width, height: state.height }}>
|
||||||
<Player />
|
<ReactPlayer ref={player} controls={state.controls} playing={state.playing}
|
||||||
|
height="100%" width="100%" url={state.url} />
|
||||||
|
<Controls />
|
||||||
</div>
|
</div>
|
||||||
|
<Modal visible={state.fullscreen} width={'60%'} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={() => { updateState({ fullscreen: false, modalUrl: null })}}>
|
||||||
|
<ReactPlayer controls={true} height="100%" width="100%" url={state.modalUrl} />
|
||||||
|
</Modal>
|
||||||
</VideoAssetWrapper>
|
</VideoAssetWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,46 @@ export const VideoAssetWrapper = styled.div`
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.player {
|
.playback {
|
||||||
top: 0;
|
top: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.player:hover .control {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player:hover .fullscreen {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control {
|
||||||
|
top: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: black;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen {
|
||||||
|
padding-right: 2px;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,14 +38,15 @@ export async function addChannelTopic(token, channelId, message, assets ) {
|
|||||||
else if (asset.video) {
|
else if (asset.video) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('asset', asset.video);
|
formData.append('asset', asset.video);
|
||||||
let transform = encodeURIComponent(JSON.stringify(["vcopy;video", 'vthumb;video']));
|
let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", 'vthumb;video']));
|
||||||
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
|
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
|
||||||
checkResponse(topicAsset);
|
checkResponse(topicAsset);
|
||||||
let assetEntry = await topicAsset.json();
|
let assetEntry = await topicAsset.json();
|
||||||
message.assets.push({
|
message.assets.push({
|
||||||
video: {
|
video: {
|
||||||
thumb: assetEntry.find(item => item.transform === 'vthumb;video').assetId,
|
thumb: assetEntry.find(item => item.transform === 'vthumb;video').assetId,
|
||||||
full: assetEntry.find(item => item.transform === 'vcopy;video').assetId,
|
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
|
||||||
|
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -39,14 +39,15 @@ export async function addContactChannelTopic(server, token, channelId, message,
|
|||||||
else if (asset.video) {
|
else if (asset.video) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('asset', asset.video);
|
formData.append('asset', asset.video);
|
||||||
let transform = encodeURIComponent(JSON.stringify(["vcopy;video", "vthumb;video"]));
|
let transform = encodeURIComponent(JSON.stringify(["vhd;video", "vlq;video", "vthumb;video"]));
|
||||||
let topicAsset = await fetch(`https://${server}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
|
let topicAsset = await fetch(`https://${server}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
|
||||||
checkResponse(topicAsset);
|
checkResponse(topicAsset);
|
||||||
let assetEntry = await topicAsset.json();
|
let assetEntry = await topicAsset.json();
|
||||||
message.assets.push({
|
message.assets.push({
|
||||||
video: {
|
video: {
|
||||||
thumb: assetEntry.find(item => item.transform === 'vthumb;video').assetId,
|
thumb: assetEntry.find(item => item.transform === 'vthumb;video').assetId,
|
||||||
full: assetEntry.find(item => item.transform === 'vcopy;video').assetId,
|
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
|
||||||
|
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user