@@ -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