diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 5c7247b..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [] -} \ No newline at end of file diff --git a/PhotoRenamer/.vscode/launch.json b/PhotoRenamer/.vscode/launch.json new file mode 100644 index 0000000..9d886c5 --- /dev/null +++ b/PhotoRenamer/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/PhotoRenamer.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/PhotoRenamer/.vscode/tasks.json similarity index 83% rename from .vscode/tasks.json rename to PhotoRenamer/.vscode/tasks.json index d04cf29..defd202 100644 --- a/.vscode/tasks.json +++ b/PhotoRenamer/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/PhotoRenamer/PhotoRenamer.csproj", + "${workspaceFolder}/PhotoRenamer.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/PhotoRenamer/PhotoRenamer.csproj", + "${workspaceFolder}/PhotoRenamer.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -32,7 +32,7 @@ "args": [ "watch", "run", - "${workspaceFolder}/PhotoRenamer/PhotoRenamer.csproj", + "${workspaceFolder}/PhotoRenamer.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], diff --git a/PhotoRenamer/PhotoRenamer.csproj b/PhotoRenamer/PhotoRenamer.csproj index dafa349..4d5e24a 100644 --- a/PhotoRenamer/PhotoRenamer.csproj +++ b/PhotoRenamer/PhotoRenamer.csproj @@ -15,6 +15,7 @@ + diff --git a/PhotoRenamer/Program.cs b/PhotoRenamer/Program.cs index f6e2e39..fe7d72a 100644 --- a/PhotoRenamer/Program.cs +++ b/PhotoRenamer/Program.cs @@ -17,8 +17,8 @@ namespace PhotoRenamer Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); try { - var p = new Renamer(configuration); - return p.Run(); + var renamer = new Renamer(configuration); + return renamer.Run(); } catch (Exception e) { diff --git a/PhotoRenamer/Renamer.cs b/PhotoRenamer/Renamer.cs index 510b563..24738cb 100644 --- a/PhotoRenamer/Renamer.cs +++ b/PhotoRenamer/Renamer.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; using MetadataExtractor; using MetadataExtractor.Formats.Exif; using MetadataExtractor.Formats.QuickTime; @@ -15,14 +18,22 @@ namespace PhotoRenamer internal class Renamer { private readonly string _sourcePath; - private readonly string _targetPath; + private readonly string _targetPath; + private readonly ProgressBarOptions _childOptions; - public Renamer(IConfiguration configuration) + public Renamer(IConfiguration configuration) { _sourcePath = Path.GetFullPath(configuration["Source"]); _targetPath = Path.GetFullPath(configuration["Target"]); Log.Information($"Source path: {_sourcePath}"); Log.Information($"Target path: {_targetPath}"); + _childOptions = new ProgressBarOptions + { + ForegroundColor = ConsoleColor.Yellow, + BackgroundColor = ConsoleColor.DarkGreen, + ProgressCharacter = '─', + CollapseWhenFinished = true + }; } public int Run() @@ -33,44 +44,58 @@ namespace PhotoRenamer ForegroundColor = ConsoleColor.Yellow, ForegroundColorDone = ConsoleColor.DarkGreen, BackgroundColor = ConsoleColor.DarkGray, - BackgroundCharacter = '\u2593' - }; + BackgroundCharacter = '\u2593' + }; + var i = 0; using var progressBar = new ProgressBar(files.Length, "Copying files", options); - foreach (var file in files) + var po = new ParallelOptions { MaxDegreeOfParallelism = 4}; + Parallel.ForEach(files, po, file => { - progressBar.Tick(); try { var directories = ImageMetadataReader.ReadMetadata(file); - var dateTime = GetDateTimeFromExif(directories) ?? GetDateTimeFromMp4(directories); - if (dateTime is null) continue; - var folder = CreateFolder(dateTime.GetValueOrDefault()); - CopyFile(folder, file); + if (!(dateTime is null)) + { + var folder = CreateFolder(dateTime.GetValueOrDefault()); + CopyFile(folder, file, progressBar); + } } catch (ImageProcessingException) { //silently ignore } - } + finally + { + System.Threading.Interlocked.Increment(ref i); + progressBar.Tick(i); + } + }); return 0; } - private static void CopyFile(string folder, string file) + private void CopyFile(string folder, string file, ProgressBarBase progressBar) { - var destination = Path.Combine(folder, Path.GetFileName(file)); - if (File.Exists(destination)) return; - File.Copy(file, destination); + var destination = new FileInfo(Path.Combine(folder, Path.GetFileName(file))); + var source = new FileInfo(file); + if (destination.Exists && destination.Length == source.Length) return; + + using var child = progressBar.Spawn(100, destination.FullName, _childOptions); + using var client = new WebClient(); + client.DownloadProgressChanged += (o, args) => child.Tick(args.ProgressPercentage); + client.DownloadFileAsync(new Uri(source.FullName), destination.FullName); + while (client.IsBusy) + { + Thread.Sleep(100); + } + //source.CopyTo(destination.FullName, true); + child.Tick(100); } private string CreateFolder(DateTime dateTime) { - var folder = Path.Combine( - _targetPath, - dateTime.Year.ToString(), - dateTime.Month.ToString("D2"), - dateTime.Day.ToString("D2")); + var folder = Path.Combine(_targetPath, dateTime.Year.ToString(), dateTime.Month.ToString("D2")); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); return folder; } @@ -81,7 +106,7 @@ namespace PhotoRenamer .OfType() .FirstOrDefault()?.GetDateTime(ExifDirectoryBase.TagDateTimeOriginal); } - + private static DateTime? GetDateTimeFromMp4(IEnumerable directories) { return directories diff --git a/PhotoRenamer/appsettings.json b/PhotoRenamer/appsettings.json index bc61897..26abaa0 100644 --- a/PhotoRenamer/appsettings.json +++ b/PhotoRenamer/appsettings.json @@ -1,4 +1,4 @@ { - "Source": "C:\\Users\\Holger\\Nextcloud\\DCIM", - "Target": "C:\\Target" + "Source": "\\\\micro\\photo\\Oneplus5", + "Target": "\\\\micro\\photo\\Oneplus5" } \ No newline at end of file