mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 09:23:13 +01:00
parent
5e6b483149
commit
e0401de1a3
@ -15,6 +15,8 @@ import CollapsibleButton from './../ascribe_collapsible/collapsible_button';
|
|||||||
|
|
||||||
import AclProxy from '../acl_proxy';
|
import AclProxy from '../acl_proxy';
|
||||||
|
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
import { extractFileExtensionFromString } from '../../utils/file_utils';
|
import { extractFileExtensionFromString } from '../../utils/file_utils';
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ const EMBED_IFRAME_HEIGHT = {
|
|||||||
video: 315,
|
video: 315,
|
||||||
audio: 62
|
audio: 62
|
||||||
};
|
};
|
||||||
const ENCODE_UPDATE_TIME = 5000;
|
|
||||||
|
|
||||||
let MediaContainer = React.createClass({
|
let MediaContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -41,21 +43,18 @@ let MediaContainer = React.createClass({
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { content: { digital_work: digitalWork }, refreshObject } = this.props;
|
const { content: { digital_work: digitalWork }, refreshObject } = this.props;
|
||||||
|
const { timerId } = this.state;
|
||||||
|
|
||||||
if (digitalWork) {
|
if (digitalWork && this.isDigitalWorkEncoding() && !timerId) {
|
||||||
const isEncoding = digitalWork.isEncoding;
|
this.setState({ timerId: window.setInterval(refreshObject, AppConstants.encodeUpdateThreshold) });
|
||||||
|
|
||||||
if (digitalWork.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
|
|
||||||
this.setState({
|
|
||||||
timerId: window.setInterval(refreshObject, ENCODE_UPDATE_TIME)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUpdate() {
|
componentWillUpdate() {
|
||||||
if (this.props.content.digital_work.isEncoding === 100) {
|
const { timerId } = this.state;
|
||||||
window.clearInterval(this.state.timerId);
|
|
||||||
|
if (!this.isDigitalWorkEncoding() && timerId) {
|
||||||
|
window.clearInterval(timerId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -63,13 +62,35 @@ let MediaContainer = React.createClass({
|
|||||||
window.clearInterval(this.state.timerId);
|
window.clearInterval(this.state.timerId);
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
/*
|
||||||
const { content, currentUser } = this.props;
|
* A digital work is encoding if:
|
||||||
// Pieces and editions are joined to the user by a foreign key in the database, so
|
*
|
||||||
// the information in content will be updated if a user updates their username.
|
* - it's either a video that has `isEncoding` < 100
|
||||||
// We also force uniqueness of usernames, so this check is safe to dtermine if the
|
* - of a .tif|.tiff file that has not yet been converted
|
||||||
// content was registered by the current user.
|
* to a .jpeg thumbnail
|
||||||
const didUserRegisterContent = currentUser && (currentUser.username === content.user_registered);
|
*/
|
||||||
|
isDigitalWorkEncoding() {
|
||||||
|
const {
|
||||||
|
content: {
|
||||||
|
digital_work: digitalWork,
|
||||||
|
thumbnail
|
||||||
|
} } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
(
|
||||||
|
digitalWork.mime === 'video' &&
|
||||||
|
typeof digitalWork.isEncoding === 'number' &&
|
||||||
|
digitalWork.isEncoding !== 100
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
digitalWork.mime === 'image' &&
|
||||||
|
(this.getFileExtensionFromUrl(thumbnail.url) === 'tif' || this.getFileExtensionFromUrl(thumbnail.url) === 'tiff')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
getFileExtensionFromUrl(url) {
|
||||||
|
|
||||||
// We want to show the file's extension as a label of the download button.
|
// We want to show the file's extension as a label of the download button.
|
||||||
// We can however not only use `extractFileExtensionFromString` on the url for that
|
// We can however not only use `extractFileExtensionFromString` on the url for that
|
||||||
@ -78,8 +99,18 @@ let MediaContainer = React.createClass({
|
|||||||
// domain: e.g. '.net/live/<hash>'.
|
// domain: e.g. '.net/live/<hash>'.
|
||||||
// Therefore, we extract the file's name (last part of url, separated with a slash)
|
// Therefore, we extract the file's name (last part of url, separated with a slash)
|
||||||
// and try to extract the file extension from there.
|
// and try to extract the file extension from there.
|
||||||
const fileName = content.digital_work.url.split('/').pop();
|
const fileName = url.split('/').pop();
|
||||||
const fileExtension = extractFileExtensionFromString(fileName);
|
return extractFileExtensionFromString(fileName);
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { content, currentUser } = this.props;
|
||||||
|
|
||||||
|
// Pieces and editions are joined to the user by a foreign key in the database, so
|
||||||
|
// the information in content will be updated if a user updates their username.
|
||||||
|
// We also force uniqueness of usernames, so this check is safe to dtermine if the
|
||||||
|
// content was registered by the current user.
|
||||||
|
const didUserRegisterContent = currentUser && (currentUser.username === content.user_registered);
|
||||||
|
|
||||||
let thumbnail = content.thumbnail.thumbnail_sizes && content.thumbnail.thumbnail_sizes['600x600'] ?
|
let thumbnail = content.thumbnail.thumbnail_sizes && content.thumbnail.thumbnail_sizes['600x600'] ?
|
||||||
content.thumbnail.thumbnail_sizes['600x600'] : content.thumbnail.url_safe;
|
content.thumbnail.thumbnail_sizes['600x600'] : content.thumbnail.url_safe;
|
||||||
@ -117,7 +148,8 @@ let MediaContainer = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<MediaPlayer
|
<MediaPlayer
|
||||||
mimetype={mimetype}
|
mimetype={mimetype}
|
||||||
preview={thumbnail}
|
thumbnail={thumbnail}
|
||||||
|
thumbnailFileExtension={this.getFileExtensionFromUrl(thumbnail)}
|
||||||
url={content.digital_work.url}
|
url={content.digital_work.url}
|
||||||
extraData={extraData}
|
extraData={extraData}
|
||||||
encodingStatus={content.digital_work.isEncoding} />
|
encodingStatus={content.digital_work.isEncoding} />
|
||||||
@ -127,7 +159,6 @@ let MediaContainer = React.createClass({
|
|||||||
<TwitterShareButton
|
<TwitterShareButton
|
||||||
text={getLangText('Check out %s ascribed piece', didUserRegisterContent ? 'my latest' : 'this' )} />
|
text={getLangText('Check out %s ascribed piece', didUserRegisterContent ? 'my latest' : 'this' )} />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<AclProxy
|
<AclProxy
|
||||||
show={['video', 'audio', 'image'].indexOf(mimetype) === -1 || content.acl.acl_download}
|
show={['video', 'audio', 'image'].indexOf(mimetype) === -1 || content.acl.acl_download}
|
||||||
aclObject={content.acl}
|
aclObject={content.acl}
|
||||||
@ -136,7 +167,7 @@ let MediaContainer = React.createClass({
|
|||||||
url={content.digital_work.url}
|
url={content.digital_work.url}
|
||||||
title={content.title}
|
title={content.title}
|
||||||
artistName={content.artist_name}
|
artistName={content.artist_name}
|
||||||
fileExtension={fileExtension} />
|
fileExtension={this.getFileExtensionFromUrl(content.digital_work.url)} />
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
{embed}
|
{embed}
|
||||||
</p>
|
</p>
|
||||||
|
@ -6,9 +6,12 @@ import Q from 'q';
|
|||||||
import Panel from 'react-bootstrap/lib/Panel';
|
import Panel from 'react-bootstrap/lib/Panel';
|
||||||
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||||
|
|
||||||
|
import AscribeSpinner from '../ascribe_spinner';
|
||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
import { escapeHTML } from '../../utils/general_utils';
|
import { escapeHTML } from '../../utils/general_utils';
|
||||||
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
import { InjectInHeadUtils } from '../../utils/inject_utils';
|
import { InjectInHeadUtils } from '../../utils/inject_utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,18 +34,18 @@ let Other = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
let filename = this.props.url.split('/').pop();
|
let filename = this.props.url.split('/').pop();
|
||||||
let tokens = filename.split('.');
|
let tokens = filename.split('.');
|
||||||
let preview;
|
let thumbnail;
|
||||||
|
|
||||||
if (tokens.length > 1) {
|
if (tokens.length > 1) {
|
||||||
preview = '.' + tokens.pop();
|
thumbnail = '.' + tokens.pop();
|
||||||
} else {
|
} else {
|
||||||
preview = 'file';
|
thumbnail = 'file';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel className="media-other">
|
<Panel className="media-other">
|
||||||
<p className="text-center">
|
<p className="text-center">
|
||||||
{preview}
|
{thumbnail}
|
||||||
</p>
|
</p>
|
||||||
</Panel>
|
</Panel>
|
||||||
);
|
);
|
||||||
@ -52,11 +55,11 @@ let Other = React.createClass({
|
|||||||
let Image = React.createClass({
|
let Image = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
url: React.PropTypes.string,
|
url: React.PropTypes.string,
|
||||||
preview: React.PropTypes.string.isRequired
|
thumbnail: React.PropTypes.string.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if(this.props.url) {
|
if (this.props.url) {
|
||||||
InjectInHeadUtils.inject(AppConstants.jquery.sdkUrl)
|
InjectInHeadUtils.inject(AppConstants.jquery.sdkUrl)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
Q.all([
|
Q.all([
|
||||||
@ -67,15 +70,15 @@ let Image = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { url, preview } = this.props;
|
const { url, thumbnail } = this.props;
|
||||||
|
|
||||||
if(url) {
|
if (url) {
|
||||||
return (
|
return (
|
||||||
<img className="shmui-ascribe" src={preview} data-large-src={url}/>
|
<img className="shmui-ascribe" src={thumbnail} data-large-src={url} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<img src={preview}/>
|
<img src={thumbnail} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +133,7 @@ let Video = React.createClass({
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
preview: React.PropTypes.string.isRequired,
|
thumbnail: React.PropTypes.string.isRequired,
|
||||||
url: React.PropTypes.string.isRequired,
|
url: React.PropTypes.string.isRequired,
|
||||||
extraData: React.PropTypes.array.isRequired,
|
extraData: React.PropTypes.array.isRequired,
|
||||||
encodingStatus: React.PropTypes.number
|
encodingStatus: React.PropTypes.number
|
||||||
@ -170,7 +173,7 @@ let Video = React.createClass({
|
|||||||
prepareVideoHTML() {
|
prepareVideoHTML() {
|
||||||
let sources = this.props.extraData.map((data) => '<source type="video/' + data.type + '" src="' + escapeHTML(data.url) + '" />');
|
let sources = this.props.extraData.map((data) => '<source type="video/' + data.type + '" src="' + escapeHTML(data.url) + '" />');
|
||||||
let html = [
|
let html = [
|
||||||
'<video id="mainvideo" class="video-js vjs-default-skin" poster="' + escapeHTML(this.props.preview) + '"',
|
'<video id="mainvideo" class="video-js vjs-default-skin" poster="' + escapeHTML(this.props.thumbnail) + '"',
|
||||||
'controls preload="none" width="auto" height="auto">',
|
'controls preload="none" width="auto" height="auto">',
|
||||||
sources.join('\n'),
|
sources.join('\n'),
|
||||||
'</video>'];
|
'</video>'];
|
||||||
@ -184,7 +187,7 @@ let Video = React.createClass({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Image preview={this.props.preview} />
|
<Image thumbnail={this.props.thumbnail} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,20 +203,31 @@ let resourceMap = {
|
|||||||
let MediaPlayer = React.createClass({
|
let MediaPlayer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
mimetype: React.PropTypes.oneOf(['image', 'video', 'audio', 'pdf', 'other']).isRequired,
|
mimetype: React.PropTypes.oneOf(['image', 'video', 'audio', 'pdf', 'other']).isRequired,
|
||||||
preview: React.PropTypes.string.isRequired,
|
thumbnail: React.PropTypes.string.isRequired,
|
||||||
|
thumbnailFileExtension: React.PropTypes.string,
|
||||||
url: React.PropTypes.string.isRequired,
|
url: React.PropTypes.string.isRequired,
|
||||||
extraData: React.PropTypes.array,
|
extraData: React.PropTypes.array,
|
||||||
encodingStatus: React.PropTypes.number
|
encodingStatus: React.PropTypes.number,
|
||||||
|
},
|
||||||
|
|
||||||
|
isVideoEncoding() {
|
||||||
|
const { mimetype, encodingStatus } = this.props;
|
||||||
|
return mimetype === 'video' && encodingStatus !== undefined && encodingStatus !== 100;
|
||||||
|
},
|
||||||
|
|
||||||
|
isImageEncoding() {
|
||||||
|
const { mimetype, thumbnailFileExtension } = this.props;
|
||||||
|
return mimetype === 'image' && (thumbnailFileExtension === 'tif' || thumbnailFileExtension === 'tiff');
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { mimetype,
|
const { mimetype,
|
||||||
preview,
|
thumbnail,
|
||||||
url,
|
url,
|
||||||
extraData,
|
extraData,
|
||||||
encodingStatus } = this.props;
|
encodingStatus } = this.props;
|
||||||
|
|
||||||
if (mimetype === 'video' && encodingStatus !== undefined && encodingStatus !== 100) {
|
if (this.isVideoEncoding()) {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-detail-header ascribe-media-player">
|
<div className="ascribe-detail-header ascribe-media-player">
|
||||||
<p>
|
<p>
|
||||||
@ -225,10 +239,23 @@ let MediaPlayer = React.createClass({
|
|||||||
className="ascribe-progress-bar" />
|
className="ascribe-progress-bar" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (this.isImageEncoding()) {
|
||||||
|
return (
|
||||||
|
<div className="ascribe-media-player encoding-image">
|
||||||
|
<AscribeSpinner color='dark-blue' size='lg' />
|
||||||
|
<em className="text-center">
|
||||||
|
{getLangText('We successfully received your image and it is now being encoded.')}
|
||||||
|
<br />
|
||||||
|
{getLangText('We will be refreshing this page as soon as encoding has finished.')}
|
||||||
|
<br />
|
||||||
|
{getLangText('(You may close this page)')}
|
||||||
|
</em>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let Component = resourceMap[mimetype] || Other;
|
let Component = resourceMap[mimetype] || Other;
|
||||||
let componentProps = {
|
let componentProps = {
|
||||||
preview,
|
thumbnail,
|
||||||
url,
|
url,
|
||||||
extraData,
|
extraData,
|
||||||
encodingStatus
|
encodingStatus
|
||||||
@ -242,7 +269,7 @@ let MediaPlayer = React.createClass({
|
|||||||
//
|
//
|
||||||
// If this is the case, we disable shmui by deleting the original `url` prop and replace
|
// If this is the case, we disable shmui by deleting the original `url` prop and replace
|
||||||
// the assigned component to `Image`.
|
// the assigned component to `Image`.
|
||||||
if(!decodeURIComponent(preview).match(/https:\/\/.*\/media\/thumbnails\/ascribe_spiral.png/) &&
|
if (!decodeURIComponent(thumbnail).match(/https:\/\/.*\/media\/thumbnails\/ascribe_spiral.png/) &&
|
||||||
Component === Other) {
|
Component === Other) {
|
||||||
Component = resourceMap.image;
|
Component = resourceMap.image;
|
||||||
delete componentProps.url;
|
delete componentProps.url;
|
||||||
|
@ -92,13 +92,15 @@ const constants = {
|
|||||||
|
|
||||||
'searchThreshold': 500,
|
'searchThreshold': 500,
|
||||||
|
|
||||||
|
'encodeUpdateThreshold': 5000,
|
||||||
|
|
||||||
'supportedThumbnailFileFormats': [
|
'supportedThumbnailFileFormats': [
|
||||||
'x-sgi-movie', 'x-msvideo', 'quicktime', 'mpeg', 'png', 'jpeg', 'gif',
|
'x-sgi-movie', 'x-msvideo', 'quicktime', 'mpeg', 'png', 'jpeg', 'gif',
|
||||||
'ogg', 'oga', 'ogv', 'ogx', 'wmv', 'wma', 'flv', '3gpp2', '3p2', '3pg',
|
'ogg', 'oga', 'ogv', 'ogx', 'wmv', 'wma', 'flv', '3gpp2', '3p2', '3pg',
|
||||||
'png', 'jpg', 'jpeg', 'gif', '264', '3g', '3g2', '3gp', '3gp2', '3gpp',
|
'png', 'jpg', 'jpeg', 'gif', '264', '3g', '3g2', '3gp', '3gp2', '3gpp',
|
||||||
'mp4', 'm4a', 'm4v', 'f4v', 'f4a', 'm4b', 'm4r', 'f4b', 'mov', 'quicktime',
|
'mp4', 'm4a', 'm4v', 'f4v', 'f4a', 'm4b', 'm4r', 'f4b', 'mov', 'quicktime',
|
||||||
'webm', 'x264', 'mpeg', 'mpeg4', 'mpg4', 'bmp', 'eps', 'jp2', 'j2k', 'jpm',
|
'webm', 'x264', 'mpeg', 'mpeg4', 'mpg4', 'bmp', 'eps', 'jp2', 'j2k', 'jpm',
|
||||||
'mj2'
|
'mj2', 'tif', 'tiff'
|
||||||
],
|
],
|
||||||
|
|
||||||
// in case of whitelabel customization, we store stuff here
|
// in case of whitelabel customization, we store stuff here
|
||||||
|
@ -115,5 +115,15 @@
|
|||||||
.vjs-default-skin .vjs-control-bar {
|
.vjs-default-skin .vjs-control-bar {
|
||||||
background-color: rgba(0,0,0,.7);
|
background-color: rgba(0,0,0,.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.encoding-image {
|
||||||
|
text-align: center;
|
||||||
|
margin: 2em 0 2em 0;
|
||||||
|
|
||||||
|
em {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user