|
@@ -1,4 +1,4 @@
|
|
|
-import React from 'react';
|
|
|
+import React, { useState, useEffect } from 'react';
|
|
|
import { Link } from 'react-router-dom';
|
|
|
import DPlayer from 'react-dplayer';
|
|
|
import APlayer from 'react-aplayer';
|
|
@@ -11,16 +11,16 @@ import { Option } from '@polkadot/types/codec';
|
|
|
import translate from '../translate';
|
|
|
import { DiscoveryProviderProps } from '../DiscoveryProvider';
|
|
|
import { DataObject, ContentId } from '@joystream/types/media';
|
|
|
-import { MyAccountContext, MyAccountContextProps } from '@polkadot/joy-utils/MyAccountContext';
|
|
|
import { VideoType } from '../schemas/video/Video';
|
|
|
import { isAccountAChannelOwner } from '../channels/ChannelHelpers';
|
|
|
import { ChannelEntity } from '../entities/ChannelEntity';
|
|
|
+import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
|
|
|
|
|
|
const PLAYER_COMMON_PARAMS = {
|
|
|
lang: 'en',
|
|
|
autoplay: true,
|
|
|
theme: '#2185d0'
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
// This is just a part of Player's methods that are used in this component.
|
|
|
// To see all the methods available on APlayer and DPlayer visit the next URLs:
|
|
@@ -37,94 +37,105 @@ export type RequiredMediaPlayerProps = {
|
|
|
contentId: ContentId
|
|
|
}
|
|
|
|
|
|
-type Props = ApiProps & I18nProps & DiscoveryProviderProps & RequiredMediaPlayerProps & {
|
|
|
+type ContentProps = {
|
|
|
contentType?: string
|
|
|
dataObjectOpt?: Option<DataObject>
|
|
|
resolvedAssetUrl?: string
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-class InnerComponent extends React.PureComponent<Props> {
|
|
|
+type MediaPlayerViewProps = ApiProps & I18nProps &
|
|
|
+ DiscoveryProviderProps & RequiredMediaPlayerProps & ContentProps
|
|
|
|
|
|
- static contextType = MyAccountContext;
|
|
|
+type PlayerProps = RequiredMediaPlayerProps & ContentProps
|
|
|
|
|
|
- private player?: PartOfPlayer = undefined;
|
|
|
+function Player(props: PlayerProps) {
|
|
|
+ const { video, resolvedAssetUrl: url, contentType = 'video/video' } = props
|
|
|
+ const { thumbnail: cover } = video
|
|
|
+ const prefix = contentType.substring(0, contentType.indexOf('/'))
|
|
|
|
|
|
- private onPlayerCreated = (player: PartOfPlayer) => {
|
|
|
- this.player = player;
|
|
|
+ const [ player, setPlayer ] = useState<PartOfPlayer>()
|
|
|
+
|
|
|
+ const onPlayerCreated = (newPlayer: PartOfPlayer) => {
|
|
|
+ console.log('onPlayerCreated:', newPlayer)
|
|
|
+ setPlayer(newPlayer)
|
|
|
}
|
|
|
|
|
|
- componentWillUnmount () {
|
|
|
- const { player } = this;
|
|
|
- if (player) {
|
|
|
- console.log('Destroy the current player');
|
|
|
- player.pause();
|
|
|
- player.destroy();
|
|
|
- }
|
|
|
+ const destroyPlayer = () => {
|
|
|
+ if (!player) return;
|
|
|
+
|
|
|
+ console.log('Destroy the current player');
|
|
|
+ player.pause();
|
|
|
+ player.destroy();
|
|
|
+ setPlayer(undefined)
|
|
|
}
|
|
|
|
|
|
- render () {
|
|
|
- const { dataObjectOpt, channel } = this.props;
|
|
|
- if (!dataObjectOpt || dataObjectOpt.isNone ) {
|
|
|
- return null;
|
|
|
+ useEffect(() => {
|
|
|
+ return () => {
|
|
|
+ destroyPlayer()
|
|
|
}
|
|
|
+ }, [ url ])
|
|
|
+
|
|
|
+ if (prefix === 'video') {
|
|
|
+ const video = { url, name, pic: cover };
|
|
|
+ return <DPlayer
|
|
|
+ video={video}
|
|
|
+ {...PLAYER_COMMON_PARAMS}
|
|
|
+ loop={false}
|
|
|
+ onLoad={onPlayerCreated} // Note that DPlayer has onLoad, but APlayer - onInit.
|
|
|
+ />;
|
|
|
+ } else if (prefix === 'audio') {
|
|
|
+ const audio = { url, name, cover };
|
|
|
+ return <APlayer
|
|
|
+ audio={audio}
|
|
|
+ {...PLAYER_COMMON_PARAMS}
|
|
|
+ loop='none'
|
|
|
+ onInit={onPlayerCreated} // Note that APlayer has onInit, but DPlayer - onLoad.
|
|
|
+ />;
|
|
|
+ }
|
|
|
|
|
|
- // TODO extract and show the next info from dataObject:
|
|
|
- // {"owner":"5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg","added_at":{"block":2781,"time":1582750854000},"type_id":1,"size":3664485,"liaison":"5HN528fspu4Jg3KXWm7Pu7aUK64RSBz2ZSbwo1XKR9iz3hdY","liaison_judgement":1,"ipfs_content_id":"QmNk4QczoJyPTAKdfoQna6KhAz3FwfjpKyRBXAZHG5djYZ"}
|
|
|
-
|
|
|
- const { video, resolvedAssetUrl: url, contentType = 'video/video' } = this.props;
|
|
|
- const { thumbnail: cover } = video;
|
|
|
- const prefix = contentType.substring(0, contentType.indexOf('/'));
|
|
|
-
|
|
|
- const myAccountCtx = this.context as MyAccountContextProps;
|
|
|
- const myAccountId = myAccountCtx.state.address;
|
|
|
- const iAmOwner = isAccountAChannelOwner(channel, myAccountId)
|
|
|
-
|
|
|
- const renderPlayer = () => {
|
|
|
- if (prefix === 'video') {
|
|
|
- const video = { url, name, pic: cover };
|
|
|
- return <DPlayer
|
|
|
- video={video}
|
|
|
- {...PLAYER_COMMON_PARAMS}
|
|
|
- loop={false}
|
|
|
- onLoad={this.onPlayerCreated} // Note that DPlayer has onLoad, but APlayer - onInit.
|
|
|
- />;
|
|
|
- } else if (prefix === 'audio') {
|
|
|
- const audio = { url, name, cover };
|
|
|
- return <APlayer
|
|
|
- audio={audio}
|
|
|
- {...PLAYER_COMMON_PARAMS}
|
|
|
- loop='none'
|
|
|
- onInit={this.onPlayerCreated} // Note that APlayer has onInit, but DPlayer - onLoad.
|
|
|
- />;
|
|
|
- } else {
|
|
|
- return <em>Unsupported type of content: {contentType}</em>;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- return (
|
|
|
- <div className='PlayBox'>
|
|
|
- {renderPlayer()}
|
|
|
- <div className='ContentHeader'>
|
|
|
- <a className='ui button outline DownloadBtn' href={`${url}?download`}><i className='cloud download icon'></i> Download</a>
|
|
|
-
|
|
|
- {iAmOwner &&
|
|
|
- <Link to={`/media/videos/${video.id}/edit`} className='ui button' style={{ float: 'right' }}>
|
|
|
- <i className='pencil alternate icon'></i>
|
|
|
- Edit
|
|
|
- </Link>
|
|
|
- }
|
|
|
-
|
|
|
- <h1>{video.title}</h1>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- );
|
|
|
+ return <em>Unsupported type of content: {contentType}</em>;
|
|
|
+}
|
|
|
+
|
|
|
+function InnerComponent(props: MediaPlayerViewProps) {
|
|
|
+ const { video, resolvedAssetUrl: url } = props
|
|
|
+
|
|
|
+ const { dataObjectOpt, channel } = props;
|
|
|
+ if (!dataObjectOpt || dataObjectOpt.isNone ) {
|
|
|
+ return null;
|
|
|
}
|
|
|
+
|
|
|
+ // TODO extract and show the next info from dataObject:
|
|
|
+ // {"owner":"5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg","added_at":{"block":2781,"time":1582750854000},"type_id":1,"size":3664485,"liaison":"5HN528fspu4Jg3KXWm7Pu7aUK64RSBz2ZSbwo1XKR9iz3hdY","liaison_judgement":1,"ipfs_content_id":"QmNk4QczoJyPTAKdfoQna6KhAz3FwfjpKyRBXAZHG5djYZ"}
|
|
|
+
|
|
|
+ const { myAccountId } = useMyMembership()
|
|
|
+ const iAmOwner = isAccountAChannelOwner(channel, myAccountId)
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='PlayBox'>
|
|
|
+
|
|
|
+ {/* Note that here we use a 'key' prop to force Player component to rerender */}
|
|
|
+ <Player {...props} key={url} />
|
|
|
+
|
|
|
+ <div className='ContentHeader'>
|
|
|
+ <a className='ui button outline DownloadBtn' href={`${url}?download`}><i className='cloud download icon'></i> Download</a>
|
|
|
+
|
|
|
+ {iAmOwner &&
|
|
|
+ <Link to={`/media/videos/${video.id}/edit`} className='ui button' style={{ float: 'right' }}>
|
|
|
+ <i className='pencil alternate icon'></i>
|
|
|
+ Edit
|
|
|
+ </Link>
|
|
|
+ }
|
|
|
+
|
|
|
+ <h1>{video.title}</h1>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
export const MediaPlayerView = withMulti(
|
|
|
InnerComponent,
|
|
|
translate,
|
|
|
- withCalls<Props>(
|
|
|
+ withCalls<MediaPlayerViewProps>(
|
|
|
['query.dataDirectory.dataObjectByContentId',
|
|
|
{ paramName: 'contentId', propName: 'dataObjectOpt' } ]
|
|
|
)
|