mirror of
https://github.com/defnull/fediwall.git
synced 2024-11-21 23:23:14 +01:00
Fallback to card preview image on posts without media.
Peertube posts have no media attachments but a preview card that shows an embedded video player in an iframe. Unfortunately this does not really support the small form-factor of a fediwall card and looks kinda ugly. Autoplay also won't work. So we just display the card preview image (if present) as a link you can click on to view the full video.
This commit is contained in:
parent
4d77c6cf8a
commit
088f0fe094
@ -43,12 +43,15 @@ const onMediaLoad = inject('fixLayout', () => undefined)
|
||||
<slot name="topleft"></slot>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div v-if="config.showMedia" class="wall-media mb-3" ref="mediaElement">
|
||||
<img v-if="media?.type === 'image'" :src="media.url" :alt="media.alt" :title="media.alt" @load="onMediaLoad">
|
||||
<video v-else-if="media?.type === 'video'" muted loop :autoplay="playVideo"
|
||||
<div v-if="config.showMedia && media" class="wall-media mb-3" ref="mediaElement">
|
||||
<img v-if="media.type === 'image'" :src="media.url" :alt="media.alt" :title="media.alt" @load="onMediaLoad">
|
||||
<video v-else-if="media.type === 'video'" muted loop :autoplay="playVideo"
|
||||
:poster="media.preview" :alt="media.alt" :title="media.alt" @loadedmetadata="onMediaLoad">
|
||||
<source v-if="playVideo" :src="media.url">
|
||||
</video>
|
||||
<a v-else-if="media.type==='card'" :href="media.url" target="_blank">
|
||||
<img :src="media.preview" :alt="media.alt" :title="media.alt" @load="onMediaLoad">
|
||||
</a>
|
||||
</div>
|
||||
<p v-if="config.showText" class="card-text" v-dompurify-html="post.content"></p>
|
||||
<p class="card-text text-end text-break"><a :href="post.url" target="_blank" :title="post.date.toLocaleString()"
|
||||
|
@ -1,7 +1,6 @@
|
||||
import type { Config, MastodonAccount, MastodonStatus, Post, PostMedia } from "@/types";
|
||||
import { regexEscape } from "@/utils";
|
||||
import { notBlank, regexEscape } from "@/utils";
|
||||
import { replaceInText } from '@/utils'
|
||||
import type { faTags } from "@fortawesome/free-solid-svg-icons";
|
||||
import DOMPurify from 'dompurify'
|
||||
|
||||
/**
|
||||
@ -236,13 +235,42 @@ const filterStatus = (cfg: Config, status: MastodonStatus) => {
|
||||
}
|
||||
|
||||
// Skip posts that would show up empty
|
||||
if (!cfg.showText && !status.media_attachments?.length) return false;
|
||||
if (!cfg.showText && findMedia(status).length == 0) return false;
|
||||
if (!cfg.showMedia && !status.content.trim()) return false;
|
||||
|
||||
// Accept anything else
|
||||
return true;
|
||||
}
|
||||
|
||||
function findMedia(status: MastodonStatus) {
|
||||
const media: PostMedia[] = []
|
||||
|
||||
status.media_attachments?.map((m): PostMedia | undefined => {
|
||||
const url = m.url;
|
||||
const alt = m.description ?? undefined
|
||||
const preview = m.preview_url ?? undefined
|
||||
switch (m.type) {
|
||||
case "image":
|
||||
return { type: "image", url, href:url, preview, alt }
|
||||
case "video":
|
||||
case "gifv":
|
||||
return { type: "video", url, href:url, preview, alt }
|
||||
case "audio":
|
||||
case "unknown":
|
||||
return
|
||||
}
|
||||
}).filter(m=>!!m).forEach(m=>media.push(m))
|
||||
|
||||
// Fall back to preview card images if no media is attached (e.g. for peertube posts)
|
||||
if(media.length == 0 && status.card) {
|
||||
const card = status.card
|
||||
if(notBlank(card.image) && notBlank(card.url))
|
||||
media.push({type:"card", url: card.url, preview:card.image, alt: status.card.description})
|
||||
}
|
||||
|
||||
return media
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a mastodon status object to a Post.
|
||||
*/
|
||||
@ -282,18 +310,7 @@ const statusToWallPost = (cfg: Config, status: MastodonStatus): Post => {
|
||||
const profile = status.account.acct
|
||||
const content = replaceEmojis(status.content, status.emojis)
|
||||
|
||||
const media = status.media_attachments?.map((m): PostMedia | undefined => {
|
||||
switch (m.type) {
|
||||
case "image":
|
||||
return { type: "image", url: m.url, preview: m.preview_url, alt: m.description ?? undefined }
|
||||
case "video":
|
||||
case "gifv":
|
||||
return { type: "video", url: m.url, preview: m.preview_url, alt: m.description ?? undefined }
|
||||
case "audio":
|
||||
case "unknown":
|
||||
return
|
||||
}
|
||||
}).filter((m): m is PostMedia => m !== undefined)
|
||||
const media = findMedia(status)
|
||||
|
||||
return {
|
||||
id: status.uri,
|
||||
|
28
src/types.ts
28
src/types.ts
@ -45,10 +45,11 @@ export type Post = {
|
||||
};
|
||||
|
||||
export type PostMedia = {
|
||||
type: "image" | "video"
|
||||
url: string,
|
||||
preview: string
|
||||
type: "image" | "video" | "card"
|
||||
url: string
|
||||
preview?: string
|
||||
alt?: string
|
||||
size?: [number,number]
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +68,7 @@ export type MastodonStatus = {
|
||||
in_reply_to_id?: string | null;
|
||||
language?: string | null;
|
||||
media_attachments: Array<MastodonMediaAttachment>;
|
||||
card?: MastodonCard,
|
||||
reblog?: MastodonStatus | null;
|
||||
sensitive: boolean;
|
||||
spoiler_text?: string | null;
|
||||
@ -114,3 +116,23 @@ export type MastodonMediaAttachment = {
|
||||
preview_url: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export type MastodonCard = {
|
||||
url: string;
|
||||
title: string;
|
||||
description: string;
|
||||
language: string;
|
||||
type: string;
|
||||
author_name: string;
|
||||
author_url: string;
|
||||
provider_name: string;
|
||||
provider_url: string;
|
||||
html: string;
|
||||
width: number;
|
||||
height: number;
|
||||
image: string;
|
||||
image_description: string;
|
||||
embed_url: string;
|
||||
blurhash: string | null;
|
||||
published_at?: any
|
||||
}
|
@ -9,6 +9,10 @@ export function isString(test: any) {
|
||||
return typeof test === 'string' || test instanceof String
|
||||
}
|
||||
|
||||
export function notBlank(test?: string) {
|
||||
return test && test.trim().length > 0
|
||||
}
|
||||
|
||||
export function arrayUnique<T>(array: T[]) {
|
||||
return array.filter((v, i, a) => a.indexOf(v) === i)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user