// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import ChannelStore from 'stores/channel_store.jsx'; import WebClient from 'client/web_client.jsx'; import * as Utils from 'utils/utils.jsx'; const ytRegex = /(?:http|https):\/\/(?:www\.|m\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#&?]*)/; import React from 'react'; export default class YoutubeVideo extends React.Component { constructor(props) { super(props); this.updateStateFromProps = this.updateStateFromProps.bind(this); this.handleReceivedMetadata = this.handleReceivedMetadata.bind(this); this.handleMetadataError = this.handleMetadataError.bind(this); this.loadWithoutKey = this.loadWithoutKey.bind(this); this.play = this.play.bind(this); this.stop = this.stop.bind(this); this.stopOnChannelChange = this.stopOnChannelChange.bind(this); this.state = { loaded: false, failed: false, playing: false, title: '' }; } componentWillMount() { this.updateStateFromProps(this.props); } componentWillReceiveProps(nextProps) { this.updateStateFromProps(nextProps); } updateStateFromProps(props) { const link = props.link; const match = link.trim().match(ytRegex); if (!match || match[1].length !== 11) { return; } if (props.show === false) { this.stop(); } this.setState({ videoId: match[1], time: this.handleYoutubeTime(link) }); } handleYoutubeTime(link) { const timeRegex = /[\\?&]t=([0-9]+h)?([0-9]+m)?([0-9]+s?)/; const time = link.match(timeRegex); if (!time || !time[0]) { return ''; } const hours = time[1] ? time[1].match(/([0-9]+)h/) : null; const minutes = time[2] ? time[2].match(/([0-9]+)m/) : null; const seconds = time[3] ? time[3].match(/([0-9]+)s?/) : null; let ticks = 0; if (hours && hours[1]) { ticks += parseInt(hours[1], 10) * 3600; } if (minutes && minutes[1]) { ticks += parseInt(minutes[1], 10) * 60; } if (seconds && seconds[1]) { ticks += parseInt(seconds[1], 10); } return '&start=' + ticks.toString(); } componentDidMount() { const key = global.window.mm_config.GoogleDeveloperKey; if (key) { WebClient.getYoutubeVideoInfo(key, this.state.videoId, this.handleReceivedMetadata, this.handleMetadataError); } else { this.loadWithoutKey(); } } loadWithoutKey() { this.setState({ loaded: true, thumb: 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault.jpg' }); } handleMetadataError() { this.setState({ failed: true, loaded: true, title: Utils.localizeMessage('youtube_video.notFound', 'Video not found') }); } handleReceivedMetadata(data) { if (!data || !data.items || !data.items.length || !data.items[0].snippet) { this.setState({ failed: true, loaded: true, title: Utils.localizeMessage('youtube_video.notFound', 'Video not found') }); return null; } const metadata = data.items[0].snippet; let thumb = 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault.jpg'; if (metadata.liveBroadcastContent === 'live') { thumb = 'https://i.ytimg.com/vi/' + this.state.videoId + '/hqdefault_live.jpg'; } this.setState({ loaded: true, receivedYoutubeData: true, title: metadata.title, thumb }); return null; } play() { this.setState({playing: true}); if (ChannelStore.getCurrentId() === this.props.channelId) { ChannelStore.addChangeListener(this.stopOnChannelChange); } } stop() { this.setState({playing: false}); } stopOnChannelChange() { if (ChannelStore.getCurrentId() !== this.props.channelId) { this.stop(); } } render() { if (!this.state.loaded) { return
; } let header; if (this.state.title) { header = (