frontend/app/Entry/EntryThumbnail.jsx (97 lines of code) (raw):

import React from 'react'; import PropTypes from 'prop-types'; import axios from 'axios'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import {createStyles, withStyles} from "@material-ui/core"; import clsx from "clsx"; const styles = createStyles({ entryThumbnail: { color: "inherit", marginLeft: "auto", marginRight: "auto", overflow: "hidden", marginTop: "auto", marginBottom: "auto", height: "80px", display: "block" }, entryThumbnailShadow: { boxShadow: "2px 2px 6px black" } }); class EntryThumbnail extends React.Component { static propTypes = { mimeType: PropTypes.object.isRequired, fileExtension: PropTypes.string, entryId: PropTypes.string.isRequired, dataTip: PropTypes.string, cancelToken: PropTypes.object }; static knownAudioExtensions = [ "wav", "aiff", "aif", "mp3", "m4a", "m3a" ]; static knownVideoExtensions = [ "mpg", "mp4", "m4v", "wmv", "mov", "avi", "mkv" ]; static knownImageExtensions = [ "jpg", "jpeg", "tif", "tiff", "tga", "png", "pict", "pct" ]; constructor(props){ super(props); this.state = { thumbnailUri: null } } componentDidMount(){ this.setState({loading: true, lastError: null},()=>{ axios.get("/api/proxy/" + this.props.entryId + "/playable?proxyType=THUMBNAIL", {cancelToken: this.props.cancelToken}) .then(result=>{ this.setState({loading: false, lastError: null, thumbnailUri: result.data.uri}) }).catch(err=>{ if(!axios.isCancel(err)) { this.setState({loading: false, lastError: err}) } }) }) } /** * deliver a "sensible" icon based on file extension, if the index does not provide us with an adequate MIME type */ iconFromExtension(){ //no file extension at all=>default icon if(!this.props.fileExtension) return <FontAwesomeIcon icon="file" size="4x" className={this.props.classes.entryThumbnail}/>; const lcXtn = this.props.fileExtension.toLowerCase(); if(EntryThumbnail.knownAudioExtensions.includes(lcXtn)) return <FontAwesomeIcon icon="volume-up" size="4x" className={this.props.classes.entryThumbnail}/>; if(EntryThumbnail.knownVideoExtensions.includes(lcXtn)) return <FontAwesomeIcon icon="film" size="4x" className={this.props.classes.entryThumbnail}/>; if(EntryThumbnail.knownImageExtensions.includes(lcXtn)) return <FontAwesomeIcon icon="image" size="4x" className={this.props.classes.entryThumbnail}/>; return <FontAwesomeIcon icon="file" size="4x" className={this.props.classes.entryThumbnail}/>; } render(){ if(this.state.thumbnailUri) return <img src={this.state.thumbnailUri} className={clsx(this.props.classes.entryThumbnail, this.props.classes.entryThumbnailShadow)}/>; if(!this.props.mimeType) return this.iconFromExtension(); if(this.props.mimeType.major==="application" && this.props.mimeType.minor==="octet-stream") return this.iconFromExtension(); if(this.props.mimeType.major==="video") return <FontAwesomeIcon icon="film" size="4x" className={this.props.classes.entryThumbnail}/>; if(this.props.mimeType.major==="audio") return <FontAwesomeIcon icon="volume-up" size="4x" className={this.props.classes.entryThumbnail}/>; if(this.props.mimeType.major==="image") return <FontAwesomeIcon icon="image" size="4x" className={this.props.classes.entryThumbnail}/>; return <FontAwesomeIcon icon="file" size="4x" className={this.props.classes.entryThumbnail}/>; } } export default withStyles(styles)(EntryThumbnail);