From 0854b91c9070e616ec41b8d98ad2bca880e5c7f9 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sun, 3 Nov 2019 19:21:37 +0100 Subject: [PATCH] PICARD-1592: Preserve case for APEv2 tags When reading APEv2 tags case insensitive, preserve existing casing. --- picard/formats/apev2.py | 18 +++++++++++++----- test/formats/test_apev2.py | 21 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/picard/formats/apev2.py b/picard/formats/apev2.py index 25e98f271..cf610d86c 100644 --- a/picard/formats/apev2.py +++ b/picard/formats/apev2.py @@ -112,21 +112,26 @@ class APEv2File(File): } __rtranslate = dict([(v.lower(), k) for k, v in __translate.items()]) + def __init__(self, filename): + super().__init__(filename) + self.__casemap = {} + def _load(self, filename): log.debug("Loading file %r", filename) + self.__casemap = {} file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): - origname = origname.lower() + name_lower = origname.lower() if (values.kind == mutagen.apev2.BINARY - and origname.startswith("cover art")): + and name_lower.startswith("cover art")): if b'\0' in values.value: descr, data = values.value.split(b'\0', 1) try: coverartimage = TagCoverArtImage( file=filename, - tag=origname, + tag=name_lower, data=data, ) except CoverArtImageError as e: @@ -139,7 +144,7 @@ class APEv2File(File): if values.kind != mutagen.apev2.TEXT: continue for value in values: - name = origname + name = name_lower if name == "year": name = "date" value = sanitize_date(value) @@ -164,6 +169,7 @@ class APEv2File(File): value = value[:start] elif name in self.__rtranslate: name = self.__rtranslate[name] + self.__casemap[name] = origname metadata.add(name, value) self._info(metadata, file) return metadata @@ -238,7 +244,9 @@ class APEv2File(File): del tags[real_name] def _get_tag_name(self, name): - if name.startswith('lyrics:'): + if name in self.__casemap: + return self.__casemap[name] + elif name.startswith('lyrics:'): return 'Lyrics' elif name == 'date': return 'Year' diff --git a/test/formats/test_apev2.py b/test/formats/test_apev2.py index 15e80d564..85cfe4d4a 100644 --- a/test/formats/test_apev2.py +++ b/test/formats/test_apev2.py @@ -87,6 +87,25 @@ class CommonApeTests: self._read_case_insensitive_tag('tracknumber', 'Track') self._read_case_insensitive_tag('discnumber', 'Disc') + @skipUnlessTestfile + def test_ci_tags_preserve_case(self): + # Ensure values are not duplicated on repeated save and are saved + # case preserving. + for name in ('CUStom', 'ARtist'): + tags = {} + tags[name] = 'foo' + save_raw(self.filename, tags) + loaded_metadata = load_metadata(self.filename) + loaded_metadata[name.lower()] = 'bar' + save_metadata(self.filename, loaded_metadata) + raw_metadata = dict(load_raw(self.filename)) + self.assertIn(name, raw_metadata) + self.assertEqual( + raw_metadata[name], + loaded_metadata[name.lower()]) + self.assertEqual(1, len(raw_metadata[name])) + self.assertNotIn(name.upper(), raw_metadata) + def _read_case_insensitive_tag(self, name, ape_name): upper_ape_name = ape_name.upper() metadata = { @@ -97,7 +116,7 @@ class CommonApeTests: self.assertEqual(metadata[upper_ape_name], loaded_metadata[name]) save_metadata(self.filename, loaded_metadata) raw_metadata = load_raw(self.filename) - self.assertIn(ape_name, raw_metadata.keys()) + self.assertIn(upper_ape_name, raw_metadata.keys()) self.assertEqual(metadata[upper_ape_name], raw_metadata[ape_name])