6 Commits
Author SHA1 Message Date
Radio f32310d05e v1.2.1 2022-04-28 17:06:28 +02:00
Radio 29f7ff3c3b Update README.md 2022-03-24 19:27:58 +01:00
Radio da502b93b1 Update README.md 2022-03-24 19:20:16 +01:00
Radio 94966979c3 v1.2 - Logging 2022-03-24 19:15:16 +01:00
Radio eed41bbcc7 Merge branch 'master' of https://github.com/Radioo/WPFLinkTool 2022-03-15 06:51:59 +01:00
Radio 238cb9e984 v1.1.1 - Fix for making hard links 2022-03-15 06:51:50 +01:00
8 changed files with 112 additions and 35 deletions
+4 -4
View File
@@ -1,7 +1,7 @@
# WPFLinkTool
WPF MVVM version of my link tool, faster, better, stronger.
If you used my old versions, your xml instances won't load but your DB folder will be compatible.
Just use the old tools to make links somewhere and add them as instances (copy files) using the WPF version.
The main purpose of this tool is to save disk space for AC data (can use it for anything but that was the main goal).
You add your games' `data` folder as an instance, then the tool will calculate the MD5 hash of each file and store it in its `DB` folder along with storing each file's location inside the `data` folder (ex. (`\sound\`, `\movie\`). Each new instance will only add unique files to the `DB`.
Then you can link your instance to wherever you want and stop copying large amounts of data.
![screenshot](https://stn.s-ul.eu/WSjdB3am.png)
![screenshot](https://stn.s-ul.eu/UgeNvAoD.png)
+28
View File
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace WPFLinkTool
{
public class Logger
{
public ObservableCollection<string> LogEntries;
public ScrollViewer Scroller;
public Logger(ScrollViewer scroller)
{
LogEntries = new();
Scroller = scroller;
}
public void Log(string message)
{
LogEntries.Add(DateTime.Now.ToString() + " " + message);
Scroller.ScrollToBottom();
}
}
}
+10 -2
View File
@@ -17,7 +17,7 @@
<RowDefinition MaxHeight="24" MinHeight="24"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition MaxHeight="24" MinHeight="24"></RowDefinition>
<RowDefinition MaxHeight="16" MinHeight="16"></RowDefinition>
<RowDefinition Height="0.3*"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
@@ -53,7 +53,15 @@
</DataGrid>
<ProgressBar Grid.Row="3" Value="{Binding Progress}" MinHeight="20"></ProgressBar>
<TextBlock Grid.Row="4" Text="{Binding HeaderText}"></TextBlock>
<ScrollViewer x:Name="Scroller" Grid.Row="4">
<ItemsControl Grid.Row="1" ItemsSource="{Binding LogEntries}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Mode=OneWay}" TextWrapping="Wrap" Background="Transparent" BorderThickness="0" IsReadOnly="True"></TextBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Border>
+1 -1
View File
@@ -26,7 +26,7 @@ namespace WPFLinkTool
{
InitializeComponent();
SharedViewModel shared = new();
DataContext = new MainWindowViewModel(shared);
DataContext = new MainWindowViewModel(shared, Scroller);
}
}
}
@@ -48,6 +48,7 @@ namespace WPFLinkTool
foreach (var file in dBFiles)
{
await Task.Run(() => File.Delete(dbDir + @"\" + file));
//vm.Loggerr.Log($"Deleting {file}");
vm.Progress += progressStep;
}
}
@@ -58,6 +59,7 @@ namespace WPFLinkTool
vm.UIEnabled = true;
vm.LinkButtonEnabled = true;
IsExecuting = false;
vm.Loggerr.Log("Delete operation finished.");
}
}
}
@@ -11,7 +11,6 @@ namespace WPFLinkTool
public class MakeHardLinksCommand : AsyncCommandBase
{
private readonly MainWindowViewModel vm;
private bool proceed = false;
private bool delet = false;
private string target;
@@ -25,10 +24,8 @@ namespace WPFLinkTool
IsExecuting = true;
vm.UIEnabled = false;
vm.LinkButtonEnabled = false;
DataInstance selectedInstance = vm.SelectedInstance;
var prompt = MessageBox.Show($"Creating hard links from {selectedInstance.InstanceName}.\nProceed to link target selection?", "Make hard links", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
var prompt = MessageBox.Show($"Creating hard links from {vm.SelectedInstance.InstanceName}.\nProceed to link target selection?", "Make hard links", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (prompt == DialogResult.Yes)
{
FolderBrowserDialog dialog = new();
@@ -36,55 +33,47 @@ namespace WPFLinkTool
{
target = dialog.SelectedPath;
foreach (var file in selectedInstance.InstanceFiles)
{
if (File.Exists(target + file.Location + @"\" + file.OriginalFileName))
{
var prompt2 = MessageBox.Show(@$"{file.Location}\{file.OriginalFileName} already exists in the target directory!" + "\n"
+ "Do you want to delete all encountered dupes before making hard links? (If you didn't know or forgot, overwriting hard linked files changes the originals) 'No' cancels the whole operation.", "Duplicate files detected!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
vm.Loggerr.Log("Checking for duplicates...");
if (prompt2 == DialogResult.Yes)
{
proceed = true;
delet = true;
break;
}
break;
}
}
bool proceed = await Task.Run(() => CheckDupes());
if (delet)
{
foreach (var file in selectedInstance.InstanceFiles)
foreach (var file in vm.SelectedInstance.InstanceFiles)
{
if (File.Exists(target + file.Location + @"\" + file.OriginalFileName))
{
//vm.Loggerr.Log(@$"Deleting {target + file.Location + @"\" + file.OriginalFileName}");
File.Delete(target + file.Location + @"\" + file.OriginalFileName);
}
}
}
vm.Loggerr.Log("Linking...");
if (proceed)
{
var uniqueFolders = (from folders in selectedInstance.InstanceFiles
var uniqueFolders = (from folders in vm.SelectedInstance.InstanceFiles
where folders.Location != string.Empty
select folders.Location).Distinct();
double progressStep = 100D / (selectedInstance.InstanceFiles.Count + uniqueFolders.Count());
double progressStep = 100D / (vm.SelectedInstance.InstanceFiles.Count + uniqueFolders.Count());
foreach (var folder in uniqueFolders)
{
if (!Directory.Exists(target + folder))
{
//vm.Loggerr.Log($@"Creating directory {target + folder}");
await Task.Run(() => Directory.CreateDirectory(target + folder));
}
vm.Progress += progressStep;
}
foreach (var file in selectedInstance.InstanceFiles)
foreach (var file in vm.SelectedInstance.InstanceFiles)
{
if (!File.Exists(target + file.Location + @"\" + file.OriginalFileName))
{
//vm.Loggerr.Log($@"Linking {target + file.Location + @"\" + file.OriginalFileName}");
await Task.Run(() => CreateHardLink(target + file.Location + @"\" + file.OriginalFileName,
dbDir + @"\" + file.HashedFileName, IntPtr.Zero));
}
@@ -97,13 +86,37 @@ namespace WPFLinkTool
vm.Progress = 0;
vm.Loggerr.Log("Link operation finished");
vm.UIEnabled = true;
vm.LinkButtonEnabled = true;
IsExecuting = false;
}
bool CheckDupes()
{
foreach (var file in vm.SelectedInstance.InstanceFiles)
{
if (File.Exists(target + file.Location + @"\" + file.OriginalFileName))
{
var prompt2 = MessageBox.Show(@$"{file.Location}\{file.OriginalFileName} already exists in the target directory!" + "\n"
+ "Do you want to delete all encountered dupes before making hard links? (If you didn't know or forgot, overwriting hard linked files changes the originals). Nothing was linked yet. 'No' cancels the whole operation.", "Duplicate files detected!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (prompt2 == DialogResult.Yes)
{
delet = true;
return true;
}
else
{
return false;
}
}
}
return true;
}
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
static extern bool CreateHardLink(
string lpFileName,
+29 -4
View File
@@ -6,6 +6,7 @@ using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Xml;
@@ -18,6 +19,22 @@ namespace WPFLinkTool
{
public SharedViewModel Shared;
public Logger Loggerr;
public ObservableCollection<string> LogEntries
{
get
{
return _logEntries;
}
set
{
_logEntries = value;
OnPropertyChanged(nameof(LogEntries));
}
}
private ObservableCollection<string> _logEntries;
private string _dBSize;
public string DBSize
{
@@ -130,18 +147,25 @@ namespace WPFLinkTool
public ICommand MakeHardLinksCommand { get; private set; }
public ICommand DeleteUnusedCommand { get; private set; }
public MainWindowViewModel(SharedViewModel shared)
public ScrollViewer Scroller;
public MainWindowViewModel(SharedViewModel shared, ScrollViewer scroller)
{
if (!Directory.Exists(dbDir))
Directory.CreateDirectory(dbDir);
Shared = shared;
Scroller = scroller;
Loggerr = new(Scroller);
OpenAddInstanceWindow = new(OpenInstanceWindow);
DeleteInstanceCommand = new(DeleteInstance);
MakeHardLinksCommand = new MakeHardLinksCommand(this, (ex) => HeaderText = ex.Message);
DeleteUnusedCommand = new DeleteUnusedCommand(this, (ex) => HeaderText = ex.Message);
MakeHardLinksCommand = new MakeHardLinksCommand(this, (ex) => Loggerr.Log(ex.Message));
DeleteUnusedCommand = new DeleteUnusedCommand(this, (ex) => Loggerr.Log(ex.Message));
LoadDBInfo();
Task.Run(() => UpdateDBSize());
Task.Run(() => UpdateSumSize());
//HeaderText = "Loading finished, probably... Have a nice day!";
LogEntries = Loggerr.LogEntries;
Loggerr.Log("Loading finished, probably... Have a nice day!");
}
private void LoadDBInfo()
@@ -171,7 +195,7 @@ namespace WPFLinkTool
public void DeleteInstance(object o)
{
var prompt = MessageBox.Show($"Delete {SelectedInstance.InstanceName}?", "Delete instance", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
var prompt = MessageBox.Show($"Delete {SelectedInstance.InstanceName}? This will not delete the files.", "Delete instance", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (prompt == DialogResult.Yes)
{
Shared.Info.InstanceList.Remove(SelectedInstance);
@@ -179,6 +203,7 @@ namespace WPFLinkTool
LinkButtonEnabled = false;
UpdateSumSize();
OnPropertyChanged(nameof(InstanceList));
Loggerr.Log("Deleting instance operation finished.");
}
}
public void UpdateDBSize()
+1
View File
@@ -6,6 +6,7 @@
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>otoge.ico</ApplicationIcon>
<Version>$(VersionPrefix)</Version>
</PropertyGroup>
<ItemGroup>