FileUpload: PixelDrain support and BypassDiscordUpload fix (#1041)
* [+] PixelDrain * [F] Fix BypassDiscordUpload key mismatch
This commit is contained in:
parent
2fda567da1
commit
77cf82dc6d
5 changed files with 107 additions and 4 deletions
|
|
@ -74,7 +74,7 @@ function interceptUploadAddFiles(event: unknown): void {
|
|||
|
||||
if (payload.draftType !== DraftType.ChannelMessage) return;
|
||||
|
||||
if (!Boolean((settings.store as { interceptDiscordUpload?: boolean; }).interceptDiscordUpload) || !isConfigured()) return;
|
||||
if (!settings.store.bypassDiscordUpload || !isConfigured()) return;
|
||||
|
||||
const files = [
|
||||
...extractFilesFromValue(payload.files),
|
||||
|
|
@ -283,7 +283,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
shouldBypassDiscordUploadSizeCheck(): boolean {
|
||||
return Boolean((settings.store as { interceptDiscordUpload?: boolean; }).interceptDiscordUpload) && isConfigured();
|
||||
return Boolean(settings.store.bypassDiscordUpload) && isConfigured();
|
||||
},
|
||||
renderUploadProgress() {
|
||||
return <ProgressBar />;
|
||||
|
|
|
|||
|
|
@ -418,6 +418,46 @@ export async function uploadToPixelVault(
|
|||
}
|
||||
}
|
||||
|
||||
export async function uploadToPixelDrain(
|
||||
_: IpcMainInvokeEvent,
|
||||
fileBuffer: ArrayBuffer,
|
||||
filename: string,
|
||||
apiKey?: string
|
||||
): Promise<NativeUploadResult> {
|
||||
try {
|
||||
const headers: Record<string, string> = {};
|
||||
if (apiKey?.trim()) {
|
||||
headers.Authorization = `Basic ${Buffer.from(`:${apiKey.trim()}`).toString("base64")}`;
|
||||
}
|
||||
|
||||
const response = await fetch(`https://pixeldrain.com/api/file/${encodeURIComponent(filename)}`, {
|
||||
method: "PUT",
|
||||
headers,
|
||||
body: new Blob([fileBuffer])
|
||||
});
|
||||
|
||||
const text = await response.text();
|
||||
let data: { id?: string; message?: string; } | null = null;
|
||||
try {
|
||||
data = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
data = null;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
return { success: false, error: data?.message || `Upload failed: ${response.status} ${text}` };
|
||||
}
|
||||
|
||||
if (!data?.id) {
|
||||
return { success: false, error: data?.message || "No URL returned from upload" };
|
||||
}
|
||||
|
||||
return { success: true, url: `https://pixeldrain.com/u/${data.id}` };
|
||||
} catch (e) {
|
||||
return { success: false, error: e instanceof Error ? e.message : "Unknown error" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchFile(
|
||||
|
||||
_: IpcMainInvokeEvent,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const serviceOptions = [
|
|||
{ label: "temp.sh", value: ServiceType.TEMPSH },
|
||||
{ label: "filebin.net", value: ServiceType.FILEBIN },
|
||||
{ label: "PixelVault", value: ServiceType.PIXELVAULT },
|
||||
{ label: "PixelDrain", value: ServiceType.PIXELDRAIN },
|
||||
{ label: "ShareX Custom Uploader", value: ServiceType.SHAREX }
|
||||
];
|
||||
|
||||
|
|
@ -207,6 +208,12 @@ export const settings = definePluginSettings({
|
|||
default: "",
|
||||
hidden: true
|
||||
},
|
||||
pixelDrainKey: {
|
||||
type: OptionType.STRING,
|
||||
description: "Optional PixelDrain API key",
|
||||
default: "",
|
||||
hidden: true
|
||||
},
|
||||
uploadTimeoutMs: {
|
||||
type: OptionType.NUMBER,
|
||||
description: "Upload timeout in milliseconds",
|
||||
|
|
@ -366,6 +373,7 @@ export function SettingsComponent() {
|
|||
const isLitterbox = store.serviceType === ServiceType.LITTERBOX;
|
||||
const isGofile = store.serviceType === ServiceType.GOFILE;
|
||||
const isPixelVault = store.serviceType === ServiceType.PIXELVAULT;
|
||||
const isPixelDrain = store.serviceType === ServiceType.PIXELDRAIN;
|
||||
const isShareX = store.serviceType === ServiceType.SHAREX;
|
||||
|
||||
const validateShareXConfig = () => {
|
||||
|
|
@ -576,6 +584,16 @@ export function SettingsComponent() {
|
|||
/>
|
||||
)}
|
||||
|
||||
{isPixelDrain && (
|
||||
<SettingTextInput
|
||||
name="PixelDrain API Key"
|
||||
description="Optional PixelDrain API key for authenticated uploads. Leave empty for anonymous uploads."
|
||||
value={store.pixelDrainKey}
|
||||
onChange={v => store.pixelDrainKey = v}
|
||||
placeholder="Your PixelDrain API key"
|
||||
/>
|
||||
)}
|
||||
|
||||
{isShareX && (
|
||||
<>
|
||||
<SettingsSection
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ export enum ServiceType {
|
|||
BUZZHEAVIER = "buzzheavier",
|
||||
TEMPSH = "tempsh",
|
||||
FILEBIN = "filebin",
|
||||
PIXELVAULT = "pixelvault"
|
||||
PIXELVAULT = "pixelvault",
|
||||
PIXELDRAIN = "pixeldrain"
|
||||
}
|
||||
|
||||
export const serviceLabels: Record<ServiceType, string> = {
|
||||
|
|
@ -35,7 +36,8 @@ export const serviceLabels: Record<ServiceType, string> = {
|
|||
[ServiceType.BUZZHEAVIER]: "buzzheavier.com",
|
||||
[ServiceType.TEMPSH]: "temp.sh",
|
||||
[ServiceType.FILEBIN]: "filebin.net",
|
||||
[ServiceType.PIXELVAULT]: "PixelVault"
|
||||
[ServiceType.PIXELVAULT]: "PixelVault",
|
||||
[ServiceType.PIXELDRAIN]: "PixelDrain"
|
||||
};
|
||||
|
||||
export const fallbackServiceOrder: ServiceType[] = [
|
||||
|
|
@ -52,6 +54,7 @@ export const fallbackServiceOrder: ServiceType[] = [
|
|||
ServiceType.TEMPSH,
|
||||
ServiceType.FILEBIN,
|
||||
ServiceType.PIXELVAULT,
|
||||
ServiceType.PIXELDRAIN,
|
||||
ServiceType.SHAREX
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ export function isConfigured(): boolean {
|
|||
case ServiceType.BUZZHEAVIER:
|
||||
case ServiceType.TEMPSH:
|
||||
case ServiceType.FILEBIN:
|
||||
case ServiceType.PIXELDRAIN:
|
||||
return true;
|
||||
case ServiceType.PIXELVAULT:
|
||||
return Boolean((settings.store as { pixelVaultKey?: string; }).pixelVaultKey);
|
||||
|
|
@ -714,6 +715,45 @@ async function uploadToPixelVault(fileBlob: Blob, filename: string): Promise<str
|
|||
return url;
|
||||
}
|
||||
|
||||
async function uploadToPixelDrain(fileBlob: Blob, filename: string): Promise<string> {
|
||||
const { pixelDrainKey } = settings.store as { pixelDrainKey?: string; };
|
||||
|
||||
if (Native) {
|
||||
const result = await Native.uploadToPixelDrain(await fileBlob.arrayBuffer(), filename, pixelDrainKey?.trim() || undefined);
|
||||
if (!result.success || !result.url) throw new Error(result.error || "No URL returned from upload");
|
||||
return result.url;
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
if (pixelDrainKey?.trim()) {
|
||||
headers.Authorization = `Basic ${btoa(`:${pixelDrainKey.trim()}`)}`;
|
||||
}
|
||||
|
||||
const response = await fetchWithTimeout(`https://pixeldrain.com/api/file/${encodeURIComponent(filename)}`, {
|
||||
method: "PUT",
|
||||
headers,
|
||||
body: fileBlob
|
||||
});
|
||||
|
||||
const text = await response.text();
|
||||
let data: { id?: string; success?: boolean; message?: string; } | null = null;
|
||||
try {
|
||||
data = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
data = null;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data?.message || `Upload failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
if (!data?.id) {
|
||||
throw new Error(data?.message || "No URL returned from upload");
|
||||
}
|
||||
|
||||
return `https://pixeldrain.com/u/${data.id}`;
|
||||
}
|
||||
|
||||
async function uploadToService(serviceType: ServiceType, fileBlob: Blob, filename: string): Promise<string> {
|
||||
switch (serviceType) {
|
||||
case ServiceType.ZIPLINE:
|
||||
|
|
@ -744,6 +784,8 @@ async function uploadToService(serviceType: ServiceType, fileBlob: Blob, filenam
|
|||
return uploadToFilebin(fileBlob, filename);
|
||||
case ServiceType.PIXELVAULT:
|
||||
return uploadToPixelVault(fileBlob, filename);
|
||||
case ServiceType.PIXELDRAIN:
|
||||
return uploadToPixelDrain(fileBlob, filename);
|
||||
default:
|
||||
throw new Error("Unknown service type");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue