Offer ibb.co and imgur as upload hosts, imgur not on Sneedchat

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-30 18:58:27 -04:00
co-authored by Claude Opus 5.5
parent 1326783f8e
commit 54df70a3cc
3 changed files with 25 additions and 12 deletions
+1 -1
Submodule nobilis updated: e1060b793e...f6c39c2b9f
@@ -164,10 +164,10 @@ function UploadHostSetting({
.catch(() => setHosts([]))
}, [])
// Only what will take this kind of file. Every host is available to every
// service - what differs is how the link is posted once it exists, which
// is the daemon's business rather than this menu's.
const usable = hosts.filter((h) => kind === 'images' || !h.imagesOnly)
// Only what will take this kind of file, and only what this service can
// use: the daemon says which hosts a service is kept from (imgur, whose
// links Sneedchat does not show as pictures).
const usable = hosts.filter((h) => (kind === 'images' || !h.imagesOnly) && !h.notFor?.includes(service))
return (
<ChoiceSetting
@@ -191,6 +191,8 @@ interface UploadHost {
id: string
label: string
imagesOnly: boolean
/** Services this host is not offered to. */
notFor?: string[]
}
export function SettingsPanel(): JSX.Element {
+18 -7
View File
@@ -750,12 +750,19 @@ function tidyDetail(detail: string): string {
* Cached because it is asked on every send with an attachment and cannot
* change while the daemon is up - the list is compiled into it.
*/
let hostListing: Promise<{ id: string; accepts: string[] | null }[]> | null = null
interface ListedHost {
id: string
accepts: string[] | null
/** Services this host is kept from - imgur from Sneedchat, which does not embed it. */
notFor?: string[]
}
async function uploadHosts(): Promise<{ id: string; accepts: string[] | null }[]> {
let hostListing: Promise<ListedHost[]> | null = null
async function uploadHosts(): Promise<ListedHost[]> {
if (!hostListing) {
hostListing = window.moho
.rpc<{ id: string; accepts: string[] | null }[]>('listUploadHosts')
.rpc<ListedHost[]>('listUploadHosts')
// An older daemon says nothing about what a host takes; assume it
// takes whatever it is given, which is what happened before this.
.catch(() => [])
@@ -763,9 +770,13 @@ async function uploadHosts(): Promise<{ id: string; accepts: string[] | null }[]
return hostListing
}
/** Whether this host will take this file, by the daemon's own account. */
async function hostAccepts(hostId: string, path: string): Promise<boolean> {
/**
* Whether this host will take this file for this service, by the daemon's
* own account.
*/
async function hostAccepts(hostId: string, path: string, service: string): Promise<boolean> {
const host = (await uploadHosts()).find((h) => h.id === hostId)
if (host?.notFor?.includes(service)) return false
if (!host || !host.accepts) return true
const ext = (path.split(/[\\/]/).pop() || '').split('.').pop()?.toLowerCase() ?? ''
return host.accepts.includes(ext)
@@ -804,10 +815,10 @@ async function uploadHost(service: string | undefined, attachmentPath: string):
(legacyUsable ? legacy : undefined) ||
fallback
if (await hostAccepts(chosen, attachmentPath)) return chosen
if (await hostAccepts(chosen, attachmentPath, perService)) return chosen
const other = prefs[`uploads.${perService}.media`] as string | undefined
if (other && other !== chosen && (await hostAccepts(other, attachmentPath))) return other
if (other && other !== chosen && (await hostAccepts(other, attachmentPath, perService))) return other
return 'catbox'
} catch {
return 'catbox'