fix: final review — cached links keep their expiry; history removal sticks; saves flushed
- A link reused from the rehost cache keeps the expiry it was uploaded with, and links near expiry are uploaded again (a dead litterbox link could be filed). - History saving moves into HistoryKeeper (tested): removing an entry or clearing the history cancels a pending save and stops tracking the series on screen; a pending edit is saved before a new search, before opening another entry and when the page is hidden; opening an entry no longer re-saves the current one. - The "couldn't be saved" line sits outside the History list, so it shows even when the list is empty; a refused IndexedDB says history is off. - Recently searched bands wrap their meta line instead of cutting the count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1cf31b26cf
commit
0d4a1a61fa
8 files changed
+362
-68
No files matched your search
+27
-3
@@ -81,6 +81,8 @@ export class Session {
|
||||
makeDefault = true;
|
||||
private conflicts = 0;
|
||||
private readonly hostedCache: Map<string, string>;
|
||||
/** When each cached link expires (epoch ms; null = never). A cached link must not outlive its host. */
|
||||
private readonly cacheUntil = new Map<string, number | null>();
|
||||
|
||||
constructor(private readonly deps: SessionDeps) {
|
||||
this.hostedCache = deps.persistHostedUrls ? loadHosted(deps.store) : new Map();
|
||||
@@ -115,7 +117,13 @@ export class Session {
|
||||
this.makeDefault = makeDefault && result.suggestedDefault !== null;
|
||||
this.input = input;
|
||||
this.conflicts = 0;
|
||||
for (const c of cards) if (c.hostedUrl && c.hosting?.key) this.hostedCache.set(c.hosting.key, c.hostedUrl);
|
||||
const now = Date.now();
|
||||
for (const c of cards) {
|
||||
if (c.hostedUrl && c.hosting?.key && !expiresSoon(c.hosting.until, now)) {
|
||||
this.hostedCache.set(c.hosting.key, c.hostedUrl);
|
||||
this.cacheUntil.set(c.hosting.key, c.hosting.until);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(sha256: string, patch: Partial<Pick<ReviewCard, "selected" | "type" | "note" | "contentRating">>): void {
|
||||
@@ -164,6 +172,14 @@ export class Session {
|
||||
/** Explicit user action only (spec §4.6). */
|
||||
async rehost(hostId: HostId, options: HostOptions, onProgress?: (done: number, total: number) => void): Promise<RehostResult> {
|
||||
const cards = this.selected();
|
||||
const now = Date.now();
|
||||
for (const [key, until] of this.cacheUntil) {
|
||||
if (expiresSoon(until, now)) {
|
||||
this.hostedCache.delete(key);
|
||||
this.cacheUntil.delete(key);
|
||||
}
|
||||
}
|
||||
const cachedBefore = new Set(this.hostedCache.keys());
|
||||
const res = await rehostAll(
|
||||
cards.map((c) => hostImage(c.cover)),
|
||||
HOSTS[hostId],
|
||||
@@ -171,10 +187,14 @@ export class Session {
|
||||
this.hostedCache,
|
||||
onProgress,
|
||||
);
|
||||
const until = linkExpiry(hostId, options, Date.now());
|
||||
const fresh = linkExpiry(hostId, options, now);
|
||||
for (const c of cards) {
|
||||
c.hostedUrl = res.hosted.get(c.cover.sha256) ?? null;
|
||||
c.hosting = c.hostedUrl ? { by: hostId, key: cacheKey(hostId, options, c.cover.sha256), until } : undefined;
|
||||
const key = cacheKey(hostId, options, c.cover.sha256);
|
||||
// A link reused from the cache keeps the expiry it was uploaded with.
|
||||
const until = key && cachedBefore.has(key) ? (this.cacheUntil.get(key) ?? fresh) : fresh;
|
||||
if (key && c.hostedUrl) this.cacheUntil.set(key, until);
|
||||
c.hosting = c.hostedUrl ? { by: hostId, key, until } : undefined;
|
||||
c.error = res.failures.find((f) => f.sha256 === c.cover.sha256)?.message ?? null;
|
||||
}
|
||||
if (this.deps.persistHostedUrls) saveHosted(this.deps.store, this.hostedCache);
|
||||
@@ -229,6 +249,10 @@ export class Session {
|
||||
}
|
||||
}
|
||||
|
||||
/** Links this close to expiry are uploaded again rather than reused. */
|
||||
const EXPIRY_MARGIN_MS = 5 * 60_000;
|
||||
const expiresSoon = (until: number | null | undefined, now: number): boolean => until != null && until <= now + EXPIRY_MARGIN_MS;
|
||||
|
||||
/** Only catbox links are kept across runs: litterbox links die within 72 hours. */
|
||||
function loadHosted(store: KeyValueStore): Map<string, string> {
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user