fix(scanner): wire all metadata fields in updateMediaItem and skip image dupes

updateMediaItem (used by force rescan) was missing 22 fields including
Language, Genre, PageCount, CopyrightYear, GoodreadsID, and all 14 new
columns from the SQL query fix. Now wires all 37 UpdateMediaItemParams.

Also adds hasSiblingBookFile() early exit in processMediaFile: if a file
is an image (jpg/png/webp/etc) and its directory contains an actual book
file (epub/pdf/cbz/etc), skip importing the image as a standalone media
item. This prevents cover images and interior art from appearing as
duplicate library entries.
This commit is contained in:
2026-05-10 11:51:43 -04:00
parent 7b9d3562ef
commit 5f3b392168
+49 -3
View File
@@ -535,6 +535,26 @@ func (s *MediaScanner) extractFolderStructureMetadata(path, rootFolder string) *
return metadata
}
var bookExtensions = map[string]bool{
".epub": true, ".pdf": true, ".mobi": true, ".azw": true, ".azw3": true,
".fb2": true, ".txt": true, ".rtf": true, ".doc": true, ".docx": true,
".lit": true, ".pdb": true, ".djvu": true,
".cbz": true, ".cbr": true, ".cb7": true, ".cbt": true,
}
func hasSiblingBookFile(dir string) bool {
entries, err := os.ReadDir(dir)
if err != nil {
return false
}
for _, entry := range entries {
if !entry.IsDir() && bookExtensions[strings.ToLower(filepath.Ext(entry.Name()))] {
return true
}
}
return false
}
func (s *MediaScanner) processMediaFile(ctx context.Context, path string) (bool, error) {
fmt.Printf("Processing media file: %s\n", path)
@@ -545,9 +565,10 @@ func (s *MediaScanner) processMediaFile(ctx context.Context, path string) (bool,
return false, fmt.Errorf("failed to get file info: %v", err)
}
fmt.Printf("File info for %s: size=%d\n", path, info.Size())
if isImageFile(path) && hasSiblingBookFile(filepath.Dir(path)) {
return false, nil
}
// Get file modification time for created_at
fileModTime := info.ModTime()
// Find library for this file's folder
@@ -2338,7 +2359,11 @@ func (t *tarFileAdapter) Open() (io.ReadCloser, error) {
// isImageFile checks if a file is an image based on extension
func isImageFile(filename string) bool {
ext := strings.ToLower(filepath.Ext(filename))
return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".webp"
switch ext {
case ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".avif", ".tiff", ".tif":
return true
}
return false
}
// countArchiveImages counts image files in a comic archive
@@ -2426,6 +2451,10 @@ func (s *MediaScanner) updateMediaItem(ctx context.Context, mediaItemID pgtype.U
tagsSearch := utils.NormalizeTagsSearch(metadata.Tags)
// Call the database update - only update fields available in MediaMetadata
var alternateInfoBytes []byte
if metadata.AlternateInfo != "" {
alternateInfoBytes = []byte(metadata.AlternateInfo)
}
_, err = s.db.UpdateMediaItem(ctx, database.UpdateMediaItemParams{
ID: mediaItemID,
Title: metadata.Title,
@@ -2442,6 +2471,23 @@ func (s *MediaScanner) updateMediaItem(ctx context.Context, mediaItemID pgtype.U
Publisher: pgtype.Text{String: metadata.Publisher, Valid: metadata.Publisher != ""},
Contributors: metadata.Contributors,
ContributorsSearch: contributorsSearch,
Language: pgtype.Text{String: metadata.Language, Valid: metadata.Language != ""},
Genre: pgtype.Text{String: metadata.Genre, Valid: metadata.Genre != ""},
PageCount: pgtype.Int4{Int32: metadata.PageCount, Valid: metadata.PageCount > 0},
MangaType: pgtype.Text{String: metadata.MangaType, Valid: metadata.MangaType != ""},
ReadingDirection: pgtype.Text{String: metadata.ReadingDirection, Valid: metadata.ReadingDirection != ""},
SeriesCount: pgtype.Int4{Int32: metadata.SeriesCount, Valid: metadata.SeriesCount > 0},
Volume: pgtype.Int4{Int32: metadata.Volume, Valid: metadata.Volume > 0},
Imprint: pgtype.Text{String: metadata.Imprint, Valid: metadata.Imprint != ""},
AgeRating: pgtype.Text{String: metadata.AgeRating, Valid: metadata.AgeRating != ""},
WebUrl: pgtype.Text{String: metadata.WebURL, Valid: metadata.WebURL != ""},
MetadataNotes: pgtype.Text{String: metadata.MetadataNotes, Valid: metadata.MetadataNotes != ""},
CommunityRating: pgtype.Float8{Float64: metadata.CommunityRating, Valid: metadata.CommunityRating > 0},
StoryArc: pgtype.Text{String: metadata.StoryArc, Valid: metadata.StoryArc != ""},
IsBlackAndWhite: pgtype.Bool{Bool: metadata.IsBlackAndWhite, Valid: metadata.IsBlackAndWhite},
AlternateInfo: alternateInfoBytes,
ScanInformation: pgtype.Text{String: metadata.ScanInformation, Valid: metadata.ScanInformation != ""},
Summary: pgtype.Text{String: metadata.Summary, Valid: metadata.Summary != ""},
})
return err
}