diff --git a/scanner/phase_1_folders.go b/scanner/phase_1_folders.go index 6107b3316..3ed69cf69 100644 --- a/scanner/phase_1_folders.go +++ b/scanner/phase_1_folders.go @@ -226,7 +226,7 @@ func (p *phaseFolders) processFolder(entry *folderEntry) (*folderEntry, error) { dbTracks[mf.Path] = &mf } - // Get list of files to import, based on modtime (or all if fullScan), + // Get list of files to import, based on modtime and size (or all if fullScan), // leave in dbTracks only tracks that are missing (not found in the FS) filesToImport := make(map[string]*model.MediaFile, len(entry.audioFiles)) for afPath, af := range entry.audioFiles { @@ -241,7 +241,12 @@ func (p *phaseFolders) processFolder(entry *folderEntry) (*folderEntry, error) { p.state.sendWarning(fmt.Sprintf("Error getting file info for %s/%s: %v", entry.path, af.Name(), err)) return entry, nil } - if info.ModTime().After(dbTrack.UpdatedAt) || dbTrack.Missing { + // Re-import when the file is newer than the DB row, when its size + // changed (some taggers rewrite tags while preserving the modtime, + // but writing a tag still changes the file size), or when it was + // previously marked missing. This keeps the per-file decision + // consistent with the folder hash, which already covers size+modtime. + if info.ModTime().After(dbTrack.UpdatedAt) || info.Size() != dbTrack.Size || dbTrack.Missing { filesToImport[fullPath] = dbTrack } } diff --git a/scanner/scanner_test.go b/scanner/scanner_test.go index 00f91699d..485fe31cd 100644 --- a/scanner/scanner_test.go +++ b/scanner/scanner_test.go @@ -562,6 +562,26 @@ var _ = Describe("Scanner", Ordered, func() { Expect(mf.Title).To(Equal("Eleanor Rigby (remix)")) }) + It("re-imports a file whose size changed even when its modtime is preserved", func() { + path := "The Beatles/Revolver/02 - Eleanor Rigby.mp3" + mf, err := findByPath(path) + Expect(err).ToNot(HaveOccurred()) + Expect(mf.Tags).ToNot(HaveKey(model.TagGrouping)) + origModTime := fsys.MapFS[path].ModTime + origSize := mf.Size + + // Some taggers rewrite tags in place while preserving the file's + // modtime, but writing a tag still changes the file size. A quick + // scan must still pick up the change. + fsys.UpdateTags(path, _t{"grouping": "Beatles Crate", "_size": origSize + 4096}, origModTime) + + Expect(runScanner(ctx, false)).To(Succeed()) + Expect(ds.MediaFile(ctx).CountAll()).To(Equal(int64(4))) + mf, err = findByPath(path) + Expect(err).ToNot(HaveOccurred()) + Expect(mf.Tags).To(HaveKeyWithValue(model.TagGrouping, []string{"Beatles Crate"})) + }) + It("upgrades file with same format in the library", func() { fsys.Add("The Beatles/Revolver/01 - Taxman.mp3", revolver(track(1, "Taxman", _t{"bitrate": 640})))