forked from Mirrors/elk
Compare commits
35 commits
main
...
feat-incre
Author | SHA1 | Date | |
---|---|---|---|
|
5b37047b00 | ||
|
7b973811c0 | ||
|
83a4ee75d0 | ||
|
705ce6ada4 | ||
|
e18443ab6f | ||
|
200bc3d3f1 | ||
|
27c0c4d6f2 | ||
|
49a9291339 | ||
|
eab2342d91 | ||
|
a650b1f369 | ||
|
174b2b2d83 | ||
|
bb013ddd18 | ||
|
797b99f122 | ||
|
e88d255c07 | ||
|
5e717cac03 | ||
|
49290b7386 | ||
|
5da564dda4 | ||
|
cfacff87be | ||
|
dff937aa89 | ||
|
ed091d284f | ||
|
2f72c03fd9 | ||
|
26bc4e7251 | ||
|
a34e7e23f0 | ||
|
0f1937340d | ||
|
b90479d169 | ||
|
bd0a2517c6 | ||
|
a4eae9891b | ||
|
2c3e0253f6 | ||
|
2a819c6d0c | ||
|
19c8393c7c | ||
|
f73219f9bd | ||
|
32e68b6c65 | ||
|
5607c2fe37 | ||
|
4e81d0e27d | ||
|
cab3ed4ad4 |
5 changed files with 72 additions and 3 deletions
|
@ -10,3 +10,5 @@ NUXT_STORAGE_DRIVER=
|
||||||
NUXT_STORAGE_FS_BASE=
|
NUXT_STORAGE_FS_BASE=
|
||||||
|
|
||||||
NUXT_PUBLIC_DISABLE_VERSION_CHECK=
|
NUXT_PUBLIC_DISABLE_VERSION_CHECK=
|
||||||
|
|
||||||
|
NUXT_OPENGRAPH_API=
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default defineComponent({
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { attrs }) {
|
setup(props, { attrs, emit }) {
|
||||||
const placeholderSrc = ref<string>()
|
const placeholderSrc = ref<string>()
|
||||||
const isLoaded = ref(false)
|
const isLoaded = ref(false)
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ export default defineComponent({
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
isLoaded.value = true
|
isLoaded.value = true
|
||||||
}
|
}
|
||||||
|
img.onerror = (ev) => {
|
||||||
|
emit('onerror', ev)
|
||||||
|
}
|
||||||
img.src = props.src
|
img.src = props.src
|
||||||
if (props.srcset)
|
if (props.srcset)
|
||||||
img.srcset = props.srcset
|
img.srcset = props.srcset
|
||||||
|
|
|
@ -11,6 +11,11 @@ const props = defineProps<{
|
||||||
const alt = $computed(() => `${props.card.title} - ${props.card.title}`)
|
const alt = $computed(() => `${props.card.title} - ${props.card.title}`)
|
||||||
const isSquare = $computed(() => props.smallPictureOnly || props.card.width === props.card.height)
|
const isSquare = $computed(() => props.smallPictureOnly || props.card.width === props.card.height)
|
||||||
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname)
|
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname)
|
||||||
|
const useFallback = ref(false)
|
||||||
|
const imageSrcset = $computed(() => props.card.image
|
||||||
|
? `${props.card.image}${useFallback.value ? '' : `, /api/og-image/${encodeURIComponent(props.card.url)} 2x`}`
|
||||||
|
: '',
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: handle card.type: 'photo' | 'video' | 'rich';
|
// TODO: handle card.type: 'photo' | 'video' | 'rich';
|
||||||
</script>
|
</script>
|
||||||
|
@ -42,10 +47,13 @@ const providerName = $computed(() => props.card.providerName ? props.card.provid
|
||||||
<CommonBlurhash
|
<CommonBlurhash
|
||||||
:blurhash="card.blurhash"
|
:blurhash="card.blurhash"
|
||||||
:src="card.image"
|
:src="card.image"
|
||||||
|
:srcset="imageSrcset"
|
||||||
:width="card.width"
|
:width="card.width"
|
||||||
:height="card.height"
|
:height="card.height"
|
||||||
:alt="alt"
|
:alt="alt"
|
||||||
w-full h-full object-cover
|
w-full
|
||||||
|
h-full object-cover
|
||||||
|
@onerror="useFallback = true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import Inspect from 'vite-plugin-inspect'
|
import Inspect from 'vite-plugin-inspect'
|
||||||
import { isCI } from 'std-env'
|
import { isCI, isDevelopment } from 'std-env'
|
||||||
import { i18n } from './config/i18n'
|
import { i18n } from './config/i18n'
|
||||||
|
|
||||||
const isPreview = process.env.PULL_REQUEST === 'true'
|
const isPreview = process.env.PULL_REQUEST === 'true'
|
||||||
|
@ -65,6 +65,7 @@ export default defineNuxtConfig({
|
||||||
namespaceId: '',
|
namespaceId: '',
|
||||||
apiToken: '',
|
apiToken: '',
|
||||||
},
|
},
|
||||||
|
opengraphApi: '',
|
||||||
public: {
|
public: {
|
||||||
env: isCI ? isPreview ? 'staging' : 'production' : 'local',
|
env: isCI ? isPreview ? 'staging' : 'production' : 'local',
|
||||||
translateApi: '',
|
translateApi: '',
|
||||||
|
@ -86,6 +87,14 @@ export default defineNuxtConfig({
|
||||||
crawlLinks: false,
|
crawlLinks: false,
|
||||||
routes: ['/', '/200.html'],
|
routes: ['/', '/200.html'],
|
||||||
},
|
},
|
||||||
|
routeRules: {
|
||||||
|
'/api/og-image/**': {
|
||||||
|
static: isCI,
|
||||||
|
cache: !isCI && !isDevelopment
|
||||||
|
? { maxAge: 86400 } // 1 day
|
||||||
|
: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
keepalive: true,
|
keepalive: true,
|
||||||
|
|
47
server/api/og-image/[url].ts
Normal file
47
server/api/og-image/[url].ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// This API-Endpoint will be cached via netlify builder function -> nitro.routeRules['/api/og-image/**']
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const { url } = getRouterParams(event)
|
||||||
|
|
||||||
|
const cardUrl = decodeURIComponent(url || '')
|
||||||
|
|
||||||
|
if (!cardUrl) {
|
||||||
|
sendError(event, {
|
||||||
|
statusCode: 422,
|
||||||
|
fatal: false,
|
||||||
|
message: 'Missing cardUrl.',
|
||||||
|
name: 'OgImageError',
|
||||||
|
unhandled: false,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First we want to try to get the og:image from the html
|
||||||
|
// But sometimes it is not included due to async JS loading
|
||||||
|
const ogImageUrl = await resolveOgImageUrlManually(cardUrl)
|
||||||
|
|
||||||
|
if (!ogImageUrl) {
|
||||||
|
// If nothing helped, send 404 so the srcset can fallback to the default image
|
||||||
|
sendError(event, {
|
||||||
|
statusCode: 404,
|
||||||
|
fatal: false,
|
||||||
|
message: 'Could not find og:image.',
|
||||||
|
name: 'OgImageError',
|
||||||
|
unhandled: false,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fetch(ogImageUrl, {
|
||||||
|
responseType: 'stream',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const OG_IMAGE_RE = /<meta[^>]*property="og:image"[^>]*content="([^"]+)"|<meta[^>]*content="([^"]+)"[^>]*property="og:image"/
|
||||||
|
|
||||||
|
async function resolveOgImageUrlManually(cardUrl: string): Promise<string> {
|
||||||
|
const html = await $fetch<string>(cardUrl)
|
||||||
|
|
||||||
|
const match = html.match(OG_IMAGE_RE)
|
||||||
|
return match?.[1] ?? match?.[2] ?? ''
|
||||||
|
}
|
Loading…
Reference in a new issue