diff --git a/scanner/metadata/metadata_test.go b/scanner/metadata/metadata_test.go index 07ad8395..98d2d830 100644 --- a/scanner/metadata/metadata_test.go +++ b/scanner/metadata/metadata_test.go @@ -40,7 +40,7 @@ var _ = Describe("Tags", func() { Expect(m.Channels()).To(Equal(2)) Expect(m.FilePath()).To(Equal("tests/fixtures/test.mp3")) Expect(m.Suffix()).To(Equal("mp3")) - Expect(m.Size()).To(Equal(int64(51876))) + Expect(m.Size()).To(Equal(int64(52050))) Expect(m.RGAlbumGain()).To(Equal(3.21518)) Expect(m.RGAlbumPeak()).To(Equal(0.9125)) Expect(m.RGTrackGain()).To(Equal(-1.48)) @@ -53,10 +53,10 @@ var _ = Describe("Tags", func() { Expect(m.Duration()).To(BeNumerically("~", 1.04, 0.01)) Expect(m.Suffix()).To(Equal("ogg")) Expect(m.FilePath()).To(Equal("tests/fixtures/test.ogg")) - Expect(m.Size()).To(Equal(int64(5065))) + Expect(m.Size()).To(Equal(int64(5178))) // TabLib 1.12 returns 18, previous versions return 39. // See https://github.com/taglib/taglib/commit/2f238921824741b2cfe6fbfbfc9701d9827ab06b - Expect(m.BitRate()).To(BeElementOf(18, 39)) + Expect(m.BitRate()).To(BeElementOf(18, 39, 40)) }) }) }) diff --git a/scanner/metadata/taglib/taglib_test.go b/scanner/metadata/taglib/taglib_test.go index 14ff223e..6bf7d3b5 100644 --- a/scanner/metadata/taglib/taglib_test.go +++ b/scanner/metadata/taglib/taglib_test.go @@ -65,7 +65,35 @@ var _ = Describe("Extractor", func() { // TabLib 1.12 returns 18, previous versions return 39. // See https://github.com/taglib/taglib/commit/2f238921824741b2cfe6fbfbfc9701d9827ab06b Expect(m).To(HaveKey("bitrate")) - Expect(m["bitrate"][0]).To(BeElementOf("18", "39")) + Expect(m["bitrate"][0]).To(BeElementOf("18", "39", "40")) + }) + + Context("ReplayGain", func() { + testGain := func(file, albumGain, albumPeak, trackGain, trackPeak string) { + file = "tests/fixtures/" + file + mds, err := e.Parse(file) + Expect(err).NotTo(HaveOccurred()) + Expect(mds).To(HaveLen(1)) + + m := mds[file] + + Expect(m).To(HaveKeyWithValue("replaygain_album_gain", []string{albumGain})) + Expect(m).To(HaveKeyWithValue("replaygain_album_peak", []string{albumPeak})) + Expect(m).To(HaveKeyWithValue("replaygain_track_gain", []string{trackGain})) + Expect(m).To(HaveKeyWithValue("replaygain_track_peak", []string{trackPeak})) + } + + It("Correctly parses m4a (aac) gain tags", func() { + testGain("01 Invisible (RED) Edit Version.m4a", "0.37", "0.48", "0.37", "0.48") + }) + + It("correctly parses mp3 tags", func() { + testGain("test.mp3", "+3.21518 dB", "0.9125", "-1.48 dB", "0.4512") + }) + + It("correctly parses ogg (vorbis) tags", func() { + testGain("test.ogg", "+7.64 dB", "0.11772506", "+7.64 dB", "0.11772506") + }) }) }) diff --git a/scanner/metadata/taglib/taglib_wrapper.cpp b/scanner/metadata/taglib/taglib_wrapper.cpp index ea7f72ea..3f111c13 100644 --- a/scanner/metadata/taglib/taglib_wrapper.cpp +++ b/scanner/metadata/taglib/taglib_wrapper.cpp @@ -15,6 +15,13 @@ #include "taglib_wrapper.h" +// Tags necessary for M4a parsing +const char *RG_TAGS[] = { + "replaygain_album_gain", + "replaygain_album_peak", + "replaygain_track_gain", + "replaygain_track_peak"}; + char has_cover(const TagLib::FileRef f); int taglib_read(const FILENAME_CHAR_T *filename, unsigned long id) { @@ -70,6 +77,29 @@ int taglib_read(const FILENAME_CHAR_T *filename, unsigned long id) { } } + TagLib::MP4::File *m4afile(dynamic_cast(f.file())); + if (m4afile != NULL) + { + const auto itemListMap = m4afile->tag(); + { + char buf[200]; + + for (const char *key : RG_TAGS) + { + snprintf(buf, sizeof(buf), "----:com.apple.iTunes:%s", key); + const auto item = itemListMap->item(buf); + if (item.isValid()) + { + char *dup = ::strdup(key); + char *val = ::strdup(item.toStringList().front().toCString(true)); + go_map_put_str(id, dup, val); + free(dup); + free(val); + } + } + } + } + if (has_cover(f)) { go_map_put_str(id, (char *)"has_picture", (char *)"true"); } diff --git a/scanner/tag_scanner_test.go b/scanner/tag_scanner_test.go index e5bb7be5..215e06bc 100644 --- a/scanner/tag_scanner_test.go +++ b/scanner/tag_scanner_test.go @@ -10,11 +10,12 @@ var _ = Describe("TagScanner", func() { It("return all audio files from the folder", func() { files, err := loadAllAudioFiles("tests/fixtures") Expect(err).ToNot(HaveOccurred()) - Expect(files).To(HaveLen(4)) + Expect(files).To(HaveLen(5)) Expect(files).To(HaveKey("tests/fixtures/test.ogg")) Expect(files).To(HaveKey("tests/fixtures/test.mp3")) Expect(files).To(HaveKey("tests/fixtures/test_no_read_permission.ogg")) Expect(files).To(HaveKey("tests/fixtures/01 Invisible (RED) Edit Version.mp3")) + Expect(files).To(HaveKey("tests/fixtures/01 Invisible (RED) Edit Version.m4a")) Expect(files).ToNot(HaveKey("tests/fixtures/._02 Invisible.mp3")) Expect(files).ToNot(HaveKey("tests/fixtures/playlist.m3u")) }) diff --git a/scanner/walk_dir_tree_test.go b/scanner/walk_dir_tree_test.go index 7ef159f0..42277adf 100644 --- a/scanner/walk_dir_tree_test.go +++ b/scanner/walk_dir_tree_test.go @@ -36,7 +36,7 @@ var _ = Describe("walk_dir_tree", func() { Expect(collected[baseDir]).To(MatchFields(IgnoreExtras, Fields{ "Images": BeEmpty(), "HasPlaylist": BeFalse(), - "AudioFilesCount": BeNumerically("==", 5), + "AudioFilesCount": BeNumerically("==", 6), })) Expect(collected[filepath.Join(baseDir, "artist", "an-album")]).To(MatchFields(IgnoreExtras, Fields{ "Images": ConsistOf("cover.jpg", "front.png", "artist.png"), diff --git a/tests/fixtures/01 Invisible (RED) Edit Version.m4a b/tests/fixtures/01 Invisible (RED) Edit Version.m4a new file mode 100644 index 00000000..55d360d8 Binary files /dev/null and b/tests/fixtures/01 Invisible (RED) Edit Version.m4a differ diff --git a/tests/fixtures/test.mp3 b/tests/fixtures/test.mp3 index 49518e34..610156f9 100644 Binary files a/tests/fixtures/test.mp3 and b/tests/fixtures/test.mp3 differ diff --git a/tests/fixtures/test.ogg b/tests/fixtures/test.ogg index be672812..9a5490d3 100644 Binary files a/tests/fixtures/test.ogg and b/tests/fixtures/test.ogg differ