Fix #26: Scale images to the correct size and use more efficient image formats
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { Post } from '$lib/mastodon/response';
|
||||
import { type Post, SongThumbnailImageKind } from '$lib/mastodon/response';
|
||||
import type { SongInfo } from '$lib/odesliResponse';
|
||||
import AvatarComponent from '$lib/components/AvatarComponent.svelte';
|
||||
import AccountComponent from '$lib/components/AccountComponent.svelte';
|
||||
import { secondsSince, relativeTime } from '$lib/relativeTime';
|
||||
@ -14,6 +15,62 @@
|
||||
dateCreated = relativeTime($timePassed) ?? absoluteDate;
|
||||
}
|
||||
|
||||
// Blurred thumbs aren't generated (yet, unclear of they ever will)
|
||||
// So blurred forces using the small one, by skipping the others and removing its media query.
|
||||
// This is technically unnecessary - the blurred one will only show if it matches the small media query,
|
||||
// but this makes it more explicit
|
||||
function getSourceSetHtml(song: SongInfo, isBlurred: boolean = false): string {
|
||||
const small = new Map<string, string[]>();
|
||||
const large = new Map<string, string[]>();
|
||||
|
||||
// Sort thumbnails by file type. This is important, because the order of the srcset entries matter.
|
||||
// We need the best format to be first
|
||||
const formatPriority = new Map<string, number>([
|
||||
['avif', 0],
|
||||
['webp', 1],
|
||||
['jpg', 99],
|
||||
['jpeg', 99]
|
||||
]);
|
||||
const thumbs = (song.resizedThumbnails ?? []).sort((a, b) => {
|
||||
const extensionA = a.file.split('.').pop() ?? '';
|
||||
const extensionB = b.file.split('.').pop() ?? '';
|
||||
const prioA = formatPriority.get(extensionA) ?? 3;
|
||||
const prioB = formatPriority.get(extensionB) ?? 3;
|
||||
return prioA - prioB;
|
||||
});
|
||||
|
||||
for (const resizedThumb of thumbs) {
|
||||
if (isBlurred && resizedThumb.kind !== SongThumbnailImageKind.Small) {
|
||||
continue;
|
||||
}
|
||||
const extension = resizedThumb.file.split('.').pop();
|
||||
const mime = extension ? `image/${extension}` : 'application/octet-stream';
|
||||
const sourceSetEntry = `${resizedThumb.file} ${resizedThumb.sizeDescriptor}`;
|
||||
switch (resizedThumb.kind) {
|
||||
case SongThumbnailImageKind.Big:
|
||||
large.set(mime, [...(large.get(mime) || []), sourceSetEntry]);
|
||||
break;
|
||||
case SongThumbnailImageKind.Small:
|
||||
small.set(mime, [...(small.get(mime) || []), sourceSetEntry]);
|
||||
break;
|
||||
case SongThumbnailImageKind.Blurred: // currently not generated
|
||||
break;
|
||||
}
|
||||
}
|
||||
let html = '';
|
||||
const mediaAttribute = isBlurred ? '' : 'media="(max-width: 650px)"';
|
||||
for (const entry of small.entries()) {
|
||||
const srcset = entry[1].join(', ');
|
||||
html += `<source srcset="${srcset}" type="${entry[0]}" ${mediaAttribute} />`;
|
||||
}
|
||||
html += '\n';
|
||||
for (const entry of large.entries()) {
|
||||
const srcset = entry[1].join(', ');
|
||||
html += `<source srcset="${srcset}" type="${entry[0]}" />`;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Display relative time only after mount:
|
||||
// When JS is disabled the server-side rendered absolute date will be shown,
|
||||
@ -33,15 +90,21 @@
|
||||
{#if post.songs}
|
||||
{#each post.songs as song (song.pageUrl)}
|
||||
<div class="info-wrapper">
|
||||
<img class="bgimage" src={song.thumbnailUrl} loading="lazy" alt="Blurred cover" />
|
||||
<picture>
|
||||
{@html getSourceSetHtml(song)}
|
||||
<img class="bgimage" src={song.thumbnailUrl} loading="lazy" alt="Blurred cover" />
|
||||
</picture>
|
||||
<a href={song.pageUrl ?? song.postedUrl} target="_blank">
|
||||
<div class="info">
|
||||
<img
|
||||
src={song.thumbnailUrl}
|
||||
class="cover"
|
||||
alt="Cover for {song.artistName} - {song.title}"
|
||||
loading="lazy"
|
||||
/>
|
||||
<picture>
|
||||
{@html getSourceSetHtml(song)}
|
||||
<img
|
||||
src={song.thumbnailUrl}
|
||||
class="cover"
|
||||
alt="Cover for {song.artistName} - {song.title}"
|
||||
loading="lazy"
|
||||
/>
|
||||
</picture>
|
||||
<span class="text">{song.artistName} - {song.title}</span>
|
||||
</div>
|
||||
</a>
|
||||
|
Reference in New Issue
Block a user