diff --git a/README.md b/README.md index cf64ce6..7991f8d 100644 --- a/README.md +++ b/README.md @@ -4,20 +4,17 @@ A Firefox extension that surfaces your forgotten bookmarks — the ones you save ## Installation -### From Firefox Add-ons (recommended) +### From Firefox Add-ons -[Install from AMO](https://addons.mozilla.org/firefox/addon/embermarks/) - -### Manual Install - -Download the latest `.xpi` from [Releases](https://github.com/gruberb/embermarks/releases) and drag it into Firefox. +[Install from AMO](https://addons.mozilla.org/en-US/firefox/addon/embermarks1/) ## Features - **Discover forgotten bookmarks** — Shows bookmarks you've rarely or never visited +- **Click to open** — Just click any bookmark to visit it +- **Refresh behavior** — Choose to see new bookmarks every time, once a day, or only when you manually refresh - **Configurable criteria** — Set maximum visit count and minimum age for "forgotten" status - **Exclude folders** — Keep certain bookmark folders out of suggestions -- **Quick actions** — Visit, skip, or delete bookmarks directly from the popup ## Building from Source @@ -37,4 +34,4 @@ npx web-ext run ## License -Mozilla Public License Version 2.0 +Mozilla Public License Version 2.0 \ No newline at end of file diff --git a/background.js b/background.js index f639a42..21245a3 100644 --- a/background.js +++ b/background.js @@ -4,13 +4,21 @@ // Minimum valid timestamp (Jan 1, 2010) - older dates are likely corrupted imports const MIN_VALID_TIMESTAMP = 1262304000000; +// Cache duration for "daily" refresh mode (24 hours in ms) +const DAILY_CACHE_DURATION = 24 * 60 * 60 * 1000; + const DEFAULT_SETTINGS = { excludedFolders: [], numBookmarks: 5, maxVisitCount: 2, // Consider "forgotten" if visited 2 or fewer times minAgeDays: 7, // Only show bookmarks older than 7 days + refreshBehavior: "always", // "always", "daily", or "manual" }; +// In-memory cache for bookmarks +let cachedBookmarks = null; +let cacheTimestamp = null; + // Get user settings async function getSettings() { const result = await browser.storage.local.get("settings"); @@ -24,6 +32,33 @@ async function saveSettings(settings) { }); } +// Get cached bookmarks if valid +async function getCachedBookmarks() { + const result = await browser.storage.local.get([ + "cachedBookmarks", + "cacheTimestamp", + ]); + return { + bookmarks: result.cachedBookmarks || null, + timestamp: result.cacheTimestamp || null, + }; +} + +// Save bookmarks to cache +async function setCachedBookmarks(bookmarks) { + await browser.storage.local.set({ + cachedBookmarks: bookmarks, + cacheTimestamp: Date.now(), + }); +} + +// Clear the cache +async function clearCache() { + await browser.storage.local.remove(["cachedBookmarks", "cacheTimestamp"]); + cachedBookmarks = null; + cacheTimestamp = null; +} + // Get all bookmarks recursively, respecting excluded folders async function getAllBookmarks(excludedFolderIds = []) { const tree = await browser.bookmarks.getTree(); @@ -71,8 +106,8 @@ async function getVisitCount(url) { } } -// Get forgotten bookmarks (low visit count, old enough) -async function getForgottenBookmarks() { +// Fetch fresh forgotten bookmarks +async function fetchFreshBookmarks() { const settings = await getSettings(); const bookmarks = await getAllBookmarks(settings.excludedFolders); @@ -118,6 +153,41 @@ async function getForgottenBookmarks() { return shuffled.slice(0, settings.numBookmarks); } +// Get forgotten bookmarks (with caching logic) +async function getForgottenBookmarks(forceRefresh = false) { + const settings = await getSettings(); + const { bookmarks: cached, timestamp } = await getCachedBookmarks(); + + // Determine if we should use cache + if (!forceRefresh && cached && timestamp) { + const now = Date.now(); + const cacheAge = now - timestamp; + + if (settings.refreshBehavior === "manual") { + // Always use cache in manual mode (until explicit refresh) + return cached; + } + + if ( + settings.refreshBehavior === "daily" && + cacheAge < DAILY_CACHE_DURATION + ) { + // Use cache if less than 24 hours old + return cached; + } + } + + // Fetch fresh bookmarks + const freshBookmarks = await fetchFreshBookmarks(); + + // Cache the results (for daily and manual modes) + if (settings.refreshBehavior !== "always") { + await setCachedBookmarks(freshBookmarks); + } + + return freshBookmarks; +} + // Get all bookmark folders for settings UI async function getBookmarkFolders() { const tree = await browser.bookmarks.getTree(); @@ -140,11 +210,14 @@ async function getBookmarkFolders() { return folders; } -// Handle messages from popup/newtab/options +// Handle messages from popup/options browser.runtime.onMessage.addListener((message, sender, sendResponse) => { switch (message.action) { case "getForgottenBookmarks": - return getForgottenBookmarks(); + return getForgottenBookmarks(message.forceRefresh || false); + + case "clearCache": + return clearCache(); case "getBookmarkFolders": return getBookmarkFolders(); diff --git a/manifest.json b/manifest.json index 6c3479d..936f376 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Embermarks", - "version": "1.0.2", + "version": "1.0.3", "description": "Rediscover your forgotten bookmarks. Surface the ones you never visit.", "author": "Bastian Gruber", "homepage_url": "https://github.com/gruberb/embermarks", diff --git a/options/options.html b/options/options.html index 248332f..b32f3e6 100644 --- a/options/options.html +++ b/options/options.html @@ -108,6 +108,15 @@ text-align: center; } + select { + padding: 0.5rem; + border: 1px solid #444; + border-radius: 6px; + background: #1a1a1a; + color: #fff; + font-size: 1rem; + } + input[type="checkbox"] { width: 20px; height: 20px; @@ -219,6 +228,18 @@ value="5" /> + +