Updated to dotnet 7
This commit is contained in:
parent
232846f4d1
commit
4157993abd
@ -1,20 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace PhotoRenamer
|
||||
namespace PhotoRenamer
|
||||
{
|
||||
public static class FilesHelper
|
||||
{
|
||||
|
76
PhotoRenamer/HttpClientExtensions.cs
Normal file
76
PhotoRenamer/HttpClientExtensions.cs
Normal file
@ -0,0 +1,76 @@
|
||||
namespace PhotoRenamer
|
||||
{
|
||||
public static class HttpClientExtensions
|
||||
{
|
||||
public static async Task DownloadAsync(
|
||||
this HttpClient client,
|
||||
string requestUri,
|
||||
Stream destination,
|
||||
IProgress<float>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Get the http headers first to examine the content length
|
||||
using var response = await client.GetAsync(
|
||||
requestUri,
|
||||
HttpCompletionOption.ResponseHeadersRead
|
||||
);
|
||||
var contentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
using var download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
// Ignore progress reporting when no progress reporter was
|
||||
// passed or when the content length is unknown
|
||||
if (progress == null || !contentLength.HasValue)
|
||||
{
|
||||
await download.CopyToAsync(destination, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
|
||||
var relativeProgress = new Progress<long>(
|
||||
totalBytes => progress.Report((float)totalBytes / contentLength.Value)
|
||||
);
|
||||
// Use extension method to report progress while downloading
|
||||
await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken);
|
||||
progress.Report(1);
|
||||
}
|
||||
|
||||
public static async Task CopyToAsync(
|
||||
this Stream source,
|
||||
Stream destination,
|
||||
int bufferSize,
|
||||
IProgress<long>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
if (!source.CanRead)
|
||||
throw new ArgumentException("Has to be readable", nameof(source));
|
||||
if (destination == null)
|
||||
throw new ArgumentNullException(nameof(destination));
|
||||
if (!destination.CanWrite)
|
||||
throw new ArgumentException("Has to be writable", nameof(destination));
|
||||
if (bufferSize < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
while (
|
||||
(
|
||||
bytesRead = await source
|
||||
.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
) != 0
|
||||
)
|
||||
{
|
||||
await destination
|
||||
.WriteAsync(buffer, 0, bytesRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
totalBytesRead += bytesRead;
|
||||
progress?.Report(totalBytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,20 +2,20 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.4.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.0.0" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.7.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Serilog;
|
||||
|
||||
namespace PhotoRenamer
|
||||
|
@ -4,13 +4,6 @@ using MetadataExtractor.Formats.QuickTime;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Serilog;
|
||||
using ShellProgressBar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Directory = System.IO.Directory;
|
||||
|
||||
namespace PhotoRenamer
|
||||
@ -49,27 +42,32 @@ namespace PhotoRenamer
|
||||
var i = 0;
|
||||
using var progressBar = new ProgressBar(files.Length, "Copying files", options);
|
||||
var po = new ParallelOptions { MaxDegreeOfParallelism = 4 };
|
||||
Parallel.ForEach(files, po, file =>
|
||||
{
|
||||
try
|
||||
Parallel.ForEach(
|
||||
files,
|
||||
po,
|
||||
file =>
|
||||
{
|
||||
var directories = ImageMetadataReader.ReadMetadata(file);
|
||||
var dateTime = GetDateTimeFromExif(directories)
|
||||
?? GetDateTimeFromMp4(directories)
|
||||
?? GetDateTimeFromLastWrite(file);
|
||||
var folder = CreateFolder(dateTime);
|
||||
CopyFile(folder, file, progressBar);
|
||||
try
|
||||
{
|
||||
var directories = ImageMetadataReader.ReadMetadata(file);
|
||||
var dateTime =
|
||||
GetDateTimeFromExif(directories)
|
||||
?? GetDateTimeFromMp4(directories)
|
||||
?? GetDateTimeFromLastWrite(file);
|
||||
var folder = CreateFolder(dateTime);
|
||||
CopyFile(folder, file, progressBar);
|
||||
}
|
||||
catch (ImageProcessingException)
|
||||
{
|
||||
//silently ignore
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Increment(ref i);
|
||||
progressBar.Tick(i);
|
||||
}
|
||||
}
|
||||
catch (ImageProcessingException)
|
||||
{
|
||||
//silently ignore
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Increment(ref i);
|
||||
progressBar.Tick(i);
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -80,24 +78,30 @@ namespace PhotoRenamer
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
private static DateTime? GetDateTimeFromExif(IEnumerable<MetadataExtractor.Directory> directories)
|
||||
private static DateTime? GetDateTimeFromExif(
|
||||
IEnumerable<MetadataExtractor.Directory> directories
|
||||
)
|
||||
{
|
||||
DateTime dateTime = default;
|
||||
return directories
|
||||
.OfType<ExifIfd0Directory>()
|
||||
.FirstOrDefault()?
|
||||
.TryGetDateTime(ExifDirectoryBase.TagDateTime, out dateTime) == true
|
||||
return
|
||||
directories
|
||||
.OfType<ExifIfd0Directory>()
|
||||
.FirstOrDefault()
|
||||
?.TryGetDateTime(ExifDirectoryBase.TagDateTime, out dateTime) == true
|
||||
? (DateTime?)dateTime
|
||||
: null;
|
||||
}
|
||||
|
||||
private static DateTime? GetDateTimeFromMp4(IEnumerable<MetadataExtractor.Directory> directories)
|
||||
private static DateTime? GetDateTimeFromMp4(
|
||||
IEnumerable<MetadataExtractor.Directory> directories
|
||||
)
|
||||
{
|
||||
DateTime dateTime = default;
|
||||
return directories
|
||||
.OfType<QuickTimeMovieHeaderDirectory>()
|
||||
.FirstOrDefault()?
|
||||
.TryGetDateTime(QuickTimeMovieHeaderDirectory.TagCreated, out dateTime) == true
|
||||
return
|
||||
directories
|
||||
.OfType<QuickTimeMovieHeaderDirectory>()
|
||||
.FirstOrDefault()
|
||||
?.TryGetDateTime(QuickTimeMovieHeaderDirectory.TagCreated, out dateTime) == true
|
||||
? (DateTime?)dateTime
|
||||
: null;
|
||||
}
|
||||
@ -110,26 +114,19 @@ namespace PhotoRenamer
|
||||
destination.CreationTimeUtc = source.CreationTimeUtc;
|
||||
}
|
||||
|
||||
private void CopyFile(string folder, string file, ProgressBarBase progressBar)
|
||||
private async void CopyFile(string folder, string file, ProgressBarBase progressBar)
|
||||
{
|
||||
var destination = new FileInfo(Path.Combine(folder, Path.GetFileName(file)));
|
||||
var source = new FileInfo(file);
|
||||
if (destination.Exists && destination.Length == source.Length) return;
|
||||
if (destination.Exists && destination.Length == source.Length)
|
||||
return;
|
||||
|
||||
using var child = progressBar.Spawn(100, destination.FullName, _childOptions);
|
||||
using var client = new WebClient();
|
||||
using var client = new HttpClient();
|
||||
using var fileStream = File.OpenWrite(destination.FullName);
|
||||
|
||||
void OnClientOnDownloadProgressChanged(object o, DownloadProgressChangedEventArgs args) =>
|
||||
child.Tick(args.ProgressPercentage);
|
||||
|
||||
client.DownloadProgressChanged += OnClientOnDownloadProgressChanged;
|
||||
client.DownloadFileAsync(new Uri(source.FullName), destination.FullName);
|
||||
while (client.IsBusy)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
client.DownloadProgressChanged -= OnClientOnDownloadProgressChanged;
|
||||
var progress = new Progress<float>(o => progressBar.Tick((int)o * 100));
|
||||
await client.DownloadAsync(source.FullName, fileStream, progress);
|
||||
ResetTimes(destination, source);
|
||||
|
||||
child.Tick(100);
|
||||
@ -137,9 +134,14 @@ namespace PhotoRenamer
|
||||
|
||||
private string CreateFolder(DateTime dateTime)
|
||||
{
|
||||
var folder = Path.Combine(_targetPath, dateTime.Year.ToString(), dateTime.Month.ToString("D2"));
|
||||
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
|
||||
var folder = Path.Combine(
|
||||
_targetPath,
|
||||
dateTime.Year.ToString(),
|
||||
dateTime.Month.ToString("D2")
|
||||
);
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace PhotoRenamer.Types
|
||||
namespace PhotoRenamer.Types
|
||||
{
|
||||
public class MediaFile
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user