From 93de24c593c7738db180651be93ff4fb4ad99f8f Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Tue, 10 Mar 2026 19:12:14 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20add=20bookmark-import=20module=20for=20?= =?UTF-8?q?micropub=20bookmark=20=E2=86=92=20blogroll=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bookmark-import.js | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 lib/bookmark-import.js diff --git a/lib/bookmark-import.js b/lib/bookmark-import.js new file mode 100644 index 0000000..4b9b1da --- /dev/null +++ b/lib/bookmark-import.js @@ -0,0 +1,79 @@ +/** + * Bookmark → blogroll import + * Called when a micropub bookmark post is created. + * Discovers feeds for the bookmarked site's origin and adds them to the blogroll. + * @module lib/bookmark-import + */ + +import { discoverFeeds } from "./utils/feed-discovery.js"; +import { upsertBlog } from "./storage/blogs.js"; + +/** + * Import a bookmarked URL's site into the blogroll. + * Extracts the origin URL, discovers feeds, and upserts the first feed as a blog entry. + * + * @param {object} application - Indiekit application object + * @param {string} bookmarkUrl - The URL that was bookmarked (bookmark-of value) + * @returns {Promise} Result { added, alreadyExists, noFeeds, error } + */ +export async function importBookmarkUrl(application, bookmarkUrl) { + // Normalise: bookmark-of may be an array in some micropub clients + const url = Array.isArray(bookmarkUrl) ? bookmarkUrl[0] : bookmarkUrl; + + let siteUrl; + try { + siteUrl = new URL(url).origin; + } catch { + return { error: `Invalid bookmark URL: ${url}` }; + } + + // Guard: blogroll DB must be available + if (typeof application.getBlogrollDb !== "function") { + console.warn("[Blogroll] bookmark-import: getBlogrollDb not available"); + return { error: "blogroll not initialised" }; + } + + const db = application.getBlogrollDb(); + + // Check if any active blog with this siteUrl is already in the blogroll + const existing = await db.collection("blogrollBlogs").findOne({ + siteUrl, + status: { $ne: "deleted" }, + }); + + if (existing) { + console.log( + `[Blogroll] bookmark-import: ${siteUrl} already in blogroll ("${existing.title}")` + ); + return { alreadyExists: true, siteUrl }; + } + + // Discover feeds from the origin + const discovery = await discoverFeeds(siteUrl); + + if (!discovery.success || discovery.feeds.length === 0) { + console.log(`[Blogroll] bookmark-import: no feeds found for ${siteUrl}`); + return { noFeeds: true, siteUrl }; + } + + // Add the first discovered feed + const feed = discovery.feeds[0]; + const result = await upsertBlog(application, { + title: discovery.pageTitle || siteUrl, + feedUrl: feed.url, + siteUrl, + feedType: feed.type || "rss", + category: "bookmarks", + source: "bookmark", + sourceId: null, + status: "active", + }); + + if (result.upserted) { + console.log( + `[Blogroll] bookmark-import: added ${feed.url} ("${discovery.pageTitle || siteUrl}")` + ); + } + + return { added: result.upserted ? 1 : 0, siteUrl }; +}