MediaPlayerView.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import React, { useState, useEffect } from 'react';
  2. import { Link } from 'react-router-dom';
  3. import DPlayer from 'react-dplayer';
  4. import APlayer from 'react-aplayer';
  5. import { ApiProps } from '@polkadot/react-api/types';
  6. import { I18nProps } from '@polkadot/react-components/types';
  7. import { withCalls, withMulti } from '@polkadot/react-api/hoc';
  8. import { Option } from '@polkadot/types/codec';
  9. import translate from '../translate';
  10. import { DiscoveryProviderProps } from '../DiscoveryProvider';
  11. import { DataObject, ContentId } from '@joystream/types/media';
  12. import { VideoType } from '../schemas/video/Video';
  13. import { isAccountAChannelOwner } from '../channels/ChannelHelpers';
  14. import { ChannelEntity } from '../entities/ChannelEntity';
  15. import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
  16. import { JoyError } from '@polkadot/joy-utils/react/components';
  17. const PLAYER_COMMON_PARAMS = {
  18. lang: 'en',
  19. autoplay: true,
  20. theme: '#2185d0'
  21. };
  22. // This is just a part of Player's methods that are used in this component.
  23. // To see all the methods available on APlayer and DPlayer visit the next URLs:
  24. // http://aplayer.js.org/#/home?id=api
  25. // http://dplayer.js.org/#/home?id=api
  26. interface PartOfPlayer {
  27. pause: () => void;
  28. destroy: () => void;
  29. }
  30. export type RequiredMediaPlayerProps = {
  31. channel: ChannelEntity;
  32. video: VideoType;
  33. contentId: ContentId;
  34. }
  35. type ContentProps = {
  36. contentType?: string;
  37. dataObjectOpt?: Option<DataObject>;
  38. resolvedAssetUrl: string;
  39. }
  40. type MediaPlayerViewProps = ApiProps & I18nProps &
  41. DiscoveryProviderProps & RequiredMediaPlayerProps & ContentProps
  42. type PlayerProps = RequiredMediaPlayerProps & ContentProps
  43. function Player (props: PlayerProps) {
  44. const { video, resolvedAssetUrl: url, contentType = 'video/video' } = props;
  45. const { thumbnail: cover } = video;
  46. const prefix = contentType.substring(0, contentType.indexOf('/'));
  47. const [player, setPlayer] = useState<PartOfPlayer>();
  48. const onPlayerCreated = (newPlayer: PartOfPlayer) => {
  49. console.log('onPlayerCreated:', newPlayer);
  50. setPlayer(newPlayer);
  51. };
  52. const destroyPlayer = () => {
  53. if (!player) return;
  54. console.log('Destroy the current player');
  55. player.pause();
  56. player.destroy();
  57. setPlayer(undefined);
  58. };
  59. useEffect(() => {
  60. return () => {
  61. destroyPlayer();
  62. };
  63. }, [url]);
  64. if (prefix === 'video') {
  65. const video = { url, name, pic: cover };
  66. return <DPlayer
  67. video={video}
  68. {...PLAYER_COMMON_PARAMS}
  69. loop={false}
  70. onLoad={onPlayerCreated} // Note that DPlayer has onLoad, but APlayer - onInit.
  71. />;
  72. } else if (prefix === 'audio') {
  73. const audio = { url, name, cover };
  74. return <APlayer
  75. audio={audio}
  76. {...PLAYER_COMMON_PARAMS}
  77. loop='none'
  78. onInit={onPlayerCreated} // Note that APlayer has onInit, but DPlayer - onLoad.
  79. />;
  80. }
  81. return <JoyError title={'Unsupported type of content'}>{contentType}</JoyError>;
  82. }
  83. function InnerComponent (props: MediaPlayerViewProps) {
  84. const { video, resolvedAssetUrl: url } = props;
  85. const { dataObjectOpt, channel } = props;
  86. const { myAccountId } = useMyMembership();
  87. if (!dataObjectOpt || dataObjectOpt.isNone) {
  88. return null;
  89. }
  90. // TODO extract and show the next info from dataObject:
  91. // {"owner":"5GSMNn8Sy8k64mGUWPDafjMZu9bQNX26GujbBQ1LeJpNbrfg","added_at":{"block":2781,"time":1582750854000},"type_id":1,"size":3664485,"liaison":"5HN528fspu4Jg3KXWm7Pu7aUK64RSBz2ZSbwo1XKR9iz3hdY","liaison_judgement":1,"ipfs_content_id":"QmNk4QczoJyPTAKdfoQna6KhAz3FwfjpKyRBXAZHG5djYZ"}
  92. const iAmOwner = isAccountAChannelOwner(channel, myAccountId);
  93. return (
  94. <div className='PlayBox'>
  95. {/* Note that here we use a 'key' prop to force Player component to rerender */}
  96. <Player {...props} key={url} />
  97. <div className='ContentHeader'>
  98. <a className='ui button outline DownloadBtn' href={`${url}?download`}><i className='cloud download icon'></i> Download</a>
  99. {iAmOwner &&
  100. <Link to={`/media/videos/${video.id}/edit`} className='ui button' style={{ float: 'right' }}>
  101. <i className='pencil alternate icon'></i>
  102. Edit
  103. </Link>
  104. }
  105. <h1>{video.title}</h1>
  106. </div>
  107. </div>
  108. );
  109. }
  110. export const MediaPlayerView = withMulti(
  111. InnerComponent,
  112. translate,
  113. withCalls<MediaPlayerViewProps>(
  114. ['query.dataDirectory.dataObjectByContentId',
  115. { paramName: 'contentId', propName: 'dataObjectOpt' }]
  116. )
  117. );