Add customizable thumbnails for audio and video attachments (#14145)
- Change audio files to not be stripped of metadata - Automatically extract cover art from audio if it exists - Add `thumbnail` parameter to `POST /api/v1/media`, `POST /api/v2/media` and `PUT /api/v1/media/:id` - Add `icon` to represent it in attachments in ActivityPub - Fix `preview_url` containing URL of missing missing image when there is no thumbnail instead of null - Fix duration of audio not being displayed on public pages until the file is loaded
This commit is contained in:
parent
fa4876a1b9
commit
64aac30733
23 changed files with 247 additions and 138 deletions
|
@ -352,7 +352,8 @@ class Status extends ImmutablePureComponent {
|
|||
<Component
|
||||
src={attachment.get('url')}
|
||||
alt={attachment.get('description')}
|
||||
poster={status.getIn(['account', 'avatar_static'])}
|
||||
poster={attachment.get('preview_url') || status.getIn(['account', 'avatar_static'])}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
|
||||
width={this.props.cachedMediaWidth}
|
||||
height={110}
|
||||
|
|
|
@ -157,6 +157,7 @@ class Audio extends React.PureComponent {
|
|||
fullscreen: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
cacheWidth: PropTypes.func,
|
||||
blurhash: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -222,32 +223,42 @@ class Audio extends React.PureComponent {
|
|||
window.addEventListener('scroll', this.handleScroll);
|
||||
window.addEventListener('resize', this.handleResize, { passive: true });
|
||||
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = () => this.handlePosterLoad(img);
|
||||
img.src = this.props.poster;
|
||||
if (!this.props.blurhash) {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = () => this.handlePosterLoad(img);
|
||||
img.src = this.props.poster;
|
||||
} else {
|
||||
this._setColorScheme();
|
||||
this._decodeBlurhash();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
if (prevProps.poster !== this.props.poster) {
|
||||
if (prevProps.poster !== this.props.poster && !this.props.blurhash) {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = () => this.handlePosterLoad(img);
|
||||
img.src = this.props.poster;
|
||||
}
|
||||
|
||||
if (prevState.blurhash !== this.state.blurhash) {
|
||||
const context = this.blurhashCanvas.getContext('2d');
|
||||
const pixels = decode(this.state.blurhash, 32, 32);
|
||||
const outputImageData = new ImageData(pixels, 32, 32);
|
||||
|
||||
context.putImageData(outputImageData, 0, 0);
|
||||
if (prevState.blurhash !== this.state.blurhash || prevProps.blurhash !== this.props.blurhash) {
|
||||
this._setColorScheme();
|
||||
this._decodeBlurhash();
|
||||
}
|
||||
|
||||
this._clear();
|
||||
this._draw();
|
||||
}
|
||||
|
||||
_decodeBlurhash () {
|
||||
const context = this.blurhashCanvas.getContext('2d');
|
||||
const pixels = decode(this.props.blurhash || this.state.blurhash, 32, 32);
|
||||
const outputImageData = new ImageData(pixels, 32, 32);
|
||||
|
||||
context.putImageData(outputImageData, 0, 0);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
|
@ -415,7 +426,7 @@ class Audio extends React.PureComponent {
|
|||
}
|
||||
|
||||
handlePosterLoad = image => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
canvas.width = image.width;
|
||||
|
@ -425,10 +436,15 @@ class Audio extends React.PureComponent {
|
|||
|
||||
const inputImageData = context.getImageData(0, 0, image.width, image.height);
|
||||
const blurhash = encode(inputImageData.data, image.width, image.height, 4, 4);
|
||||
|
||||
this.setState({ blurhash });
|
||||
}
|
||||
|
||||
_setColorScheme () {
|
||||
const blurhash = this.props.blurhash || this.state.blurhash;
|
||||
const averageColor = decodeRGB(decode83(blurhash.slice(2, 6)));
|
||||
|
||||
this.setState({
|
||||
blurhash,
|
||||
color: adjustColor(averageColor),
|
||||
darkText: luma(averageColor) >= 165,
|
||||
});
|
||||
|
|
|
@ -125,7 +125,8 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
src={attachment.get('url')}
|
||||
alt={attachment.get('description')}
|
||||
duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
|
||||
poster={status.getIn(['account', 'avatar_static'])}
|
||||
poster={attachment.get('preview_url') || status.getIn(['account', 'avatar_static'])}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
height={150}
|
||||
/>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue