feat(media-hosting): add multi-provider configurable upload with fallback

Add Random/Preferred/None modes, preferred provider selection, and provider-order fallback. Catbox/Imgur/PostImages on Android via WebView; Electron CDP automation for Imgur/PostImages. Hide upload controls on web runtime.
This commit is contained in:
plebeius
2026-02-18 18:51:02 +08:00
parent 72b70915fd
commit 96a4aaec0e
63 changed files with 1991 additions and 201 deletions
+28 -7
View File
@@ -1,23 +1,44 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { ProviderId, UploadMode } from '../lib/media-hosting/types';
import { MEDIA_HOSTING_PROVIDERS as PROVIDER_REGISTRY } from '../lib/media-hosting/providers';
export const MEDIA_HOSTING_PROVIDERS = [{ id: 'catbox', name: 'Catbox', url: 'https://catbox.moe' }] as const;
export type MediaHostingSelection = (typeof MEDIA_HOSTING_PROVIDERS)[number]['id'] | 'none' | string;
/** Provider registry for UI: id, label, homepage URL, runtime support */
export const MEDIA_HOSTING_PROVIDERS = PROVIDER_REGISTRY;
interface MediaHostingStore {
selectedProvider: MediaHostingSelection;
setSelectedProvider: (provider: string) => void;
uploadMode: UploadMode;
preferredProvider: ProviderId;
setUploadMode: (mode: UploadMode) => void;
setPreferredProvider: (provider: ProviderId) => void;
}
const PERSIST_VERSION = 2;
function migrate(_state: unknown): MediaHostingStore {
return {
uploadMode: 'random',
preferredProvider: 'catbox',
} as MediaHostingStore;
}
const useMediaHostingStore = create<MediaHostingStore>()(
persist(
(set) => ({
selectedProvider: 'catbox',
setSelectedProvider: (provider) => set({ selectedProvider: provider }),
uploadMode: 'random',
preferredProvider: 'catbox',
setUploadMode: (mode) => set({ uploadMode: mode }),
setPreferredProvider: (provider) => set({ preferredProvider: provider }),
}),
{
name: 'media-hosting-storage',
version: PERSIST_VERSION,
migrate: (persistedState, version) => {
if (version < PERSIST_VERSION) {
return migrate(persistedState);
}
return persistedState as MediaHostingStore;
},
},
),
);