diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 0594cd1316..2cca3ceaeb 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -225,11 +225,6 @@ namespace osu.Game.Beatmaps
remove => beatmapModelManager.ItemRemoved -= value;
}
- public Task ImportFromStableAsync(StableStorage stableStorage)
- {
- return beatmapModelManager.ImportFromStableAsync(stableStorage);
- }
-
public void Export(BeatmapSetInfo item)
{
beatmapModelManager.Export(item);
diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs
index ae395c6da6..63cdd0b852 100644
--- a/osu.Game/Beatmaps/BeatmapModelManager.cs
+++ b/osu.Game/Beatmaps/BeatmapModelManager.cs
@@ -58,10 +58,6 @@ namespace osu.Game.Beatmaps
protected override string[] HashableFileTypes => new[] { ".osu" };
- protected override string ImportFromStablePath => ".";
-
- protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage();
-
private readonly BeatmapStore beatmaps;
private readonly RulesetStore rulesets;
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index adbb71c8da..e5919cb5c4 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -728,17 +728,6 @@ namespace osu.Game.Database
#region osu-stable import
- ///
- /// The relative path from osu-stable's data directory to import items from.
- ///
- protected virtual string ImportFromStablePath => null;
-
- ///
- /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in .
- ///
- protected virtual IEnumerable GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath)
- .Select(path => storage.GetFullPath(path));
-
///
/// Whether this specified path should be removed after successful import.
///
@@ -746,29 +735,6 @@ namespace osu.Game.Database
/// Whether to perform deletion.
protected virtual bool ShouldDeleteArchive(string path) => false;
- public Task ImportFromStableAsync(StableStorage stableStorage)
- {
- var storage = PrepareStableStorage(stableStorage);
-
- // Handle situations like when the user does not have a Skins folder.
- if (!storage.ExistsDirectory(ImportFromStablePath))
- {
- string fullPath = storage.GetFullPath(ImportFromStablePath);
-
- Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error);
- return Task.CompletedTask;
- }
-
- return Task.Run(async () => await Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false));
- }
-
- ///
- /// Run any required traversal operations on the stable storage location before performing operations.
- ///
- /// The stable storage.
- /// The usable storage. Return the unchanged if no traversal is required.
- protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage;
-
#endregion
///
diff --git a/osu.Game/Database/IModelManager.cs b/osu.Game/Database/IModelManager.cs
index 15ad455f21..6c9cca7c7a 100644
--- a/osu.Game/Database/IModelManager.cs
+++ b/osu.Game/Database/IModelManager.cs
@@ -4,8 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Threading.Tasks;
-using osu.Game.IO;
namespace osu.Game.Database
{
@@ -26,11 +24,6 @@ namespace osu.Game.Database
///
event Action ItemRemoved;
- ///
- /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
- ///
- Task ImportFromStableAsync(StableStorage stableStorage);
-
///
/// Exports an item to a legacy (.zip based) package.
///
diff --git a/osu.Game/Database/StableBeatmapImporter.cs b/osu.Game/Database/StableBeatmapImporter.cs
new file mode 100644
index 0000000000..7aaa8ba013
--- /dev/null
+++ b/osu.Game/Database/StableBeatmapImporter.cs
@@ -0,0 +1,18 @@
+using osu.Framework.Platform;
+using osu.Game.Beatmaps;
+using osu.Game.IO;
+
+namespace osu.Game.Database
+{
+ public class StableBeatmapImporter : StableImporter
+ {
+ protected override string ImportFromStablePath => ".";
+
+ protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage();
+
+ public StableBeatmapImporter(IModelImporter importer)
+ : base(importer)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Database/StableImportManager.cs b/osu.Game/Database/StableImportManager.cs
index fe8c14c085..0a30fcb2be 100644
--- a/osu.Game/Database/StableImportManager.cs
+++ b/osu.Game/Database/StableImportManager.cs
@@ -51,18 +51,22 @@ namespace osu.Game.Database
var stableStorage = await getStableStorage().ConfigureAwait(false);
var importTasks = new List();
+ var beatmapImporter = new StableBeatmapImporter(beatmaps);
+ var skinImporter = new StableSkinImporter(skins);
+ var scoreImporter = new StableScoreImporter(scores);
+
Task beatmapImportTask = Task.CompletedTask;
if (content.HasFlagFast(StableContent.Beatmaps))
- importTasks.Add(beatmapImportTask = beatmaps.ImportFromStableAsync(stableStorage));
+ importTasks.Add(beatmapImportTask = beatmapImporter.ImportFromStableAsync(stableStorage));
if (content.HasFlagFast(StableContent.Skins))
- importTasks.Add(skins.ImportFromStableAsync(stableStorage));
+ importTasks.Add(skinImporter.ImportFromStableAsync(stableStorage));
if (content.HasFlagFast(StableContent.Collections))
importTasks.Add(beatmapImportTask.ContinueWith(_ => collections.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
if (content.HasFlagFast(StableContent.Scores))
- importTasks.Add(beatmapImportTask.ContinueWith(_ => scores.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
+ importTasks.Add(beatmapImportTask.ContinueWith(_ => scoreImporter.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false);
}
diff --git a/osu.Game/Database/StableImporter.cs b/osu.Game/Database/StableImporter.cs
new file mode 100644
index 0000000000..e56737959e
--- /dev/null
+++ b/osu.Game/Database/StableImporter.cs
@@ -0,0 +1,60 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using osu.Framework.Logging;
+using osu.Framework.Platform;
+using osu.Game.IO;
+
+namespace osu.Game.Database
+{
+ ///
+ /// A class which handled importing various user data from osu-stable.
+ ///
+ public class StableImporter
+ where TModel : class
+ {
+ ///
+ /// The relative path from osu-stable's data directory to import items from.
+ ///
+ protected virtual string ImportFromStablePath => null;
+
+ ///
+ /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in .
+ ///
+ protected virtual IEnumerable GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath)
+ .Select(path => storage.GetFullPath(path));
+
+ protected readonly IModelImporter Importer;
+
+ public StableImporter(IModelImporter importer)
+ {
+ Importer = importer;
+ }
+
+ public Task ImportFromStableAsync(StableStorage stableStorage)
+ {
+ var storage = PrepareStableStorage(stableStorage);
+
+ // Handle situations like when the user does not have a Skins folder.
+ if (!storage.ExistsDirectory(ImportFromStablePath))
+ {
+ string fullPath = storage.GetFullPath(ImportFromStablePath);
+
+ Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {Importer.HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error);
+ return Task.CompletedTask;
+ }
+
+ return Task.Run(async () => await Importer.Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false));
+ }
+
+ ///
+ /// Run any required traversal operations on the stable storage location before performing operations.
+ ///
+ /// The stable storage.
+ /// The usable storage. Return the unchanged if no traversal is required.
+ protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage;
+ }
+}
diff --git a/osu.Game/Database/StableScoreImporter.cs b/osu.Game/Database/StableScoreImporter.cs
new file mode 100644
index 0000000000..fede10c7ea
--- /dev/null
+++ b/osu.Game/Database/StableScoreImporter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using osu.Framework.Platform;
+using osu.Game.Scoring;
+
+namespace osu.Game.Database
+{
+ public class StableScoreImporter : StableImporter
+ {
+ protected override string ImportFromStablePath => Path.Combine("Data", "r");
+
+ protected override IEnumerable GetStableImportPaths(Storage storage)
+ => storage.GetFiles(ImportFromStablePath).Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
+ .Select(path => storage.GetFullPath(path));
+
+ public StableScoreImporter(IModelImporter importer)
+ : base(importer)
+ {
+ }
+ }
+}
diff --git a/osu.Game/Database/StableSkinImporter.cs b/osu.Game/Database/StableSkinImporter.cs
new file mode 100644
index 0000000000..65601e85b7
--- /dev/null
+++ b/osu.Game/Database/StableSkinImporter.cs
@@ -0,0 +1,14 @@
+using osu.Game.Skinning;
+
+namespace osu.Game.Database
+{
+ public class StableSkinImporter : StableImporter
+ {
+ protected override string ImportFromStablePath => "Skins";
+
+ public StableSkinImporter(IModelImporter importer)
+ : base(importer)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs
index 29144e7bdc..d25671d77e 100644
--- a/osu.Game/Scoring/ScoreManager.cs
+++ b/osu.Game/Scoring/ScoreManager.cs
@@ -15,7 +15,6 @@ using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
-using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.Online.API;
using osu.Game.Overlays.Notifications;
@@ -263,11 +262,6 @@ namespace osu.Game.Scoring
remove => scoreModelManager.ItemRemoved -= value;
}
- public Task ImportFromStableAsync(StableStorage stableStorage)
- {
- return scoreModelManager.ImportFromStableAsync(stableStorage);
- }
-
public void Export(ScoreInfo item)
{
scoreModelManager.Export(item);
diff --git a/osu.Game/Scoring/ScoreModelManager.cs b/osu.Game/Scoring/ScoreModelManager.cs
index c194a7166d..9da739237b 100644
--- a/osu.Game/Scoring/ScoreModelManager.cs
+++ b/osu.Game/Scoring/ScoreModelManager.cs
@@ -26,8 +26,6 @@ namespace osu.Game.Scoring
protected override string[] HashableFileTypes => new[] { ".osr" };
- protected override string ImportFromStablePath => Path.Combine("Data", "r");
-
private readonly RulesetStore rulesets;
private readonly Func beatmaps;
@@ -81,9 +79,5 @@ namespace osu.Game.Scoring
using (var inputStream = Files.Storage.GetStream(file.FileInfo.GetStoragePath()))
inputStream.CopyTo(outputStream);
}
-
- protected override IEnumerable GetStableImportPaths(Storage storage)
- => storage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
- .Select(path => storage.GetFullPath(path));
}
}
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index a840e17ed1..679b35799e 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -301,11 +301,6 @@ namespace osu.Game.Skinning
remove => skinModelManager.ItemRemoved -= value;
}
- public Task ImportFromStableAsync(StableStorage stableStorage)
- {
- return skinModelManager.ImportFromStableAsync(stableStorage);
- }
-
public void Export(SkinInfo item)
{
skinModelManager.Export(item);
diff --git a/osu.Game/Skinning/SkinModelManager.cs b/osu.Game/Skinning/SkinModelManager.cs
index f28b0c066b..572ae5cbfc 100644
--- a/osu.Game/Skinning/SkinModelManager.cs
+++ b/osu.Game/Skinning/SkinModelManager.cs
@@ -34,8 +34,6 @@ namespace osu.Game.Skinning
protected override string[] HashableFileTypes => new[] { ".ini", ".json" };
- protected override string ImportFromStablePath => "Skins";
-
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == @".osk";
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? @"No name" };