add random image command

This commit is contained in:
Ray Hao 2025-09-16 22:46:44 +12:00
parent e3cf985c49
commit 9f8ea565c5
8 changed files with 63 additions and 7 deletions

View file

@ -20,6 +20,7 @@ interface Props {
fetcher: Fetcher;
onFetcherChange: (fetcher: Fetcher) => void;
settings: PluginSettings;
random: boolean;
onSelect: (image: Image) => void;
}
@ -27,6 +28,7 @@ const ImagesModal = ({
fetcher: defaultFetcher,
onFetcherChange,
settings,
random,
onSelect,
}: Props) => {
const [fetcher, setFetcher] = useState(defaultFetcher);
@ -39,9 +41,12 @@ const ImagesModal = ({
const [loading, setLoading] = useState(false);
const filteredImageProviders = random ? [ImageProvider.unsplash] : imageProviders
const fetchImages = async (query: string) => {
try {
const images = await fetcher.searchImages(query);
const fetchFunc = random ? fetcher.randomImage : fetcher.searchImages
const images = await fetchFunc(query);
setImages(images);
setSelectedImage(0);
} catch (e) {
@ -127,11 +132,11 @@ const ImagesModal = ({
prev - 1 < 0 ? images.length - 1 : prev - 1,
);
} else if (e.ctrlKey && e.key === "u") {
let index = imageProviders.indexOf(fetcher.imageProvider) + 1;
if (index >= imageProviders.length) {
let index = filteredImageProviders.indexOf(fetcher.imageProvider) + 1;
if (index >= filteredImageProviders.length) {
index = 0;
}
onProviderChange(imageProviders[index]);
onProviderChange(filteredImageProviders[index]);
} else if (e.ctrlKey && e.key === "i") {
let index = imageSizes.indexOf(fetcher.imageSize) + 1;
if (index >= imageSizes.length) {
@ -188,7 +193,7 @@ const ImagesModal = ({
onChange={onProviderSelectorChange}
className="selector"
>
{imageProviders.map((provider) => (
{filteredImageProviders.map((provider) => (
<option key={provider} value={provider}>
{providerMapping[provider]}
</option>

View file

@ -7,7 +7,7 @@ import { createRoot } from "react-dom/client";
import { getFetcher } from "./fetchers";
import { Fetcher, Image } from "./fetchers/constants";
import { ImagesModal } from "./ImagesModal";
import { PluginSettings } from "./SettingTab";
import { ImageProvider, PluginSettings } from "./SettingTab";
export enum InsertPlace {
default = "default",
@ -19,12 +19,14 @@ export class ModalWrapper extends Modal {
fetcher: ReturnType<typeof getFetcher>;
settings: PluginSettings;
insertPlace: InsertPlace;
random: boolean;
constructor(
app: App,
editor: Editor,
settings: PluginSettings,
insertPlace: InsertPlace = InsertPlace.default,
random = false,
) {
super(app);
this.editor = editor;
@ -32,8 +34,9 @@ export class ModalWrapper extends Modal {
...settings,
useMarkdownLinks: app.vault.config.useMarkdownLinks,
};
this.fetcher = getFetcher(this.settings, app.vault);
this.fetcher = getFetcher({ ...this.settings, imageProvider: random ? ImageProvider.unsplash : this.settings.imageProvider }, app.vault);
this.insertPlace = insertPlace;
this.random = random
this.containerEl.addClass("image-inserter-container");
}
@ -51,6 +54,7 @@ export class ModalWrapper extends Modal {
fetcher={this.fetcher}
onFetcherChange={this.onFetcherChange.bind(this)}
settings={this.settings}
random={this.random}
onSelect={this.onChooseSuggestion.bind(this)}
/>
</React.StrictMode>,

View file

@ -53,6 +53,7 @@ export interface Fetcher {
prevPage: () => void;
nextPage: () => void;
searchImages: (query: string) => Promise<Image[]>;
randomImage: (query: string) => Promise<Image[]>;
touchDownloadLocation?: (url: string) => Promise<void>;
downloadImage: (url: string) => Promise<ArrayBuffer>;
downloadAndInsertImage: (

View file

@ -51,6 +51,9 @@ export const local = (settings: PluginSettings, vault: Vault) => {
};
});
},
async randomImage(_: string): Promise<Image[]> {
return []
},
async downloadImage(_: string): Promise<ArrayBuffer> {
return new ArrayBuffer(0);
},

View file

@ -79,6 +79,9 @@ export const pexels = (settings: PluginSettings, vault: Vault) => {
};
});
},
async randomImage(_: string): Promise<Image[]> {
return []
},
async downloadImage(url: string): Promise<ArrayBuffer> {
const res = await requestUrl({ url });
return res.arrayBuffer;

View file

@ -85,6 +85,9 @@ export const pixabay = (settings: PluginSettings, vault: Vault) => {
};
});
},
async randomImage(_: string): Promise<Image[]> {
return []
},
async downloadImage(url: string): Promise<ArrayBuffer> {
const res = await requestUrl({ url });
return res.arrayBuffer;

View file

@ -82,6 +82,27 @@ export const unsplash = (settings: PluginSettings, vault: Vault) => {
};
});
},
async randomImage(query: string): Promise<Image[]> {
const url = new URL("/photos/random", proxyServer);
url.searchParams.set("query", query);
if (orientation != "not_specified") {
url.searchParams.set("orientation", orientation);
}
const res = await requestUrl({ url: url.toString() });
const item: Unsplash.Photo = res.json;
return [{
desc: (item.description || item.alt_description || "").replace(
new RegExp(/\n/g),
" ",
),
thumb: item.urls.thumb,
url: item.urls[imageSizeMapping[imageSize]],
downloadLocationUrl: item.links.download_location,
pageUrl: item.links.html,
username: item.user.name,
userUrl: `https://unsplash.com/@${item.user.username}?${UTM}`,
}];
},
async touchDownloadLocation(url: string): Promise<void> {
await requestUrl({
url: url.replace("https://api.unsplash.com", proxyServer),

16
main.ts
View file

@ -25,6 +25,22 @@ export default class InsertUnsplashImage extends Plugin {
new ModalWrapper(this.app, editor, this.settings, InsertPlace.frontmatter).open();
}
});
this.addCommand({
id: 'insert-random',
name: 'Insert random image (only support Unsplash)',
editorCallback: (editor: Editor) => {
new ModalWrapper(this.app, editor, this.settings, InsertPlace.default, true).open();
}
});
this.addCommand({
id: 'insert-random-in-frontmatter',
name: 'Insert random image in frontmatter (only support Unsplash)',
editorCallback: (editor: Editor) => {
new ModalWrapper(this.app, editor, this.settings, InsertPlace.frontmatter, true).open();
}
});
}
onunload() {}