feat: asynchronous album covers

This commit is contained in:
not-nullptr 2024-11-14 19:59:00 +00:00
parent 1328cdcb05
commit aac176816b
5 changed files with 87 additions and 47 deletions

View File

@ -47,7 +47,7 @@
class="absolute w-full h-full"
style="
z-index: {index + 2};
backdrop-filter: blur({blurIntensity}px);
backdrop-filter: blur( calc({blurIntensity}px * var(--blur-amount, 1)) );
mask: {mask};
"
></div>
@ -63,6 +63,6 @@
></div>
<div
class="absolute top-0 left-0 w-full h-full z-50"
style="background: linear-gradient({getGradientDirection()}, transparent 0%, {fadeTo} 100%);"
style="background: linear-gradient({getGradientDirection()}, transparent 0%, {fadeTo} 100%); opacity: var(--blur-amount, 1);"
></div>
</div>

View File

@ -16,18 +16,21 @@ export class VertFile {
public to = $state("");
public blobUrl = $state<string>();
public converter: Converter | null = null;
constructor(
public readonly file: File,
to: string,
converter?: Converter,
public readonly blobUrl?: string,
blobUrl?: string,
) {
this.to = to;
this.converter = converter ?? null;
this.convert = this.convert.bind(this);
this.download = this.download.bind(this);
this.blobUrl = blobUrl;
}
public async convert() {

View File

@ -11,8 +11,10 @@ export const load = ({ url, request, cookies }) => {
const { pathname } = url;
const ua = request.headers.get("user-agent");
const isMobile = /mobile/i.test(ua || "");
const isFirefox = /firefox/i.test(ua || "");
return {
pathname,
isMobile,
isFirefox,
};
};

View File

@ -63,49 +63,35 @@
img.onerror = async () => {
// resolve(new VertFile(f, to, converter));
const reader = new FileReader();
const file = new VertFile(f, to, converter);
resolve(file);
reader.onload = async (e) => {
try {
const tags = await new Promise<TagType>(
(resolve, reject) => {
jsmediatags.read(
new Blob([
new Uint8Array(
e.target
?.result as ArrayBuffer,
),
]),
{
onSuccess: (tag) =>
resolve(tag),
onError: (error) =>
reject(error),
},
);
},
);
console.log(tags);
const picture = tags.tags.picture;
if (!picture) {
resolve(new VertFile(f, to, converter));
return;
}
const blob = new Blob(
[new Uint8Array(picture.data)],
{
type: picture.format,
},
);
resolve(
new VertFile(
f,
to,
converter,
URL.createObjectURL(blob),
),
);
} catch {
resolve(new VertFile(f, to, converter));
}
const tags = await new Promise<TagType>(
(resolve, reject) => {
jsmediatags.read(
new Blob([
new Uint8Array(
e.target?.result as ArrayBuffer,
),
]),
{
onSuccess: (tag) => resolve(tag),
onError: (error) => reject(error),
},
);
},
);
const picture = tags.tags.picture;
if (!picture) return;
const blob = new Blob(
[new Uint8Array(picture.data)],
{
type: picture.format,
},
);
const url = URL.createObjectURL(blob);
file.blobUrl = url;
};
reader.readAsArrayBuffer(f);
};

View File

@ -13,6 +13,13 @@
import { ArrowRight, Disc2Icon, FileAudioIcon, XIcon } from "lucide-svelte";
import { onMount } from "svelte";
import { quintOut } from "svelte/easing";
import {
fade,
type EasingFunction,
type TransitionConfig,
} from "svelte/transition";
const { data } = $props();
const reversedFiles = $derived(files.files.slice().reverse());
@ -131,6 +138,33 @@
files.files = [];
goto("/");
};
export const progBlur = (
_: HTMLElement,
config:
| Partial<{
duration: number;
easing: EasingFunction;
}>
| undefined,
dir: {
direction: "in" | "out" | "both";
},
): TransitionConfig => {
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)",
).matches;
if (!config) config = {};
if (!config.duration) config.duration = 300;
if (!config.easing) config.easing = quintOut;
return {
duration: prefersReducedMotion ? 0 : config?.duration || 300,
css: (t) => {
return "--blur-amount: " + (dir.direction !== "in" ? t : 1 - t);
},
easing: config?.easing,
};
};
</script>
<svelte:head>
@ -279,7 +313,9 @@
)}
style="background-color: color-mix(in srgb, var(--{file.result
? 'accent-bg'
: 'bg'}), transparent var(--transparency)); backdrop-filter: blur(18px);"
: 'bg'}), transparent var(--transparency)); backdrop-filter: blur({data.isFirefox
? 0
: 18}px);"
>
<div
class="w-full grid grid-cols-1 grid-rows-1"
@ -418,10 +454,23 @@
{#if file.blobUrl}
<div
class="bg-cover bg-center w-full h-full"
style="background-image: url({file.blobUrl});"
style="background-image: url({file.blobUrl})"
in:blur={{
blurMultiplier: 24,
scale: {
start: 1.1,
end: 1,
},
duration,
easing: quintOut,
}}
></div>
<div
class="absolute left-0 top-0 pt-[50px] h-full w-full"
transition:progBlur={{
duration,
easing: quintOut,
}}
>
<ProgressiveBlur
direction="bottom"