diff --git a/src/NCMDumpCLI/NCMDumpCLI.csproj b/src/NCMDump.CLI/NCMDump.CLI.csproj
similarity index 79%
rename from src/NCMDumpCLI/NCMDumpCLI.csproj
rename to src/NCMDump.CLI/NCMDump.CLI.csproj
index 7ab55f9..422e480 100644
--- a/src/NCMDumpCLI/NCMDumpCLI.csproj
+++ b/src/NCMDump.CLI/NCMDump.CLI.csproj
@@ -5,10 +5,9 @@
net8.0
enable
enable
- NCMDumpCLI
NCMDump.ico
app.manifest
- 2.3.0
+ 2.4.0
x64
@@ -18,8 +17,10 @@
+
+
-
+
diff --git a/src/NCMDumpCLI/NCMDump.ico b/src/NCMDump.CLI/NCMDump.ico
similarity index 100%
rename from src/NCMDumpCLI/NCMDump.ico
rename to src/NCMDump.CLI/NCMDump.ico
diff --git a/src/NCMDumpCLI/NCMDumpCLI - Backup.csproj b/src/NCMDump.CLI/NCMDumpCLI - Backup.csproj
similarity index 100%
rename from src/NCMDumpCLI/NCMDumpCLI - Backup.csproj
rename to src/NCMDump.CLI/NCMDumpCLI - Backup.csproj
diff --git a/src/NCMDump.CLI/Program.cs b/src/NCMDump.CLI/Program.cs
new file mode 100644
index 0000000..421ce9c
--- /dev/null
+++ b/src/NCMDump.CLI/Program.cs
@@ -0,0 +1,77 @@
+using NCMDump.Core;
+
+namespace NCMDump.CLI
+{
+ public class Application
+ {
+ public static NCMDumper Dumper = new();
+
+ public static void Main(params string[] args)
+ {
+ int depth = 0;
+ if (args.Length == 0)
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ Console.WriteLine("Drag [*.ncm] file or directory on exe to start...");
+ Console.WriteLine("./ncmdump.exe [ ... ]");
+ }
+ if (OperatingSystem.IsLinux())
+ {
+ Console.WriteLine("./ncmdump [ ... ]");
+ }
+ return;
+ }
+
+ try
+ {
+ foreach (string path in args)
+ {
+ if (new DirectoryInfo(path).Exists)
+ {
+ WalkThrough(new DirectoryInfo(path));
+ }
+ else if (new FileInfo(path).Exists)
+ {
+ Console.Write($"Dumping: {new FileInfo(path).FullName} ......");
+ if (Dumper.Convert(path)) Console.WriteLine("OK");
+ else Console.WriteLine("Fail");
+ Console.WriteLine();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+
+ Console.Write("Press Enter to Exit...");
+ Console.ReadLine();
+ return;
+
+ void WalkThrough(DirectoryInfo dir)
+ {
+ depth++;
+ if (depth > 16)
+ {
+ depth--;
+ return;
+ }
+ Console.WriteLine("DIR: " + dir.FullName);
+ foreach (DirectoryInfo d in dir.GetDirectories())
+ {
+ WalkThrough(d);
+ }
+ foreach (FileInfo f in dir.EnumerateFiles("*.ncm"))
+ {
+ Console.Write($"Dumping: {f.FullName} ......");
+ if (Dumper.Convert(f.FullName)) Console.WriteLine("OK");
+ else Console.WriteLine("...Fail");
+ }
+
+ Console.WriteLine();
+ depth--;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NCMDumpCLI/app.manifest b/src/NCMDump.CLI/app.manifest
similarity index 97%
rename from src/NCMDumpCLI/app.manifest
rename to src/NCMDump.CLI/app.manifest
index eee9064..6b02c6d 100644
--- a/src/NCMDumpCLI/app.manifest
+++ b/src/NCMDump.CLI/app.manifest
@@ -39,7 +39,7 @@
-
+
diff --git a/src/NCMDumpCLI/ncmdump.png b/src/NCMDump.CLI/ncmdump.png
similarity index 100%
rename from src/NCMDumpCLI/ncmdump.png
rename to src/NCMDump.CLI/ncmdump.png
diff --git a/src/NCMDump.Core/IRC4_NCM_Stream.cs b/src/NCMDump.Core/IRC4_NCM_Stream.cs
new file mode 100644
index 0000000..cab148c
--- /dev/null
+++ b/src/NCMDump.Core/IRC4_NCM_Stream.cs
@@ -0,0 +1,21 @@
+namespace NCMDump.Core
+{
+ public interface IRC4_NCM_Stream : IDisposable
+ {
+ public bool CanRead { get; }
+ public bool CanSeek { get; }
+ public bool CanWrite { get; }
+ public long Length { get; }
+ public long Position { get; set; }
+
+ public long Seek(long offset, SeekOrigin origin);
+
+ public int Read(byte[] buffer, int offset, int count);
+
+ public int Read(Span buffer);
+
+ public Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
+
+ public ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default);
+ }
+}
\ No newline at end of file
diff --git a/src/NCMDumpCore/MetaInfo.cs b/src/NCMDump.Core/MetaInfo.cs
similarity index 96%
rename from src/NCMDumpCore/MetaInfo.cs
rename to src/NCMDump.Core/MetaInfo.cs
index 6188ff1..6981f1f 100644
--- a/src/NCMDumpCore/MetaInfo.cs
+++ b/src/NCMDump.Core/MetaInfo.cs
@@ -1,4 +1,4 @@
-namespace NCMDumpCore
+namespace NCMDump.Core
{
public class MetaInfo
{
diff --git a/src/NCMDumpCore/NCMDumpCore.csproj b/src/NCMDump.Core/NCMDump.Core.csproj
similarity index 90%
rename from src/NCMDumpCore/NCMDumpCore.csproj
rename to src/NCMDump.Core/NCMDump.Core.csproj
index 991d571..40fd00d 100644
--- a/src/NCMDumpCore/NCMDumpCore.csproj
+++ b/src/NCMDump.Core/NCMDump.Core.csproj
@@ -5,7 +5,7 @@
net8.0;
enable
enable
- 2.3.0
+ 2.4.0
x64
diff --git a/src/NCMDumpCore/NCMDumper.cs b/src/NCMDump.Core/NCMDumper.cs
similarity index 86%
rename from src/NCMDumpCore/NCMDumper.cs
rename to src/NCMDump.Core/NCMDumper.cs
index e042c8e..e6352fa 100644
--- a/src/NCMDumpCore/NCMDumper.cs
+++ b/src/NCMDump.Core/NCMDumper.cs
@@ -6,13 +6,13 @@
using System.Text.Json;
using TagLib;
-namespace NCMDumpCore
+namespace NCMDump.Core
{
public class NCMDumper
{
private readonly int vectorSize = Vector256.Count;
- private readonly byte[] coreKey = [0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57];
- private readonly byte[] metaKey = [0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28];
+ private static readonly byte[] coreKey = [0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57];
+ private static readonly byte[] metaKey = [0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28];
private bool VerifyHeader(ref MemoryStream ms)
{
@@ -53,7 +53,7 @@ private byte[] ReadRC4Key(ref MemoryStream ms)
{
aes.Mode = CipherMode.ECB;
aes.Key = coreKey;
- var cleanText = aes.DecryptEcb(buffer.ToArray(), PaddingMode.PKCS7).ToArray()[17..];
+ var cleanText = aes.DecryptEcb(buffer, PaddingMode.PKCS7)[17..];
return cleanText;
}
}
@@ -80,15 +80,16 @@ private MetaInfo ReadMeta(ref MemoryStream ms)
buffer[i] ^= 0x63;
}
- buffer = System.Convert.FromBase64String(Encoding.ASCII.GetString(buffer.ToArray()[22..]));
+ buffer = System.Convert.FromBase64String(Encoding.ASCII.GetString(buffer[22..]));
// decrypt meta data which is a json contains info of the song
using (Aes aes = Aes.Create())
{
aes.Mode = CipherMode.ECB;
aes.Key = metaKey;
- var cleanText = aes.DecryptEcb(buffer.ToArray(), PaddingMode.PKCS7);
- var MetaJsonString = Encoding.UTF8.GetString(cleanText[6..]);
+ var cleanText = aes.DecryptEcb(buffer, PaddingMode.PKCS7);
+ var MetaJsonString = Encoding.UTF8.GetString(cleanText.AsSpan(6));
+ JsonSerializerOptions option = new JsonSerializerOptions();
MetaInfo metainfo = JsonSerializer.Deserialize(MetaJsonString);
return metainfo;
}
@@ -96,7 +97,7 @@ private MetaInfo ReadMeta(ref MemoryStream ms)
private async Task ReadAudioData(MemoryStream ms, byte[] Key)
{
- using (RC4_NCM_Stream rc4s = new(ms, Key))
+ using (IRC4_NCM_Stream rc4s = new RC4_NCM_Stream(ms, Key))
{
byte[] data = new byte[ms.Length - ms.Position];
Memory m_data = new(data);
@@ -105,7 +106,7 @@ private async Task ReadAudioData(MemoryStream ms, byte[] Key)
}
}
- private void AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
+ private async Task AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
{
var tagfile = TagLib.File.Create(fileName);
@@ -113,16 +114,16 @@ private void AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
if (ImgData is not null)
{
var PicEmbedded = new Picture(new ByteVector(ImgData));
- tagfile.Tag.Pictures = new Picture[] { PicEmbedded };
+ tagfile.Tag.Pictures = [PicEmbedded];
}
//Use Internet Picture
else if (metainfo.albumPic != "")
{
- byte[]? NetImgData = FetchUrl(new Uri(metainfo.albumPic));
+ byte[]? NetImgData = await FetchUrl(new Uri(metainfo.albumPic));
if (NetImgData is not null)
{
var PicFromNet = new Picture(new ByteVector(NetImgData));
- tagfile.Tag.Pictures = new Picture[] { PicFromNet };
+ tagfile.Tag.Pictures = [PicFromNet];
}
}
@@ -130,16 +131,16 @@ private void AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
tagfile.Tag.Title = metainfo.musicName;
tagfile.Tag.Performers = metainfo.artist.Select(x => x[0]).ToArray();
tagfile.Tag.Album = metainfo.album;
- tagfile.Tag.Subtitle = String.Join(@";", metainfo.alias);
+ tagfile.Tag.Subtitle = string.Join(@";", metainfo.alias);
tagfile.Save();
}
- private byte[]? FetchUrl(Uri uri)
+ private async Task FetchUrl(Uri uri)
{
HttpClient client = new();
try
{
- var response = client.GetAsync(uri).Result;
+ var response = await client.GetAsync(uri);
Console.WriteLine(response.StatusCode);
if (response.StatusCode == HttpStatusCode.OK)
{
@@ -230,8 +231,7 @@ public async Task ConvertAsync(string path)
//Flush Audio Data to disk drive
string OutputPath = path[..path.LastIndexOf('.')];
- string format = metainfo.format;
- if (format is null or "") format = "mp3";
+ string format = metainfo.format ?? "mp3";
await System.IO.File.WriteAllBytesAsync($"{OutputPath}.{format}", AudioData);
//Add tag and cover
diff --git a/src/NCMDumpCore/RC4_NCM.cs b/src/NCMDump.Core/RC4_NCM.cs
similarity index 68%
rename from src/NCMDumpCore/RC4_NCM.cs
rename to src/NCMDump.Core/RC4_NCM.cs
index 1a64a6a..ca1c7ef 100644
--- a/src/NCMDumpCore/RC4_NCM.cs
+++ b/src/NCMDump.Core/RC4_NCM.cs
@@ -1,4 +1,4 @@
-namespace NCMDumpCore
+namespace NCMDump.Core
{
public class RC4_NCM
{
@@ -19,12 +19,11 @@ public RC4_NCM(byte[] key)
public byte[] Encrypt(byte[] data)
{
- Span span = new(data);
- Encrypt(ref span);
- return span.ToArray();
+ Encrypt(data.AsSpan());
+ return data;
}
- public int Encrypt(ref Span data)
+ public int Encrypt(Span data)
{
for (int m = 0; m < data.Length; m++)
{
@@ -37,13 +36,7 @@ public int Encrypt(ref Span data)
public int Encrypt(Memory data)
{
- for (int m = 0; m < data.Length; m++)
- {
- i = (i + 1) & 0xFF;
- j = (i + Keybox[i]) & 0xFF;
- data.Span[m] ^= Keybox[(Keybox[i] + Keybox[j]) & 0xFF];
- }
- return data.Length;
+ return Encrypt(data.Span);
}
public byte[] Decrypt(byte[] data)
@@ -53,7 +46,12 @@ public byte[] Decrypt(byte[] data)
public int Decrypt(Span data)
{
- return Encrypt(ref data);
+ return Encrypt(data);
+ }
+
+ public int Decrypt(Memory data)
+ {
+ return Encrypt(data);
}
}
}
\ No newline at end of file
diff --git a/src/NCMDump.Core/RC4_NCM_Stream.cs b/src/NCMDump.Core/RC4_NCM_Stream.cs
new file mode 100644
index 0000000..b85468f
--- /dev/null
+++ b/src/NCMDump.Core/RC4_NCM_Stream.cs
@@ -0,0 +1,83 @@
+namespace NCMDump.Core
+{
+ public class RC4_NCM_Stream : Stream, IRC4_NCM_Stream
+ {
+ private readonly Stream _innerStream;
+ private readonly RC4_NCM rc4;
+
+ public RC4_NCM_Stream(Stream innerStream, byte[] key)
+ {
+ this._innerStream = innerStream;
+ rc4 = new RC4_NCM(key);
+ }
+
+ public override bool CanRead => _innerStream.CanRead;
+ public override bool CanSeek => _innerStream.CanSeek;
+ public override bool CanWrite => _innerStream.CanWrite;
+ public override long Length => _innerStream.Length;
+
+ public override long Position
+ {
+ get => _innerStream.Position;
+ set => _innerStream.Position = value;
+ }
+
+ public override void Flush()
+ {
+ _innerStream.Flush();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int bytesRead = Read(buffer.AsSpan(offset, count));
+ return bytesRead;
+ }
+
+ public override int Read(Span buffer)
+ {
+ int bytesRead = _innerStream.Read(buffer);
+ rc4.Encrypt(buffer);
+ return bytesRead;
+ }
+
+ public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ return new Task(() => Read(buffer.AsSpan(offset, count)));
+ }
+
+ public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default)
+ {
+ int bytesRead = _innerStream.Read(buffer.Span);
+ return new ValueTask(rc4.Encrypt(buffer));
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return _innerStream.Seek(offset, origin);
+ }
+
+ public override void SetLength(long value)
+ {
+ _innerStream.SetLength(value);
+ }
+
+ public override bool CanTimeout => base.CanTimeout;
+
+ public override void Close() => base.Close();
+
+ public override void Write(byte[] buffer, int offset, int count)
+ => throw new NotSupportedException();
+
+ public override void Write(ReadOnlySpan buffer)
+ => throw new NotSupportedException();
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ => throw new NotSupportedException();
+
+ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default)
+ => throw new NotSupportedException();
+
+ public override void CopyTo(Stream destination, int bufferSize)
+ => throw new NotSupportedException();
+ }
+}
\ No newline at end of file
diff --git a/src/NCMDump.Net.sln b/src/NCMDump.Net.sln
index 5524e59..0099679 100644
--- a/src/NCMDump.Net.sln
+++ b/src/NCMDump.Net.sln
@@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDumpCore", "NCMDumpCore\NCMDumpCore.csproj", "{6D29FF99-9A20-4AC2-8246-746C2AE4FB73}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDump.Core", "NCMDump.Core\NCMDump.Core.csproj", "{6D29FF99-9A20-4AC2-8246-746C2AE4FB73}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDumpCLI", "NCMDumpCLI\NCMDumpCLI.csproj", "{4CB104C3-FE3A-4CF4-9910-5FB0150B22A6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDump.CLI", "NCMDump.CLI\NCMDump.CLI.csproj", "{4CB104C3-FE3A-4CF4-9910-5FB0150B22A6}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDumpGUI", "NCMDumpGUI\NCMDumpGUI.csproj", "{F4B097C1-58BB-4A79-8997-8225639D2A92}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDump.WPF", "NCMDump.WPF\NCMDump.WPF.csproj", "{F4B097C1-58BB-4A79-8997-8225639D2A92}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDumpGUI_WinUI", "NCMDumpGUI_WinUI\NCMDumpGUI_WinUI.csproj", "{1F6956D8-3F8D-4F68-893E-790329FAA441}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCMDump.WinUI", "NCMDump.WinUI\NCMDump.WinUI.csproj", "{1F6956D8-3F8D-4F68-893E-790329FAA441}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/src/NCMDumpGUI/App.xaml b/src/NCMDump.WPF/App.xaml
similarity index 92%
rename from src/NCMDumpGUI/App.xaml
rename to src/NCMDump.WPF/App.xaml
index 3a323f0..853b313 100644
--- a/src/NCMDumpGUI/App.xaml
+++ b/src/NCMDump.WPF/App.xaml
@@ -1,4 +1,4 @@
-
diff --git a/src/NCMDumpGUI/App.xaml.cs b/src/NCMDump.WPF/App.xaml.cs
similarity index 85%
rename from src/NCMDumpGUI/App.xaml.cs
rename to src/NCMDump.WPF/App.xaml.cs
index 8eb8cc7..2c8ceca 100644
--- a/src/NCMDumpGUI/App.xaml.cs
+++ b/src/NCMDump.WPF/App.xaml.cs
@@ -1,17 +1,18 @@
-using Microsoft.Extensions.DependencyInjection;
-using NCMDumpCore;
-using System;
+using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
+using Microsoft.Extensions.DependencyInjection;
+using NCMDump.Core;
-namespace NCMDumpGUI
+namespace NCMDump.WPF
{
public partial class App : Application
{
private IServiceProvider _serviceProvider;
private ObservableCollection NCMCollection = new();
+ private int depth;
protected override void OnStartup(StartupEventArgs e)
{
@@ -26,8 +27,8 @@ protected override void OnStartup(StartupEventArgs e)
MainWindowViewModel vm = _serviceProvider.GetRequiredService();
vm.NCMCollection = NCMCollection;
}
- var mainWindow = _serviceProvider.GetRequiredService();
- mainWindow.Show();
+ MainWindow = _serviceProvider.GetRequiredService();
+ MainWindow.Show();
}
private void ConfigureServices(IServiceCollection services)
@@ -65,6 +66,12 @@ private void OnDrop(string[] args)
private void WalkThrough(DirectoryInfo dir)
{
+ depth++;
+ if (depth > 16)
+ {
+ depth--;
+ return;
+ }
foreach (DirectoryInfo d in dir.GetDirectories())
{
WalkThrough(d);
@@ -74,6 +81,7 @@ private void WalkThrough(DirectoryInfo dir)
if (f.FullName.EndsWith(@".ncm") && !NCMCollection.Any(x => x.FilePath == f.FullName))
NCMCollection.Add(new NCMProcessStatus(f.FullName, "Await"));
}
+ depth--;
}
}
}
\ No newline at end of file
diff --git a/src/NCMDumpGUI/AssemblyInfo.cs b/src/NCMDump.WPF/AssemblyInfo.cs
similarity index 100%
rename from src/NCMDumpGUI/AssemblyInfo.cs
rename to src/NCMDump.WPF/AssemblyInfo.cs
diff --git a/src/NCMDumpGUI/Converter/BackdropConverter.cs b/src/NCMDump.WPF/Converter/BackdropConverter.cs
similarity index 98%
rename from src/NCMDumpGUI/Converter/BackdropConverter.cs
rename to src/NCMDump.WPF/Converter/BackdropConverter.cs
index ac1131d..cd5f429 100644
--- a/src/NCMDumpGUI/Converter/BackdropConverter.cs
+++ b/src/NCMDump.WPF/Converter/BackdropConverter.cs
@@ -3,7 +3,7 @@
using System.Windows.Data;
using Wpf.Ui.Controls;
-namespace NCMDumpGUI.Converter
+namespace NCMDump.WPF.Converter
{
public class BackdropConverter : IValueConverter
{
diff --git a/src/NCMDumpGUI/Converter/InverseBoolConverter.cs b/src/NCMDump.WPF/Converter/InverseBoolConverter.cs
similarity index 95%
rename from src/NCMDumpGUI/Converter/InverseBoolConverter.cs
rename to src/NCMDump.WPF/Converter/InverseBoolConverter.cs
index dd7e77c..579797d 100644
--- a/src/NCMDumpGUI/Converter/InverseBoolConverter.cs
+++ b/src/NCMDump.WPF/Converter/InverseBoolConverter.cs
@@ -2,7 +2,7 @@
using System.Globalization;
using System.Windows.Data;
-namespace NCMDumpGUI.Converter
+namespace NCMDump.WPF.Converter
{
public class InverseBoolConverter : IValueConverter
{
diff --git a/src/NCMDumpGUI/MainWindow.xaml b/src/NCMDump.WPF/MainWindow.xaml
similarity index 91%
rename from src/NCMDumpGUI/MainWindow.xaml
rename to src/NCMDump.WPF/MainWindow.xaml
index 1b2a02c..87fe8c1 100644
--- a/src/NCMDumpGUI/MainWindow.xaml
+++ b/src/NCMDump.WPF/MainWindow.xaml
@@ -1,13 +1,13 @@
-
+ Command="{Binding AddFileCommand}"
+ IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBoolConverter}}" />
+ Command="{Binding AddFolderCommand}"
+ IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBoolConverter}}" />
+ Command="{Binding ClearCommand}"
+ IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBoolConverter}}" />
\ No newline at end of file
diff --git a/src/NCMDumpGUI/MainWindow.xaml.cs b/src/NCMDump.WPF/MainWindow.xaml.cs
similarity index 98%
rename from src/NCMDumpGUI/MainWindow.xaml.cs
rename to src/NCMDump.WPF/MainWindow.xaml.cs
index d8ceed0..3e33337 100644
--- a/src/NCMDumpGUI/MainWindow.xaml.cs
+++ b/src/NCMDump.WPF/MainWindow.xaml.cs
@@ -3,7 +3,7 @@
using Wpf.Ui.Appearance;
using Wpf.Ui.Controls;
-namespace NCMDumpGUI
+namespace NCMDump.WPF
{
public partial class MainWindow : FluentWindow
{
diff --git a/src/NCMDumpGUI/MainWindowViewModel.cs b/src/NCMDump.WPF/MainWindowViewModel.cs
similarity index 76%
rename from src/NCMDumpGUI/MainWindowViewModel.cs
rename to src/NCMDump.WPF/MainWindowViewModel.cs
index cefd1f2..598035f 100644
--- a/src/NCMDumpGUI/MainWindowViewModel.cs
+++ b/src/NCMDump.WPF/MainWindowViewModel.cs
@@ -1,22 +1,21 @@
-using CommunityToolkit.Mvvm.ComponentModel;
-using CommunityToolkit.Mvvm.Input;
-using Microsoft.WindowsAPICodePack.Dialogs;
-using NCMDumpCore;
-using System;
+using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Microsoft.Win32;
+using NCMDump.Core;
using Wpf.Ui.Appearance;
using Wpf.Ui.Controls;
-namespace NCMDumpGUI
+namespace NCMDump.WPF
{
- [ObservableObject]
- public partial class MainWindowViewModel
+ public partial class MainWindowViewModel : ObservableObject
{
- private readonly NCMDumper Core;
+ private readonly NCMDumper Dumper;
private bool _isBusy = false;
public bool IsBusy
@@ -66,14 +65,20 @@ public WindowBackdropType SelectedBackdrop
}
}
+ public IAsyncRelayCommand AddFolderCommand { get; }
+ public IAsyncRelayCommand AddFileCommand { get; }
+ public IAsyncRelayCommand ClearCommand { get; }
+ public IAsyncRelayCommand ConvertCommand { get; }
+ public IAsyncRelayCommand ThemeCommand { get; }
+
public MainWindowViewModel(NCMDumper _core)
{
- Core = _core;
+ Dumper = _core;
WillDeleteNCM = true;
ApplicationTitle = "NCMDump.NET";
NCMCollection = [];
- AddFolderCommand = new AsyncRelayCommand(FolderDialog);
- AddFileCommand = new AsyncRelayCommand(FileDialog);
+ AddFolderCommand = new AsyncRelayCommand(OpenSelectFolderDialog);
+ AddFileCommand = new AsyncRelayCommand(OpenSelectFileDialog);
ClearCommand = new AsyncRelayCommand(ClearList, () => NCMCollection.Count > 0);
ConvertCommand = new AsyncRelayCommand(StartConvert, () => NCMCollection.Count > 0);
ThemeCommand = new AsyncRelayCommand(SwitchTheme);
@@ -96,18 +101,18 @@ public MainWindowViewModel(NCMDumper _core)
}
}
- public void OnDrop(string[] args)
+ public void OnDrop(params string[] paths)
{
- foreach (string _path in args)
+ foreach (string path in paths)
{
- if (new DirectoryInfo(_path).Exists)
+ if (new DirectoryInfo(path).Exists)
{
- WalkThrough(new DirectoryInfo(_path));
+ WalkThrough(new DirectoryInfo(path));
}
- else if (new FileInfo(_path).Exists)
+ else if (new FileInfo(path).Exists)
{
- if (_path.EndsWith(@".ncm") && !NCMCollection.Any(x => x.FilePath == _path))
- NCMCollection.Add(new NCMProcessStatus(_path, "Await"));
+ if (path.EndsWith(@".ncm") && !NCMCollection.Any(x => x.FilePath == path))
+ NCMCollection.Add(new NCMProcessStatus(path, "Await"));
}
}
ConvertCommand.NotifyCanExecuteChanged();
@@ -127,12 +132,6 @@ private void WalkThrough(DirectoryInfo dir)
}
}
- public IAsyncRelayCommand AddFolderCommand { get; }
- public IAsyncRelayCommand AddFileCommand { get; }
- public IAsyncRelayCommand ClearCommand { get; }
- public IAsyncRelayCommand ConvertCommand { get; }
- public IAsyncRelayCommand ThemeCommand { get; }
-
private async Task StartConvert()
{
IsBusy = true;
@@ -142,19 +141,19 @@ await Parallel.ForAsync(0, NCMCollection.Count, async (i, state) =>
{
try
{
- if (await Core.ConvertAsync(NCMCollection[i].FilePath))
+ if (await Dumper.ConvertAsync(NCMCollection[i].FilePath))
{
NCMCollection[i].FileStatus = "Success";
- try
+ if (WillDeleteNCM)
{
- if (WillDeleteNCM)
+ try
{
File.Delete(NCMCollection[i].FilePath);
}
- }
- catch (Exception ex)
- {
- Debug.WriteLine(ex.ToString());
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.ToString());
+ }
}
}
else
@@ -174,35 +173,29 @@ await Parallel.ForAsync(0, NCMCollection.Count, async (i, state) =>
IsBusy = false;
}
- private async Task FolderDialog()
+ private async Task OpenSelectFolderDialog()
{
- var dialog = new CommonOpenFileDialog
+ OpenFolderDialog ofp = new OpenFolderDialog
{
- IsFolderPicker = true,
- Title = "选择文件夹"
+ Multiselect = true,
};
- if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
+ if (ofp.ShowDialog() == true)
{
- string folderPath = dialog.FileName;
- OnDrop([folderPath]);
+ OnDrop(ofp.FolderNames);
}
}
- private async Task FileDialog()
+ private async Task OpenSelectFileDialog()
{
- Microsoft.Win32.OpenFileDialog ofp = new()
+ OpenFileDialog ofp = new OpenFileDialog
{
Multiselect = true,
Filter = "NCM File(*.ncm)|*.ncm"
};
if (ofp.ShowDialog() == true)
{
- foreach (string file in ofp.FileNames)
- {
- if (file.EndsWith(@".ncm") && !NCMCollection.Any(x => x.FilePath == file))
- NCMCollection.Add(new NCMProcessStatus(file, "Await"));
- }
+ OnDrop(ofp.FileNames);
}
}
diff --git a/src/NCMDumpGUI/NCMDumpGUI.csproj b/src/NCMDump.WPF/NCMDump.WPF.csproj
similarity index 66%
rename from src/NCMDumpGUI/NCMDumpGUI.csproj
rename to src/NCMDump.WPF/NCMDump.WPF.csproj
index 1fe6a79..3b2ffb2 100644
--- a/src/NCMDumpGUI/NCMDumpGUI.csproj
+++ b/src/NCMDump.WPF/NCMDump.WPF.csproj
@@ -6,8 +6,9 @@
enable
True
NCMDump.ico
- 2.3.0
+ 2.4.0
x64
+ app.manifest
@@ -16,15 +17,13 @@
-
+
+
+
-
-
-
-
-
+
diff --git a/src/NCMDumpGUI/NCMDump.ico b/src/NCMDump.WPF/NCMDump.ico
similarity index 100%
rename from src/NCMDumpGUI/NCMDump.ico
rename to src/NCMDump.WPF/NCMDump.ico
diff --git a/src/NCMDumpGUI/NCMProcessStatus.cs b/src/NCMDump.WPF/NCMProcessStatus.cs
similarity index 53%
rename from src/NCMDumpGUI/NCMProcessStatus.cs
rename to src/NCMDump.WPF/NCMProcessStatus.cs
index 412acd9..28e84d0 100644
--- a/src/NCMDumpGUI/NCMProcessStatus.cs
+++ b/src/NCMDump.WPF/NCMProcessStatus.cs
@@ -1,18 +1,18 @@
using CommunityToolkit.Mvvm.ComponentModel;
-namespace NCMDumpGUI
+namespace NCMDump.WPF
{
public partial class NCMProcessStatus : ObservableObject
{
- private string filePath;
+ private string _filePath;
public string FilePath
{
- get => filePath;
- set => SetProperty(ref filePath, value);
+ get => _filePath;
+ set => SetProperty(ref _filePath, value);
}
- public string _filestatus;
+ private string _filestatus;
public string FileStatus
{
@@ -20,10 +20,10 @@ public string FileStatus
set => SetProperty(ref _filestatus, value);
}
- public NCMProcessStatus(string _path, string _status)
+ public NCMProcessStatus(string path, string status)
{
- FilePath = _path;
- FileStatus = _status;
+ FilePath = path;
+ FileStatus = status;
}
}
}
\ No newline at end of file
diff --git a/src/NCMDumpGUI/Properties/launchSettings.json b/src/NCMDump.WPF/Properties/launchSettings.json
similarity index 74%
rename from src/NCMDumpGUI/Properties/launchSettings.json
rename to src/NCMDump.WPF/Properties/launchSettings.json
index 1a1c9aa..d0be389 100644
--- a/src/NCMDumpGUI/Properties/launchSettings.json
+++ b/src/NCMDump.WPF/Properties/launchSettings.json
@@ -1,6 +1,6 @@
{
"profiles": {
- "NCMDumpGUI": {
+ "NCMDump.WPF": {
"commandName": "Project"
}
}
diff --git a/src/NCMDump.WPF/app.manifest b/src/NCMDump.WPF/app.manifest
new file mode 100644
index 0000000..8672c07
--- /dev/null
+++ b/src/NCMDump.WPF/app.manifest
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PerMonitorV2
+
+
+
+
diff --git a/src/NCMDumpGUI/ncmdump.png b/src/NCMDump.WPF/ncmdump.png
similarity index 100%
rename from src/NCMDumpGUI/ncmdump.png
rename to src/NCMDump.WPF/ncmdump.png
diff --git a/src/NCMDumpGUI_WinUI/App.xaml b/src/NCMDump.WinUI/App.xaml
similarity index 95%
rename from src/NCMDumpGUI_WinUI/App.xaml
rename to src/NCMDump.WinUI/App.xaml
index b73358c..bd0a680 100644
--- a/src/NCMDumpGUI_WinUI/App.xaml
+++ b/src/NCMDump.WinUI/App.xaml
@@ -1,6 +1,6 @@
diff --git a/src/NCMDump.WinUI/App.xaml.cs b/src/NCMDump.WinUI/App.xaml.cs
new file mode 100644
index 0000000..528d1d1
--- /dev/null
+++ b/src/NCMDump.WinUI/App.xaml.cs
@@ -0,0 +1,160 @@
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.UI.Dispatching;
+using Microsoft.UI.Xaml;
+using Microsoft.Windows.AppLifecycle;
+using Microsoft.Windows.AppNotifications;
+using NCMDump.Core;
+using NCMDump.WinUI.ViewModels;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace NCMDump.WinUI
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : Application
+ {
+ private IServiceProvider _serviceProvider;
+
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Invoked when the application is launched.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+ var services = new ServiceCollection();
+ ConfigureServices(services);
+ _serviceProvider = services.BuildServiceProvider();
+
+ MainWindow = _serviceProvider.GetRequiredService();
+ MainWindow.Activate();
+
+ AppNotificationManager notificationManager = AppNotificationManager.Default;
+ notificationManager.NotificationInvoked += NotificationManager_NotificationInvoked;
+ notificationManager.Register();
+
+ var activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
+ var activationKind = activatedArgs.Kind;
+ if (activationKind != ExtendedActivationKind.AppNotification)
+ {
+ LaunchAndBringToForegroundIfNeeded();
+ }
+ else
+ {
+ HandleNotification((AppNotificationActivatedEventArgs)activatedArgs.Data);
+ }
+ }
+
+ public Window MainWindow;
+
+ private void ConfigureServices(IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public static TEnum GetEnum(string text) where TEnum : struct
+ {
+ if (!typeof(TEnum).GetTypeInfo().IsEnum)
+ {
+ throw new InvalidOperationException("Generic parameter 'TEnum' must be an enum.");
+ }
+ return (TEnum)Enum.Parse(typeof(TEnum), text);
+ }
+
+ private void NotificationManager_NotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
+ {
+ HandleNotification(args);
+ }
+
+ private void LaunchAndBringToForegroundIfNeeded()
+ {
+ if (MainWindow == null)
+ {
+ MainWindow = _serviceProvider.GetRequiredService();
+ MainWindow.Activate();
+
+ // Additionally we show using our helper, since if activated via a app notification, it doesn't
+ // activate the window correctly
+ WindowHelper.ShowWindow(MainWindow);
+ }
+ else
+ {
+ WindowHelper.ShowWindow(MainWindow);
+ }
+ }
+
+ private void HandleNotification(AppNotificationActivatedEventArgs args)
+ {
+ // Use the dispatcher from the window if present, otherwise the app dispatcher
+ var dispatcherQueue = MainWindow?.DispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
+
+ dispatcherQueue.TryEnqueue(async delegate
+ {
+ var arguments = args.Arguments;
+ switch (args.Arguments["action"])
+ {
+ // Send a background message
+ case "clicked":
+ Debug.WriteLine("Clicked");
+ // TODO: Send it
+
+ // If the UI app isn't open
+ if (MainWindow == null)
+ {
+ // Close since we're done
+ Process.GetCurrentProcess().Kill();
+ }
+
+ break;
+
+ // View a message
+ case "viewMessage":
+
+ // Launch/bring window to foreground
+ LaunchAndBringToForegroundIfNeeded();
+
+ // TODO: Open the message
+ break;
+ }
+ });
+ }
+ }
+
+ internal static class WindowHelper
+ {
+ [DllImport("user32.dll")]
+ private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ public static void ShowWindow(Window window)
+ {
+ // Bring the window to the foreground... first get the window handle...
+ var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
+
+ // Restore window if minimized... requires DLL import above
+ ShowWindow(hwnd, 0x00000009);
+
+ // And call SetForegroundWindow... requires DLL import above
+ SetForegroundWindow(hwnd);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NCMDumpGUI_WinUI/Assets/LockScreenLogo.scale-200.png b/src/NCMDump.WinUI/Assets/LockScreenLogo.scale-200.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/LockScreenLogo.scale-200.png
rename to src/NCMDump.WinUI/Assets/LockScreenLogo.scale-200.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/NCMDump.ico b/src/NCMDump.WinUI/Assets/NCMDump.ico
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/NCMDump.ico
rename to src/NCMDump.WinUI/Assets/NCMDump.ico
diff --git a/src/NCMDumpGUI_WinUI/Assets/SplashScreen.scale-200.png b/src/NCMDump.WinUI/Assets/SplashScreen.scale-200.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/SplashScreen.scale-200.png
rename to src/NCMDump.WinUI/Assets/SplashScreen.scale-200.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/Square150x150Logo.scale-200.png b/src/NCMDump.WinUI/Assets/Square150x150Logo.scale-200.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/Square150x150Logo.scale-200.png
rename to src/NCMDump.WinUI/Assets/Square150x150Logo.scale-200.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/Square44x44Logo.scale-200.png b/src/NCMDump.WinUI/Assets/Square44x44Logo.scale-200.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/Square44x44Logo.scale-200.png
rename to src/NCMDump.WinUI/Assets/Square44x44Logo.scale-200.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/src/NCMDump.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
rename to src/NCMDump.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/StoreLogo.png b/src/NCMDump.WinUI/Assets/StoreLogo.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/StoreLogo.png
rename to src/NCMDump.WinUI/Assets/StoreLogo.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/Wide310x150Logo.scale-200.png b/src/NCMDump.WinUI/Assets/Wide310x150Logo.scale-200.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/Wide310x150Logo.scale-200.png
rename to src/NCMDump.WinUI/Assets/Wide310x150Logo.scale-200.png
diff --git a/src/NCMDumpGUI_WinUI/Assets/ncmdump.png b/src/NCMDump.WinUI/Assets/ncmdump.png
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Assets/ncmdump.png
rename to src/NCMDump.WinUI/Assets/ncmdump.png
diff --git a/src/NCMDumpGUI_WinUI/Converter/BackdropConverter.cs b/src/NCMDump.WinUI/Converter/BackdropConverter.cs
similarity index 94%
rename from src/NCMDumpGUI_WinUI/Converter/BackdropConverter.cs
rename to src/NCMDump.WinUI/Converter/BackdropConverter.cs
index 5919b97..83158ee 100644
--- a/src/NCMDumpGUI_WinUI/Converter/BackdropConverter.cs
+++ b/src/NCMDump.WinUI/Converter/BackdropConverter.cs
@@ -1,8 +1,7 @@
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
-using System;
-namespace NCMDumpGUI_WinUI.Converter
+namespace NCMDump.WinUI.Converter
{
public class BackdropConverter : IValueConverter
{
diff --git a/src/NCMDumpGUI_WinUI/MainWindow.xaml b/src/NCMDump.WinUI/MainWindow.xaml
similarity index 85%
rename from src/NCMDumpGUI_WinUI/MainWindow.xaml
rename to src/NCMDump.WinUI/MainWindow.xaml
index 35e7751..a59a15a 100644
--- a/src/NCMDumpGUI_WinUI/MainWindow.xaml
+++ b/src/NCMDump.WinUI/MainWindow.xaml
@@ -1,6 +1,6 @@
@@ -64,13 +64,13 @@
-
-
-
+
+
+
-
-
-
+
+
+
@@ -82,13 +82,13 @@
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/src/NCMDumpGUI_WinUI/MainWindow.xaml.cs b/src/NCMDump.WinUI/MainWindow.xaml.cs
similarity index 97%
rename from src/NCMDumpGUI_WinUI/MainWindow.xaml.cs
rename to src/NCMDump.WinUI/MainWindow.xaml.cs
index 643ff10..87099ba 100644
--- a/src/NCMDumpGUI_WinUI/MainWindow.xaml.cs
+++ b/src/NCMDump.WinUI/MainWindow.xaml.cs
@@ -1,9 +1,7 @@
using CommunityToolkit.WinUI.UI.Controls;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
-using NCMDumpGUI_WinUI.ViewModels;
-using System;
-using System.Linq;
+using NCMDump.WinUI.ViewModels;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.UI.ViewManagement;
@@ -11,7 +9,7 @@
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
-namespace NCMDumpGUI_WinUI
+namespace NCMDump.WinUI
{
///
/// An empty window that can be used on its own or navigated to within a Frame.
@@ -112,7 +110,7 @@ private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
private void Window_Closed(object sender, WindowEventArgs e)
{
- App.Current.Exit();
+ Application.Current.Exit();
}
}
}
\ No newline at end of file
diff --git a/src/NCMDumpGUI_WinUI/Models/NCMProcessStatus.cs b/src/NCMDump.WinUI/Models/NCMProcessStatus.cs
similarity index 97%
rename from src/NCMDumpGUI_WinUI/Models/NCMProcessStatus.cs
rename to src/NCMDump.WinUI/Models/NCMProcessStatus.cs
index 56c5f50..f1c51ba 100644
--- a/src/NCMDumpGUI_WinUI/Models/NCMProcessStatus.cs
+++ b/src/NCMDump.WinUI/Models/NCMProcessStatus.cs
@@ -3,7 +3,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
-namespace NCMDumpGUI_WinUI.Models
+namespace NCMDump.WinUI.Models
{
public partial class NCMProcessStatus : ObservableObject
{
diff --git a/src/NCMDumpGUI_WinUI/NCMDumpGUI_WinUI.csproj b/src/NCMDump.WinUI/NCMDump.WinUI.csproj
similarity index 77%
rename from src/NCMDumpGUI_WinUI/NCMDumpGUI_WinUI.csproj
rename to src/NCMDump.WinUI/NCMDump.WinUI.csproj
index 41ed934..51dfa1b 100644
--- a/src/NCMDumpGUI_WinUI/NCMDumpGUI_WinUI.csproj
+++ b/src/NCMDump.WinUI/NCMDump.WinUI.csproj
@@ -3,7 +3,7 @@
WinExe
net8.0-windows10.0.19041.0
10.0.19041.0
- NCMDumpGUI_WinUI
+ NCMDump.WinUI
app.manifest
x64
win-x64
@@ -13,19 +13,12 @@
10.0.19041.0
true
x64
- 2.3.0
+ 2.4.0
WinUI
Assets\NCMDump.ico
- en-US
+ None
+ enable
-
-
-
-
-
-
-
-
@@ -52,19 +45,17 @@
-
+
-
-
-
-
-
+
+
+
@@ -75,25 +66,19 @@
-->
-
-
-
-
-
PreserveNewest
PreserveNewest
-
-
MSBuild:Compile
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NCMDumpGUI_WinUI/Properties/launchSettings.json b/src/NCMDump.WinUI/Properties/launchSettings.json
similarity index 70%
rename from src/NCMDumpGUI_WinUI/Properties/launchSettings.json
rename to src/NCMDump.WinUI/Properties/launchSettings.json
index 276e077..2f5f800 100644
--- a/src/NCMDumpGUI_WinUI/Properties/launchSettings.json
+++ b/src/NCMDump.WinUI/Properties/launchSettings.json
@@ -1,6 +1,6 @@
{
"profiles": {
- "NCMDumpGUI_WinUI (Unpackaged)": {
+ "NCMDump.WinUI (Unpackaged)": {
"commandName": "Project",
"nativeDebugging": false
}
diff --git a/src/NCMDumpGUI_WinUI/Resources/StringDictionary.xaml b/src/NCMDump.WinUI/Resources/StringDictionary.xaml
similarity index 100%
rename from src/NCMDumpGUI_WinUI/Resources/StringDictionary.xaml
rename to src/NCMDump.WinUI/Resources/StringDictionary.xaml
diff --git a/src/NCMDumpGUI_WinUI/ViewModels/MainWindowViewModel.cs b/src/NCMDump.WinUI/ViewModels/MainWindowViewModel.cs
similarity index 79%
rename from src/NCMDumpGUI_WinUI/ViewModels/MainWindowViewModel.cs
rename to src/NCMDump.WinUI/ViewModels/MainWindowViewModel.cs
index 9b5537d..86ac17c 100644
--- a/src/NCMDumpGUI_WinUI/ViewModels/MainWindowViewModel.cs
+++ b/src/NCMDump.WinUI/ViewModels/MainWindowViewModel.cs
@@ -1,20 +1,18 @@
-using CommunityToolkit.Mvvm.ComponentModel;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.Helpers;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
-using Microsoft.WindowsAPICodePack.Dialogs;
-using NCMDumpCore;
-using NCMDumpGUI_WinUI.Models;
-using System;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
+using Microsoft.Windows.AppNotifications;
+using Microsoft.Windows.AppNotifications.Builder;
+using NCMDump.Core;
+using NCMDump.WinUI.Models;
+using Windows.Storage.Pickers;
-namespace NCMDumpGUI_WinUI.ViewModels
+namespace NCMDump.WinUI.ViewModels
{
public partial class MainWindowViewModel : ObservableObject
{
@@ -108,7 +106,7 @@ public MainWindowViewModel(NCMDumper _core)
}
}
- public void OnDrop(string[] args)
+ public void OnDrop(params string[] args)
{
foreach (string _path in args)
{
@@ -204,46 +202,47 @@ await Parallel.ForAsync(0, NCMCollection.Count, async (i, state) =>
GC.WaitForPendingFinalizers();
IsBusy = false;
+
+ int total = NCMCollection.Count;
+ int success = NCMCollection.Count(x => x.FileStatus == "Success");
+ //https://learn.microsoft.com/zh-cn/windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/guides/toast-notifications?tabs=appsdk
+ var builder = new AppNotificationBuilder()
+ .AddText($"Dumped! ")
+ .AddText($"Success ({success}/{total})")
+ .AddArgument("action", "clicked");
+
+ AppNotificationManager.Default.Show(builder.BuildNotification());
}
private async Task FolderDialog()
{
- var dialog = new CommonOpenFileDialog
- {
- IsFolderPicker = true
- };
-
- if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
+ var hwnd = WinRT.Interop.WindowNative.GetWindowHandle((App.Current as App).MainWindow);
+ FolderPicker folderPicker = new FolderPicker();
+ folderPicker.ViewMode = PickerViewMode.Thumbnail;
+ folderPicker.FileTypeFilter.Add("*");
+ WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hwnd);
+ var folder = await folderPicker.PickSingleFolderAsync();
+ if (folder != null)
{
- string folderPath = dialog.FileName;
- OnDrop([folderPath]);
+ OnDrop([folder.Path]);
}
}
private async Task FileDialog()
{
- Microsoft.Win32.OpenFileDialog ofp = new Microsoft.Win32.OpenFileDialog();
- ofp.Multiselect = true;
- ofp.Filter = "NCM File(*.ncm)|*.ncm";
- if (ofp.ShowDialog() == true)
- {
- OnDrop(ofp.FileNames);
- }
-
//WinRT shithole
- //var hwnd = WinRT.Interop.WindowNative.GetWindowHandle((App.Current as App).MainWindow);
- //FileOpenPicker filePicker = new FileOpenPicker();
- //filePicker.ViewMode = PickerViewMode.List;
- //filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
- //filePicker.FileTypeFilter.Add("*");
- //WinRT.Interop.InitializeWithWindow.Initialize(filePicker, hwnd);
- //var files = await filePicker.PickMultipleFilesAsync();
- //if (files != null)
- //{
- // var filelist = files.Select(x => x.Path).ToArray();
- // OnDrop(filelist);
- //}
+ var hwnd = WinRT.Interop.WindowNative.GetWindowHandle((App.Current as App).MainWindow);
+ FileOpenPicker filePicker = new FileOpenPicker();
+ filePicker.ViewMode = PickerViewMode.Thumbnail;
+ filePicker.FileTypeFilter.Add(".ncm");
+ WinRT.Interop.InitializeWithWindow.Initialize(filePicker, hwnd);
+ var files = await filePicker.PickMultipleFilesAsync();
+ if (files != null)
+ {
+ var filelist = files.Select(x => x.Path).ToArray();
+ OnDrop(filelist);
+ }
}
private async Task ClearList()
diff --git a/src/NCMDump.WinUI/app.manifest b/src/NCMDump.WinUI/app.manifest
new file mode 100644
index 0000000..781a0c6
--- /dev/null
+++ b/src/NCMDump.WinUI/app.manifest
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PerMonitorV2
+
+
+
\ No newline at end of file
diff --git a/src/NCMDumpCLI/Program.cs b/src/NCMDumpCLI/Program.cs
deleted file mode 100644
index d47e0ad..0000000
--- a/src/NCMDumpCLI/Program.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using NCMDumpCore;
-
-public class NCMDumpCLI
-{
- public static void Main(params string[] args)
- {
- NCMDumper Core = new();
-
- if (args.Length == 0)
- {
- Console.WriteLine("Drag [*.ncm] file or directory on exe to start");
- }
- else
- {
- try
- {
- foreach (string path in args)
- {
- if (new DirectoryInfo(path).Exists)
- {
- WalkThrough(new DirectoryInfo(path));
- }
- else if (new FileInfo(path).Exists)
- {
- Console.WriteLine("FILE: " + new FileInfo(path).FullName);
- if (Core.Convert(path)) Console.WriteLine("... Convert OK");
- else Console.WriteLine("... Convert Fail");
- Console.WriteLine();
- }
- Console.WriteLine();
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
-
- Console.Write("Press Any Key to Exit...");
- Console.ReadLine();
- return;
-
- void WalkThrough(DirectoryInfo dir)
- {
- Console.WriteLine("DIR: " + dir.FullName);
- foreach (DirectoryInfo d in dir.GetDirectories())
- {
- WalkThrough(d);
- }
- foreach (FileInfo f in dir.EnumerateFiles())
- {
- Console.WriteLine("Converting : " + f.FullName);
- if (Core.Convert(f.FullName)) Console.WriteLine("...OK");
- else Console.WriteLine("...Fail");
- Console.WriteLine();
- }
-
- Console.WriteLine();
- }
- }
-}
\ No newline at end of file
diff --git a/src/NCMDumpCore/RC4_NCM_Stream.cs b/src/NCMDumpCore/RC4_NCM_Stream.cs
deleted file mode 100644
index 95f2539..0000000
--- a/src/NCMDumpCore/RC4_NCM_Stream.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-namespace NCMDumpCore
-{
- public class RC4_NCM_Stream : Stream
- {
- private readonly Stream innerStream;
- private readonly RC4_NCM rc4;
-
- public RC4_NCM_Stream(Stream innerStream, byte[] key)
- {
- this.innerStream = innerStream;
- rc4 = new RC4_NCM(key);
- }
-
- public override bool CanRead => innerStream.CanRead;
- public override bool CanSeek => innerStream.CanSeek;
- public override bool CanWrite => innerStream.CanWrite;
- public override long Length => innerStream.Length;
-
- public override long Position
- {
- get => innerStream.Position;
- set => innerStream.Position = value;
- }
-
- public override void Flush()
- {
- innerStream.Flush();
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- Span span = new byte[count];
- innerStream.Seek(offset, SeekOrigin.Current);
- int bytesRead = Read(span);
- span.CopyTo(buffer);
-
- //int bytesRead = innerStream.Read(buffer, offset, count);
- //byte[] decryptedBytes = rc4.Encrypt(buffer[offset..(offset + bytesRead)]);
- //Array.Copy(decryptedBytes, 0, buffer, offset, decryptedBytes.Length);
- return bytesRead;
- }
-
- public override int Read(Span buffer)
- {
- int bytesRead = innerStream.Read(buffer);
- rc4.Encrypt(ref buffer);
- return bytesRead;
- }
-
- public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- innerStream.Seek(offset, SeekOrigin.Current);
- int bytesRead = await Task.Run(() => Read(buffer));
- return bytesRead;
- }
-
- public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default)
- {
- int bytesRead = innerStream.Read(buffer.Span);
- await Task.Run(() => rc4.Encrypt(buffer));
- return bytesRead;
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- return innerStream.Seek(offset, origin);
- }
-
- public override void SetLength(long value)
- {
- innerStream.SetLength(value);
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- Span span = buffer.AsSpan(offset, count);
- rc4.Encrypt(ref span);
- innerStream.Write(span);
- }
-
- public override void Write(ReadOnlySpan buffer)
- {
- Span span = new byte[buffer.Length];
- buffer.CopyTo(span);
- rc4.Encrypt(ref span);
-
- innerStream.Write(buffer);
- }
-
- public override async Task WriteAsync(byte[] data, int offset, int count, CancellationToken cancellationToken)
- {
- byte[] buffer = data[offset..(offset + count)];
- byte[] encrypted = await Task.Run(() => rc4.Encrypt(buffer));
- await innerStream.WriteAsync(encrypted, cancellationToken);
- return;
- }
-
- public override async ValueTask WriteAsync(ReadOnlyMemory data, CancellationToken cancellationToken = default)
- {
- byte[] buffer = data.ToArray();
- await Task.Run(() => rc4.Encrypt(buffer));
- await innerStream.WriteAsync(buffer, cancellationToken);
- return;
- }
- }
-}
\ No newline at end of file
diff --git a/src/NCMDumpGUI/NCMDumpGUI - Backup.csproj b/src/NCMDumpGUI/NCMDumpGUI - Backup.csproj
deleted file mode 100644
index ffb87fa..0000000
--- a/src/NCMDumpGUI/NCMDumpGUI - Backup.csproj
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- WinExe
- net7.0-windows10.0.19041.0
- enable
- True
- NCMDump.ico
- True
- 1.6.2
- x64
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/NCMDumpGUI_WinUI/App.xaml.cs b/src/NCMDumpGUI_WinUI/App.xaml.cs
deleted file mode 100644
index 11a440a..0000000
--- a/src/NCMDumpGUI_WinUI/App.xaml.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.UI.Xaml;
-using NCMDumpCore;
-using NCMDumpGUI_WinUI.ViewModels;
-using System;
-using System.Reflection;
-
-// To learn more about WinUI, the WinUI project structure,
-// and more about our project templates, see: http://aka.ms/winui-project-info.
-
-namespace NCMDumpGUI_WinUI
-{
- ///
- /// Provides application-specific behavior to supplement the default Application class.
- ///
- public partial class App : Application
- {
- private IServiceProvider _serviceProvider;
-
- ///
- /// Initializes the singleton application object. This is the first line of authored code
- /// executed, and as such is the logical equivalent of main() or WinMain().
- ///
- public App()
- {
- this.InitializeComponent();
- }
-
- ///
- /// Invoked when the application is launched.
- ///
- /// Details about the launch request and process.
- protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
- {
- var services = new ServiceCollection();
- ConfigureServices(services);
- _serviceProvider = services.BuildServiceProvider();
- MainWindow = _serviceProvider.GetRequiredService();
- MainWindow.Activate();
- }
-
- public Window MainWindow;
-
- private void ConfigureServices(IServiceCollection services)
- {
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- }
-
- public static TEnum GetEnum(string text) where TEnum : struct
- {
- if (!typeof(TEnum).GetTypeInfo().IsEnum)
- {
- throw new InvalidOperationException("Generic parameter 'TEnum' must be an enum.");
- }
- return (TEnum)Enum.Parse(typeof(TEnum), text);
- }
- }
-}
\ No newline at end of file
diff --git a/src/NCMDumpGUI_WinUI/app.manifest b/src/NCMDumpGUI_WinUI/app.manifest
deleted file mode 100644
index 9caf2e7..0000000
--- a/src/NCMDumpGUI_WinUI/app.manifest
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- PerMonitorV2
-
-
-
\ No newline at end of file