From c2883a4d77454f39053629c491331d3872a60be3 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Sun, 14 Jan 2024 00:06:51 +0100
Subject: [PATCH] added new class to convert wav to mp3, maximize volume and
 set mp3 tags

---
 Mp3Converter.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++
 poetry.lock     | 13 +++++++++-
 pyproject.toml  |  1 +
 3 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 Mp3Converter.py

diff --git a/Mp3Converter.py b/Mp3Converter.py
new file mode 100644
index 0000000..a449398
--- /dev/null
+++ b/Mp3Converter.py
@@ -0,0 +1,68 @@
+import re
+import subprocess
+
+from TheCodeLabs_BaseUtils.DefaultLogger import DefaultLogger
+from mutagen.easyid3 import EasyID3
+
+LOG_FORMAT = '[%(levelname)-7s] - %(asctime)s - %(message)s'
+LOGGER = DefaultLogger().create_logger_if_not_exists('Mp3Converter', logFormat=LOG_FORMAT)
+
+
+class Mp3Converter:
+    _PATTERN_MAX_VOLUME = re.compile(r'max_volume: ([-.\d+]*)\s')
+
+    @staticmethod
+    def convert_to_mp3(inputFilePath: str, outputFilePath: str) -> None:
+        output = subprocess.check_output(['ffmpeg',
+                                          '-i', inputFilePath,
+                                          '-af', 'volumedetect',
+                                          '-vn',  # ignore video streams
+                                          '-sn',  # ignore subtitle streams
+                                          '-sn',  # ignore data streams
+                                          '-hide_banner',  # suppress unnecessary log messages
+                                          '-f', 'null',
+                                          'NULL'],
+                                         stderr=subprocess.STDOUT)
+        output = output.decode('utf-8')
+        matches = re.findall(Mp3Converter._PATTERN_MAX_VOLUME, output)
+        detectedMaxVolume = None
+        if matches:
+            detectedMaxVolume = float(matches[0])
+            LOGGER.debug(f'\t\tDetected max volume: {detectedMaxVolume}dB')
+
+        arguments = ['ffmpeg',
+                     '-i', inputFilePath,
+                     '-y',  # overwrite if already exists
+                     '-hide_banner',  # suppress unnecessary log messages
+                     '-loglevel', 'error',
+                     '-vn',  # ignore video streams
+                     '-sn',  # ignore subtitle streams
+                     '-sn',  # ignore data streams
+                     '-ac', '2',  # 2 channels
+                     '-b:a', '320k']  # 320k bitrate
+
+        if detectedMaxVolume is not None and detectedMaxVolume < 0:
+            arguments.extend(['-filter:a', f'volume={abs(detectedMaxVolume)}dB'])  # normalizes volume
+
+        arguments.append(outputFilePath)
+
+        LOGGER.info(f'\t\tRunning {" ".join(arguments)}')
+        subprocess.check_call(arguments)
+
+    @staticmethod
+    def set_mp3_tags(filePath: str, title: str, artist: str, album: str) -> None:
+        LOGGER.info(f'\t\tSetting mp3 tags for "{filePath}"')
+        audio = EasyID3(filePath)
+        audio['title'] = title
+        audio['artist'] = artist
+        audio['album'] = album
+        audio.save()
+
+
+if __name__ == '__main__':
+    Mp3Converter.convert_to_mp3('C:/Programmierung/SpotifyBackup/recorder/1 - Bignic - tetrapod.wav',
+                                'C:/Programmierung/SpotifyBackup/recorder/a.mp3')
+    Mp3Converter.set_mp3_tags('C:/Programmierung/SpotifyBackup/recorder/a.mp3',
+                              title='Fancy Song',
+                              artist='Various Artists',
+                              album='Album #1')
diff --git a/poetry.lock b/poetry.lock
index b9c4de7..41b2cc8 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -132,6 +132,17 @@ files = [
     {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
 ]
 
+[[package]]
+name = "mutagen"
+version = "1.47.0"
+description = "read and write audio tags for many formats"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719"},
+    {file = "mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99"},
+]
+
 [[package]]
 name = "psutil"
 version = "5.9.7"
@@ -341,4 +352,4 @@ zstd = ["zstandard (>=0.18.0)"]
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.11"
-content-hash = "a10c10003642c988271028a8a2a44227cae6123d1e05e4a66f3cb2dbab5a655a"
+content-hash = "bb77de02b25207bf10249bf1370a69682b27ad88452311d42abc7d9830eb5494"
diff --git a/pyproject.toml b/pyproject.toml
index 58bc489..e35ccc9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -14,6 +14,7 @@ python = "^3.11"
 thecodelabs-baseutils = {version = "*", source = "TheCodeLabs" }
 spotipy = "2.22.0"
 PyAudioWPatch = "0.2.12.6"
+mutagen = "1.47.0"
 
 [tool.poetry.dev-dependencies]
 
-- 
GitLab