Online browser + post detail: SPA talks to e621 directly
Backend:
- POST /api/files/lookup/ reports which MD5s are already in the library
Frontend:
- e621 client extended with post/tag/favorite types and helpers: post
search, post detail, batch posts by id, tag autocomplete, toggle
favorite
- /online: tag search with autocomplete, post grid with rating colors
and in-library badges, numbered pagination, page tag cloud, blacklist
panel and filtered counts from /users/me.json, anonymous hint
- /online/view/🆔 media viewer (sample or original, video support),
taxonomy-colored tags by category, specs sheet, favorite/unfavorite,
description, sources, pools and parent/children thumbnails
- Shared CollapsibleSidebar extracted from the library page; Online
added to the nav, command palette and sidebar toggle
This commit is contained in:
@@ -1,12 +1,19 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
import { api } from "@/lib/api";
|
||||
import type { E621Credentials } from "@/lib/e621";
|
||||
import {
|
||||
effectiveCredentials,
|
||||
verifyE621Credentials,
|
||||
type E621Credentials,
|
||||
} from "@/lib/e621";
|
||||
|
||||
interface E621State {
|
||||
credentials: E621Credentials | null;
|
||||
blacklist: string[];
|
||||
loading: boolean;
|
||||
ready: boolean;
|
||||
load: () => Promise<void>;
|
||||
loadBlacklist: () => Promise<void>;
|
||||
save: (values: {
|
||||
username: string;
|
||||
api_key: string;
|
||||
@@ -15,17 +22,35 @@ interface E621State {
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export const useE621 = create<E621State>((set) => ({
|
||||
export const useE621 = create<E621State>((set, get) => ({
|
||||
credentials: null,
|
||||
blacklist: [],
|
||||
loading: false,
|
||||
ready: false,
|
||||
|
||||
load: async () => {
|
||||
set({ loading: true });
|
||||
try {
|
||||
const credentials = await api<E621Credentials>("/api/auth/e621/");
|
||||
set({ credentials, loading: false });
|
||||
set({ credentials, ready: true, loading: false });
|
||||
void get().loadBlacklist();
|
||||
} catch {
|
||||
set({ credentials: null, loading: false });
|
||||
set({ credentials: null, ready: true, loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
loadBlacklist: async () => {
|
||||
try {
|
||||
const user = await verifyE621Credentials(
|
||||
effectiveCredentials(get().credentials),
|
||||
);
|
||||
const tags = (user.blacklisted_tags ?? "")
|
||||
.split("\n")
|
||||
.map((tag) => tag.trim())
|
||||
.filter(Boolean);
|
||||
set({ blacklist: tags });
|
||||
} catch {
|
||||
// Keep the last known blacklist when e621 is unreachable.
|
||||
}
|
||||
},
|
||||
|
||||
@@ -35,8 +60,9 @@ export const useE621 = create<E621State>((set) => ({
|
||||
json: values,
|
||||
});
|
||||
set({ credentials });
|
||||
void get().loadBlacklist();
|
||||
return credentials;
|
||||
},
|
||||
|
||||
clear: () => set({ credentials: null }),
|
||||
clear: () => set({ credentials: null, blacklist: [], ready: false }),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user