fix(api,frontend): render files by name without fetching, previewable share links
This commit is contained in:
@@ -4,13 +4,13 @@
|
||||
import { type MediaResult, requestMedia } from "$lib/api/client";
|
||||
import { downloadMedia } from "$lib/api/download";
|
||||
import { fetchMedia, getMessageMedia } from "$lib/api/endpoints";
|
||||
import type { ViewerItem } from "$lib/api/media";
|
||||
import { isPreviewable, type ViewerItem } from "$lib/api/media";
|
||||
import Button from "$lib/components/ui/Button.svelte";
|
||||
import ContextMenu from "$lib/components/ui/ContextMenu.svelte";
|
||||
import ContextMenuItem from "$lib/components/ui/ContextMenuItem.svelte";
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import Spinner from "$lib/components/ui/Spinner.svelte";
|
||||
import { mediaKindLabel } from "$lib/format/media";
|
||||
import { formatBytes, mediaKindLabel } from "$lib/format/media";
|
||||
import { poster } from "$lib/media/poster";
|
||||
import { shareUi } from "$lib/stores/shares.svelte";
|
||||
import { toasts } from "$lib/stores/toasts.svelte";
|
||||
@@ -33,6 +33,8 @@
|
||||
let messageId = $state<number | null>(null);
|
||||
let currentMediaId = $state<number | null>(null);
|
||||
let fileName = $state<string | null>(null);
|
||||
let fileSize = $state<number | null>(null);
|
||||
let fileOnly = $state(false);
|
||||
let result = $state<MediaResult | null>(null);
|
||||
let loading = $state(false);
|
||||
let saving = $state(false);
|
||||
@@ -48,12 +50,12 @@
|
||||
);
|
||||
const hasNav = $derived(items.length > 1);
|
||||
const canSave = $derived(
|
||||
currentMediaId !== null && result?.state === "ready"
|
||||
currentMediaId !== null && (fileOnly || result?.state === "ready")
|
||||
);
|
||||
const title = $derived(fileName ?? mediaKindLabel(kind) ?? "Медиа");
|
||||
|
||||
function revoke() {
|
||||
if (result?.state === "ready") {
|
||||
if (result?.state === "ready" && result.url) {
|
||||
URL.revokeObjectURL(result.url);
|
||||
}
|
||||
}
|
||||
@@ -66,25 +68,39 @@
|
||||
messageId = item.messageId;
|
||||
currentMediaId = null;
|
||||
fileName = item.fileName;
|
||||
fileSize = item.fileSize;
|
||||
fileOnly = false;
|
||||
const current = ++token;
|
||||
try {
|
||||
let mediaId = item.mediaId;
|
||||
let downloaded = item.downloaded;
|
||||
let name = item.fileName;
|
||||
let size = item.fileSize;
|
||||
let mimeType = item.mime;
|
||||
if (mediaId === null) {
|
||||
const meta = await getMessageMedia(chatId, item.messageId);
|
||||
mediaId = meta.id;
|
||||
downloaded = meta.downloaded;
|
||||
kind = meta.kind;
|
||||
name = meta.file_name;
|
||||
size = meta.file_size;
|
||||
mimeType = meta.mime;
|
||||
}
|
||||
const plainFile = downloaded && !isPreviewable(kind, mimeType);
|
||||
let next: MediaResult;
|
||||
if (plainFile) {
|
||||
next = { state: "ready", url: "", mime: mimeType };
|
||||
} else if (downloaded) {
|
||||
next = await requestMedia(mediaId);
|
||||
} else {
|
||||
next = { state: "not-downloaded" } as MediaResult;
|
||||
}
|
||||
const next = downloaded
|
||||
? await requestMedia(mediaId)
|
||||
: ({ state: "not-downloaded" } as MediaResult);
|
||||
if (current === token) {
|
||||
result = next;
|
||||
currentMediaId = mediaId;
|
||||
fileName = name;
|
||||
fileSize = size;
|
||||
fileOnly = plainFile;
|
||||
}
|
||||
} catch {
|
||||
if (current === token) {
|
||||
@@ -233,10 +249,17 @@
|
||||
<!-- biome-ignore lint/a11y/useMediaCaption: archived media has no captions -->
|
||||
<audio src={result.url} controls></audio>
|
||||
{:else if result?.state === "ready"}
|
||||
<button class="media-download" type="button" onclick={save}>
|
||||
<Icon name="download" />
|
||||
Скачать файл
|
||||
</button>
|
||||
<div class="media-file">
|
||||
<span class="file-glyph"><Icon name="document" size="2rem" /></span>
|
||||
<p class="file-name">{title}</p>
|
||||
{#if fileSize}
|
||||
<p class="file-size">{formatBytes(fileSize)}</p>
|
||||
{/if}
|
||||
<button class="media-download" type="button" onclick={save}>
|
||||
<Icon name="download" />
|
||||
Скачать файл
|
||||
</button>
|
||||
</div>
|
||||
{:else if result?.state === "not-downloaded"}
|
||||
<div class="media-message">
|
||||
<p>Файл ещё не скачан в архив.</p>
|
||||
@@ -354,6 +377,42 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.media-file {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
max-width: min(24rem, 90vw);
|
||||
color: var(--color-white);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.file-glyph {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 4.5rem;
|
||||
height: 4.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
overflow-wrap: anywhere;
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 0.8125rem;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.media-download {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user