diff --git a/meta/dedupe/dedupe_books.go b/meta/dedupe/dedupe_books.go
index 8c414d14730c0958d8de06463ea4239ce92d7df8..ba0eeedbe0f1ed96d358b3cc36c0a701e4c433d1 100644
--- a/meta/dedupe/dedupe_books.go
+++ b/meta/dedupe/dedupe_books.go
@@ -1,6 +1,9 @@
 package dedupe
 
 import (
+	"log"
+	"net/url"
+
 	"git.autistici.org/ale/ebooks/collection"
 	"git.autistici.org/ale/ebooks/internal/metautil"
 	"git.autistici.org/ale/ebooks/meta/model"
@@ -57,7 +60,7 @@ type booksMerger struct{}
 
 func (*booksMerger) Class() string { return model.ClassBook }
 
-func (*booksMerger) Merge(coll collection.Collection, _ storage.FS, oldObj, newObj model.Object) model.Object {
+func (*booksMerger) Merge(coll collection.Collection, fs storage.FS, oldObj, newObj model.Object) model.Object {
 	oldBook := oldObj.(*model.Book)
 	newBook := newObj.(*model.Book)
 
@@ -71,7 +74,20 @@ func (*booksMerger) Merge(coll collection.Collection, _ storage.FS, oldObj, newO
 
 	newBook.Metadata.Merge(&oldBook.Metadata)
 
-	// TODO: delete cover image files.
+	// Delete cover image files.
+	for _, uri := range []string{
+		oldBook.Metadata.Cover.Original,
+		oldBook.Metadata.Cover.Thumbnail,
+	} {
+		if uri == "" {
+			continue
+		}
+		if parsed, err := url.Parse(uri); err == nil {
+			if err := fs.Delete(parsed); err != nil {
+				log.Printf("error deleting %s: %v", uri, err)
+			}
+		}
+	}
 
 	return newBook
 }