Skip to content

Commit 2261ede

Browse files
author
Meyn
committed
Implemented strict volume matching for slskd results
1 parent 2eb438d commit 2261ede

File tree

2 files changed

+157
-49
lines changed

2 files changed

+157
-49
lines changed

Tubifarry/Core/Model/AudioMetadataHandler.cs

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,30 @@ internal class AudioMetadataHandler
1919
public byte[]? AlbumCover { get; set; }
2020
public bool UseID3v2_3 { get; set; }
2121

22-
2322
public AudioMetadataHandler(string originalPath)
2423
{
2524
TrackPath = originalPath;
26-
_logger = NzbDroneLogger.GetLogger(this); ;
25+
_logger = NzbDroneLogger.GetLogger(this);
2726
}
2827

2928
private static readonly Dictionary<AudioFormat, string[]> ConversionParameters = new()
30-
{
31-
{ AudioFormat.AAC, new[] { "-codec:a aac", "-q:a 0", "-movflags +faststart" } },
32-
{ AudioFormat.MP3, new[] { "-codec:a libmp3lame", "-q:a 0", "-preset insane" } },
33-
{ AudioFormat.Opus, new[] { "-codec:a libopus", "-vbr on", "-compression_level 10", "-application audio" } },
34-
{ AudioFormat.Vorbis, new[] { "-codec:a libvorbis", "-q:a 7" } },
35-
{ AudioFormat.FLAC, new[] { "-codec:a flac" } },
36-
{ AudioFormat.ALAC, new[] { "-codec:a alac" } },
37-
{ AudioFormat.WAV, new[] { "-codec:a pcm_s16le" } },
38-
{ AudioFormat.MP4, new[] { "-codec:a aac", "-q:a 0", "-movflags +faststart" } },
39-
{ AudioFormat.AIFF, new[] { "-codec:a pcm_s16le" } },
40-
{ AudioFormat.OGG, new[] { "-codec:a libvorbis", "-q:a 7" } },
41-
{ AudioFormat.AMR, new[] { "-codec:a libopencore_amrnb", "-ar 8000", "-ab 12.2k" } },
42-
{ AudioFormat.WMA, new[] { "-codec:a wmav2", "-b:a 192k" } }
43-
};
44-
29+
{
30+
{ AudioFormat.AAC, new[] { "-codec:a aac", "-q:a 0", "-movflags +faststart" } },
31+
{ AudioFormat.MP3, new[] { "-codec:a libmp3lame", "-q:a 0", "-preset insane" } },
32+
{ AudioFormat.Opus, new[] { "-codec:a libopus", "-vbr on", "-compression_level 10", "-application audio" } },
33+
{ AudioFormat.Vorbis, new[] { "-codec:a libvorbis", "-q:a 7" } },
34+
{ AudioFormat.FLAC, new[] { "-codec:a flac" } },
35+
{ AudioFormat.ALAC, new[] { "-codec:a alac" } },
36+
{ AudioFormat.WAV, new[] { "-codec:a pcm_s16le" } },
37+
{ AudioFormat.MP4, new[] { "-codec:a aac", "-q:a 0", "-movflags +faststart" } },
38+
{ AudioFormat.AIFF, new[] { "-codec:a pcm_s16le" } },
39+
{ AudioFormat.OGG, new[] { "-codec:a libvorbis", "-q:a 7" } },
40+
{ AudioFormat.AMR, new[] { "-codec:a libopencore_amrnb", "-ar 8000", "-ab 12.2k" } },
41+
{ AudioFormat.WMA, new[] { "-codec:a wmav2", "-b:a 192k" } }
42+
};
4543

4644
private static readonly string[] ExtractionParameters = new[]
47-
{
45+
{
4846
"-codec:a copy",
4947
"-vn",
5048
"-movflags +faststart"
@@ -59,12 +57,16 @@ public AudioMetadataHandler(string originalPath)
5957

6058
public async Task<bool> TryConvertToFormatAsync(AudioFormat audioFormat)
6159
{
60+
_logger?.Trace($"Converting {Path.GetFileName(TrackPath)} to {audioFormat}");
61+
6262
if (!CheckFFmpegInstalled())
6363
return false;
6464

6565
if (!await TryExtractAudioFromVideoAsync())
6666
return false;
6767

68+
_logger?.Trace($"Looking up audio format: {audioFormat}");
69+
6870
if (audioFormat == AudioFormat.Unknown)
6971
return true;
7072

@@ -83,6 +85,7 @@ public async Task<bool> TryConvertToFormatAsync(AudioFormat audioFormat)
8385
foreach (string parameter in ConversionParameters[audioFormat])
8486
conversion.AddParameter(parameter);
8587

88+
_logger?.Trace($"Starting FFmpeg conversion to {audioFormat}");
8689
await conversion.Start();
8790

8891
if (File.Exists(TrackPath))
@@ -118,7 +121,10 @@ public async Task<bool> IsVideoContainerAsync()
118121
string containerType = kvp.Key;
119122
byte[] signature = kvp.Value;
120123
if (header.Skip(4).Take(signature.Length).SequenceEqual(signature))
124+
{
125+
_logger?.Trace($"Detected {containerType} video container via signature");
121126
return true;
127+
}
122128
}
123129
return false;
124130
}
@@ -138,13 +144,18 @@ public async Task<bool> TryExtractAudioFromVideoAsync()
138144
if (!isVideo)
139145
return true;
140146

147+
_logger?.Trace($"Extracting audio from video file: {Path.GetFileName(TrackPath)}");
148+
141149
try
142150
{
143151
IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(TrackPath);
144152
IAudioStream? audioStream = mediaInfo.AudioStreams.FirstOrDefault();
145153

146154
if (audioStream == null)
155+
{
156+
_logger?.Trace("No audio stream found in video file");
147157
return false;
158+
}
148159

149160
string codec = audioStream.Codec.ToLower();
150161
string finalOutputPath = Path.ChangeExtension(TrackPath, AudioFormatHelper.GetFileExtensionForCodec(codec));
@@ -164,11 +175,12 @@ public async Task<bool> TryExtractAudioFromVideoAsync()
164175

165176
File.Move(tempOutputPath, finalOutputPath, true);
166177
TrackPath = finalOutputPath;
178+
_logger?.Trace($"Successfully extracted audio to {Path.GetFileName(TrackPath)}");
167179
return true;
168180
}
169181
catch (Exception ex)
170182
{
171-
_logger?.Error(ex, $"Failed to extract audio from MP4: {TrackPath}");
183+
_logger?.Error(ex, $"Failed to extract audio from video: {TrackPath}");
172184
return false;
173185
}
174186
}
@@ -182,9 +194,16 @@ public async Task<bool> TryCreateLrcFileAsync(CancellationToken token)
182194
string lrcContent = string.Join(Environment.NewLine, Lyric.SyncedLyrics
183195
.Where(lyric => !string.IsNullOrEmpty(lyric.LrcTimestamp) && !string.IsNullOrEmpty(lyric.Line))
184196
.Select(lyric => $"{lyric.LrcTimestamp} {lyric.Line}"));
185-
await File.WriteAllTextAsync(Path.ChangeExtension(TrackPath, ".lrc"), lrcContent, token);
197+
198+
string lrcPath = Path.ChangeExtension(TrackPath, ".lrc");
199+
await File.WriteAllTextAsync(lrcPath, lrcContent, token);
200+
_logger?.Trace($"Created LRC file with {Lyric.SyncedLyrics.Count} synced lyrics");
201+
}
202+
catch (Exception ex)
203+
{
204+
_logger?.Error(ex, $"Failed to create LRC file: {Path.ChangeExtension(TrackPath, ".lrc")}");
205+
return false;
186206
}
187-
catch (Exception) { return false; }
188207
return true;
189208
}
190209

@@ -207,17 +226,23 @@ public async Task<bool> EnsureFileExtAsync()
207226
if (!string.Equals(currentExtension, correctExtension, StringComparison.OrdinalIgnoreCase))
208227
{
209228
string newPath = Path.ChangeExtension(TrackPath, correctExtension);
229+
_logger?.Trace($"Correcting file extension from {currentExtension} to {correctExtension} for codec {codec}");
210230
File.Move(TrackPath, newPath);
211231
TrackPath = newPath;
212232
}
213233
return true;
214234
}
215-
catch (Exception) { return false; }
235+
catch (Exception ex)
236+
{
237+
_logger?.Error(ex, $"Failed to ensure correct file extension: {TrackPath}");
238+
return false;
239+
}
216240
}
217241

218-
219242
public bool TryEmbedMetadata(AlbumInfo albumInfo, AlbumSongInfo trackInfo, ReleaseInfo releaseInfo)
220243
{
244+
_logger?.Trace($"Embedding metadata for track: {trackInfo.Name}");
245+
221246
try
222247
{
223248
using TagLib.File file = TagLib.File.Create(TrackPath);
@@ -264,23 +289,22 @@ public bool TryEmbedMetadata(AlbumInfo albumInfo, AlbumSongInfo trackInfo, Relea
264289
}
265290
catch (Exception ex)
266291
{
267-
_logger?.Error(ex, $"Failed to embed cover in track: {TrackPath}");
292+
_logger?.Error(ex, "Failed to embed album cover");
268293
}
269294

270295
if (!string.IsNullOrEmpty(Lyric?.PlainLyrics))
271296
file.Tag.Lyrics = Lyric.PlainLyrics;
272297

273298
file.Save();
299+
return true;
274300
}
275301
catch (Exception ex)
276302
{
277303
_logger?.Error(ex, $"Failed to embed metadata in track: {TrackPath}");
278304
return false;
279305
}
280-
return true;
281306
}
282307

283-
284308
public static bool CheckFFmpegInstalled()
285309
{
286310
if (_isFFmpegInstalled.HasValue)
@@ -293,7 +317,9 @@ public static bool CheckFFmpegInstalled()
293317
string[] ffmpegPatterns = new[] { "ffmpeg", "ffmpeg.exe", "ffmpeg.bin" };
294318
string[] files = Directory.GetFiles(FFmpeg.ExecutablesPath);
295319
if (files.Any(file => ffmpegPatterns.Contains(Path.GetFileName(file), StringComparer.OrdinalIgnoreCase) && IsExecutable(file)))
320+
{
296321
isInstalled = true;
322+
}
297323
}
298324

299325
if (!isInstalled)
@@ -314,11 +340,13 @@ public static bool CheckFFmpegInstalled()
314340
}
315341
}
316342

343+
if (!isInstalled)
344+
NzbDroneLogger.GetLogger(typeof(AudioMetadataHandler)).Trace("FFmpeg not found in configured path or system PATH");
345+
317346
_isFFmpegInstalled = isInstalled;
318347
return isInstalled;
319348
}
320349

321-
322350
private static bool IsExecutable(string filePath)
323351
{
324352
try
@@ -336,20 +364,18 @@ private static bool IsExecutable(string filePath)
336364
if (magicNumber[0] == 0xCE && magicNumber[1] == 0xFA && magicNumber[2] == 0xED && magicNumber[3] == 0xFE)
337365
return true;
338366
}
339-
catch
340-
{
341-
}
342-
367+
catch { }
343368
return false;
344369
}
345370

346371
public static void ResetFFmpegInstallationCheck() => _isFFmpegInstalled = null;
347372

348373
public static Task InstallFFmpeg(string path)
349374
{
375+
NzbDroneLogger.GetLogger(typeof(AudioMetadataHandler)).Trace($"Installing FFmpeg to: {path}");
350376
ResetFFmpegInstallationCheck();
351377
FFmpeg.SetExecutablesPath(path);
352378
return CheckFFmpegInstalled() ? Task.CompletedTask : FFmpegDownloader.GetLatestVersion(FFmpegVersion.Official, path);
353379
}
354380
}
355-
}
381+
}

0 commit comments

Comments
 (0)