feat: the extension picks a Discord source's posters from who posts in the channel, stored by id (#4488)
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
CI and images / extension-test (push) Successful in 18s
CI and images / frontend-build (push) Successful in 26s
CI and images / backend-lint-and-test (push) Successful in 32s
CI and images / integration (push) Successful in 2m24s
CI and images / build-agent (push) Successful in 5s
CI and images / sign-extension (push) Successful in 6m13s
CI and images / build-web (push) Successful in 1m38s
CI and images / smoke-web (push) Successful in 54s
CI and images / promote (push) Successful in 2s
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
CI and images / extension-test (push) Successful in 18s
CI and images / frontend-build (push) Successful in 26s
CI and images / backend-lint-and-test (push) Successful in 32s
CI and images / integration (push) Successful in 2m24s
CI and images / build-agent (push) Successful in 5s
CI and images / sign-extension (push) Successful in 6m13s
CI and images / build-web (push) Successful in 1m38s
CI and images / smoke-web (push) Successful in 54s
CI and images / promote (push) Successful in 2s
On a Discord channel page the Add panel lists who posted in the newest 200 messages, the creator the server is named for (or owned by) ticked. On a channel FabledCurator already follows, the chip opens the same list with Save and Open artist. The list is kept as user ids, so a rename never quietly stops it matching; the name each was picked under rides beside it for display, and the Subscriptions dialog shows it. - DiscordClient.recent_posters + rank_posters (owner / name-matches-server; bots never suggested; it suggests, the operator ticks). - GET/POST /api/extension/discord/posters; quick-add takes discord_authors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+13
-1
@@ -106,8 +106,11 @@ class FabledCuratorAPI {
|
||||
// artist from the URL. A Discord channel always sends one.
|
||||
// usePlatformName: a Patreon source joining an existing artist renames it
|
||||
// to the Patreon display name (Patreon is canon; name only, never the slug).
|
||||
quickAddSource(url, { artistId = null, artistName = null, usePlatformName = false } = {}) {
|
||||
// discordAuthors ([{id, name}], #4488): a Discord source's poster list, set
|
||||
// in the same step.
|
||||
quickAddSource(url, { artistId = null, artistName = null, usePlatformName = false, discordAuthors = null } = {}) {
|
||||
const body = { url };
|
||||
if (discordAuthors) body.discord_authors = discordAuthors;
|
||||
if (artistId != null) body.artist_id = artistId;
|
||||
else if (artistName) body.artist_name = artistName;
|
||||
if (usePlatformName) body.use_platform_name = true;
|
||||
@@ -123,6 +126,15 @@ class FabledCuratorAPI {
|
||||
const qs = new URLSearchParams(params).toString();
|
||||
return this.request('GET', `/extension/probe?${qs}`);
|
||||
}
|
||||
// #4488: who posts in the Discord channel `url` shows, lately, with the
|
||||
// likely creator marked; and setting the list on the source that follows it.
|
||||
getDiscordPosters(url) {
|
||||
const qs = new URLSearchParams({ url }).toString();
|
||||
return this.request('GET', `/extension/discord/posters?${qs}`);
|
||||
}
|
||||
setDiscordPosters(url, authors) {
|
||||
return this.request('POST', '/extension/discord/posters', { url, authors });
|
||||
}
|
||||
// Latest published extension version on this instance — drives the in-app
|
||||
// update prompt. Public endpoint (no key needed, but request() sends it
|
||||
// harmlessly). Returns {version, xpi_url, latest_url, sha256}.
|
||||
|
||||
@@ -144,3 +144,49 @@ function inlineCompletion(typed, results) {
|
||||
if (!t) return null;
|
||||
return (results || []).find((a) => a.name.length > t.length && a.name.toLowerCase().startsWith(t)) || null;
|
||||
}
|
||||
|
||||
// ---- Discord poster picker (#4488) ----
|
||||
// /api/extension/discord/posters lists who posted in the channel lately, with
|
||||
// the creator the server is named for (or owned by) marked `suggested`. The
|
||||
// picker ticks posters; the source keeps their ids, since a username can
|
||||
// change on a whim and an id can't.
|
||||
|
||||
/** "Todding (@todding)" — the display name, then the handle when it differs. */
|
||||
function posterLabel(p) {
|
||||
const shown = p?.global_name || p?.username || p?.id || '';
|
||||
const handle = p?.username && p.username !== shown ? ` (@${p.username})` : '';
|
||||
return `${shown}${handle}`;
|
||||
}
|
||||
|
||||
/** What the picker starts with: the source's current list when it has one,
|
||||
* else the suggested creator(s). A set of ids. */
|
||||
function initialPosterPick(data) {
|
||||
const current = (data?.selected || []).map(String);
|
||||
if (current.length) return new Set(current);
|
||||
return new Set((data?.posters || []).filter((p) => p.suggested).map((p) => String(p.id)));
|
||||
}
|
||||
|
||||
/** The checklist's rows: who posted lately, then anyone already on the
|
||||
* source's list who hasn't — by the name they were picked under — so they
|
||||
* can still be unticked. */
|
||||
function withSelected(data) {
|
||||
const posters = [...(data?.posters || [])];
|
||||
const shown = new Set(posters.map((p) => String(p.id)));
|
||||
const labels = data?.selected_labels || {};
|
||||
for (const id of (data?.selected || []).map(String)) {
|
||||
if (shown.has(id)) continue;
|
||||
posters.push({ id, global_name: labels[id] || null, username: null,
|
||||
messages: 0, images: 0, reasons: ['on the list, not posting lately'] });
|
||||
}
|
||||
return posters;
|
||||
}
|
||||
|
||||
/** The picked posters as the API takes them: [{id, name}], in list order.
|
||||
* An id already on the source but no longer posting lately is kept. */
|
||||
function postersRequest(posters, picked) {
|
||||
const byId = new Map((posters || []).map((p) => [String(p.id), p]));
|
||||
return [...picked].map((id) => ({
|
||||
id,
|
||||
name: byId.has(id) ? (byId.get(id).global_name || byId.get(id).username || id) : null,
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user