import React from 'react';
import superagent from 'superagent';
import ReactPlayer from 'react-player'
import DraggableTableRow from '../Util/DraggableTableRow.jsx';
import constants from '../CloudApi/Constants.js';
import {
Container,
Segment,
Grid,
Header,
Image,
Icon,
Button,
Table,
Form,
Label,
Message,
Menu,
Tab,
Dropdown,
Modal,
Card,
Divider} from 'semantic-ui-react'
import MoviesTVWrapper from './MoviesTVWrapper.jsx';
const Views = {
Loading: "Loading",
Channels: "Channels",
ChannelEditor: "ChannelEditor",
ChannelGroups: "ChannelGroups",
ChannelGroupEditor: "ChannelGroupEditor"
}
class TVDashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
query: null,
currentChannel: null,
currentChannelGroup: null,
channels: [],
channelGroups: [],
selectedChannelId: null,
plutoChannelQueries: null,
currentVideoUri: null,
view: Views.Loading,
nextContent: constants.ContentQueryTypes[0].value,
imageLoading: false,
loading: false
};
}
async componentDidMount() {
if (this.props.match.params.channelId) {
this.setState({ view: Views.Loading });
try {
const mediaProductTrailersRes = await superagent.get(`/api/admin/media/products?entitlementClass=FREE_FOR_ALL`).accept('json');
const freeMediaProductOptions = mediaProductTrailersRes.body.map(mediaProduct => {
return {
"key": mediaProduct.bigMediaId,
"value": mediaProduct.bigMediaId,
"text": `${mediaProduct.title}`,
"image": { src: mediaProduct.marketingData["en-US"].unityPosterTexture && mediaProduct.marketingData["en-US"].unityPosterTexture["src"] }
}
});
this.setState({ mediaProductTrailers: mediaProductTrailersRes.body, freeMediaProductOptions });
const response = await superagent.get("/api/admin/tv/channel/" + this.props.match.params.channelId);
this.setState({ currentChannel: response.body, view: Views.ChannelEditor, loading: false });
} catch (e) {
console.log(e);
}
} else if (this.props.match.params.channelGroupId) {
this.setState({ view: Views.Loading });
try {
const channelsResponse = await superagent.get("/api/admin/tv/channels");
const response = await superagent.get("/api/admin/tv/channel_group/" + this.props.match.params.channelGroupId);
this.setState({ channels: channelsResponse.body, currentChannelGroup: response.body, view: Views.ChannelGroupEditor, loading: false });
} catch (e) {
console.log(e);
}
} else if (this.props.view) {
if (this.props.view === Views.ChannelGroups) {
await this.onShowChannelGroups();
} else if (this.props.views === Views.Channels) {
await this.onShowChannels();
} else {
await this.onShowChannels();
}
} else {
await this.onShowChannels();
}
await this.getChannelQueryOptions();
}
refreshData() {
}
onChange(e, { name, value }) {
this.setState({ [name]: value })
}
onChangeCurrentChannel(e, { name, value }) {
if (this.state.currentChannel) {
const _currentChannel = this.state.currentChannel;
_currentChannel[name] = value;
this.setState({ currentChannel: _currentChannel });
}
}
onChangeCurrentChannelRoomSettings(e, { name, value }) {
if (this.state.currentChannel) {
const _currentChannel = this.state.currentChannel;
if (!_currentChannel.roomSettings) {
_currentChannel.roomSettings = {};
}
_currentChannel.roomSettings[name] = value;
console.log(_currentChannel);
this.setState({ currentChannel: _currentChannel });
}
}
onChangeCurrentChannelGroup(e, { name, value }) {
if (this.state.currentChannelGroup) {
const _currentChannelGroup = this.state.currentChannelGroup;
_currentChannelGroup[name] = value;
this.setState({ currentChannelGroup: _currentChannelGroup });
}
}
async onShowChannels(e) {
this.setState({ loading: true });
const response = await superagent.get("/api/admin/tv/channels");
this.setState({ channels: response.body, view: Views.Channels, loading: false });
}
onCreateChannel(e) {
this.setState({ currentChannel: { geo: [], streams: [], queries: [], roomSettings: {} }, view: Views.ChannelEditor });
}
async onShowChannelGroups(e) {
this.setState({ loading: true });
const response = await superagent.get("/api/admin/tv/channel_groups");
this.setState({ channelGroups: response.body, view: Views.ChannelGroups, loading: false });
}
async getChannelQueryOptions(e) {
this.setState({ plutoChannelQueries: null });
const response = await superagent.get("/api/admin/tv/channel_query/pluto");
const options = response.body.map(nv => { return {"key": nv.value, "value": nv.value, "text": nv.name}});
this.setState({ plutoChannelQueries: options });
}
onCreateChannelGroup(e) {
this.setState({ currentChannelGroup: { channels: [] }, view: Views.ChannelGroupEditor });
}
async onSaveChannel(e) {
try {
this.setState({ loading: true });
if (this.state.currentChannel) {
if (this.state.currentChannel.id) {
const result = await superagent.put("/api/admin/tv/channel").send(this.state.currentChannel);
this.setState({ currentChannel: result.body, loading: false });
} else {
const result = await superagent.post("/api/admin/tv/channel").send(this.state.currentChannel);
this.setState({ currentChannel: result.body, loading: false });
}
}
} catch (e) {
console.log(e);
}
}
onAddStream(e) {
e.preventDefault();
let currentChannel = this.state.currentChannel;
currentChannel.streams.push({
type: this.state.nextContent,
uri: ""
});
this.setState({currentChannel});
}
onAddQuery(e) {
e.preventDefault();
let currentChannel = this.state.currentChannel;
currentChannel.queries.push({
name: "twitch",
value: ""
});
this.setState({currentChannel});
}
renderChannelEditor() {
const geo = (this.state.currentChannel.geo.length == 0) ? All Geographies :
(
{this.state.currentChannel.geo.map(geo => {
return (
{geo}
)
})}
);
const details = (
);
const extraDetail = (
);
const roomSettings = (
);
const channelContent = (
{(this.state.currentChannel.queries.length > 0) && (
Priority
Source
Value
Edit
)}
{this.state.currentChannel.queries.map((query, queryIndex) => {
let onQueryChange = function(e, { name, value }) {
let currentChannel = this.state.currentChannel;
currentChannel.queries[queryIndex][name] = value;
this.setState({currentChannel});
}
let onRemoveQuery = function(e) {
let currentChannel = this.state.currentChannel;
currentChannel.queries.splice(queryIndex, 1);
this.setState({currentChannel});
}
let queryElement =
;
if (query.name === "pluto") {
queryElement = (
);
} else if (query.name === "twitch") {
queryElement = (
);
} else if (query.name === "youtube") {
queryElement = (
);
} else if (query.name === "BigMediaProduct") {
queryElement = (
);
}
return (
Query #{queryIndex + 1}
{queryElement}
Remove
)
})}
Add query
{(this.state.currentChannel.streams.length > 0) && (
Priority
Data
Preview
Edit
)}
{this.state.currentChannel.streams.map((stream, streamIndex) => {
let onStreamEntryChange = function(e, { name, value }) {
let currentChannel = this.state.currentChannel;
currentChannel.streams[streamIndex][name] = value;
this.setState({currentChannel});
}
let onMutedChanged = function(e) {
let currentChannel = this.state.currentChannel;
currentChannel.streams[streamIndex].isMuted = !currentChannel.streams[streamIndex].isMuted;
this.setState({currentChannel});
}
let onIsStaticFile = function(e) {
let currentChannel = this.state.currentChannel;
currentChannel.streams[streamIndex].onIsStaticFile = !currentChannel.streams[streamIndex].onIsStaticFile;
this.setState({currentChannel});
}
let onStereoChanged = function(e, { name, value }) {
let currentChannel = this.state.currentChannel;
if (value === 0) {
currentChannel.streams[streamIndex].isStereo = false;
currentChannel.streams[streamIndex].stereoPacking = "None";
} else if (value === 1) {
currentChannel.streams[streamIndex].isStereo = true;
currentChannel.streams[streamIndex].stereoPacking = "LeftRight";
} else if (value === 2) {
currentChannel.streams[streamIndex].isStereo = true;
currentChannel.streams[streamIndex].stereoPacking = "OverUnder";
}
this.setState({currentChannel});
}
let onRemoveStream = function(e) {
let currentChannel = this.state.currentChannel;
currentChannel.streams.splice(streamIndex, 1);
this.setState({currentChannel});
}
return (
#{streamIndex + 1}
URI
Stereo
Format
Remove
)
})}
Add stream
)
const panes = [
{ menuItem: 'Details', render: () => {details} {extraDetail} },
{ menuItem: 'Room Settings', render: () => {roomSettings} },
{ menuItem: 'Content', render: () => {channelContent} }
];
const tabs = (
);
//
return (
)
}
onSelectChannel(channel, e) {
this.props.history.push({pathname: `/tv/channel/${channel.id}`});
}
onSorted(clickedColumn) {
const { channels, channelDirection } = this.state;
const newChannelDirection = channelDirection === 'ascending' ? 'descending' : 'ascending';
const sortedChannels = _.sortBy(channels, [clickedColumn]);
if (newChannelDirection === "descending") {
sortedChannels.reverse();
}
this.setState({
channels: sortedChannels,
channelDirection: newChannelDirection
});
}
renderChannels() {
return (
Create a New Channel
Name
Display title + description
Geography
Room Settings
Active Streams
Content Queries
{this.state.channels.map((channel, channelIndex) => {
const streamData = channel.streams.length > 0 ? `${channel.streams.length} streams (${channel.streams[0].type})` : "";
const queryData = channel.queries.length > 0 ? `(${channel.queries[0].name})` : "";
const geo = (channel.geo.length == 0) ? All Geographies :
(
{channel.geo.map(geo => {
return (
{geo}
)
})}
)
return (
{channel.name}
{channel.title}
{channel.description}
{(channel.streams.length === 0 && channel.queries.length === 0) && No streams! }
{geo}
{(channel.roomSettings) && {channel.roomSettings.environment} (Size: {channel.roomSettings.size})
}
{streamData}
{queryData}
)
})}
)
}
onSelectChannelGroup(channelGroup, e) {
this.props.history.push({pathname: `/tv/channel_group/${channelGroup.id}`});
}
renderChannelGroups() {
return (
Create a New Channel Group
Name
Published
Notes
Display title
Number of Channels
{this.state.channelGroups.map((channelGroup, channelGroupIndex) => {
return (
{channelGroup.name}
{(channelGroup.isPublished === false) && ( )}
{(channelGroup.channels.length === 0) && No channels! }
{channelGroup.title}
{channelGroup.channels.length}
)
})}
)
}
async onSaveChannelGroup(e) {
try {
this.setState({ loading: true });
await superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
this.setState({ loading: false });
} catch (e) {
console.log(e);
}
}
/**
* The unity texture asset takes a while to generate - keep trying to load it until it shows up.
*/
async tryLoadImage() {
try {
this.setState({ imageLoading: true });
const result = await superagent.get(this.state.currentChannelGroup.textures[0].url);
this.setState({ imageLoading: false });
} catch (e) {
setTimeout(this.tryLoadImage.bind(this), 500);
}
}
renderChannelGroupEditor() {
const channelSelectionList = this.state.channels.map(chan => {
return { "key": chan.id, "value": chan.id, "text": `${chan.title} (${chan.name})` }
});
let onChannelSelectionChanged = function(e, { name, value }) {
this.setState({selectedChannelId: value});
}
let onAddChannelToList = async function (e) {
e.preventDefault();
if (this.state.selectedChannelId) {
const channel = _.find(this.state.channels, ["id", this.state.selectedChannelId]);
const currentChannelGroup = this.state.currentChannelGroup;
currentChannelGroup.channelIds.push(this.state.selectedChannelId);
currentChannelGroup.channels.push(channel);
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
let onRebuildChannelGroup = async function onRebuildChannelGroup() {
try {
this.setState({ loading: true });
const result = await superagent.get("/api/admin/tv/rebuild_channel_group/" + this.state.currentChannelGroup.id);
this.setState({ currentChannelGroup: result.body, loading: false });
await this.tryLoadImage();
} catch (e) {
console.log(e);
}
}
let onRemoveChannelFromList = async function(channelIndex, e) {
e.preventDefault();
if (this.state.currentChannelGroup) {
const currentChannelGroup = this.state.currentChannelGroup;
currentChannelGroup.channelIds.splice(channelIndex, 1);
currentChannelGroup.channels.splice(channelIndex, 1);
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
let onMoveChannelUp = async function(channelIndex, e) {
e.preventDefault();
if (this.state.currentChannelGroup) {
const currentChannelGroup = this.state.currentChannelGroup;
if(channelIndex > currentChannelGroup.channels.length || channelIndex == 0){
alert("top");
return;
}
const movedChannelId = currentChannelGroup.channelIds[channelIndex];
const movedChannel = currentChannelGroup.channels[channelIndex];
currentChannelGroup.channelIds.splice(channelIndex, 1);
currentChannelGroup.channels.splice(channelIndex, 1);
currentChannelGroup.channelIds.splice(channelIndex-1, 0, movedChannelId);
currentChannelGroup.channels.splice(channelIndex-1, 0, movedChannel);
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
let onMoveChannelDown = async function(channelIndex, e) {
e.preventDefault();
if (this.state.currentChannelGroup) {
const currentChannelGroup = this.state.currentChannelGroup;
if(channelIndex > currentChannelGroup.channels.length || channelIndex+1 == currentChannelGroup.channels.length){
alert('already bottom');
return;
}
const movedChannelId = currentChannelGroup.channelIds[channelIndex];
const movedChannel = currentChannelGroup.channels[channelIndex];
currentChannelGroup.channelIds.splice(channelIndex, 1);
currentChannelGroup.channels.splice(channelIndex, 1);
currentChannelGroup.channelIds.splice(channelIndex+1, 0, movedChannelId);
currentChannelGroup.channels.splice(channelIndex+1, 0, movedChannel);
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
let onMoveChannelToTop = async function(channelIndex, e) {
e.preventDefault();
if (this.state.currentChannelGroup) {
const currentChannelGroup = this.state.currentChannelGroup;
if(channelIndex > currentChannelGroup.channels.length || channelIndex == 0){
return;
}
const movedChannelId = currentChannelGroup.channelIds[channelIndex];
const movedChannel = currentChannelGroup.channels[channelIndex];
currentChannelGroup.channelIds.splice(channelIndex, 1);
currentChannelGroup.channels.splice(channelIndex, 1);
currentChannelGroup.channelIds.splice(0, 0, movedChannelId);
currentChannelGroup.channels.splice(0, 0, movedChannel);
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
let onChannelSwap = async function(channelIndexA, channelIndexB) {
//e.preventDefault();
if (channelIndexA >= this.state.currentChannelGroup.channelIds.length || channelIndexA < 0) {
return;
}
console.log("dest", channelIndexA, "src", channelIndexB);
if (this.state.currentChannelGroup) {
const currentChannelGroup = this.state.currentChannelGroup;
const movedChannelId = currentChannelGroup.channelIds[channelIndexB];
currentChannelGroup.channelIds.splice(channelIndexB, 1);
currentChannelGroup.channelIds.splice(channelIndexA, 0, movedChannelId);
const movedChannel = currentChannelGroup.channels[channelIndexB];
currentChannelGroup.channels.splice(channelIndexB, 1);
currentChannelGroup.channels.splice(channelIndexA, 0, movedChannel);
//currentChannelGroup.channelIds[channelIndexA] = currentChannelGroup.channelIds.splice(channelIndexB, 1, currentChannelGroup.channelIds)[0];
//currentChannelGroup.channels[channelIndexA] = currentChannelGroup.channels.splice(channelIndexB, 1, currentChannelGroup.channels)[0];
this.setState({ currentChannelGroup });
superagent.put("/api/admin/tv/channel_group").send(this.state.currentChannelGroup);
}
}
//
return (
}
{this.state.currentChannelGroup.id &&
{ this.setState({copyText: "Copied!"}); setTimeout(() => { this.setState({copyText: undefined})}, 2000); navigator.clipboard.writeText(this.state.currentChannelGroup.name)}}>{this.state.copyText || "Copy 😮"}
}
{(this.state.currentChannelGroup.id) && (
{(this.state.currentChannelGroup.channels.length == 0 && this.state.currentChannelGroup.channels.length == 0) &&
(
This list does not have any channels!
)}
Add channel to list
Channel
Remove
Move Up
Move Down
Move To Top
{this.state.currentChannelGroup.channels.map((channel, channelIndex) => {
return (
{channel.title}
{channel.description}
);
})}
Rebuild this texture if you've changed channels outside this group...
After the texture has been rebuilt, it may take several seconds before it reloads.
Rebuild Unity Texture
{(this.state.imageLoading === false && this.state.currentChannelGroup.textures[0] && this.state.currentChannelGroup.textures[0].url) && }
)}
{(!this.state.currentChannelGroup.id) && }
{(this.state.currentChannelGroup.id) && }
)
}
render() {
let contents = null;
let title = null;
if (this.state.view === Views.Channels) {
title = "Channels";
contents = this.renderChannels();
} else if (this.state.view === Views.ChannelGroups) {
title = "All Channel Groups";
contents = this.renderChannelGroups();
} else if (this.state.view === Views.ChannelEditor) {
title = (this.state.currentChannel.id) ? this.state.currentChannel.name : "Create Channel";
contents = this.renderChannelEditor();
} else if (this.state.view === Views.ChannelGroupEditor) {
title = (this.state.currentChannelGroup.id) ? "Edit Channel Group" : "Create Channel Group";
contents = this.renderChannelGroupEditor();
} else if (this.state.view === Views.Loading) {
contents = (
)
}
return (
{contents}
);
}
}
export default TVDashboard;