Skip to content

Commit

Permalink
Add: Ability to export map sets back to .osz archives
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotrekol committed Jul 18, 2022
1 parent 98549cc commit c3eab1c
Show file tree
Hide file tree
Showing 12 changed files with 374 additions and 12 deletions.
81 changes: 81 additions & 0 deletions App/BeatmapListingActionsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@
using CollectionManagerExtensionsDll.Utils;
using Common;
using GuiComponents.Interfaces;
using SharpCompress.Archives.Zip;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;

namespace App
{
Expand Down Expand Up @@ -42,6 +48,7 @@ public BeatmapListingActionsHandler(ICollectionEditor collectionEditor, IUserDia
{BeatmapListingAction.OpenBeatmapPages, OpenBeatmapPages },
{BeatmapListingAction.OpenBeatmapFolder, OpenBeatmapFolder },
{BeatmapListingAction.PullWholeMapSet, PullWholeMapsets },
{BeatmapListingAction.ExportBeatmapSets, ExportBeatmapSets },
};
}

Expand All @@ -60,6 +67,80 @@ private void BeatmapListingModel_BeatmapOperation(object sender, BeatmapListingA
{
_beatmapOperationHandlers[args](sender);
}

private void ExportBeatmapSets(object sender)
{
var model = (IBeatmapListingModel)sender;
if (model.SelectedBeatmaps?.Count == 0)
{
_userDialogs.OkMessageBox("No beatmaps selected", "Info");
return;
}

var saveDirectory = _userDialogs.SelectDirectory("Select directory for exported maps", true);
var beatmapSets = model.SelectedBeatmaps.Select(b => (Beatmap: b, FileName: OsuDownloadManager.CreateOszFileName(b)))
.GroupBy(e => e.FileName).Select(e => e.First()).ToList();
if (!Directory.Exists(saveDirectory))
return;

var backgroundWorker = new BackgroundWorker();
var stringProgress = new Progress<string>();
var percentageProgress = new Progress<int>();
using var cancelationTokenSource = new CancellationTokenSource();
var progressForm = _userDialogs.ProgressForm(stringProgress, percentageProgress);
progressForm.AbortClicked += (_, __) => cancelationTokenSource.Cancel();
backgroundWorker.DoWork += (_, eventArgs) =>
{
var cancellationToken = cancelationTokenSource.Token;
var totalCount = beatmapSets.Count();
var stringProgressReporter = (IProgress<string>)stringProgress;
var percentageProgressReporter = (IProgress<int>)percentageProgress;
var failedMapSets = new StringBuilder();
var failedMapSetsCount = 0;
for (int i = 0; i < totalCount; i++)
{
var beatmapset = beatmapSets[i];
if (cancellationToken.IsCancellationRequested)
{
progressForm.Close();
return;
}

stringProgressReporter.Report($"Processing map set {i + 1} of {totalCount}.{Environment.NewLine}\"{beatmapset.FileName}\"");
var fileSaveLocation = Path.Combine(saveDirectory, beatmapset.FileName);
if (File.Exists(fileSaveLocation))
{
percentageProgressReporter.Report(Convert.ToInt32((double)(i + 1) / totalCount * 100));
continue;
}

var beatmapDirectory = beatmapset.Beatmap.BeatmapDirectory();
try
{
ZipFile.CreateFromDirectory(beatmapDirectory, fileSaveLocation);
}
catch (Exception e)
{
failedMapSets.AppendFormat("failed processing map set located at \"{0}\" with exception:{2}{1}{2}{2}", beatmapDirectory, e, Environment.NewLine);
failedMapSetsCount++;
}

percentageProgressReporter.Report(Convert.ToInt32((double)(i + 1) / totalCount * 100));
}

if (failedMapSetsCount > 0)
{
File.WriteAllText(Path.Combine(saveDirectory, "log.txt"), failedMapSets.ToString());
stringProgressReporter.Report($"Processed {totalCount - failedMapSetsCount} of {totalCount} map sets.{Environment.NewLine}{failedMapSetsCount} map sets failed to save, see full log in log.txt file in export directory");
}
else
stringProgressReporter.Report($"Processed {totalCount} map sets without issues.");
};

backgroundWorker.RunWorkerAsync();
progressForm.ShowAndBlock();
}

private void PullWholeMapsets(object sender)
{
var model = (IBeatmapListingModel)sender;
Expand Down
4 changes: 2 additions & 2 deletions App/OsuDownloadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@ private DownloadItem GetDownloadItem(Beatmap beatmap)
if (beatmap.MapSetId < 1 || ListedMapSetIds.Contains(beatmap.MapSetId))
return null;
long currentId = ++_downloadId;
var oszFileName = CreateFileName(beatmap);
var oszFileName = CreateOszFileName(beatmap);
var downloadUrl = string.Format(SelectedDownloadSource.BaseDownloadUrl, beatmap.MapSetId) + (DownloadWithVideo != null && DownloadWithVideo.Value ? string.Empty : "?noVideo=1");

var downloadItem = _mapDownloader.DownloadFileAsync(downloadUrl, oszFileName, string.Format(SelectedDownloadSource.Referer, beatmap.MapSetId), currentId,SelectedDownloadSource.RequestTimeout);
downloadItem.Id = currentId;
return downloadItem;
}

private string CreateFileName(Beatmap map)
public static string CreateOszFileName(Beatmap map)
{
var filename = map.MapSetId + " " + map.ArtistRoman + " - " + map.TitleRoman;
return Helpers.StripInvalidFileNameCharacters(filename, "_") + ".osz";
Expand Down
6 changes: 3 additions & 3 deletions CollectionManager.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.452
# Visual Studio Version 17
VisualStudioVersion = 17.2.32526.322
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CollectionManagerDll", "CollectionManagerDll\CollectionManagerDll.csproj", "{533AB47A-D1B5-45DB-A37E-F053FA3699C4}"
EndProject
Expand Down
1 change: 1 addition & 0 deletions Common/BeatmapListingAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public enum BeatmapListingAction
CopyBeatmapsAsText, //Copy text representation of selected beatmaps
CopyBeatmapsAsUrls, //Copy map links of selected beatmaps
PullWholeMapSet, //Finds all mapsets from selected maps and adds them to current collection
ExportBeatmapSets, //Compress selected mapsets back to .osz archives
}
}
9 changes: 9 additions & 0 deletions Common/Interfaces/Forms/IProgressForm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace GuiComponents.Interfaces
{
public interface IProgressForm : IForm
{
event EventHandler AbortClicked;
}
}
2 changes: 2 additions & 0 deletions Common/Interfaces/IUserDialogs.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Common;
using System;

namespace GuiComponents.Interfaces
{
Expand All @@ -11,6 +12,7 @@ public interface IUserDialogs
string SaveFile(string title, string types = "all|*.*");
bool YesNoMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info);
(bool Result, bool doNotAskAgain) YesNoMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info,string doNotAskAgainText = null);
IProgressForm ProgressForm(Progress<string> userProgressMessage, Progress<int> completionPercentage);
void OkMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info);
}
}
24 changes: 17 additions & 7 deletions GuiComponents/Controls/BeatmapListingView.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions GuiComponents/Controls/BeatmapListingView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ private void MenuStripClick(object sender, EventArgs e)
BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.OpenBeatmapFolder);
else if (sender == PullMapsetMenuStrip)
BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.PullWholeMapSet);
else if (sender == exportBeatmapSetsMenuItem)
BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.ExportBeatmapSets);
}

private void ListViewBeatmaps_KeyUp(object sender, KeyEventArgs e)
Expand Down
87 changes: 87 additions & 0 deletions GuiComponents/ProgressForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions GuiComponents/ProgressForm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using GuiComponents.Forms;
using GuiComponents.Interfaces;
using System;
using System.Windows.Forms;

namespace GuiComponents
{
public partial class ProgressForm : BaseForm, IProgressForm
{
public event EventHandler AbortClicked;
public ProgressForm()
{
InitializeComponent();
}

private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams myCp = base.CreateParams;
myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON;
return myCp;
}
}
internal static IProgressForm ShowDialog(Progress<string> userProgressMessage, Progress<int> completionPercentage)
{
var form = new ProgressForm();
userProgressMessage.ProgressChanged += (_, message) => form.label_text.Text = message;
completionPercentage.ProgressChanged += form.CompletionPercentage_ProgressChanged;
form.button_cancel.Click += (_, __) => form.AbortClicked?.Invoke(form, EventArgs.Empty);

form.Text = $"Collection Manager - Beatmap Export";
return form;
}

private void CompletionPercentage_ProgressChanged(object sender, int percentage)
{
progressBar1.Value = percentage;
if (percentage == progressBar1.Maximum)
button_cancel.Text = "Close";
}
}
}
Loading

0 comments on commit c3eab1c

Please sign in to comment.