feat(userbot,api,frontend): file links, media downloads, story hold-pause, drop scheduled dupes
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { request } from "$lib/api/client";
|
||||
import type { FileShare, FileShareHit, ShareSubject } from "$lib/api/types";
|
||||
import { accounts } from "$lib/stores/accounts.svelte";
|
||||
|
||||
export interface ShareSettings {
|
||||
expiresInSeconds: number | null;
|
||||
keepExpiry?: boolean;
|
||||
maxDownloads: number | null;
|
||||
}
|
||||
|
||||
function subjectQuery(subject: ShareSubject): Record<string, number | string> {
|
||||
const query: Record<string, number | string> = { kind: subject.kind };
|
||||
if (subject.mediaId !== undefined) {
|
||||
query.media_id = subject.mediaId;
|
||||
}
|
||||
if (subject.versionId !== undefined) {
|
||||
query.version_id = subject.versionId;
|
||||
}
|
||||
if (subject.peerId !== undefined) {
|
||||
query.peer_id = subject.peerId;
|
||||
}
|
||||
if (subject.storyId !== undefined) {
|
||||
query.story_id = subject.storyId;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
export function listShares(activeOnly = false): Promise<FileShare[]> {
|
||||
return request<FileShare[]>("/shares", {
|
||||
account: true,
|
||||
query: { active_only: activeOnly, limit: 200 },
|
||||
});
|
||||
}
|
||||
|
||||
export function lookupShare(subject: ShareSubject): Promise<FileShare | null> {
|
||||
return request<FileShare | null>("/shares/lookup", {
|
||||
account: true,
|
||||
query: subjectQuery(subject),
|
||||
});
|
||||
}
|
||||
|
||||
export function createShare(
|
||||
subject: ShareSubject,
|
||||
settings: ShareSettings
|
||||
): Promise<FileShare> {
|
||||
return request<FileShare>("/shares", {
|
||||
method: "POST",
|
||||
body: {
|
||||
account_id: accounts.selectedId,
|
||||
kind: subject.kind,
|
||||
media_id: subject.mediaId ?? null,
|
||||
version_id: subject.versionId ?? null,
|
||||
peer_id: subject.peerId ?? null,
|
||||
story_id: subject.storyId ?? null,
|
||||
expires_in_seconds: settings.expiresInSeconds,
|
||||
max_downloads: settings.maxDownloads,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function updateShare(
|
||||
id: number,
|
||||
settings: ShareSettings
|
||||
): Promise<FileShare> {
|
||||
return request<FileShare>(`/shares/${id}`, {
|
||||
method: "PATCH",
|
||||
body: {
|
||||
expires_in_seconds: settings.expiresInSeconds,
|
||||
keep_expiry: settings.keepExpiry ?? false,
|
||||
max_downloads: settings.maxDownloads,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function revokeShare(id: number): Promise<FileShare> {
|
||||
return request<FileShare>(`/shares/${id}/revoke`, { method: "POST" });
|
||||
}
|
||||
|
||||
export function reissueShare(id: number): Promise<FileShare> {
|
||||
return request<FileShare>(`/shares/${id}/reissue`, { method: "POST" });
|
||||
}
|
||||
|
||||
export function deleteShare(id: number): Promise<void> {
|
||||
return request<void>(`/shares/${id}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
export function listShareHits(id: number): Promise<FileShareHit[]> {
|
||||
return request<FileShareHit[]>(`/shares/${id}/hits`, {
|
||||
query: { limit: 50 },
|
||||
});
|
||||
}
|
||||
|
||||
const TRAILING_SLASH = /\/$/;
|
||||
|
||||
export function shareUrl(share: FileShare): string {
|
||||
const origin =
|
||||
typeof window === "undefined"
|
||||
? ""
|
||||
: window.location.origin.replace(TRAILING_SLASH, "");
|
||||
return `${origin}/f/${share.token}`;
|
||||
}
|
||||
|
||||
export function shareState(
|
||||
share: FileShare
|
||||
): "active" | "revoked" | "expired" | "exhausted" {
|
||||
if (share.revoked_at) {
|
||||
return "revoked";
|
||||
}
|
||||
if (share.expires_at && Date.parse(share.expires_at) <= Date.now()) {
|
||||
return "expired";
|
||||
}
|
||||
if (
|
||||
share.max_downloads !== null &&
|
||||
share.download_count >= share.max_downloads
|
||||
) {
|
||||
return "exhausted";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
Reference in New Issue
Block a user