Skip to content

Commit ba4d4e1

Browse files
authored
Add logging (#3)
* update publish settings * add serilog logging * fix unit tests to work with logging * codemaid cleanup via VS2022
1 parent 8e3ba99 commit ba4d4e1

9 files changed

Lines changed: 116 additions & 30 deletions

File tree

MediaSorter/App.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using MediaSorter.Models;
22
using MediaSorter.Services.Interfaces;
33
using MediaSorter.Utils;
4+
using Microsoft.Extensions.Logging;
45
using System.Reflection;
56
using System.Text;
67

@@ -14,6 +15,7 @@ public class App
1415
private readonly IDateParser _dateParser;
1516
private readonly IDirectoryProvider _directoryProvider;
1617
private readonly IFileSorter _fileSorter;
18+
private readonly ILogger<App> _logger;
1719
private readonly IMediaScanner _mediaScanner;
1820
private readonly IMetadataProvider _metadataProvider;
1921
private readonly string _version = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "X.X.X.X";
@@ -22,12 +24,14 @@ public App(
2224
IDateParser dateParser,
2325
IDirectoryProvider directoryProvider,
2426
IFileSorter fileSorter,
27+
ILogger<App> logger,
2528
IMediaScanner mediaScanner,
2629
IMetadataProvider metadataProvider)
2730
{
2831
_dateParser = dateParser;
2932
_directoryProvider = directoryProvider;
3033
_fileSorter = fileSorter;
34+
_logger = logger;
3135
_metadataProvider = metadataProvider;
3236
_mediaScanner = mediaScanner;
3337
}
@@ -58,9 +62,11 @@ public void Run(string[] args)
5862

5963
var mediaWithDatesTaken = ParseMediaDatesTaken(mediaWithMetadata);
6064
SortMediaFiles(outputDirectory, mediaWithDatesTaken);
65+
_logger.LogDebug("Done sorting {count} files.", mediaWithDatesTaken.Count());
6166
}
6267
catch (Exception ex)
6368
{
69+
_logger.LogError(ex.ToString());
6470
CliUtils.DisplayMessageWithColor($"An error occurred: {ex.Message}", ConsoleColor.Red);
6571
CliUtils.DisplayMessageAndExit("Exiting...", ConsoleColor.Red, 1);
6672
}
@@ -72,7 +78,9 @@ private IEnumerable<string> GetMediaPaths(string sourceDirectory)
7278
var mediaPaths = _mediaScanner.GetMediaInPath(sourceDirectory);
7379
if (!mediaPaths.Any())
7480
CliUtils.DisplayMessageAndExit("No media files were found. Exiting...", ConsoleColor.Yellow, 0);
81+
7582
Console.WriteLine("Found {0} media files.", mediaPaths.Count());
83+
_logger.LogDebug("Found {count} media file(s) to sort.", mediaPaths.Count());
7684

7785
return mediaPaths;
7886
}
@@ -83,6 +91,8 @@ private string GetOutputDirectory()
8391
if (outputDirectory is null)
8492
CliUtils.DisplayMessageAndExit("Exiting...", ConsoleColor.Yellow, 0);
8593

94+
_logger.LogDebug("Output Directory: \"{directory}\"", outputDirectory);
95+
8696
return outputDirectory;
8797
}
8898

@@ -92,6 +102,8 @@ private string GetSourceDirectory()
92102
if (sourceDirectory is null)
93103
CliUtils.DisplayMessageAndExit("Exiting...", ConsoleColor.Yellow, 0);
94104

105+
_logger.LogDebug("Source Directory: \"{directory}\"", sourceDirectory);
106+
95107
return sourceDirectory;
96108
}
97109

MediaSorter/Constants/MetadataConstants.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
public static class MetadataConstants
44
{
55
public const string EXIF = "EXIF";
6-
public const string File = "File";
7-
public const string GPS = "GPS";
8-
public const string ICC = "ICC";
9-
public const string IPTC = "IPTC";
10-
public const string QuickTime = "QuickTime";
11-
126
public const string ExifDateFormat = "yyyy:MM:dd HH:mm:ss";
7+
public const string File = "File";
138
public const string FileDateFormat = "ddd MMM dd HH:mm:ss zzz yyyy";
9+
public const string GPS = "GPS";
1410
public const string GpsDateFormat = "yyyy:MM:dd";
11+
public const string ICC = "ICC";
1512
public const string IccDateFormat = "yyyy:MM:dd HH:mm:ss";
13+
public const string IPTC = "IPTC";
1614
public const string IptcDateFormat = "MM/dd/yyyy";
15+
public const string QuickTime = "QuickTime";
1716
public const string QuickTimeDateFormat = "ddd MMM dd HH:mm:ss yyyy";
1817
}
1918
}

MediaSorter/MediaSorter.csproj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,28 @@
55
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
8+
<PublishTrimmed>True</PublishTrimmed>
9+
<SignAssembly>False</SignAssembly>
10+
<Description>A simple app that sorts images and videos into folders based on the date they were taken.</Description>
11+
<PackageProjectUrl>https://github.com/adamgate/MediaSorter</PackageProjectUrl>
12+
<AssemblyVersion>1.1.0</AssemblyVersion>
13+
<FileVersion>1.1.0</FileVersion>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
17+
<DebugType>none</DebugType>
18+
</PropertyGroup>
19+
20+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
21+
<DebugType>none</DebugType>
822
</PropertyGroup>
923

1024
<ItemGroup>
1125
<PackageReference Include="MetadataExtractor" Version="2.9.0" />
1226
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.2.25502.107" />
27+
<PackageReference Include="Serilog" Version="4.3.0" />
28+
<PackageReference Include="Serilog.Extensions.Logging" Version="10.0.0" />
29+
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
1330
<PackageReference Include="System.Collections" Version="4.3.0" />
1431
</ItemGroup>
1532

MediaSorter/Program.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using MediaSorter.Services.Interfaces;
33
using Microsoft.Extensions.DependencyInjection;
44
using Microsoft.Extensions.Hosting;
5+
using Serilog;
56

67
namespace MediaSorter
78
{
@@ -14,6 +15,16 @@ private static void Main(string[] args)
1415
{
1516
var builder = Host.CreateApplicationBuilder(args);
1617

18+
builder.Services.AddLogging(builder =>
19+
{
20+
var logger = new LoggerConfiguration()
21+
.MinimumLevel.Debug()
22+
.WriteTo.File("log.txt")
23+
.CreateLogger();
24+
25+
builder.AddSerilog(logger); // register serilog as a logging provider
26+
});
27+
1728
builder.Services.AddScoped<IDateParser, DateParser>();
1829
builder.Services.AddScoped<IDirectoryProvider, CliDirectoryProvider>();
1930
builder.Services.AddScoped<IFileSorter, FileSorter>();
@@ -23,6 +34,7 @@ private static void Main(string[] args)
2334
builder.Services.AddTransient<App>();
2435

2536
var app = builder.Build();
37+
2638
app.Services.GetRequiredService<App>().Run(args);
2739
}
2840
}

MediaSorter/Services/Implementations/DateParser.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
using MediaSorter.Constants;
22
using MediaSorter.Models;
33
using MediaSorter.Services.Interfaces;
4+
using Microsoft.Extensions.Logging;
45
using System.Globalization;
56

67
namespace MediaSorter.Services.Implementations
78
{
9+
/// <summary>
10+
/// Parses date metadata into DateTime.
11+
/// </summary>
812
public class DateParser : IDateParser
913
{
14+
private readonly ILogger<DateParser> _logger;
15+
16+
public DateParser(ILogger<DateParser> logger)
17+
{
18+
_logger = logger;
19+
}
20+
21+
/// <summary>
22+
/// Attempts to parse the raw metadata date strings into <see cref="DateTime"/> and selects the most accurate date for each media path.
23+
/// </summary>
24+
/// <param name="mediaPathsWithMetadata"></param>
25+
/// <returns></returns>
1026
public IDictionary<string, DateMetadata> Parse(IDictionary<string, IEnumerable<RawMetadata>> mediaPathsWithMetadata)
1127
{
1228
var mediaWithDateMetadata = new Dictionary<string, DateMetadata>();
@@ -16,11 +32,15 @@ public IDictionary<string, DateMetadata> Parse(IDictionary<string, IEnumerable<R
1632
if (!media.Value.Any())
1733
{
1834
mediaWithDateMetadata.Add(media.Key, new DateMetadata("", "", "", DateTime.MinValue, 0));
35+
_logger.LogDebug("No date metadata found for \"{mediaPath}\"", media.Key);
1936
continue;
2037
}
2138

2239
var parsedDates = media.Value.Select(x => Parse(x)).ToList();
40+
_logger.LogDebug("Media Path: \"{mediaPath}\" | {parsedDates}", media.Key, string.Join(",", parsedDates));
41+
2342
var mostAccurateDate = SelectMostAccurateDate(parsedDates);
43+
_logger.LogDebug("Most accurate date selected for {mediaPath}: {mostAccurateDate}", media.Key, mostAccurateDate);
2444

2545
mediaWithDateMetadata.Add(media.Key, mostAccurateDate);
2646
}

MediaSorter/Services/Implementations/FileSorter.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using MediaSorter.Models;
22
using MediaSorter.Services.Interfaces;
33
using MediaSorter.Utils;
4-
using System.Text;
4+
using Microsoft.Extensions.Logging;
55

66
namespace MediaSorter.Services.Implementations
77
{
@@ -10,6 +10,13 @@ namespace MediaSorter.Services.Implementations
1010
/// </summary>
1111
public class FileSorter : IFileSorter
1212
{
13+
private readonly ILogger<FileSorter> _logger;
14+
15+
public FileSorter(ILogger<FileSorter> logger)
16+
{
17+
_logger = logger;
18+
}
19+
1320
/// <summary>
1421
/// Attempts to sort media files by their taken date if possible, otherwise by their original name.
1522
/// </summary>
@@ -27,12 +34,11 @@ public void SortMediaFilesByDate(string writePath, IDictionary<string, DateMetad
2734
else
2835
SaveMediaWithDate(writePath, media.Key, media.Value.DateTaken);
2936

30-
// TODO - log this so the class is decoupled from CLI
3137
CliUtils.DisplayMessageWithColor($"Sorted {Path.GetFileName(media.Key)}", ConsoleColor.Gray);
3238
}
3339
}
3440

35-
private static void SaveMediaWithDate(string baseWritePath, string mediaFile, DateTime dateTaken)
41+
private void SaveMediaWithDate(string baseWritePath, string mediaFile, DateTime dateTaken)
3642
{
3743
var newFileName = dateTaken.Date.ToString("yyyyMMdd") + "_" + Path.GetFileName(mediaFile);
3844
var yearTaken = dateTaken.Date.ToString("yyyy");
@@ -42,11 +48,13 @@ private static void SaveMediaWithDate(string baseWritePath, string mediaFile, Da
4248
FileUtils.CreateDirectoryIfDoesntExist(outputDirectory);
4349

4450
var destinationFilePath = Path.Join(outputDirectory, newFileName);
51+
_logger.LogDebug("Attempting to save \"{file}\" to \"{destination}\"", mediaFile, destinationFilePath);
4552
FileUtils.CopyFile(mediaFile, destinationFilePath);
4653
}
4754

48-
private static void SaveMediaWithUnknownDate(string baseWriteFilePath, string mediaFile, string newFileName)
55+
private void SaveMediaWithUnknownDate(string baseWriteFilePath, string mediaFile, string newFileName)
4956
{
57+
_logger.LogDebug("Couldn't determine date taken for {file}. Saving to \"unkown\" folder", mediaFile);
5058
var destinationFile = Path.GetFileName(mediaFile);
5159
var destinationFilePath = Path.Join(baseWriteFilePath, destinationFile);
5260

MediaSorter/Services/Implementations/MetadataProvider.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using MediaSorter.Services.Interfaces;
33
using MediaSorter.Utils;
44
using MetadataExtractor;
5-
using static System.Runtime.InteropServices.JavaScript.JSType;
5+
using Microsoft.Extensions.Logging;
66

77
namespace MediaSorter.Services.Implementations
88
{
@@ -11,6 +11,13 @@ namespace MediaSorter.Services.Implementations
1111
/// </summary>
1212
public class MetadataProvider : IMetadataProvider
1313
{
14+
private readonly ILogger<MetadataProvider> _logger;
15+
16+
public MetadataProvider(ILogger<MetadataProvider> logger)
17+
{
18+
_logger = logger;
19+
}
20+
1421
/// <summary>
1522
/// Extacts the date taken metadata from the provided media.
1623
/// </summary>
@@ -23,6 +30,7 @@ public IDictionary<string, IEnumerable<RawMetadata>> EvaluateMediaMetadata(IEnum
2330
foreach (var mediaItem in mediaPaths)
2431
{
2532
var rawMetadata = ImageMetadataReader.ReadMetadata(mediaItem);
33+
_logger.LogDebug("Raw metadata for \"{media}\" : {rawMetadata}", mediaItem, @rawMetadata);
2634

2735
var mediaItemDateMetadata = new List<RawMetadata>();
2836
foreach (var directory in rawMetadata)
Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using MediaSorter.Models;
22
using MediaSorter.Services.Implementations;
3+
using Microsoft.Extensions.Logging;
4+
using Moq;
35
using System.Diagnostics.CodeAnalysis;
46

57
namespace MediaSorterTests.Services
@@ -8,21 +10,8 @@ namespace MediaSorterTests.Services
810
[ExcludeFromCodeCoverage]
911
public class DateParserTests
1012
{
11-
private DateParser _sut = new();
12-
13-
[TestMethod]
14-
public void Parse_NoMetadata_ReturnsDefault()
15-
{
16-
// Arrange
17-
var rawMetadataCollection = new List<RawMetadata>();
18-
var input = new Dictionary<string, IEnumerable<RawMetadata>> { { "test", rawMetadataCollection } };
19-
20-
// Act
21-
var result = _sut.Parse(input);
22-
23-
// Assert
24-
Assert.AreEqual(DateTime.MinValue, result.First().Value.DateTaken);
25-
}
13+
private Mock<ILogger<DateParser>> _logger;
14+
private DateParser _sut;
2615

2716
private static IEnumerable<object[]> ParseMetadataTypeData
2817
{
@@ -45,15 +34,36 @@ private static IEnumerable<object[]> ParseMetadataTypeData
4534
[DynamicData(nameof(ParseMetadataTypeData))]
4635
public void Parse_MetadataType_ReturnsExpected(RawMetadata rawMetadata, DateTime expectedDate)
4736
{
48-
// Arrange
37+
// Arrange
4938
var rawMetadataCollection = new List<RawMetadata>() { rawMetadata };
50-
var input = new Dictionary<string, IEnumerable<RawMetadata>> { { "test", rawMetadataCollection } };
39+
var input = new Dictionary<string, IEnumerable<RawMetadata>> { { "test", rawMetadataCollection } };
5140

5241
// Act
5342
var result = _sut.Parse(input);
5443

5544
// Assert
5645
Assert.AreEqual(expectedDate, result.First().Value.DateTaken, rawMetadata.Directory);
5746
}
47+
48+
[TestMethod]
49+
public void Parse_NoMetadata_ReturnsDefault()
50+
{
51+
// Arrange
52+
var rawMetadataCollection = new List<RawMetadata>();
53+
var input = new Dictionary<string, IEnumerable<RawMetadata>> { { "test", rawMetadataCollection } };
54+
55+
// Act
56+
var result = _sut.Parse(input);
57+
58+
// Assert
59+
Assert.AreEqual(DateTime.MinValue, result.First().Value.DateTaken);
60+
}
61+
62+
[TestInitialize]
63+
public void Setup()
64+
{
65+
_logger = new();
66+
_sut = new(_logger.Object);
67+
}
5868
}
59-
}
69+
}

MediaSorterTests/Utils/CliUtilsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace MediaSorterTests.Utils
55
{
66
[TestClass]
7-
[ExcludeFromCodeCoverage]
7+
[ExcludeFromCodeCoverage]
88
public class CliUtilsTests
99
{
1010
private const string _displayMessage = "Display Message";

0 commit comments

Comments
 (0)