|
|
@ -198,6 +198,7 @@ public partial class CheckpointFolder : ViewModelBase |
|
|
|
var textBox = new TextBox(); |
|
|
|
var textBox = new TextBox(); |
|
|
|
var dialog = new ContentDialog |
|
|
|
var dialog = new ContentDialog |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
Title = "Folder name", |
|
|
|
Content = textBox, |
|
|
|
Content = textBox, |
|
|
|
DefaultButton = ContentDialogButton.Primary, |
|
|
|
DefaultButton = ContentDialogButton.Primary, |
|
|
|
PrimaryButtonText = "OK", |
|
|
|
PrimaryButtonText = "OK", |
|
|
@ -232,106 +233,112 @@ public partial class CheckpointFolder : ViewModelBase |
|
|
|
/// </summary> |
|
|
|
/// </summary> |
|
|
|
public async Task ImportFilesAsync(IEnumerable<string> files, bool convertToConnected = false) |
|
|
|
public async Task ImportFilesAsync(IEnumerable<string> files, bool convertToConnected = false) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Progress.Value = 0; |
|
|
|
try |
|
|
|
var copyPaths = files.ToDictionary(k => k, v => Path.Combine(DirectoryPath, Path.GetFileName(v))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var progress = new Progress<ProgressReport>(report => |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Progress.IsIndeterminate = false; |
|
|
|
|
|
|
|
Progress.Value = report.Percentage; |
|
|
|
|
|
|
|
// For multiple files, add count |
|
|
|
|
|
|
|
Progress.Text = copyPaths.Count > 1 ? $"Importing {report.Title} ({report.Message})" : $"Importing {report.Title}"; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await FileTransfers.CopyFiles(copyPaths, progress); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hash files and convert them to connected model if found |
|
|
|
|
|
|
|
if (convertToConnected) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
var modelFilesCount = copyPaths.Count; |
|
|
|
Progress.Value = 0; |
|
|
|
var modelFiles = copyPaths.Values |
|
|
|
var copyPaths = files.ToDictionary(k => k, v => Path.Combine(DirectoryPath, Path.GetFileName(v))); |
|
|
|
.Select(path => new FilePath(path)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Holds tasks for model queries after hash |
|
|
|
var progress = new Progress<ProgressReport>(report => |
|
|
|
var modelQueryTasks = new List<Task<bool>>(); |
|
|
|
{ |
|
|
|
|
|
|
|
Progress.IsIndeterminate = false; |
|
|
|
|
|
|
|
Progress.Value = report.Percentage; |
|
|
|
|
|
|
|
// For multiple files, add count |
|
|
|
|
|
|
|
Progress.Text = copyPaths.Count > 1 ? $"Importing {report.Title} ({report.Message})" : $"Importing {report.Title}"; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var (i, modelFile) in modelFiles.Enumerate()) |
|
|
|
await FileTransfers.CopyFiles(copyPaths, progress); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hash files and convert them to connected model if found |
|
|
|
|
|
|
|
if (convertToConnected) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var hashProgress = new Progress<ProgressReport>(report => |
|
|
|
var modelFilesCount = copyPaths.Count; |
|
|
|
{ |
|
|
|
var modelFiles = copyPaths.Values |
|
|
|
Progress.IsIndeterminate = false; |
|
|
|
.Select(path => new FilePath(path)); |
|
|
|
Progress.Value = report.Percentage; |
|
|
|
|
|
|
|
Progress.Text = modelFilesCount > 1 ? |
|
|
|
|
|
|
|
$"Computing metadata for {modelFile.Info.Name} ({i}/{modelFilesCount})" : |
|
|
|
|
|
|
|
$"Computing metadata for {report.Title}"; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var hashBlake3 = await FileHash.GetBlake3Async(modelFile, hashProgress); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start a task to query the model in background |
|
|
|
// Holds tasks for model queries after hash |
|
|
|
var queryTask = Task.Run(async () => |
|
|
|
var modelQueryTasks = new List<Task<bool>>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var (i, modelFile) in modelFiles.Enumerate()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var result = await modelFinder.LocalFindModel(hashBlake3); |
|
|
|
var hashProgress = new Progress<ProgressReport>(report => |
|
|
|
result ??= await modelFinder.RemoteFindModel(hashBlake3); |
|
|
|
{ |
|
|
|
|
|
|
|
Progress.IsIndeterminate = report.IsIndeterminate; |
|
|
|
|
|
|
|
Progress.Value = report.Percentage; |
|
|
|
|
|
|
|
Progress.Text = modelFilesCount > 1 ? |
|
|
|
|
|
|
|
$"Computing metadata for {modelFile.Name} ({i}/{modelFilesCount})" : |
|
|
|
|
|
|
|
$"Computing metadata for {modelFile.Name}"; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var hashBlake3 = await FileHash.GetBlake3Async(modelFile, hashProgress); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start a task to query the model in background |
|
|
|
|
|
|
|
var queryTask = Task.Run(async () => |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var result = await modelFinder.LocalFindModel(hashBlake3); |
|
|
|
|
|
|
|
result ??= await modelFinder.RemoteFindModel(hashBlake3); |
|
|
|
|
|
|
|
|
|
|
|
if (result is null) return false; // Not found |
|
|
|
if (result is null) return false; // Not found |
|
|
|
|
|
|
|
|
|
|
|
var (model, version, file) = result.Value; |
|
|
|
var (model, version, file) = result.Value; |
|
|
|
|
|
|
|
|
|
|
|
// Save connected model info json |
|
|
|
// Save connected model info json |
|
|
|
var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Info.Name); |
|
|
|
var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Info.Name); |
|
|
|
var modelInfo = new ConnectedModelInfo( |
|
|
|
var modelInfo = new ConnectedModelInfo( |
|
|
|
model, version, file, DateTimeOffset.UtcNow); |
|
|
|
model, version, file, DateTimeOffset.UtcNow); |
|
|
|
await modelInfo.SaveJsonToDirectory(DirectoryPath, modelFileName); |
|
|
|
await modelInfo.SaveJsonToDirectory(DirectoryPath, modelFileName); |
|
|
|
|
|
|
|
|
|
|
|
// If available, save thumbnail |
|
|
|
// If available, save thumbnail |
|
|
|
var image = version.Images?.FirstOrDefault(); |
|
|
|
var image = version.Images?.FirstOrDefault(); |
|
|
|
if (image != null) |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
|
|
|
|
var imageExt = Path.GetExtension(image.Url).TrimStart('.'); |
|
|
|
|
|
|
|
if (imageExt is "jpg" or "jpeg" or "png") |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
var imageDownloadPath = Path.GetFullPath( |
|
|
|
var imageExt = Path.GetExtension(image.Url).TrimStart('.'); |
|
|
|
Path.Combine(DirectoryPath, $"{modelFileName}.preview.{imageExt}")); |
|
|
|
if (imageExt is "jpg" or "jpeg" or "png") |
|
|
|
await downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); |
|
|
|
{ |
|
|
|
|
|
|
|
var imageDownloadPath = Path.GetFullPath( |
|
|
|
|
|
|
|
Path.Combine(DirectoryPath, $"{modelFileName}.preview.{imageExt}")); |
|
|
|
|
|
|
|
await downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
}); |
|
|
|
}); |
|
|
|
modelQueryTasks.Add(queryTask); |
|
|
|
modelQueryTasks.Add(queryTask); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Set progress to indeterminate |
|
|
|
// Set progress to indeterminate |
|
|
|
Progress.IsIndeterminate = true; |
|
|
|
Progress.IsIndeterminate = true; |
|
|
|
Progress.Text = "Checking connected model information"; |
|
|
|
Progress.Text = "Checking connected model information"; |
|
|
|
|
|
|
|
|
|
|
|
// Wait for all model queries to finish |
|
|
|
// Wait for all model queries to finish |
|
|
|
var modelQueryResults = await Task.WhenAll(modelQueryTasks); |
|
|
|
var modelQueryResults = await Task.WhenAll(modelQueryTasks); |
|
|
|
|
|
|
|
|
|
|
|
var successCount = modelQueryResults.Count(r => r); |
|
|
|
var successCount = modelQueryResults.Count(r => r); |
|
|
|
var totalCount = modelQueryResults.Length; |
|
|
|
var totalCount = modelQueryResults.Length; |
|
|
|
var failCount = totalCount - successCount; |
|
|
|
var failCount = totalCount - successCount; |
|
|
|
|
|
|
|
|
|
|
|
await IndexAsync(); |
|
|
|
await IndexAsync(); |
|
|
|
|
|
|
|
|
|
|
|
Progress.Value = 100; |
|
|
|
Progress.Value = 100; |
|
|
|
Progress.Text = successCount switch |
|
|
|
Progress.Text = successCount switch |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
0 when failCount > 0 => |
|
|
|
|
|
|
|
"Import complete. No connected data found.", |
|
|
|
|
|
|
|
> 0 when failCount > 0 => |
|
|
|
|
|
|
|
$"Import complete. Found connected data for {successCount} of {totalCount} models.", |
|
|
|
|
|
|
|
1 when failCount == 0 => |
|
|
|
|
|
|
|
"Import complete. Found connected data for 1 model.", |
|
|
|
|
|
|
|
_ => $"Import complete. Found connected data for all {totalCount} models." |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
0 when failCount > 0 => |
|
|
|
Progress.Text = "Import complete"; |
|
|
|
"Import complete. No connected data found.", |
|
|
|
Progress.Value = 100; |
|
|
|
> 0 when failCount > 0 => |
|
|
|
await IndexAsync(); |
|
|
|
$"Import complete. Found connected data for {successCount} of {totalCount} models.", |
|
|
|
} |
|
|
|
_ => $"Import complete. Found connected data for all {totalCount} models." |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DelayedClearProgress(TimeSpan.FromSeconds(1.5)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
finally |
|
|
|
{ |
|
|
|
{ |
|
|
|
Progress.Text = "Import complete"; |
|
|
|
|
|
|
|
Progress.Value = 100; |
|
|
|
|
|
|
|
await IndexAsync(); |
|
|
|
|
|
|
|
DelayedClearProgress(TimeSpan.FromSeconds(1.5)); |
|
|
|
DelayedClearProgress(TimeSpan.FromSeconds(1.5)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -345,6 +352,7 @@ public partial class CheckpointFolder : ViewModelBase |
|
|
|
{ |
|
|
|
{ |
|
|
|
IsImportInProgress = false; |
|
|
|
IsImportInProgress = false; |
|
|
|
Progress.Value = 0; |
|
|
|
Progress.Value = 0; |
|
|
|
|
|
|
|
Progress.IsIndeterminate = false; |
|
|
|
Progress.Text = string.Empty; |
|
|
|
Progress.Text = string.Empty; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|