diff --git a/beets/util/extension.py b/beets/util/extension.py index 7b87a98c93..fb3d7da493 100644 --- a/beets/util/extension.py +++ b/beets/util/extension.py @@ -170,7 +170,12 @@ def remux_mpeglayer3_wav(path: AnyPath) -> AnyPath | None: mp3_path = syspath.with_suffix(".mp3") mp3_path.write_bytes(mp3_data) - util.remove(path) + # When the source already has an `.mp3` extension, it has just been + # rewritten in place with the extracted stream, so there is no separate + # original left to remove. Compare with `samefile` so that a case-only + # difference on a case-insensitive filesystem is caught too. + if not util.samefile(mp3_path, syspath): + util.remove(path) if isinstance(path, str): return str(mp3_path) diff --git a/docs/changelog.rst b/docs/changelog.rst index acbd3294fe..b5b318366e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -95,6 +95,10 @@ Bug fixes valid date/time string" error instead of crashing with an uncaught ``KeyError``. A ``|`` was being accepted as a relative-date unit due to a regular expression character-class typo. +- ``remux_mp3_in_wav`` no longer deletes the imported file when a + MPEGLAYER3 WAV has an ``.mp3`` extension: the remuxed stream was written back + to the same path and then removed as if it were a leftover original. + :bug:`6748` .. For plugin developers diff --git a/test/test_importer.py b/test/test_importer.py index c626202c7b..44a2a32bfc 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -1894,6 +1894,32 @@ def test_remux_mpeglayer3_wav(self): assert mp3_path.exists() assert not dest.exists() + def test_remux_mpeglayer3_wav_mp3_extension(self): + """A MPEGLAYER3 WAV with an `.mp3` extension must not be deleted. + + See #6748. + """ + src = _common.RSRC / "mpeglayer3.wav" + dest = self.temp_path / "mpeglayer3.mp3" + shutil.copy(syspath(src), syspath(dest)) + + mp3_path = remux_mpeglayer3_wav(dest) + + assert mp3_path == dest + assert dest.exists() + + def test_remux_mpeglayer3_wav_mp3_extension_uppercase(self): + """The same holds when the extension differs only by case.""" + src = _common.RSRC / "mpeglayer3.wav" + dest = self.temp_path / "mpeglayer3.MP3" + shutil.copy(syspath(src), syspath(dest)) + + mp3_path = remux_mpeglayer3_wav(dest) + + assert dest.exists() + assert mp3_path is not None + assert mp3_path.exists() + def test_remux_mpeglayer3_wav_disabled(self): """When remux_mp3_in_wav is disabled, WAV file should not be remuxed.""" self.config["import"]["remux_mp3_in_wav"] = False