Files
HKSingleParty/99_references/voyager-main/src/services/lemmy.ts
2025-05-28 09:55:51 +08:00

105 lines
2.5 KiB
TypeScript

import { LemmyHttp } from "lemmy-js-client";
import { reduceFileSize } from "../helpers/imageCompress";
import { isNative, supportsWebp } from "../helpers/device";
import nativeFetch from "./nativeFetch";
export function buildBaseLemmyUrl(url: string): string {
if (import.meta.env.VITE_FORCE_LEMMY_INSECURE) {
return `http://${url}`;
}
return `https://${url}`;
}
export function getClient(url: string, jwt?: string): LemmyHttp {
return new LemmyHttp(buildBaseLemmyUrl(url), {
fetchFunction: isNative() ? nativeFetch : fetch.bind(globalThis),
headers: jwt
? {
Authorization: `Bearer ${jwt}`,
["Cache-Control"]: "no-cache", // otherwise may get back cached site response (despite JWT)
}
: undefined,
});
}
export const LIMIT = 50;
/**
* upload image, compressing before upload if needed
*
* @returns relative pictrs URL
*/
export async function _uploadImage(client: LemmyHttp, image: File) {
let compressedImageIfNeeded;
try {
compressedImageIfNeeded = await reduceFileSize(
image,
990_000, // 990 kB - Lemmy's default limit is 1MB
1500,
1500,
0.85,
);
} catch (error) {
compressedImageIfNeeded = image;
console.error("Image compress failed", error);
}
const response = await client.uploadImage({
image: compressedImageIfNeeded as File,
});
// lemm.ee uses response.message for error messages (e.g. account too new)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!response.url) throw new Error(response.msg ?? (response as any).message);
return response;
}
interface ImageOptions {
/**
* maximum image dimension
*/
size?: number;
devicePixelRatio?: number;
format?: "jpg" | "png" | "webp";
}
const defaultFormat = supportsWebp() ? "webp" : "jpg";
export function getImageSrc(url: string, options?: ImageOptions) {
if (!options || !options.size) return url;
let mutableUrl;
try {
mutableUrl = new URL(url);
} catch (_) {
return url;
}
const params = mutableUrl.searchParams;
if (options.size) {
params.set(
"thumbnail",
`${Math.round(
options.size * (options?.devicePixelRatio ?? window.devicePixelRatio),
)}`,
);
}
params.set("format", options.format ?? defaultFormat);
return mutableUrl.toString();
}
export const customBackOff = async (attempt = 0, maxRetries = 5) => {
await new Promise((resolve) => {
setTimeout(resolve, Math.min(attempt, maxRetries) * 4_000);
});
};