import React from 'react'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import Image from './common/Image'; import url from 'url'; import MarkupUtils from '../utils/MarkupUtils'; import moment from 'moment'; import classnames from 'classnames'; import {int2hex} from '../../discord_common/js/utils/ColorUtils'; import MaskedLink from '../components/common/MaskedLink'; import SnowflakeUtils from '../utils/SnowflakeUtils'; import './Embed.styl'; const VIDEO_PROVIDERS = /youtube|steam|imgur|vimeo|sketchfab|vine|soundcloud|streamable|twitch|vid\.me|twitter/i; const VIDEO_PROVIDER_CHECK_UNIX_TIMESTAMP = 1492472454139; const EmbedGIFV = React.createClass({ mixins: [PureRenderMixin], propTypes: { url: React.PropTypes.string.isRequired, thumbnail: React.PropTypes.shape({ url: React.PropTypes.string, // eslint-disable-next-line camelcase proxy_url: React.PropTypes.string, width: React.PropTypes.width, height: React.PropTypes.height, }), video: React.PropTypes.shape({ url: React.PropTypes.string, width: React.PropTypes.width, height: React.PropTypes.height, }), scale: React.PropTypes.bool, }, render() { const {url, scale, thumbnail, video, trusted} = this.props; let {width, height} = thumbnail; const maxWidth = scale ? 512 : width; const maxHeight = scale ? 384 : height; let widthRatio = 1; if (width > maxWidth) { widthRatio = maxWidth / width; } width = Math.round(width * widthRatio); height = Math.round(height * widthRatio); let heightRatio = 1; if (height > maxHeight) { heightRatio = maxHeight / height; } width = Math.round(width * heightRatio); height = Math.round(height * heightRatio); return ( ); }, }); const EmbedVideo = React.createClass({ mixins: [PureRenderMixin], propTypes: { url: React.PropTypes.string.isRequired, playable: React.PropTypes.bool, thumbnail: React.PropTypes.shape({ url: React.PropTypes.string, // eslint-disable-next-line camelcase proxy_url: React.PropTypes.string, width: React.PropTypes.width, height: React.PropTypes.height, }), video: React.PropTypes.shape({ url: React.PropTypes.string, width: React.PropTypes.width, height: React.PropTypes.height, }), scale: React.PropTypes.bool, useVideoSizeWhenPlaying: React.PropTypes.bool, }, getInitialState() { return { play: false, }; }, getDefaultProps() { return { scale: true, useVideoSizeWhenPlaying: false, playable: false, }; }, handlePlay() { this.setState({play: true}); }, componentWillMount() { this.messageListener = null; }, componentWillUnmount() { this.removeMessageListener(); }, removeMessageListener() { if (this.messageListener != null) { window.removeEventListener('message', this.messageListener); this.messageListener = null; } }, installMessageListener(listener) { this.removeMessageListener(); const messageListener = (this.messageListener = e => { if (listener(e) === false && messageListener === this.messageListener) { this.removeMessageListener(); } }); window.addEventListener('message', messageListener); }, handleRef(src, el) { if (this.props.provider === 'Vine') { // This hack tricks vine into thinking that the video is in view and ready to be played, by emulating // functionality in their embed code that does scroll watching. In our case, we can just treat loading // the iframe as being in view. const expectedMessage = `ping::${src}`; this.installMessageListener(e => { if (el && el.contentWindow === e.source && e.origin === 'https://vine.co' && e.data === expectedMessage) { e.source.postMessage('pong', '*'); e.source.postMessage('fullyInView', '*'); e.source.postMessage('play', '*'); return false; } }); } }, render() { let {width, height} = this.props.thumbnail; if (this.state.play && this.props.useVideoSizeWhenPlaying) { if (this.props.video.width && this.props.video.height) { width = this.props.video.width; height = this.props.video.height; } } const maxWidth = this.props.scale ? 400 : width; const maxHeight = this.props.scale ? 300 : height; let widthRatio = 1; if (width > maxWidth) { widthRatio = maxWidth / width; } width = Math.round(width * widthRatio); height = Math.round(height * widthRatio); let heightRatio = 1; if (height > maxHeight) { heightRatio = maxHeight / height; } width = Math.round(width * heightRatio); height = Math.round(height * heightRatio); if (this.state.play) { const urlObj = url.parse(this.props.video.url, true); urlObj.query.autoplay = 1; urlObj.query['auto_play'] = 1; delete urlObj.search; const src = url.format(urlObj); return (