Use image thumbnails from pictshare. Fixes #555

This commit is contained in:
Dessalines 2020-02-27 12:55:23 -05:00
parent e784cc8b72
commit 2092cf3f4e
4 changed files with 72 additions and 60 deletions

View file

@ -188,16 +188,6 @@ hr {
border: unset; border: unset;
} }
.img-expand-overlay {
position: absolute;
top: 0;
right: 0;
padding: 2px;
background: rgba(0,0,0,.4);
border-bottom-left-radius: 0.25rem !important;
border-top-right-radius: 0.25rem !important;
}
.link-overlay:hover { .link-overlay:hover {
transition: .1s; transition: .1s;
opacity: 1; opacity: 1;

4
ui/package.json vendored
View file

@ -1,9 +1,9 @@
{ {
"name": "lemmy", "name": "lemmy",
"description": "A simple UI for lemmy", "description": "The official Lemmy UI",
"version": "1.0.0", "version": "1.0.0",
"author": "Dessalines", "author": "Dessalines",
"license": "GPL-2.0-or-later", "license": "AGPL-3.0-or-later",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "node fuse prod", "build": "node fuse prod",

View file

@ -51,6 +51,7 @@ interface PostListingState {
downvotes: number; downvotes: number;
url: string; url: string;
iframely: FramelyData; iframely: FramelyData;
thumbnail: string;
} }
interface PostListingProps { interface PostListingProps {
@ -80,6 +81,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
downvotes: this.props.post.downvotes, downvotes: this.props.post.downvotes,
url: this.props.post.url, url: this.props.post.url,
iframely: null, iframely: null,
thumbnail: null,
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -92,6 +94,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.handleEditCancel = this.handleEditCancel.bind(this); this.handleEditCancel = this.handleEditCancel.bind(this);
if (this.state.url) { if (this.state.url) {
this.setThumbnail();
this.fetchIframely(); this.fetchIframely();
} }
} }
@ -105,9 +108,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (nextProps.post.url !== this.state.url) { if (nextProps.post.url !== this.state.url) {
this.state.url = nextProps.post.url; this.state.url = nextProps.post.url;
if (this.state.url) { if (this.state.url) {
this.setThumbnail();
this.fetchIframely(); this.fetchIframely();
} else { } else {
this.state.iframely = null; this.state.iframely = null;
this.state.thumbnail = null;
} }
} }
@ -132,6 +137,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
); );
} }
imgThumbnail() {
let post = this.props.post;
return (
<object
className={`img-fluid thumbnail rounded ${(post.nsfw ||
post.community_nsfw) &&
'img-blur'}`}
data={imageThumbnailer(this.state.thumbnail)}
></object>
);
}
listing() { listing() {
let post = this.props.post; let post = this.props.post;
return ( return (
@ -161,37 +178,32 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</button> </button>
)} )}
</div> </div>
{this.hasImage() && !this.state.imageExpanded && ( {this.state.thumbnail && !this.state.imageExpanded && (
<div class="mx-2 mt-1 float-left position-relative"> <div class="mx-2 mt-1 float-left position-relative">
{isImage(this.state.url) ? (
<span
class="text-body pointer"
title={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
{this.imgThumbnail()}
<svg class="icon rounded link-overlay hover-link">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
) : (
<a <a
className="text-body" className="text-body"
href={this.state.url} href={this.state.url}
target="_blank" target="_blank"
title={this.state.url} title={this.state.url}
> >
<object {this.imgThumbnail()}
className={`img-fluid thumbnail rounded ${(post.nsfw ||
post.community_nsfw) &&
'img-blur'}`}
data={imageThumbnailer(this.getImage())}
>
<svg class="icon rounded placeholder">
<use xlinkHref="#icon-external-link"></use>
</svg>
</object>
<svg class="icon rounded link-overlay hover-link"> <svg class="icon rounded link-overlay hover-link">
<use xlinkHref="#icon-external-link"></use> <use xlinkHref="#icon-external-link"></use>
</svg> </svg>
</a> </a>
<span )}
title={i18n.t('expand_here')}
class="pointer"
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<svg class="icon img-expand-overlay">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
</div> </div>
)} )}
{this.state.url && isVideo(this.state.url) && ( {this.state.url && isVideo(this.state.url) && (
@ -247,7 +259,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</a> </a>
</small> </small>
)} )}
{this.hasImage() && ( {this.state.thumbnail && (
<> <>
{!this.state.imageExpanded ? ( {!this.state.imageExpanded ? (
<span <span
@ -272,7 +284,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
> >
<object <object
class="img-fluid img-expanded" class="img-fluid img-expanded"
data={this.getImage()} data={this.state.thumbnail}
> >
<svg class="icon rounded placeholder"> <svg class="icon rounded placeholder">
<use xlinkHref="#icon-external-link"></use> <use xlinkHref="#icon-external-link"></use>
@ -795,29 +807,39 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
.then(res => { .then(res => {
this.state.iframely = res; this.state.iframely = res;
this.setState(this.state); this.setState(this.state);
// Store and fetch the image in pictshare
if (
this.state.iframely.thumbnail_url &&
isImage(this.state.iframely.thumbnail_url)
) {
fetch(
`/pictshare/api/geturl.php?url=${this.state.iframely.thumbnail_url}`
)
.then(res => res.json())
.then(res => {
let url = `${window.location.origin}/pictshare/${res.url}`;
if (res.filetype == 'mp4') {
url += '/raw';
}
this.state.thumbnail = url;
this.setState(this.state);
});
}
}) })
.catch(error => { .catch(error => {
console.error(`Iframely service not set up properly. ${error}`); console.error(`Iframely service not set up properly. ${error}`);
}); });
} }
hasImage(): boolean { setThumbnail() {
return (
(this.state.url && isImage(this.state.url)) ||
(this.state.iframely && this.state.iframely.thumbnail_url !== undefined)
);
}
getImage(): string {
let simpleImg = isImage(this.state.url); let simpleImg = isImage(this.state.url);
if (simpleImg) { if (simpleImg) {
return this.state.url; this.state.thumbnail = this.state.url;
} else if (this.state.iframely) { } else {
let iframelyThumbnail = this.state.iframely.thumbnail_url; this.state.thumbnail = null;
if (iframelyThumbnail) {
return iframelyThumbnail;
}
} }
this.setState(this.state);
} }
handlePostLike(i: PostListing) { handlePostLike(i: PostListing) {

10
ui/src/utils.ts vendored
View file

@ -220,9 +220,9 @@ export function routeSearchTypeToEnum(type: string): SearchType {
} }
export async function getPageTitle(url: string) { export async function getPageTitle(url: string) {
let res = await fetch(`https://textance.herokuapp.com/title/${url}`); let res = await fetch(`/iframely/oembed?url=${url}`).then(res => res.json());
let data = await res.text(); let title = await res.title;
return data; return title;
} }
export function debounce( export function debounce(
@ -386,7 +386,7 @@ export function objectFlip(obj: any) {
export function pictshareAvatarThumbnail(src: string): string { export function pictshareAvatarThumbnail(src: string): string {
// sample url: http://localhost:8535/pictshare/gs7xuu.jpg // sample url: http://localhost:8535/pictshare/gs7xuu.jpg
let split = src.split('pictshare'); let split = src.split('pictshare');
let out = `${split[0]}pictshare/96x96${split[1]}`; let out = `${split[0]}pictshare/96${split[1]}`;
return out; return out;
} }
@ -401,7 +401,7 @@ export function showAvatars(): boolean {
export function imageThumbnailer(url: string): string { export function imageThumbnailer(url: string): string {
let split = url.split('pictshare'); let split = url.split('pictshare');
if (split.length > 1) { if (split.length > 1) {
let out = `${split[0]}pictshare/192x192${split[1]}`; let out = `${split[0]}pictshare/192${split[1]}`;
return out; return out;
} else { } else {
return url; return url;