FileUpload: add 0x0 and catbox (#756)

* FileUpload: add 0x0 and catbox

* FileUpload: add litterbox
This commit is contained in:
Key 2026-02-10 16:35:27 +00:00 • committed by GitHub
parent e6d3cbf3eb
commit 999136b73a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 135 additions and 6 deletions

View file

@ -22,7 +22,10 @@ export const settings = definePluginSettings({
options: [
{ label: "Zipline", value: ServiceType.ZIPLINE, default: true },
{ label: "E-Z Host", value: ServiceType.EZHOST },
{ label: "Nest", value: ServiceType.NEST }
{ label: "Nest", value: ServiceType.NEST },
{ label: "Catbox.moe", value: ServiceType.CATBOX },
{ label: "0x0.st", value: ServiceType.ZEROX0 },
{ label: "Litterbox", value: ServiceType.LITTERBOX }
],
hidden: true
},
@ -50,6 +53,18 @@ export const settings = definePluginSettings({
default: "",
hidden: true
},
litterboxExpiry: {
type: OptionType.SELECT,
description: "",
options: [
{ label: "1 hour", value: "1h" },
{ label: "12 hours", value: "12h" },
{ label: "24 hours", value: "24h", default: true },
{ label: "72 hours", value: "72h" }
],
default: "24h",
hidden: true
},
folderId: {
type: OptionType.STRING,
description: "",

View file

@ -18,11 +18,15 @@ export function SettingsComponent() {
const isNest = store.serviceType === ServiceType.NEST;
const isEzHost = store.serviceType === ServiceType.EZHOST;
const isZipline = store.serviceType === ServiceType.ZIPLINE;
const isLitterbox = store.serviceType === ServiceType.LITTERBOX;
const serviceOptions = [
{ label: "Zipline", value: ServiceType.ZIPLINE },
{ label: "E-Z Host", value: ServiceType.EZHOST },
{ label: "Nest", value: ServiceType.NEST }
{ label: "Nest", value: ServiceType.NEST },
{ label: "Catbox.moe", value: ServiceType.CATBOX },
{ label: "0x0.st", value: ServiceType.ZEROX0 },
{ label: "Litterbox", value: ServiceType.LITTERBOX }
];
return (
@ -90,6 +94,26 @@ export function SettingsComponent() {
</SettingsSection>
)}
{isLitterbox && (
<SettingsSection name="Litterbox Expiry" description="How long uploads are retained">
<Select
options={[
{ label: "1 hour", value: "1h" },
{ label: "12 hours", value: "12h" },
{ label: "24 hours", value: "24h" },
{ label: "72 hours", value: "72h" }
]}
isSelected={v => v === store.litterboxExpiry}
select={v => {
store.litterboxExpiry = v;
update();
}}
serialize={v => v}
placeholder="Select expiry"
/>
</SettingsSection>
)}
<SettingsSection tag="label" name="Strip Query Parameters" description="Strip query parameters from the uploaded file URL" inlineSetting>
<Switch
checked={store.stripQueryParams}

View file

@ -7,14 +7,19 @@
export enum ServiceType {
ZIPLINE = "zipline",
NEST = "nest",
EZHOST = "ezhost"
EZHOST = "ezhost",
CATBOX = "catbox",
ZEROX0 = "0x0",
LITTERBOX = "litterbox"
}
export const serviceLabels: Record<ServiceType, string> = {
[ServiceType.ZIPLINE]: "Zipline",
[ServiceType.NEST]: "Nest"
,
[ServiceType.EZHOST]: "E-Z Host"
[ServiceType.NEST]: "Nest",
[ServiceType.EZHOST]: "E-Z Host",
[ServiceType.CATBOX]: "Catbox",
[ServiceType.ZEROX0]: "0x0.st",
[ServiceType.LITTERBOX]: "Litterbox"
};
export interface UploadResponse {

View file

@ -122,6 +122,10 @@ export function isConfigured(): boolean {
return Boolean(nestToken);
case ServiceType.EZHOST:
return Boolean((settings.store as { ezHostKey?: string }).ezHostKey);
case ServiceType.CATBOX:
case ServiceType.ZEROX0:
case ServiceType.LITTERBOX:
return true;
case ServiceType.ZIPLINE:
default:
return Boolean(serviceUrl && ziplineToken);
@ -173,6 +177,78 @@ async function uploadToEzHost(fileBlob: Blob, filename: string): Promise<string>
return data.imageUrl || data.rawUrl;
}
async function uploadToCatbox(fileBlob: Blob, filename: string): Promise<string> {
const formData = new FormData();
formData.append("reqtype", "fileupload");
formData.append("fileToUpload", fileBlob, filename);
const proxiedUrl = `${CORS_PROXY}?url=${encodeURIComponent("https://catbox.moe/user/api.php")}`;
const response = await fetch(proxiedUrl, {
method: "POST",
body: formData
});
if (!response.ok) {
const text = await response.text();
throw new Error(`Upload failed: ${response.status} ${text}`);
}
const text = (await response.text()).trim();
if (!text) {
throw new Error("No URL returned from upload");
}
return text;
}
async function uploadTo0x0(fileBlob: Blob, filename: string): Promise<string> {
const formData = new FormData();
formData.append("file", fileBlob, filename);
const proxiedUrl = `${CORS_PROXY}?url=${encodeURIComponent("https://0x0.st")}`;
const response = await fetch(proxiedUrl, {
method: "POST",
body: formData
});
if (!response.ok) {
const text = await response.text();
throw new Error(`Upload failed: ${response.status} ${text}`);
}
const text = (await response.text()).trim();
if (!text) {
throw new Error("No URL returned from upload");
}
return text;
}
async function uploadToLitterbox(fileBlob: Blob, filename: string): Promise<string> {
const formData = new FormData();
formData.append("reqtype", "fileupload");
formData.append("time", settings.store.litterboxExpiry || "24h");
formData.append("fileToUpload", fileBlob, filename);
const proxiedUrl = `${CORS_PROXY}?url=${encodeURIComponent("https://litterbox.catbox.moe/resources/internals/api.php")}`;
const response = await fetch(proxiedUrl, {
method: "POST",
body: formData
});
if (!response.ok) {
const text = await response.text();
throw new Error(`Upload failed: ${response.status} ${text}`);
}
const text = (await response.text()).trim();
if (!text) {
throw new Error("No URL returned from upload");
}
return text;
}
export async function uploadFile(url: string): Promise<void> {
if (isUploading) {
showToast("Upload already in progress", Toasts.Type.MESSAGE);
@ -248,6 +324,15 @@ export async function uploadFile(url: string): Promise<void> {
case ServiceType.EZHOST:
uploadedUrl = await uploadToEzHost(typedBlob, filename);
break;
case ServiceType.CATBOX:
uploadedUrl = await uploadToCatbox(typedBlob, filename);
break;
case ServiceType.ZEROX0:
uploadedUrl = await uploadTo0x0(typedBlob, filename);
break;
case ServiceType.LITTERBOX:
uploadedUrl = await uploadToLitterbox(typedBlob, filename);
break;
default:
throw new Error("Unknown service type");
}