diff --git a/OsuPlayer.CrashHandler/OsuPlayer.CrashHandler.csproj b/OsuPlayer.CrashHandler/OsuPlayer.CrashHandler.csproj
index 5ea0f13e..aac58edb 100644
--- a/OsuPlayer.CrashHandler/OsuPlayer.CrashHandler.csproj
+++ b/OsuPlayer.CrashHandler/OsuPlayer.CrashHandler.csproj
@@ -40,7 +40,4 @@
CrashHandlerMainWindow.axaml
-
-
-
-
+
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/DataModels/DbMapEntry.cs b/OsuPlayer.Data/DataModels/DbMapEntry.cs
similarity index 94%
rename from OsuPlayer.IO/DbReader/DataModels/DbMapEntry.cs
rename to OsuPlayer.Data/DataModels/DbMapEntry.cs
index 6f419879..5a9ff371 100644
--- a/OsuPlayer.IO/DbReader/DataModels/DbMapEntry.cs
+++ b/OsuPlayer.Data/DataModels/DbMapEntry.cs
@@ -1,13 +1,13 @@
using System.Diagnostics;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
-namespace OsuPlayer.IO.DbReader.DataModels;
+namespace OsuPlayer.Data.DataModels;
///
/// a full beatmap entry with optionally used data
/// only created on a call
///
-internal class DbMapEntry : DbMapEntryBase, IMapEntry
+public class DbMapEntry : DbMapEntryBase, IMapEntry
{
public string ArtistUnicode { get; init; } = string.Empty;
public string TitleUnicode { get; init; } = string.Empty;
diff --git a/OsuPlayer.Data/DataModels/DbMapEntryBase.cs b/OsuPlayer.Data/DataModels/DbMapEntryBase.cs
new file mode 100644
index 00000000..1a25baf3
--- /dev/null
+++ b/OsuPlayer.Data/DataModels/DbMapEntryBase.cs
@@ -0,0 +1,112 @@
+using System.Text;
+using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
+
+namespace OsuPlayer.Data.DataModels;
+
+///
+/// a minimal beatmap entry with only frequently used data
+///
+public class DbMapEntryBase : IMapEntryBase
+{
+ public required IDbReaderFactory DbReaderFactory { get; init; }
+
+ public long DbOffset { get; init; }
+ public string? OsuPath { get; init; }
+ public string Artist { get; init; } = string.Empty;
+ public string Title { get; init; } = string.Empty;
+ public string Hash { get; init; } = string.Empty;
+ public int BeatmapSetId { get; init; }
+ public int TotalTime { get; init; }
+ public string TotalTimeString => TimeSpan.FromMilliseconds(TotalTime).FormatTime();
+ public string SongName => GetSongName();
+ public string ArtistString => GetArtist();
+ public string TitleString => GetTitle();
+
+ ///
+ /// Gets the artist
+ /// may be overridden for usage with
+ ///
+ /// the artist
+ public virtual string GetArtist()
+ {
+ return Artist;
+ }
+
+ ///
+ /// Gets the title
+ /// may be overridden for usage with
+ ///
+ /// the title
+ public virtual string GetTitle()
+ {
+ return Title;
+ }
+
+ public string GetSongName()
+ {
+ return $"{GetArtist()} - {GetTitle()}";
+ }
+
+ ///
+ /// Reads a osu!.db map entry and fills a full with data
+ ///
+ /// a new generated from osu!.db data
+ public IMapEntry? ReadFullEntry()
+ {
+ if (OsuPath == null) return null;
+
+ var reader = GetReader();
+
+ if (reader == default)
+ return null;
+
+ return reader.ReadFullEntry(OsuPath, this, dbOffset: DbOffset);
+ }
+
+ public IDatabaseReader? GetReader()
+ {
+ if (OsuPath == null)
+ return null;
+
+ return DbReaderFactory.CreateDatabaseReader(OsuPath);
+ }
+
+ public bool Equals(IMapEntryBase? other)
+ {
+ return Hash == other?.Hash;
+ }
+
+ public int CompareTo(IMapEntryBase? other)
+ {
+ return string.Compare(Hash, other?.Hash, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public override string ToString()
+ {
+ return GetSongName();
+ }
+
+ public static bool operator ==(DbMapEntryBase? left, IMapEntryBase? right)
+ {
+ return left?.Hash == right?.Hash;
+ }
+
+ public static bool operator !=(DbMapEntryBase? left, IMapEntryBase? right)
+ {
+ return left?.Hash != right?.Hash;
+ }
+
+ public override bool Equals(object? other)
+ {
+ if (other is IMapEntryBase map)
+ return Hash == map.Hash;
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return BitConverter.ToInt32(Encoding.UTF8.GetBytes(Hash));
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntry.cs b/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntry.cs
similarity index 76%
rename from OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntry.cs
rename to OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntry.cs
index ad137c31..51c3bc4b 100644
--- a/OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntry.cs
+++ b/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntry.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
-namespace OsuPlayer.IO.DbReader.DataModels.Extensions;
+namespace OsuPlayer.Data.DataModels.Extensions;
public class HistoricalMapEntry : IComparable
{
@@ -9,7 +9,7 @@ public class HistoricalMapEntry : IComparable
public string TimePlayedString => $"Last Played: {TimePlayed:G}";
- public HistoricalMapEntry(IMapEntryBase mapEntry) :this(mapEntry, DateTimeOffset.Now)
+ public HistoricalMapEntry(IMapEntryBase mapEntry) : this(mapEntry, DateTimeOffset.Now)
{
}
@@ -26,7 +26,7 @@ public int CompareTo(HistoricalMapEntry other)
public override bool Equals(object? obj)
{
- if(obj is HistoricalMapEntry other)
+ if (obj is HistoricalMapEntry other)
{
return MapEntry.Hash == other.MapEntry.Hash;
}
diff --git a/OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntryComparer.cs b/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntryComparer.cs
similarity index 66%
rename from OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntryComparer.cs
rename to OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntryComparer.cs
index 0764ecee..3d84cb7f 100644
--- a/OsuPlayer.IO/DbReader/DataModels/Extensions/HistoricalMapEntryComparer.cs
+++ b/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntryComparer.cs
@@ -1,12 +1,12 @@
-namespace OsuPlayer.IO.DbReader.DataModels.Extensions;
+namespace OsuPlayer.Data.DataModels.Extensions;
public class HistoricalMapEntryComparer : IEqualityComparer
{
public bool Equals(HistoricalMapEntry? x, HistoricalMapEntry? y)
{
- if(x == null && y == null) return true;
- if(x == null || y == null) return false;
-
+ if (x == null && y == null) return true;
+ if (x == null || y == null) return false;
+
return x.MapEntry.Hash == y.MapEntry.Hash;
}
diff --git a/OsuPlayer.Data/DataModels/IDbReaderFactory.cs b/OsuPlayer.Data/DataModels/IDbReaderFactory.cs
new file mode 100644
index 00000000..834eee00
--- /dev/null
+++ b/OsuPlayer.Data/DataModels/IDbReaderFactory.cs
@@ -0,0 +1,11 @@
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.Enums;
+
+namespace OsuPlayer.Data.DataModels;
+
+public interface IDbReaderFactory
+{
+ public DbCreationType Type { get; set; }
+
+ public IDatabaseReader CreateDatabaseReader(string path);
+}
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/Interfaces/IDatabaseReader.cs b/OsuPlayer.Data/DataModels/Interfaces/IDatabaseReader.cs
similarity index 53%
rename from OsuPlayer.IO/DbReader/Interfaces/IDatabaseReader.cs
rename to OsuPlayer.Data/DataModels/Interfaces/IDatabaseReader.cs
index 36d7bff4..dcc38cb8 100644
--- a/OsuPlayer.IO/DbReader/Interfaces/IDatabaseReader.cs
+++ b/OsuPlayer.Data/DataModels/Interfaces/IDatabaseReader.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.DbReader.Interfaces;
+namespace OsuPlayer.Data.DataModels.Interfaces;
///
/// Interface used by the database readers used to read the osu databases.
@@ -22,6 +22,16 @@ public interface IDatabaseReader : IDisposable
/// Reads the osu! collections from the database.
///
/// the osu! path
- /// a list of s
- public Task?> GetCollections(string path);
+ /// a list of s
+ public Task?> GetCollections(string path);
+
+ ///
+ /// Reads the full map entry from the existing
+ ///
+ /// the osu! path
+ /// the corresponding
+ /// the db offset (if applicable)
+ /// the database id (if applicable)
+ ///
+ public IMapEntry? ReadFullEntry(string path, IMapEntryBase mapEntryBase, long? dbOffset = null, Guid? id = null);
}
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/Interfaces/IMapEntry.cs b/OsuPlayer.Data/DataModels/Interfaces/IMapEntry.cs
similarity index 91%
rename from OsuPlayer.IO/DbReader/Interfaces/IMapEntry.cs
rename to OsuPlayer.Data/DataModels/Interfaces/IMapEntry.cs
index 8709fef9..b615a6ec 100644
--- a/OsuPlayer.IO/DbReader/Interfaces/IMapEntry.cs
+++ b/OsuPlayer.Data/DataModels/Interfaces/IMapEntry.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.DbReader.Interfaces;
+namespace OsuPlayer.Data.DataModels.Interfaces;
public interface IMapEntry : IMapEntryBase
{
diff --git a/OsuPlayer.IO/DbReader/Interfaces/IMapEntryBase.cs b/OsuPlayer.Data/DataModels/Interfaces/IMapEntryBase.cs
similarity index 90%
rename from OsuPlayer.IO/DbReader/Interfaces/IMapEntryBase.cs
rename to OsuPlayer.Data/DataModels/Interfaces/IMapEntryBase.cs
index 9a7ed504..28d23163 100644
--- a/OsuPlayer.IO/DbReader/Interfaces/IMapEntryBase.cs
+++ b/OsuPlayer.Data/DataModels/Interfaces/IMapEntryBase.cs
@@ -1,9 +1,11 @@
using Nein.Extensions;
-namespace OsuPlayer.IO.DbReader.Interfaces;
+namespace OsuPlayer.Data.DataModels.Interfaces;
public interface IMapEntryBase : IEquatable, IComparable
{
+ public IDbReaderFactory DbReaderFactory { get; init; }
+
public string Artist { get; }
public string Title { get; }
public string Hash { get; }
@@ -34,7 +36,7 @@ public string GetSongName()
/// a full for extended usage. Returns null if the path doesn't exist or the map was not
/// found.
///
- public Task ReadFullEntry();
+ public IMapEntry? ReadFullEntry();
///
/// Gets the corresponding of the beatmap
diff --git a/OsuPlayer.Data/DataModels/Interfaces/IUser.cs b/OsuPlayer.Data/DataModels/Interfaces/IUser.cs
new file mode 100644
index 00000000..1ad1e83a
--- /dev/null
+++ b/OsuPlayer.Data/DataModels/Interfaces/IUser.cs
@@ -0,0 +1,23 @@
+using Avalonia.Media;
+
+namespace OsuPlayer.Data.DataModels.Interfaces;
+
+public interface IUser
+{
+ public Guid UniqueId { get; }
+
+ public string SongsPlayedString { get; }
+ public string LevelAndTotalXpString { get; }
+ public string LevelProgressString { get; }
+ public Brush RoleColor { get; }
+ public string RoleString { get; }
+ public string DescriptionTitleString { get; }
+ public string LevelString { get; }
+ public string JoinDateString { get; }
+ public string TotalXpString { get; }
+
+ public int GetXpNeededForNextLevel();
+ public static abstract int GetXpNeededForNextLevel(int level);
+ public Brush GetRoleColorBrush();
+ public string GetRoleString();
+}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/Services/ObservableSorter.cs b/OsuPlayer.Data/DataModels/ObservableSorter.cs
similarity index 87%
rename from OsuPlayer/Modules/Services/ObservableSorter.cs
rename to OsuPlayer.Data/DataModels/ObservableSorter.cs
index 809a7d93..74bf2720 100644
--- a/OsuPlayer/Modules/Services/ObservableSorter.cs
+++ b/OsuPlayer.Data/DataModels/ObservableSorter.cs
@@ -1,17 +1,12 @@
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Data.DataModels;
public class ObservableSorter : IObservable>
{
- private readonly List>> _observers;
+ private readonly List>> _observers = new();
private IComparer? _lastComparer;
- public ObservableSorter()
- {
- _observers = new List>>();
- }
-
public IDisposable Subscribe(IObserver> observer)
{
if (!_observers.Contains(observer))
diff --git a/OsuPlayer.Network/Online/Article.cs b/OsuPlayer.Data/DataModels/Online/Article.cs
similarity index 89%
rename from OsuPlayer.Network/Online/Article.cs
rename to OsuPlayer.Data/DataModels/Online/Article.cs
index ddd5718e..8bcfa1b2 100644
--- a/OsuPlayer.Network/Online/Article.cs
+++ b/OsuPlayer.Data/DataModels/Online/Article.cs
@@ -1,6 +1,6 @@
using System.Globalization;
-namespace OsuPlayer.Network.Online;
+namespace OsuPlayer.Data.DataModels.Online;
public sealed class Article
{
diff --git a/OsuPlayer.Network/Online/News.cs b/OsuPlayer.Data/DataModels/Online/News.cs
similarity index 89%
rename from OsuPlayer.Network/Online/News.cs
rename to OsuPlayer.Data/DataModels/Online/News.cs
index aa410675..e88a492b 100644
--- a/OsuPlayer.Network/Online/News.cs
+++ b/OsuPlayer.Data/DataModels/Online/News.cs
@@ -1,6 +1,6 @@
using System.Globalization;
-namespace OsuPlayer.Network.Online;
+namespace OsuPlayer.Data.DataModels.Online;
public sealed class News
{
diff --git a/OsuPlayer.Network/Online/OnlineUserStatusModelExtended.cs b/OsuPlayer.Data/DataModels/Online/OnlineUserStatusModelExtended.cs
similarity index 92%
rename from OsuPlayer.Network/Online/OnlineUserStatusModelExtended.cs
rename to OsuPlayer.Data/DataModels/Online/OnlineUserStatusModelExtended.cs
index faf7eb3d..267ca252 100644
--- a/OsuPlayer.Network/Online/OnlineUserStatusModelExtended.cs
+++ b/OsuPlayer.Data/DataModels/Online/OnlineUserStatusModelExtended.cs
@@ -1,7 +1,7 @@
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.Enums;
-namespace OsuPlayer.Network.Online;
+namespace OsuPlayer.Data.DataModels.Online;
public sealed class OnlineUserStatusModelExtended : UserOnlineStatusModel
{
diff --git a/OsuPlayer.Network/Online/UserColors.cs b/OsuPlayer.Data/DataModels/Online/UserColors.cs
similarity index 92%
rename from OsuPlayer.Network/Online/UserColors.cs
rename to OsuPlayer.Data/DataModels/Online/UserColors.cs
index 74689dda..e9c1f087 100644
--- a/OsuPlayer.Network/Online/UserColors.cs
+++ b/OsuPlayer.Data/DataModels/Online/UserColors.cs
@@ -1,6 +1,6 @@
using Avalonia.Media;
-namespace OsuPlayer.Network.Online;
+namespace OsuPlayer.Data.DataModels.Online;
///
/// A list of all available role colors
diff --git a/OsuPlayer.IO/DbReader/Collection.cs b/OsuPlayer.Data/DataModels/OsuCollection.cs
similarity index 63%
rename from OsuPlayer.IO/DbReader/Collection.cs
rename to OsuPlayer.Data/DataModels/OsuCollection.cs
index 12a02fa8..debef5ba 100644
--- a/OsuPlayer.IO/DbReader/Collection.cs
+++ b/OsuPlayer.Data/DataModels/OsuCollection.cs
@@ -1,18 +1,18 @@
-namespace OsuPlayer.IO.DbReader;
+namespace OsuPlayer.Data.DataModels;
///
/// Represents a collection from osu!
///
-public class Collection
+public class OsuCollection
{
public string Name { get; set; } = string.Empty;
public List BeatmapHashes { get; private set; } = new();
- public Collection()
+ public OsuCollection()
{
}
- public Collection(string name, List beatmapHashes)
+ public OsuCollection(string name, List beatmapHashes)
{
Name = name;
BeatmapHashes = beatmapHashes;
diff --git a/OsuPlayer.IO/DbReader/DataModels/RealmMapEntry.cs b/OsuPlayer.Data/DataModels/RealmMapEntry.cs
similarity index 88%
rename from OsuPlayer.IO/DbReader/DataModels/RealmMapEntry.cs
rename to OsuPlayer.Data/DataModels/RealmMapEntry.cs
index 9be8cdd7..56d7c140 100644
--- a/OsuPlayer.IO/DbReader/DataModels/RealmMapEntry.cs
+++ b/OsuPlayer.Data/DataModels/RealmMapEntry.cs
@@ -1,12 +1,12 @@
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
-namespace OsuPlayer.IO.DbReader.DataModels;
+namespace OsuPlayer.Data.DataModels;
///
/// a full beatmap entry with optionally used data
/// only created on a call
///
-internal class RealmMapEntry : RealmMapEntryBase, IMapEntry
+public class RealmMapEntry : RealmMapEntryBase, IMapEntry
{
public string BackgroundFileLocation { get; init; } = string.Empty;
public string ArtistUnicode { get; init; } = string.Empty;
diff --git a/OsuPlayer.Data/DataModels/RealmMapEntryBase.cs b/OsuPlayer.Data/DataModels/RealmMapEntryBase.cs
new file mode 100644
index 00000000..f94d03d5
--- /dev/null
+++ b/OsuPlayer.Data/DataModels/RealmMapEntryBase.cs
@@ -0,0 +1,98 @@
+using System.Text;
+using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
+
+namespace OsuPlayer.Data.DataModels;
+
+///
+/// a minimal beatmap entry with only frequently used data
+///
+public class RealmMapEntryBase : IMapEntryBase
+{
+ public required IDbReaderFactory DbReaderFactory { get; init; }
+
+ public Guid Id { get; init; }
+ public string? OsuPath { get; init; }
+ public string Artist { get; init; } = string.Empty;
+ public string Title { get; init; } = string.Empty;
+ public string Hash { get; init; } = string.Empty;
+ public int BeatmapSetId { get; init; }
+ public int TotalTime { get; init; }
+ public string TotalTimeString => TimeSpan.FromMilliseconds(TotalTime).FormatTime();
+ public string SongName => GetSongName();
+ public string ArtistString => GetArtist();
+ public string TitleString => GetTitle();
+
+ public virtual string GetArtist()
+ {
+ return Artist;
+ }
+
+ public virtual string GetTitle()
+ {
+ return Title;
+ }
+
+ public virtual string GetSongName()
+ {
+ return $"{GetArtist()} - {GetTitle()}";
+ }
+
+ public IMapEntry? ReadFullEntry()
+ {
+ if (OsuPath == null) return null;
+
+ var reader = GetReader();
+
+ if (reader == default)
+ return null;
+
+ return reader.ReadFullEntry(OsuPath, this, id: Id);
+ }
+
+ public IDatabaseReader? GetReader()
+ {
+ if (OsuPath == null)
+ return null;
+
+ return DbReaderFactory.CreateDatabaseReader(OsuPath);
+ }
+
+ public bool Equals(IMapEntryBase? other)
+ {
+ return Hash == other?.Hash;
+ }
+
+ public int CompareTo(IMapEntryBase? other)
+ {
+ return string.Compare(Hash, other?.Hash, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public override string ToString()
+ {
+ return GetSongName();
+ }
+
+ public static bool operator ==(RealmMapEntryBase? left, IMapEntryBase? right)
+ {
+ return left?.Hash == right?.Hash;
+ }
+
+ public static bool operator !=(RealmMapEntryBase? left, IMapEntryBase? right)
+ {
+ return left?.Hash != right?.Hash;
+ }
+
+ public override bool Equals(object? other)
+ {
+ if (other is IMapEntryBase map)
+ return Hash == map.Hash;
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return BitConverter.ToInt32(Encoding.UTF8.GetBytes(Hash));
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer.Network/Online/User.cs b/OsuPlayer.Data/DataModels/User.cs
similarity index 96%
rename from OsuPlayer.Network/Online/User.cs
rename to OsuPlayer.Data/DataModels/User.cs
index 1b193967..d7d7cd4e 100644
--- a/OsuPlayer.Network/Online/User.cs
+++ b/OsuPlayer.Data/DataModels/User.cs
@@ -2,13 +2,15 @@
using Avalonia.Media;
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.Enums;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.DataModels.Online;
-namespace OsuPlayer.Network.Online;
+namespace OsuPlayer.Data.DataModels;
///
/// Represents a osu!player user
///
-public sealed class User : UserModel
+public sealed class User : UserModel, IUser
{
public string SongsPlayedString
{
diff --git a/OsuPlayer.Data/Enums/DbCreationType.cs b/OsuPlayer.Data/Enums/DbCreationType.cs
new file mode 100644
index 00000000..f2444b36
--- /dev/null
+++ b/OsuPlayer.Data/Enums/DbCreationType.cs
@@ -0,0 +1,7 @@
+namespace OsuPlayer.Data.Enums;
+
+public enum DbCreationType
+{
+ OsuDb,
+ Realm
+}
\ No newline at end of file
diff --git a/OsuPlayer.Data/Enums/LogType.cs b/OsuPlayer.Data/Enums/LogType.cs
new file mode 100644
index 00000000..73eb14a3
--- /dev/null
+++ b/OsuPlayer.Data/Enums/LogType.cs
@@ -0,0 +1,10 @@
+namespace OsuPlayer.Services;
+
+public enum LogType
+{
+ Info,
+ Success,
+ Warning,
+ Error,
+ Debug
+}
\ No newline at end of file
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapDifficulty.cs b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapDifficulty.cs
index aff4b87c..a305c376 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapDifficulty.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapDifficulty.cs
@@ -1,6 +1,6 @@
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapInfo.cs
index a2e9348f..4f705651 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapInfo.cs
@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
-using OsuPlayer.IO.Storage.LazerModels.Extensions;
-using OsuPlayer.IO.Storage.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Extensions;
+using OsuPlayer.Data.LazerModels.Files;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
@@ -20,7 +20,8 @@ public class BeatmapInfo : RealmObject, IHasGuidPrimaryKey, IBeatmapInfo, IEquat
public BeatmapSetInfo? BeatmapSet { get; set; }
- [Ignored] public RealmNamedFileUsage? File => BeatmapSet?.Files.FirstOrDefault(f => f.File.Hash == Hash);
+ [Ignored]
+ public RealmNamedFileUsage? File => BeatmapSet?.Files.FirstOrDefault(f => f.File.Hash == Hash);
[Ignored]
public BeatmapOnlineStatus Status
@@ -29,13 +30,16 @@ public BeatmapOnlineStatus Status
set => StatusInt = (int) value;
}
- [MapTo(nameof(Status))] public int StatusInt { get; set; } = (int) BeatmapOnlineStatus.None;
+ [MapTo(nameof(Status))]
+ public int StatusInt { get; set; } = (int) BeatmapOnlineStatus.None;
- [JsonIgnore] public bool Hidden { get; set; }
+ [JsonIgnore]
+ public bool Hidden { get; set; }
public string DifficultyName { get; set; } = string.Empty;
- [Indexed] public int OnlineID { get; set; } = -1;
+ [Indexed]
+ public int OnlineID { get; set; } = -1;
public double Length { get; set; }
@@ -52,7 +56,8 @@ public BeatmapOnlineStatus Status
IRulesetInfo IBeatmapInfo.Ruleset => Ruleset;
IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => Difficulty;
- [PrimaryKey] public Guid ID { get; set; }
+ [PrimaryKey]
+ public Guid ID { get; set; }
public BeatmapInfo(RulesetInfo? ruleset = null, BeatmapDifficulty? difficulty = null, BeatmapMetadata? metadata = null)
{
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapMetadata.cs b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapMetadata.cs
index 0a4e898d..b38ea30b 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapMetadata.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapMetadata.cs
@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
-using OsuPlayer.IO.Storage.LazerModels.Extensions;
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Extensions;
+using OsuPlayer.Data.LazerModels.Interfaces;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
@@ -16,15 +16,18 @@ public class BeatmapMetadata : RealmObject, IBeatmapMetadataInfo
public string Title { get; set; } = string.Empty;
- [JsonProperty("title_unicode")] public string TitleUnicode { get; set; } = string.Empty;
+ [JsonProperty("title_unicode")]
+ public string TitleUnicode { get; set; } = string.Empty;
public string Artist { get; set; } = string.Empty;
- [JsonProperty("artist_unicode")] public string ArtistUnicode { get; set; } = string.Empty;
+ [JsonProperty("artist_unicode")]
+ public string ArtistUnicode { get; set; } = string.Empty;
public string Source { get; set; } = string.Empty;
- [JsonProperty(@"tags")] public string Tags { get; set; } = string.Empty;
+ [JsonProperty(@"tags")]
+ public string Tags { get; set; } = string.Empty;
///
/// The time in milliseconds to begin playing the track for preview purposes.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapOnlineStatus.cs b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapOnlineStatus.cs
index 9ba1f7da..2350b7ab 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapOnlineStatus.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapOnlineStatus.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapSetInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapSetInfo.cs
index fb135c92..2f97239c 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapSetInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapSetInfo.cs
@@ -1,17 +1,18 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
-using OsuPlayer.IO.Storage.LazerModels.Extensions;
-using OsuPlayer.IO.Storage.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Extensions;
+using OsuPlayer.Data.LazerModels.Files;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
[MapTo("BeatmapSet")]
public class BeatmapSetInfo : RealmObject, IHasRealmFiles, IEquatable, IBeatmapSetInfo
{
- [PrimaryKey] public Guid ID { get; set; }
+ [PrimaryKey]
+ public Guid ID { get; set; }
public IList Beatmaps { get; } = null!;
@@ -22,7 +23,8 @@ public BeatmapOnlineStatus Status
set => StatusInt = (int) value;
}
- [MapTo(nameof(Status))] public int StatusInt { get; set; } = (int) BeatmapOnlineStatus.None;
+ [MapTo(nameof(Status))]
+ public int StatusInt { get; set; } = (int) BeatmapOnlineStatus.None;
public bool DeletePending { get; set; }
@@ -31,11 +33,13 @@ public BeatmapOnlineStatus Status
///
public bool Protected { get; set; }
- [Indexed] public int OnlineID { get; set; } = -1;
+ [Indexed]
+ public int OnlineID { get; set; } = -1;
public DateTimeOffset DateAdded { get; set; }
- [JsonIgnore] public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
+ [JsonIgnore]
+ public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
public double MaxStarDifficulty => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.StarRating);
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapDifficultyInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapDifficultyInfo.cs
index 0dad82e7..bcd01e28 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapDifficultyInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapDifficultyInfo.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapInfo.cs
index bbcc17d7..15910207 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapInfo.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapMetadataInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapMetadataInfo.cs
index a3e10206..42c8dbbc 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapMetadataInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapMetadataInfo.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapSetInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapSetInfo.cs
index 6e689949..e6479166 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapSetInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapSetInfo.cs
@@ -1,7 +1,7 @@
-using OsuPlayer.IO.Storage.LazerModels.Files;
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IRulesetInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IRulesetInfo.cs
index 7cfc5acb..48ac09d4 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IRulesetInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IRulesetInfo.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/IScoreInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/IScoreInfo.cs
index c4def931..4a76c82b 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/IScoreInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/IScoreInfo.cs
@@ -1,7 +1,7 @@
-using OsuPlayer.IO.Storage.LazerModels.Files;
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Beatmaps/RulesetInfo.cs b/OsuPlayer.Data/LazerModels/Beatmaps/RulesetInfo.cs
index 1b54193d..812c3b68 100644
--- a/OsuPlayer.Data/LazerModels/Beatmaps/RulesetInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Beatmaps/RulesetInfo.cs
@@ -1,7 +1,7 @@
using JetBrains.Annotations;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+namespace OsuPlayer.Data.LazerModels.Beatmaps;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
@@ -10,9 +10,11 @@ public class RulesetInfo : RealmObject, IEquatable, IComparable. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
public enum ScoreRank
{
- [Description(@"D")] D,
+ [Description(@"D")]
+ D,
- [Description(@"C")] C,
+ [Description(@"C")]
+ C,
- [Description(@"B")] B,
+ [Description(@"B")]
+ B,
- [Description(@"A")] A,
+ [Description(@"A")]
+ A,
- [Description(@"S")] S,
+ [Description(@"S")]
+ S,
- [Description(@"S+")] SH,
+ [Description(@"S+")]
+ SH,
- [Description(@"SS")] X,
+ [Description(@"SS")]
+ X,
- [Description(@"SS+")] XH
+ [Description(@"SS+")]
+ XH
}
\ No newline at end of file
diff --git a/OsuPlayer.Data/LazerModels/Collections/BeatmapCollection.cs b/OsuPlayer.Data/LazerModels/Collections/BeatmapCollection.cs
index 04f0c89e..19f1c18e 100644
--- a/OsuPlayer.Data/LazerModels/Collections/BeatmapCollection.cs
+++ b/OsuPlayer.Data/LazerModels/Collections/BeatmapCollection.cs
@@ -2,11 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using JetBrains.Annotations;
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
-using OsuPlayer.IO.Storage.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Files;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Collections;
+namespace OsuPlayer.Data.LazerModels.Collections;
///
/// A collection of beatmaps grouped by a name.
@@ -34,7 +34,8 @@ public class BeatmapCollection : RealmObject, IHasGuidPrimaryKey
///
public DateTimeOffset LastModified { get; set; }
- [PrimaryKey] public Guid ID { get; set; }
+ [PrimaryKey]
+ public Guid ID { get; set; }
public BeatmapCollection(string? name = null, IList? beatmapMD5Hashes = null)
{
diff --git a/OsuPlayer.Data/LazerModels/Extensions/BeatmapInfoExtionsions.cs b/OsuPlayer.Data/LazerModels/Extensions/BeatmapInfoExtionsions.cs
index eacb24a3..49b3f223 100644
--- a/OsuPlayer.Data/LazerModels/Extensions/BeatmapInfoExtionsions.cs
+++ b/OsuPlayer.Data/LazerModels/Extensions/BeatmapInfoExtionsions.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Beatmaps;
-namespace OsuPlayer.IO.Storage.LazerModels.Extensions;
+namespace OsuPlayer.Data.LazerModels.Extensions;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Extensions/BeatmapMetadataInfoExtensions.cs b/OsuPlayer.Data/LazerModels/Extensions/BeatmapMetadataInfoExtensions.cs
index 3f32270c..157db15b 100644
--- a/OsuPlayer.Data/LazerModels/Extensions/BeatmapMetadataInfoExtensions.cs
+++ b/OsuPlayer.Data/LazerModels/Extensions/BeatmapMetadataInfoExtensions.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Beatmaps;
-namespace OsuPlayer.IO.Storage.LazerModels.Extensions;
+namespace OsuPlayer.Data.LazerModels.Extensions;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Extensions/CollectionExtensions.cs b/OsuPlayer.Data/LazerModels/Extensions/CollectionExtensions.cs
index f577b0b5..4da7a82a 100644
--- a/OsuPlayer.Data/LazerModels/Extensions/CollectionExtensions.cs
+++ b/OsuPlayer.Data/LazerModels/Extensions/CollectionExtensions.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Extensions;
+namespace OsuPlayer.Data.LazerModels.Extensions;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Extensions/ModelExtension.cs b/OsuPlayer.Data/LazerModels/Extensions/ModelExtension.cs
index 91cf7258..d5d5bddc 100644
--- a/OsuPlayer.Data/LazerModels/Extensions/ModelExtension.cs
+++ b/OsuPlayer.Data/LazerModels/Extensions/ModelExtension.cs
@@ -1,8 +1,8 @@
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
-using OsuPlayer.IO.Storage.LazerModels.Files;
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Files;
+using OsuPlayer.Data.LazerModels.Interfaces;
-namespace OsuPlayer.IO.Storage.LazerModels.Extensions;
+namespace OsuPlayer.Data.LazerModels.Extensions;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Extensions/ScoreInfoExtensions.cs b/OsuPlayer.Data/LazerModels/Extensions/ScoreInfoExtensions.cs
index 823e5169..44d3cdef 100644
--- a/OsuPlayer.Data/LazerModels/Extensions/ScoreInfoExtensions.cs
+++ b/OsuPlayer.Data/LazerModels/Extensions/ScoreInfoExtensions.cs
@@ -1,6 +1,6 @@
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Beatmaps;
-namespace OsuPlayer.IO.Storage.LazerModels.Extensions;
+namespace OsuPlayer.Data.LazerModels.Extensions;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/IFileInfo.cs b/OsuPlayer.Data/LazerModels/Files/IFileInfo.cs
index ded44752..6b3f227e 100644
--- a/OsuPlayer.Data/LazerModels/Files/IFileInfo.cs
+++ b/OsuPlayer.Data/LazerModels/Files/IFileInfo.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/IHasGuidPrimaryKey.cs b/OsuPlayer.Data/LazerModels/Files/IHasGuidPrimaryKey.cs
index 5748e545..848042c1 100644
--- a/OsuPlayer.Data/LazerModels/Files/IHasGuidPrimaryKey.cs
+++ b/OsuPlayer.Data/LazerModels/Files/IHasGuidPrimaryKey.cs
@@ -1,11 +1,13 @@
using Newtonsoft.Json;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
public interface IHasGuidPrimaryKey
{
- [JsonIgnore] [PrimaryKey] Guid ID { get; }
+ [JsonIgnore]
+ [PrimaryKey]
+ Guid ID { get; }
}
\ No newline at end of file
diff --git a/OsuPlayer.Data/LazerModels/Files/IHasNamedFiles.cs b/OsuPlayer.Data/LazerModels/Files/IHasNamedFiles.cs
index c3fab856..dadaee0c 100644
--- a/OsuPlayer.Data/LazerModels/Files/IHasNamedFiles.cs
+++ b/OsuPlayer.Data/LazerModels/Files/IHasNamedFiles.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/IHasRealmFiles.cs b/OsuPlayer.Data/LazerModels/Files/IHasRealmFiles.cs
index dac595ea..2f7ce483 100644
--- a/OsuPlayer.Data/LazerModels/Files/IHasRealmFiles.cs
+++ b/OsuPlayer.Data/LazerModels/Files/IHasRealmFiles.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/INamedFile.cs b/OsuPlayer.Data/LazerModels/Files/INamedFile.cs
index 3d464506..729ef0ee 100644
--- a/OsuPlayer.Data/LazerModels/Files/INamedFile.cs
+++ b/OsuPlayer.Data/LazerModels/Files/INamedFile.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/INamedFileUsage.cs b/OsuPlayer.Data/LazerModels/Files/INamedFileUsage.cs
index 236fc22e..846b7b2b 100644
--- a/OsuPlayer.Data/LazerModels/Files/INamedFileUsage.cs
+++ b/OsuPlayer.Data/LazerModels/Files/INamedFileUsage.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Files/RealmFile.cs b/OsuPlayer.Data/LazerModels/Files/RealmFile.cs
index 40b99a4d..c1250d77 100644
--- a/OsuPlayer.Data/LazerModels/Files/RealmFile.cs
+++ b/OsuPlayer.Data/LazerModels/Files/RealmFile.cs
@@ -1,11 +1,12 @@
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
[MapTo("File")]
public class RealmFile : RealmObject, IFileInfo
{
- [PrimaryKey] public string Hash { get; set; } = string.Empty;
+ [PrimaryKey]
+ public string Hash { get; set; } = string.Empty;
}
\ No newline at end of file
diff --git a/OsuPlayer.Data/LazerModels/Files/RealmNamedFileUsage.cs b/OsuPlayer.Data/LazerModels/Files/RealmNamedFileUsage.cs
index 6ef57a2b..2cb9459d 100644
--- a/OsuPlayer.Data/LazerModels/Files/RealmNamedFileUsage.cs
+++ b/OsuPlayer.Data/LazerModels/Files/RealmNamedFileUsage.cs
@@ -1,7 +1,7 @@
using JetBrains.Annotations;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels.Files;
+namespace OsuPlayer.Data.LazerModels.Files;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Interfaces/IHasOnlineID.cs b/OsuPlayer.Data/LazerModels/Interfaces/IHasOnlineID.cs
index 5cbcb700..460ab0c8 100644
--- a/OsuPlayer.Data/LazerModels/Interfaces/IHasOnlineID.cs
+++ b/OsuPlayer.Data/LazerModels/Interfaces/IHasOnlineID.cs
@@ -1,6 +1,6 @@
// ReSharper disable InconsistentNaming
-namespace OsuPlayer.IO.Storage.LazerModels.Interfaces;
+namespace OsuPlayer.Data.LazerModels.Interfaces;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Interfaces/IMapperBase.cs b/OsuPlayer.Data/LazerModels/Interfaces/IMapperBase.cs
index c8b5a93e..16371a60 100644
--- a/OsuPlayer.Data/LazerModels/Interfaces/IMapperBase.cs
+++ b/OsuPlayer.Data/LazerModels/Interfaces/IMapperBase.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Interfaces;
+namespace OsuPlayer.Data.LazerModels.Interfaces;
public interface IMapperBase
{
diff --git a/OsuPlayer.Data/LazerModels/Interfaces/IMappingOperationOptions.cs b/OsuPlayer.Data/LazerModels/Interfaces/IMappingOperationOptions.cs
index 42749b13..70b7ec47 100644
--- a/OsuPlayer.Data/LazerModels/Interfaces/IMappingOperationOptions.cs
+++ b/OsuPlayer.Data/LazerModels/Interfaces/IMappingOperationOptions.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Interfaces;
+namespace OsuPlayer.Data.LazerModels.Interfaces;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/Interfaces/IUser.cs b/OsuPlayer.Data/LazerModels/Interfaces/IUser.cs
index 5802fda4..807e4835 100644
--- a/OsuPlayer.Data/LazerModels/Interfaces/IUser.cs
+++ b/OsuPlayer.Data/LazerModels/Interfaces/IUser.cs
@@ -1,4 +1,4 @@
-namespace OsuPlayer.IO.Storage.LazerModels.Interfaces;
+namespace OsuPlayer.Data.LazerModels.Interfaces;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/LazerModels/RealmUser.cs b/OsuPlayer.Data/LazerModels/RealmUser.cs
index 6625f0c1..cd4cfea9 100644
--- a/OsuPlayer.Data/LazerModels/RealmUser.cs
+++ b/OsuPlayer.Data/LazerModels/RealmUser.cs
@@ -1,7 +1,7 @@
-using OsuPlayer.IO.Storage.LazerModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Interfaces;
using Realms;
-namespace OsuPlayer.IO.Storage.LazerModels;
+namespace OsuPlayer.Data.LazerModels;
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
diff --git a/OsuPlayer.Data/OsuPlayer.Data.csproj b/OsuPlayer.Data/OsuPlayer.Data.csproj
index deb23eb1..2fa92e5f 100644
--- a/OsuPlayer.Data/OsuPlayer.Data.csproj
+++ b/OsuPlayer.Data/OsuPlayer.Data.csproj
@@ -9,9 +9,11 @@
+
+
diff --git a/OsuPlayer.IO/DbReader/DataModels/DbMapEntryBase.cs b/OsuPlayer.IO/DbReader/DataModels/DbMapEntryBase.cs
deleted file mode 100644
index 3c82f353..00000000
--- a/OsuPlayer.IO/DbReader/DataModels/DbMapEntryBase.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-using System.Text;
-using Nein.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
-
-namespace OsuPlayer.IO.DbReader.DataModels;
-
-///
-/// a minimal beatmap entry with only frequently used data
-/// created on call of
-///
-public class DbMapEntryBase : IMapEntryBase
-{
- public long DbOffset { get; init; }
- public string? OsuPath { get; init; }
- public string Artist { get; init; } = string.Empty;
- public string Title { get; init; } = string.Empty;
- public string Hash { get; init; } = string.Empty;
- public int BeatmapSetId { get; init; }
- public int TotalTime { get; init; }
- public string TotalTimeString => TimeSpan.FromMilliseconds(TotalTime).FormatTime();
- public string SongName => GetSongName();
- public string ArtistString => GetArtist();
- public string TitleString => GetTitle();
-
- ///
- /// Gets the artist
- /// may be overridden for usage with
- ///
- /// the artist
- public virtual string GetArtist()
- {
- return Artist;
- }
-
- ///
- /// Gets the title
- /// may be overridden for usage with
- ///
- /// the title
- public virtual string GetTitle()
- {
- return Title;
- }
-
- public string GetSongName()
- {
- return $"{GetArtist()} - {GetTitle()}";
- }
-
- ///
- /// Reads a osu!.db map entry and fills a full with data
- ///
- /// a new generated from osu!.db data
- public async Task ReadFullEntry()
- {
- if (OsuPath == null) return null;
-
- var version = OsuDbReader.OsuDbVersion;
-
- var dbLoc = Path.Combine(OsuPath, "osu!.db");
-
- if (!File.Exists(dbLoc)) return null;
-
- await using var file = File.OpenRead(dbLoc);
-
- using var r = new OsuDbReader(file);
-
- r.BaseStream.Seek(DbOffset, SeekOrigin.Begin);
-
- r.ReadString(true); //Artist
-
- var artistUnicode = "Unknown Artist";
- if (version >= 20121008)
- artistUnicode = r.ReadString();
-
- r.ReadString(true); //Title
-
- var titleUnicode = "Unknown Title";
- if (version >= 20121008)
- titleUnicode = r.ReadString();
-
- r.ReadString(true); //Creator
- r.ReadString(true); //Difficulty
-
- var audioFileName = r.ReadString();
- r.ReadString(true); //Hash
-
- r.ReadString(true); //BeatmapFileName
- r.ReadByte(); //RankedStatus
- r.ReadUInt16(); //CountHitCircles
- r.ReadUInt16(); //CountSliders
- r.ReadUInt16(); //CountSpinners
- r.ReadDateTime(); //LastModifiedTime
-
- if (version >= 20140609)
- {
- r.ReadSingle(); //ApproachRate
- r.ReadSingle(); //CircleSize
- r.ReadSingle(); //HPDrainRate
- r.ReadSingle(); //OverallDifficulty
- }
- else
- {
- //Float
- r.ReadByte(); //ApproachRate
- r.ReadByte(); //CircleSize
- r.ReadByte(); //HPDrainRate
- r.ReadByte(); //OverallDifficulty
- }
-
- r.ReadDouble(); //SliderVelocity
-
- if (version >= 20140609)
- {
- r.ReadStarRating();
- r.ReadStarRating();
- r.ReadStarRating();
- r.ReadStarRating();
- }
-
- r.ReadInt32(); //DrainTimeSeconds
- r.ReadInt32(); //TotalTimeSeconds
-
- r.ReadInt32(); //AudioPreviewTime
- var timingCount = r.ReadInt32();
-
- r.BaseStream.Position += 17 * timingCount;
-
- r.ReadInt32();
- r.ReadInt32(); //beatmapSetId
-
- r.ReadInt32(); //ThreadId
- r.ReadByte(); //GradeStandard
- r.ReadByte(); //GradeTaiko
- r.ReadByte(); //GradeCtB
- r.ReadByte(); //GradeMania
- r.ReadInt16(); //OffsetLocal
- r.ReadSingle(); //StackLeniency
- r.ReadByte(); //GameMode
- r.ReadString(true); //SongSource
- r.ReadString(true); //SongTags
- r.ReadInt16(); //OffsetOnline
- r.ReadString(true); //TitleFont
- r.ReadBoolean(); //Unplayed
- r.ReadDateTime(); //LastPlayed
- r.ReadBoolean(); //IsOsz2
-
- var folderName = r.ReadString();
-
- r.ReadDateTime(); //LastCheckAgainstOsuRepo
- r.ReadBoolean(); //IgnoreBeatmapSounds
- r.ReadBoolean(); //IgnoreBeatmapSkin
- r.ReadBoolean(); //DisableStoryBoard
- r.ReadBoolean(); //DisableVideo
- r.ReadBoolean(); //
-
- if (version < 20140609)
- r.ReadInt16(); //OldUnknown1
-
- r.ReadInt32(); //LastEditTime
- r.ReadByte(); //ManiaScrollSpeed
-
- var fullPath = Path.Combine(OsuPath, "Songs", folderName, audioFileName);
- var folderPath = Path.Combine(OsuPath, "Songs", folderName);
-
- return new DbMapEntry
- {
- DbOffset = DbOffset,
- OsuPath = OsuPath,
- Artist = Artist,
- ArtistUnicode = artistUnicode,
- Title = Title,
- TitleUnicode = titleUnicode,
- AudioFileName = audioFileName,
- BeatmapSetId = BeatmapSetId,
- FolderName = folderName,
- FolderPath = folderPath,
- FullPath = fullPath,
- Hash = Hash,
- TotalTime = TotalTime
- };
- }
-
- public IDatabaseReader? GetReader()
- {
- if (OsuPath == null) return null;
-
- var dbLoc = Path.Combine(OsuPath, "osu!.db");
-
- if (!File.Exists(dbLoc)) return null;
-
- var file = File.OpenRead(dbLoc);
-
- return new OsuDbReader(file, OsuPath);
- }
-
- public bool Equals(IMapEntryBase? other)
- {
- return Hash == other?.Hash;
- }
-
- public int CompareTo(IMapEntryBase? other)
- {
- return string.Compare(Hash, other?.Hash, StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ToString()
- {
- return GetSongName();
- }
-
- public static bool operator ==(DbMapEntryBase? left, IMapEntryBase? right)
- {
- return left?.Hash == right?.Hash;
- }
-
- public static bool operator !=(DbMapEntryBase? left, IMapEntryBase? right)
- {
- return left?.Hash != right?.Hash;
- }
-
- public override bool Equals(object? other)
- {
- if (other is IMapEntryBase map)
- return Hash == map.Hash;
-
- return false;
- }
-
- public override int GetHashCode()
- {
- return BitConverter.ToInt32(Encoding.UTF8.GetBytes(Hash));
- }
-}
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/DataModels/RealmMapEntryBase.cs b/OsuPlayer.IO/DbReader/DataModels/RealmMapEntryBase.cs
deleted file mode 100644
index b63b5191..00000000
--- a/OsuPlayer.IO/DbReader/DataModels/RealmMapEntryBase.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using System.Text;
-using Nein.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
-using OsuPlayer.IO.Storage.LazerModels.Files;
-using Realms;
-using Realms.Dynamic;
-
-namespace OsuPlayer.IO.DbReader.DataModels;
-
-///
-/// a minimal beatmap entry with only frequently used data
-/// created on call of
-///
-public class RealmMapEntryBase : IMapEntryBase
-{
- public Guid Id { get; init; }
- public string? OsuPath { get; init; }
- public string Artist { get; init; } = string.Empty;
- public string Title { get; init; } = string.Empty;
- public string Hash { get; init; } = string.Empty;
- public int BeatmapSetId { get; init; }
- public int TotalTime { get; init; }
- public string TotalTimeString => TimeSpan.FromMilliseconds(TotalTime).FormatTime();
- public string SongName => GetSongName();
- public string ArtistString => GetArtist();
- public string TitleString => GetTitle();
-
- public virtual string GetArtist()
- {
- return Artist;
- }
-
- public virtual string GetTitle()
- {
- return Title;
- }
-
- public virtual string GetSongName()
- {
- return $"{GetArtist()} - {GetTitle()}";
- }
-
- public async Task ReadFullEntry()
- {
- if (OsuPath == null) return null;
-
- var realmLoc = Path.Combine(OsuPath, "client.realm");
-
- var realmConfig = new RealmConfiguration(realmLoc)
- {
- IsDynamic = true,
- IsReadOnly = true
- };
-
- var realm = await Realm.GetInstanceAsync(realmConfig);
- var beatmap = (DynamicRealmObject) realm.DynamicApi.Find("BeatmapSet", Id);
-
- if (beatmap == default) return null;
-
- var beatmaps = beatmap.DynamicApi.GetList(nameof(BeatmapSetInfo.Beatmaps));
- var metadata = beatmaps.First().DynamicApi.Get(nameof(BeatmapInfo.Metadata)).DynamicApi;
-
- var files = (RealmList) beatmap.DynamicApi.GetList(nameof(BeatmapSetInfo.Files));
-
- var audioFileName = metadata.Get(nameof(BeatmapMetadata.AudioFile));
- var backgroundFileName = metadata.Get(nameof(BeatmapMetadata.BackgroundFile));
-
- var audioFile = (IRealmObjectBase) files.FirstOrDefault(x =>
- string.Equals(x.DynamicApi.Get(nameof(RealmNamedFileUsage.Filename)), audioFileName, StringComparison.CurrentCultureIgnoreCase));
- var backgroundFile = (IRealmObjectBase) files.FirstOrDefault(x =>
- string.Equals(x.DynamicApi.Get(nameof(RealmNamedFileUsage.Filename)), backgroundFileName, StringComparison.CurrentCultureIgnoreCase));
-
- if (audioFile == null) return null;
-
- var audioHash = audioFile.DynamicApi.Get(nameof(RealmNamedFileUsage.File)).DynamicApi.Get(nameof(RealmFile.Hash));
- var backgroundHash = backgroundFile?.DynamicApi.Get(nameof(RealmNamedFileUsage.File)).DynamicApi.Get(nameof(RealmFile.Hash));
-
- var audioFolderName = Path.Combine($"{audioHash[0]}", $"{audioHash[0]}{audioHash[1]}");
- var backgroundFolderName = Path.Combine($"{backgroundHash?[0]}", $"{backgroundHash?[0]}{backgroundHash?[1]}");
-
- var newMap = new RealmMapEntry
- {
- Id = Id,
- OsuPath = string.Intern(OsuPath),
- Artist = string.Intern(Artist),
- ArtistUnicode = metadata.Get(nameof(BeatmapMetadata.ArtistUnicode)),
- Title = Title,
- TitleUnicode = metadata.Get(nameof(BeatmapMetadata.TitleUnicode)),
- AudioFileName = audioFileName,
- BackgroundFileLocation = string.IsNullOrEmpty(backgroundFolderName)
- ? string.Empty
- : Path.Combine(OsuPath, "files", backgroundFolderName, backgroundHash!),
- Hash = Hash,
- BeatmapSetId = BeatmapSetId,
- FolderName = audioFolderName,
- FolderPath = Path.Combine("files", audioFolderName),
- FullPath = Path.Combine(OsuPath, "files", audioFolderName, audioHash)
- };
-
- realm.Dispose();
-
- return newMap;
- }
-
- public IDatabaseReader? GetReader()
- {
- return OsuPath != null ? new RealmReader(OsuPath) : null;
- }
-
- public bool Equals(IMapEntryBase? other)
- {
- return Hash == other?.Hash;
- }
-
- public int CompareTo(IMapEntryBase? other)
- {
- return string.Compare(Hash, other?.Hash, StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ToString()
- {
- return GetSongName();
- }
-
- public static bool operator ==(RealmMapEntryBase? left, IMapEntryBase? right)
- {
- return left?.Hash == right?.Hash;
- }
-
- public static bool operator !=(RealmMapEntryBase? left, IMapEntryBase? right)
- {
- return left?.Hash != right?.Hash;
- }
-
- public override bool Equals(object? other)
- {
- if (other is IMapEntryBase map)
- return Hash == map.Hash;
-
- return false;
- }
-
- public override int GetHashCode()
- {
- return BitConverter.ToInt32(Encoding.UTF8.GetBytes(Hash));
- }
-}
\ No newline at end of file
diff --git a/OsuPlayer.IO/DbReader/OsuCollectionReader.cs b/OsuPlayer.IO/DbReader/OsuCollectionReader.cs
index 4ebdd00a..e80489ce 100644
--- a/OsuPlayer.IO/DbReader/OsuCollectionReader.cs
+++ b/OsuPlayer.IO/DbReader/OsuCollectionReader.cs
@@ -1,4 +1,5 @@
using System.Text;
+using OsuPlayer.Data.DataModels;
namespace OsuPlayer.IO.DbReader;
@@ -14,10 +15,10 @@ public OsuCollectionReader(Stream input) : base(input)
/// Reads the collection from the collection.db
///
/// the osu full path
- /// a list
- public static async Task?> Read(string osuPath)
+ /// a list
+ public static async Task?> Read(string osuPath)
{
- var collections = new List();
+ var collections = new List();
var colLoc = Path.Combine(osuPath, "collection.db");
if (!File.Exists(colLoc)) return null;
@@ -37,9 +38,9 @@ public OsuCollectionReader(Stream input) : base(input)
return collections;
}
- private static Collection ReadFromStream(OsuCollectionReader r)
+ private static OsuCollection ReadFromStream(OsuCollectionReader r)
{
- var collection = new Collection
+ var collection = new OsuCollection
{
Name = r.ReadString()
};
diff --git a/OsuPlayer.IO/DbReader/OsuDbReader.cs b/OsuPlayer.IO/DbReader/OsuDbReader.cs
index 6d40df55..14ac1cc2 100644
--- a/OsuPlayer.IO/DbReader/OsuDbReader.cs
+++ b/OsuPlayer.IO/DbReader/OsuDbReader.cs
@@ -1,6 +1,7 @@
using System.Text;
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using Splat;
namespace OsuPlayer.IO.DbReader;
@@ -10,15 +11,14 @@ namespace OsuPlayer.IO.DbReader;
public class OsuDbReader : BinaryReader, IDatabaseReader
{
private readonly byte[] _buf = new byte[512];
- private string _path = string.Empty;
- public static int OsuDbVersion { get; private set; }
+ private readonly string _path;
+ private static int _osuDbVersion;
+ private readonly IDbReaderFactory _readerFactory;
- public OsuDbReader(Stream input) : base(input)
+ public OsuDbReader(Stream input, string path, IDbReaderFactory readerFactory) : base(input)
{
- }
+ _readerFactory = readerFactory;
- public OsuDbReader(Stream input, string path) : base(input)
- {
_path = string.Intern(path);
}
@@ -27,7 +27,7 @@ public OsuDbReader(Stream input, string path) : base(input)
var minBeatMaps = new List();
var ver = ReadInt32();
- OsuDbVersion = ver;
+ _osuDbVersion = ver;
var flag = ver is >= 20160408 and < 20191107;
ReadInt32();
@@ -76,7 +76,7 @@ public Dictionary GetBeatmapHashes()
var hashes = new Dictionary();
var ver = ReadInt32();
- OsuDbVersion = ver;
+ _osuDbVersion = ver;
var flag = ver is >= 20160408 and < 20191107;
ReadInt32();
@@ -104,22 +104,133 @@ public Dictionary GetBeatmapHashes()
return hashes;
}
- public async Task?> GetCollections(string path)
+ public async Task?> GetCollections(string path)
{
return await OsuCollectionReader.Read(path);
}
- public static async Task?> Read(string path)
+ public IMapEntry? ReadFullEntry(string path, IMapEntryBase mapEntryBase, long? dbOffset = null, Guid? id = null)
{
- var dbLoc = Path.Combine(path, "osu!.db");
+ if (dbOffset == null)
+ return null;
+
+ var version = _osuDbVersion;
+
+ BaseStream.Seek(dbOffset.Value, SeekOrigin.Begin);
+
+ ReadString(true); //Artist
+
+ var artistUnicode = "Unknown Artist";
+ if (version >= 20121008)
+ artistUnicode = ReadString();
+
+ ReadString(true); //Title
+
+ var titleUnicode = "Unknown Title";
+ if (version >= 20121008)
+ titleUnicode = ReadString();
+
+ ReadString(true); //Creator
+ ReadString(true); //Difficulty
+
+ var audioFileName = ReadString();
+ ReadString(true); //Hash
+
+ ReadString(true); //BeatmapFileName
+ ReadByte(); //RankedStatus
+ ReadUInt16(); //CountHitCircles
+ ReadUInt16(); //CountSliders
+ ReadUInt16(); //CountSpinners
+ ReadDateTime(); //LastModifiedTime
+
+ if (version >= 20140609)
+ {
+ ReadSingle(); //ApproachRate
+ ReadSingle(); //CircleSize
+ ReadSingle(); //HPDrainRate
+ ReadSingle(); //OverallDifficulty
+ }
+ else
+ {
+ //Float
+ ReadByte(); //ApproachRate
+ ReadByte(); //CircleSize
+ ReadByte(); //HPDrainRate
+ ReadByte(); //OverallDifficulty
+ }
+
+ ReadDouble(); //SliderVelocity
+
+ if (version >= 20140609)
+ {
+ ReadStarRating();
+ ReadStarRating();
+ ReadStarRating();
+ ReadStarRating();
+ }
+
+ ReadInt32(); //DrainTimeSeconds
+ ReadInt32(); //TotalTimeSeconds
+
+ ReadInt32(); //AudioPreviewTime
+ var timingCount = ReadInt32();
+
+ BaseStream.Position += 17 * timingCount;
+
+ ReadInt32();
+ ReadInt32(); //beatmapSetId
+
+ ReadInt32(); //ThreadId
+ ReadByte(); //GradeStandard
+ ReadByte(); //GradeTaiko
+ ReadByte(); //GradeCtB
+ ReadByte(); //GradeMania
+ ReadInt16(); //OffsetLocal
+ ReadSingle(); //StackLeniency
+ ReadByte(); //GameMode
+ ReadString(true); //SongSource
+ ReadString(true); //SongTags
+ ReadInt16(); //OffsetOnline
+ ReadString(true); //TitleFont
+ ReadBoolean(); //Unplayed
+ ReadDateTime(); //LastPlayed
+ ReadBoolean(); //IsOsz2
+
+ var folderName = ReadString();
+
+ ReadDateTime(); //LastCheckAgainstOsuRepo
+ ReadBoolean(); //IgnoreBeatmapSounds
+ ReadBoolean(); //IgnoreBeatmapSkin
+ ReadBoolean(); //DisableStoryBoard
+ ReadBoolean(); //DisableVideo
+ ReadBoolean(); //
- if (!File.Exists(dbLoc)) return null;
+ if (version < 20140609)
+ ReadInt16(); //OldUnknown1
- var file = File.OpenRead(dbLoc);
+ ReadInt32(); //LastEditTime
+ ReadByte(); //ManiaScrollSpeed
- var reader = new OsuDbReader(file, path);
+ var fullPath = Path.Combine(path, "Songs", folderName, audioFileName);
+ var folderPath = Path.Combine(path, "Songs", folderName);
- return await reader.ReadBeatmaps();
+ return new DbMapEntry
+ {
+ DbReaderFactory = _readerFactory,
+ DbOffset = dbOffset.Value,
+ OsuPath = path,
+ Artist = mapEntryBase.Artist,
+ ArtistUnicode = artistUnicode,
+ Title = mapEntryBase.Title,
+ TitleUnicode = titleUnicode,
+ AudioFileName = audioFileName,
+ BeatmapSetId = mapEntryBase.BeatmapSetId,
+ FolderName = folderName,
+ FolderPath = folderPath,
+ FullPath = fullPath,
+ Hash = mapEntryBase.Hash,
+ TotalTime = mapEntryBase.TotalTime
+ };
}
///
@@ -134,7 +245,7 @@ private void ReadFromStream(out DbMapEntryBase minBeatmap)
if (artist.Length == 0)
artist = "Unknown Artist";
- if (OsuDbVersion >= 20121008)
+ if (_osuDbVersion >= 20121008)
ReadString(true);
var title = string.Intern(ReadString());
@@ -142,7 +253,7 @@ private void ReadFromStream(out DbMapEntryBase minBeatmap)
if (title.Length == 0)
title = "Unknown Title";
- if (OsuDbVersion >= 20121008)
+ if (_osuDbVersion >= 20121008)
ReadString(true);
ReadString(true);
@@ -153,9 +264,9 @@ private void ReadFromStream(out DbMapEntryBase minBeatmap)
ReadString(true); //BeatmapFileName
- BaseStream.Seek(OsuDbVersion >= 20140609 ? 39 : 27, SeekOrigin.Current);
+ BaseStream.Seek(_osuDbVersion >= 20140609 ? 39 : 27, SeekOrigin.Current);
- if (OsuDbVersion >= 20140609)
+ if (_osuDbVersion >= 20140609)
{
ReadStarRating();
ReadStarRating();
@@ -187,10 +298,11 @@ private void ReadFromStream(out DbMapEntryBase minBeatmap)
ReadBoolean(); //IsOsz2
ReadString(true);
- BaseStream.Seek(OsuDbVersion < 20140609 ? 20 : 18, SeekOrigin.Current);
+ BaseStream.Seek(_osuDbVersion < 20140609 ? 20 : 18, SeekOrigin.Current);
minBeatmap = new DbMapEntryBase
{
+ DbReaderFactory = _readerFactory,
OsuPath = string.Intern(_path),
Artist = artist,
Title = title,
@@ -212,10 +324,10 @@ private long CalculateMapLength(out int setId, out string hash)
var initOffset = BaseStream.Position;
ReadString(true);
- if (OsuDbVersion >= 20121008) ReadString(true);
+ if (_osuDbVersion >= 20121008) ReadString(true);
ReadString(true);
- if (OsuDbVersion >= 20121008) ReadString(true);
+ if (_osuDbVersion >= 20121008) ReadString(true);
ReadString(true);
ReadString(true);
@@ -225,10 +337,10 @@ private long CalculateMapLength(out int setId, out string hash)
ReadString(true);
BaseStream.Seek(15, SeekOrigin.Current);
- BaseStream.Seek(OsuDbVersion >= 20140609 ? 16 : 4, SeekOrigin.Current);
+ BaseStream.Seek(_osuDbVersion >= 20140609 ? 16 : 4, SeekOrigin.Current);
BaseStream.Seek(8, SeekOrigin.Current);
- if (OsuDbVersion >= 20140609)
+ if (_osuDbVersion >= 20140609)
{
ReadStarRating();
ReadStarRating();
@@ -257,7 +369,7 @@ private long CalculateMapLength(out int setId, out string hash)
ReadString(true);
- BaseStream.Seek(OsuDbVersion < 20140609 ? 20 : 18, SeekOrigin.Current);
+ BaseStream.Seek(_osuDbVersion < 20140609 ? 20 : 18, SeekOrigin.Current);
return BaseStream.Position - initOffset;
}
diff --git a/OsuPlayer.IO/DbReader/RealmReader.cs b/OsuPlayer.IO/DbReader/RealmReader.cs
index 8c7ce07a..22899aaf 100644
--- a/OsuPlayer.IO/DbReader/RealmReader.cs
+++ b/OsuPlayer.IO/DbReader/RealmReader.cs
@@ -1,9 +1,11 @@
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
-using OsuPlayer.IO.Storage.LazerModels.Beatmaps;
-using OsuPlayer.IO.Storage.LazerModels.Collections;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.LazerModels.Beatmaps;
+using OsuPlayer.Data.LazerModels.Collections;
+using OsuPlayer.Data.LazerModels.Files;
using Realms;
using Realms.Dynamic;
+using Splat;
namespace OsuPlayer.IO.DbReader;
@@ -14,12 +16,16 @@ public class RealmReader : IDatabaseReader
{
private readonly string _path;
private readonly Realm _realm;
+ private readonly IDbReaderFactory _readerFactory;
- public RealmReader(string path)
+ public RealmReader(string path, IDbReaderFactory readerFactory)
{
+ _readerFactory = readerFactory;
+
_path = string.Intern(path);
var realmLoc = Path.Combine(_path, "client.realm");
+
var realmConfig = new RealmConfiguration(realmLoc)
{
IsDynamic = true,
@@ -44,20 +50,20 @@ public Dictionary GetBeatmapHashes()
return hashes;
}
- public Task> GetCollections(string path)
+ public Task> GetCollections(string path)
{
if (File.Exists(Path.Combine(path, "collection.db"))) return OsuCollectionReader.Read(path);
var dynamicRealmObjects = _realm.DynamicApi.All(nameof(BeatmapCollection)).ToList().OfType().ToList();
- var collections = new List();
+ var collections = new List();
foreach (var realmObject in dynamicRealmObjects)
{
var name = realmObject.DynamicApi.Get(nameof(BeatmapCollection.Name));
var hashes = realmObject.DynamicApi.GetList(nameof(BeatmapCollection.BeatmapMD5Hashes));
- var col = new Collection(name, hashes.ToList());
+ var col = new OsuCollection(name, hashes.ToList());
collections.Add(col);
}
@@ -65,6 +71,63 @@ public Task> GetCollections(string path)
return Task.FromResult(collections);
}
+ public IMapEntry? ReadFullEntry(string path, IMapEntryBase mapEntryBase, long? dbOffset = null, Guid? id = null)
+ {
+ if (string.IsNullOrWhiteSpace(path) || id == null)
+ return null;
+
+ var beatmap = (DynamicRealmObject) _realm.DynamicApi.Find("BeatmapSet", id);
+
+ if (beatmap == default)
+ return null;
+
+ var beatmaps = beatmap.DynamicApi.GetList(nameof(BeatmapSetInfo.Beatmaps));
+ var metadata = beatmaps.First().DynamicApi.Get(nameof(BeatmapInfo.Metadata)).DynamicApi;
+
+ var files = (RealmList) beatmap.DynamicApi.GetList(nameof(BeatmapSetInfo.Files));
+
+ var audioFileName = metadata.Get(nameof(BeatmapMetadata.AudioFile));
+ var backgroundFileName = metadata.Get(nameof(BeatmapMetadata.BackgroundFile));
+
+ var audioFile = (IRealmObjectBase) files.FirstOrDefault(x =>
+ string.Equals(x.DynamicApi.Get(nameof(RealmNamedFileUsage.Filename)), audioFileName, StringComparison.CurrentCultureIgnoreCase));
+ var backgroundFile = (IRealmObjectBase) files.FirstOrDefault(x =>
+ string.Equals(x.DynamicApi.Get(nameof(RealmNamedFileUsage.Filename)), backgroundFileName, StringComparison.CurrentCultureIgnoreCase));
+
+ if (audioFile == null)
+ return null;
+
+ var audioHash = audioFile.DynamicApi.Get(nameof(RealmNamedFileUsage.File)).DynamicApi.Get(nameof(RealmFile.Hash));
+ var backgroundHash = backgroundFile?.DynamicApi.Get(nameof(RealmNamedFileUsage.File)).DynamicApi.Get(nameof(RealmFile.Hash));
+
+ var audioFolderName = Path.Combine($"{audioHash[0]}", $"{audioHash[0]}{audioHash[1]}");
+ var backgroundFolderName = Path.Combine($"{backgroundHash?[0]}", $"{backgroundHash?[0]}{backgroundHash?[1]}");
+
+ var newMap = new RealmMapEntry
+ {
+ DbReaderFactory = _readerFactory,
+ Id = id.Value,
+ OsuPath = string.Intern(path),
+ Artist = string.Intern(mapEntryBase.Artist),
+ ArtistUnicode = metadata.Get(nameof(BeatmapMetadata.ArtistUnicode)),
+ Title = mapEntryBase.Title,
+ TitleUnicode = metadata.Get(nameof(BeatmapMetadata.TitleUnicode)),
+ AudioFileName = audioFileName,
+ BackgroundFileLocation = string.IsNullOrEmpty(backgroundFolderName)
+ ? string.Empty
+ : Path.Combine(path, "files", backgroundFolderName, backgroundHash!),
+ Hash = mapEntryBase.Hash,
+ BeatmapSetId = mapEntryBase.BeatmapSetId,
+ FolderName = audioFolderName,
+ FolderPath = Path.Combine("files", audioFolderName),
+ FullPath = Path.Combine(path, "files", audioFolderName, audioHash)
+ };
+
+ _realm.Dispose();
+
+ return newMap;
+ }
+
public Task?> ReadBeatmaps()
{
var minBeatMaps = new List();
@@ -86,6 +149,7 @@ public Task> GetCollections(string path)
minBeatMaps.Add(new RealmMapEntryBase
{
+ DbReaderFactory = _readerFactory,
OsuPath = string.Intern(_path),
Artist = string.Intern(artist),
Hash = hash,
@@ -116,7 +180,7 @@ public void Dispose()
/// an of read from the client.realm
public static async Task?> Read(string path)
{
- using var reader = new RealmReader(path);
+ using var reader = new RealmReader(path, Locator.Current.GetService());
return await reader.ReadBeatmaps();
}
diff --git a/OsuPlayer.IO/Importer/ISongSourceProvider.cs b/OsuPlayer.IO/Importer/ISongSourceProvider.cs
index 6e531ebc..43aa9812 100644
--- a/OsuPlayer.IO/Importer/ISongSourceProvider.cs
+++ b/OsuPlayer.IO/Importer/ISongSourceProvider.cs
@@ -1,7 +1,6 @@
using System.Collections.ObjectModel;
using DynamicData;
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
namespace OsuPlayer.IO.Importer;
diff --git a/OsuPlayer.IO/Importer/SongImporter.cs b/OsuPlayer.IO/Importer/SongImporter.cs
index 5acf558f..503138df 100644
--- a/OsuPlayer.IO/Importer/SongImporter.cs
+++ b/OsuPlayer.IO/Importer/SongImporter.cs
@@ -1,8 +1,12 @@
-using OsuPlayer.Data.OsuPlayer.Enums;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.Enums;
+using OsuPlayer.Data.OsuPlayer.Enums;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.DbReader;
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Config;
+using OsuPlayer.Services;
+using Splat;
namespace OsuPlayer.IO.Importer;
@@ -54,10 +58,19 @@ public static async Task ImportSongsAsync(ISongSourceProvider songSourceProvider
IEnumerable? readMaps = null;
+ var dbReaderFactory = Locator.Current.GetService();
+ var loggingService = Locator.Current.GetService();
+
if (File.Exists(Path.Combine(path, "osu!.db")))
- readMaps = await OsuDbReader.Read(path);
+ dbReaderFactory.Type = DbCreationType.OsuDb;
else if (File.Exists(Path.Combine(path, "client.realm")))
- readMaps = await RealmReader.Read(path);
+ dbReaderFactory.Type = DbCreationType.Realm;
+
+ using var reader = dbReaderFactory.CreateDatabaseReader(path);
+
+ loggingService.Log("Starting beatmap import...");
+
+ readMaps = await reader.ReadBeatmaps();
if (readMaps == null) return null;
@@ -65,6 +78,8 @@ public static async Task ImportSongsAsync(ISongSourceProvider songSourceProvider
//.DistinctBy(x => x.Title)
.Where(x => !string.IsNullOrEmpty(x.Title)).ToArray();
+ loggingService.Log($"Successfully imported {maps.Length} beatmaps.", LogType.Success);
+
return !maps.Any() ? null : maps;
}
}
\ No newline at end of file
diff --git a/OsuPlayer.IO/OsuPlayer.IO.csproj b/OsuPlayer.IO/OsuPlayer.IO.csproj
index e9638183..d722bca2 100644
--- a/OsuPlayer.IO/OsuPlayer.IO.csproj
+++ b/OsuPlayer.IO/OsuPlayer.IO.csproj
@@ -9,7 +9,7 @@
-
+
@@ -36,4 +36,4 @@
-
+
\ No newline at end of file
diff --git a/OsuPlayer.IO/Storage/Blacklist/Blacklist.cs b/OsuPlayer.IO/Storage/Blacklist/Blacklist.cs
index 4af58d13..976cd42e 100644
--- a/OsuPlayer.IO/Storage/Blacklist/Blacklist.cs
+++ b/OsuPlayer.IO/Storage/Blacklist/Blacklist.cs
@@ -1,7 +1,6 @@
using Newtonsoft.Json;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
namespace OsuPlayer.IO.Storage.Blacklist;
diff --git a/OsuPlayer.IO/Storage/Playlists/PlaylistManager.cs b/OsuPlayer.IO/Storage/Playlists/PlaylistManager.cs
index 953086d2..4377f772 100644
--- a/OsuPlayer.IO/Storage/Playlists/PlaylistManager.cs
+++ b/OsuPlayer.IO/Storage/Playlists/PlaylistManager.cs
@@ -1,6 +1,5 @@
-using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.DataModels;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.OsuPlayer.StorageModels;
namespace OsuPlayer.IO.Storage.Playlists;
diff --git a/OsuPlayer.Interfaces/OsuPlayer.Interfaces.csproj b/OsuPlayer.Interfaces/OsuPlayer.Interfaces.csproj
new file mode 100644
index 00000000..b2d779b3
--- /dev/null
+++ b/OsuPlayer.Interfaces/OsuPlayer.Interfaces.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OsuPlayer.Interfaces/Service/Endpoint/IOsuPlayerApiUserEndpoint.cs b/OsuPlayer.Interfaces/Service/Endpoint/IOsuPlayerApiUserEndpoint.cs
new file mode 100644
index 00000000..b78f8008
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/Endpoint/IOsuPlayerApiUserEndpoint.cs
@@ -0,0 +1,22 @@
+using System.Collections;
+using Avalonia.Media.Imaging;
+using OsuPlayer.Api.Data.API.EntityModels;
+using OsuPlayer.Api.Data.API.RequestModels.User;
+
+namespace OsuPlayer.Interfaces.Service.Endpoint;
+
+public interface IOsuPlayerApiUserEndpoint
+{
+ Task UpdateSongsPlayed(int amount, int beatmapSetId = -1);
+ Task UpdateXp(UpdateXpModel updateXpModel);
+ Task SetOnlineStatus(UserOnlineStatusModel data);
+ Task GetProfilePictureAsync(Guid currentUserUniqueId);
+ Task GetUserFromLoginToken();
+ Task EditUser(EditUserModel editUserModel);
+ Task SaveProfilePicture(byte[] data);
+ Task GetProfileBannerAsync(string? bannerUrl);
+ Task DeleteUser();
+ Task?> GetAllUsers();
+ Task?> GetActivityOfUser(Guid selectedUserUniqueId);
+ Task Register(AddUserModel addUserModel);
+}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/Services/IHistoryProvider.cs b/OsuPlayer.Interfaces/Service/IHistoryProvider.cs
similarity index 65%
rename from OsuPlayer/Modules/Services/IHistoryProvider.cs
rename to OsuPlayer.Interfaces/Service/IHistoryProvider.cs
index 8669353e..eee58386 100644
--- a/OsuPlayer/Modules/Services/IHistoryProvider.cs
+++ b/OsuPlayer.Interfaces/Service/IHistoryProvider.cs
@@ -1,8 +1,8 @@
-using System.Collections;
-using OsuPlayer.IO.DbReader.DataModels.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
+using Nein.Extensions.Bindables;
+using OsuPlayer.Data.DataModels.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
-namespace OsuPlayer.Modules.Audio.Interfaces;
+namespace OsuPlayer.Interfaces.Service;
///
/// This interface provides historic capabilities
diff --git a/OsuPlayer.Interfaces/Service/ILastFmApiService.cs b/OsuPlayer.Interfaces/Service/ILastFmApiService.cs
new file mode 100644
index 00000000..430b3abc
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/ILastFmApiService.cs
@@ -0,0 +1,14 @@
+namespace OsuPlayer.Interfaces.Service;
+
+public interface ILastFmApiService
+{
+ public void SetApiKeyAndSecret(string apiKey, string secret);
+ public Task Scrobble(string title, string artist);
+ public bool LoadSessionKey();
+ public Task LoadSessionKeyAsync();
+ public bool IsAuthorized();
+ public Task GetAuthToken();
+ public void AuthorizeToken();
+ public Task GetSessionKey();
+ public Task SaveSessionKeyAsync();
+}
\ No newline at end of file
diff --git a/OsuPlayer.Interfaces/Service/ILoggingService.cs b/OsuPlayer.Interfaces/Service/ILoggingService.cs
new file mode 100644
index 00000000..c743ff84
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/ILoggingService.cs
@@ -0,0 +1,8 @@
+using OsuPlayer.Services;
+
+namespace OsuPlayer.Interfaces.Service;
+
+public interface ILoggingService
+{
+ public void Log(string message, LogType logType = LogType.Info, object? data = null);
+}
\ No newline at end of file
diff --git a/OsuPlayer.Interfaces/Service/IOsuPlayerApiService.cs b/OsuPlayer.Interfaces/Service/IOsuPlayerApiService.cs
new file mode 100644
index 00000000..1fc7aaa6
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/IOsuPlayerApiService.cs
@@ -0,0 +1,12 @@
+using OsuPlayer.Api.Data.API.EntityModels;
+using OsuPlayer.Interfaces.Service.Endpoint;
+
+namespace OsuPlayer.Interfaces.Service;
+
+public interface IOsuPlayerApiService
+{
+ public IOsuPlayerApiUserEndpoint User { get; set; }
+
+ public Task LoginAndSaveAuthToken(string username, string password);
+ public Task LoginWithTokenAndSaveNewToken(string token);
+}
\ No newline at end of file
diff --git a/OsuPlayer.Interfaces/Service/IOsuPlayerService.cs b/OsuPlayer.Interfaces/Service/IOsuPlayerService.cs
new file mode 100644
index 00000000..92b0433d
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/IOsuPlayerService.cs
@@ -0,0 +1,7 @@
+namespace OsuPlayer.Interfaces.Service;
+
+public interface IOsuPlayerService
+{
+ protected abstract string ServiceName { get; }
+ protected abstract string ServiceTag();
+}
\ No newline at end of file
diff --git a/OsuPlayer.Interfaces/Service/IProfileManagerService.cs b/OsuPlayer.Interfaces/Service/IProfileManagerService.cs
new file mode 100644
index 00000000..f93baa70
--- /dev/null
+++ b/OsuPlayer.Interfaces/Service/IProfileManagerService.cs
@@ -0,0 +1,11 @@
+using OsuPlayer.Data.DataModels;
+
+namespace OsuPlayer.Interfaces.Service;
+
+public interface IProfileManagerService
+{
+ public User? User { get; set; }
+
+ public Task Login(string username, string password);
+ public Task Login(string token);
+}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/ShuffleImpl/IShuffleImpl.cs b/OsuPlayer.Interfaces/Service/IShuffleImpl.cs
similarity index 96%
rename from OsuPlayer/Modules/ShuffleImpl/IShuffleImpl.cs
rename to OsuPlayer.Interfaces/Service/IShuffleImpl.cs
index 7078d486..8067aec0 100644
--- a/OsuPlayer/Modules/ShuffleImpl/IShuffleImpl.cs
+++ b/OsuPlayer.Interfaces/Service/IShuffleImpl.cs
@@ -1,6 +1,6 @@
using OsuPlayer.Data.OsuPlayer.Enums;
-namespace OsuPlayer.Modules.ShuffleImpl;
+namespace OsuPlayer.Interfaces.Service;
///
/// This interface is used as a base for all shuffle algorithm implementations.
diff --git a/OsuPlayer/Modules/Services/IShuffleServiceProvider.cs b/OsuPlayer.Interfaces/Service/IShuffleServiceProvider.cs
similarity index 85%
rename from OsuPlayer/Modules/Services/IShuffleServiceProvider.cs
rename to OsuPlayer.Interfaces/Service/IShuffleServiceProvider.cs
index fe444010..68270a55 100644
--- a/OsuPlayer/Modules/Services/IShuffleServiceProvider.cs
+++ b/OsuPlayer.Interfaces/Service/IShuffleServiceProvider.cs
@@ -1,6 +1,4 @@
-using OsuPlayer.Modules.ShuffleImpl;
-
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Interfaces.Service;
///
/// This interface provides a service provider for shuffle implementations.
diff --git a/OsuPlayer/Modules/Services/ISortProvider.cs b/OsuPlayer.Interfaces/Service/ISortProvider.cs
similarity index 71%
rename from OsuPlayer/Modules/Services/ISortProvider.cs
rename to OsuPlayer.Interfaces/Service/ISortProvider.cs
index 84dff434..78ad9d33 100644
--- a/OsuPlayer/Modules/Services/ISortProvider.cs
+++ b/OsuPlayer.Interfaces/Service/ISortProvider.cs
@@ -1,8 +1,10 @@
using DynamicData;
+using Nein.Extensions.Bindables;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
-using OsuPlayer.IO.DbReader.Interfaces;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Interfaces.Service;
public interface ISortProvider
{
diff --git a/OsuPlayer/Modules/Services/IStatisticsProvider.cs b/OsuPlayer.Interfaces/Service/IStatisticsProvider.cs
similarity index 95%
rename from OsuPlayer/Modules/Services/IStatisticsProvider.cs
rename to OsuPlayer.Interfaces/Service/IStatisticsProvider.cs
index 55580ca2..5373d607 100644
--- a/OsuPlayer/Modules/Services/IStatisticsProvider.cs
+++ b/OsuPlayer.Interfaces/Service/IStatisticsProvider.cs
@@ -1,9 +1,9 @@
using System.ComponentModel;
-using System.Threading.Tasks;
using LiveChartsCore.Defaults;
+using Nein.Extensions.Bindables;
using OsuPlayer.Api.Data.API.Enums;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Interfaces.Service;
public interface IStatisticsProvider
{
diff --git a/OsuPlayer.Network/API/Service/AbstractApiBase.cs b/OsuPlayer.Network/API/AbstractApiBase.cs
similarity index 82%
rename from OsuPlayer.Network/API/Service/AbstractApiBase.cs
rename to OsuPlayer.Network/API/AbstractApiBase.cs
index 81c450c9..0de2993b 100644
--- a/OsuPlayer.Network/API/Service/AbstractApiBase.cs
+++ b/OsuPlayer.Network/API/AbstractApiBase.cs
@@ -3,22 +3,37 @@
using System.Text;
using Newtonsoft.Json;
using OsuPlayer.Api.Data.API;
-using OsuPlayer.Network.Online;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Services;
+using Splat;
-namespace OsuPlayer.Network.API.Service;
+namespace OsuPlayer.Network.API;
public abstract class AbstractApiBase
{
+ protected internal abstract string ApiName { get; }
+
+ protected internal readonly ILoggingService loggingService;
+ private readonly IProfileManagerService _profileManager;
+
protected static CancellationTokenSource CancellationTokenSource = new();
protected internal string Url => GetApiUrl();
protected string? UserAuthToken { get; set; }
-
+
+ protected AbstractApiBase()
+ {
+ loggingService = Locator.Current.GetService();
+ _profileManager = Locator.Current.GetService();
+
+ loggingService.Log($"{ApiName} uses the following base URL: {Url}");
+ }
+
private string GetApiUrl()
{
var url = "https://osuplayer.founntain.dev/";
-
+
bool.TryParse(Environment.GetEnvironmentVariable("USE_LOCAL_API"), out var useLocalApi);
bool.TryParse(Environment.GetEnvironmentVariable("USE_SANDBOX_API"), out var useSandboxApi);
@@ -35,12 +50,14 @@ private string GetApiUrl()
return url;
}
- protected internal void ParseWebException(Exception ex)
+ protected internal void ParseWebException(Exception ex, Uri url)
{
if (ex.GetType() != typeof(WebException)) return;
var webEx = (WebException) ex;
+ loggingService.Log($"Error while requesting {url}: {webEx.Message}", LogType.Error, webEx);
+
if (webEx.Status != WebExceptionStatus.ConnectFailure && webEx.Status != WebExceptionStatus.Timeout) return;
if (Constants.OfflineMode) return;
@@ -52,10 +69,10 @@ protected internal void ParseWebException(Exception ex)
///
// protected void CancelCancellationToken()
// {
- // // TODO: Currently does nothing, because it breaks the functionality a bit.
+ // // TODO: Currently does nothing, because it breaks the functionality a bit.
// // TODO: This needs to be re-thinked a bit!
// return;
- //
+ //
// CancellationTokenSource.Cancel();
// CancellationTokenSource = new ();
// }
@@ -83,15 +100,17 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}{controller}/{action}");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}{controller}/{action}");
-
var req = new HttpRequestMessage(HttpMethod.Delete, url);
- req.Headers.Add("username", ProfileManager.User?.Name);
+ req.Headers.Add("username", _profileManager.User?.Name);
req.Headers.Add("session-token", UserAuthToken);
req.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
@@ -108,7 +127,7 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -152,19 +171,19 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}{controller}/{action}");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}{controller}/{action}");
-
var req = new HttpRequestMessage(HttpMethod.Get, url);
- req.Headers.Add("username", ProfileManager.User?.Name);
+ req.Headers.Add("username", _profileManager.User?.Name);
req.Headers.Add("session-token", UserAuthToken);
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -175,7 +194,7 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -194,19 +213,19 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}{controller}/{action}?{parameters}");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}{controller}/{action}?{parameters}");
-
var req = new HttpRequestMessage(HttpMethod.Get, url);
- req.Headers.Add("username", ProfileManager.User?.Name);
+ req.Headers.Add("username", _profileManager.User?.Name);
req.Headers.Add("session-token", UserAuthToken);
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -217,7 +236,7 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -241,21 +260,21 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}{controller}/{action}");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}{controller}/{action}");
-
var req = new HttpRequestMessage(HttpMethod.Post, url);
- req.Headers.Add("username", ProfileManager.User?.Name);
+ req.Headers.Add("username", _profileManager.User?.Name);
req.Headers.Add("session-token", UserAuthToken);
req.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -266,7 +285,7 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -286,19 +305,19 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}{controller}/{action}?{parameters}");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}{controller}/{action}?{parameters}");
-
var req = new HttpRequestMessage(HttpMethod.Post, url);
- req.Headers.Add("username", ProfileManager.User?.Name);
+ req.Headers.Add("username", _profileManager.User?.Name);
req.Headers.Add("session-token", UserAuthToken);
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -309,7 +328,7 @@ protected AuthenticationHeaderValue GetAuthorizationHeader(string username, stri
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/Nortfox.cs b/OsuPlayer.Network/API/NorthFox/Nortfox.cs
similarity index 83%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/Nortfox.cs
rename to OsuPlayer.Network/API/NorthFox/Nortfox.cs
index dcdd6b0b..a94563c8 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/Nortfox.cs
+++ b/OsuPlayer.Network/API/NorthFox/Nortfox.cs
@@ -3,15 +3,19 @@
using OsuPlayer.Api.Data.API;
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.RequestModels.User.Responses;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Interfaces.Service.Endpoint;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
///
/// NorthFox is the wrapper for the OsuPlayer.API and provides access to all public available API Endpoints!
-/// Yes I like foxes C:
+/// Yes I like foxes 🦊
///
-public class NorthFox : AbstractApiBase
+public class NorthFox : AbstractApiBase, IOsuPlayerApiService
{
+ protected internal override string ApiName => "NorthFox API 🦊";
+
#region API Endpoints
public NorthFoxActivityEndpoint Activity { get; set; }
@@ -19,7 +23,7 @@ public class NorthFox : AbstractApiBase
public NorthFoxBadgeEndpoint Badge { get; set; }
public NorthFoxBeatmapEndpoint Beatmap { get; set; }
public NorthFoxEventEndpoint Event { get; set; }
- public NorthFoxUserEndpoint User { get; set; }
+ public IOsuPlayerApiUserEndpoint User { get; set; }
public NorthFoxUserStatisticsEndpoint UserStatistics { get; set; }
#endregion
@@ -34,9 +38,9 @@ public NorthFox()
User = new NorthFoxUserEndpoint(this);
UserStatistics = new NorthFoxUserStatisticsEndpoint(this);
}
-
+
#region Authentication
-
+
public async Task LoginAndSaveAuthToken(string username, string password)
{
var response = await Login(username, password);
@@ -64,17 +68,17 @@ public NorthFox()
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}User/login");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}User/login");
-
var req = new HttpRequestMessage(HttpMethod.Post, url);
req.Headers.Authorization = GetAuthorizationHeader(username, password);
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -85,7 +89,7 @@ public NorthFox()
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -96,18 +100,18 @@ public NorthFox()
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{Url}User/loginWithToken");
+
+ loggingService.Log($"Requesting => {ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{Url}User/loginWithToken");
-
var req = new HttpRequestMessage(HttpMethod.Post, url);
req.Headers.Add("session-token", token);
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject>(await result.Content.ReadAsStringAsync());
@@ -118,7 +122,7 @@ public NorthFox()
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Activity.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.Activity.cs
similarity index 89%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Activity.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.Activity.cs
index 2aa89b71..bb08166d 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Activity.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.Activity.cs
@@ -1,16 +1,16 @@
using OsuPlayer.Api.Data.API.EntityModels;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxActivityEndpoint
{
private readonly AbstractApiBase _apiBase;
-
+
public NorthFoxActivityEndpoint(AbstractApiBase apiBase)
{
_apiBase = apiBase;
}
-
+
#region GET Requests
public async Task?> GetAllActivities()
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.ApiStatistics.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.ApiStatistics.cs
similarity index 89%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.ApiStatistics.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.ApiStatistics.cs
index 96c7481d..7216ee97 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.ApiStatistics.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.ApiStatistics.cs
@@ -1,16 +1,16 @@
using OsuPlayer.Api.Data.API.Models;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxApiStatisticsEndpoint
{
private readonly AbstractApiBase _apiBase;
-
+
public NorthFoxApiStatisticsEndpoint(AbstractApiBase apiBase)
{
_apiBase = apiBase;
}
-
+
#region GET Requests
public async Task GetApiStatistics()
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Badge.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.Badge.cs
similarity index 96%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Badge.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.Badge.cs
index 624598c8..956a28a9 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Badge.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.Badge.cs
@@ -1,6 +1,6 @@
using OsuPlayer.Api.Data.API.EntityModels;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxBadgeEndpoint
{
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Beatmap.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.Beatmap.cs
similarity index 95%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Beatmap.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.Beatmap.cs
index bbc0db11..8a52ae99 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Beatmap.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.Beatmap.cs
@@ -3,7 +3,7 @@
using OsuPlayer.Api.Data.API.RequestModels.Statistics;
using OsuPlayer.Api.Data.API.ResponseModels;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxBeatmapEndpoint
{
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Event.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.Event.cs
similarity index 90%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Event.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.Event.cs
index 2bed1e97..3a4aaed0 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.Event.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.Event.cs
@@ -1,6 +1,6 @@
using OsuPlayer.Api.Data.API.EntityModels;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxEventEndpoint
{
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.User.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.User.cs
similarity index 88%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.User.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.User.cs
index 6a38d8f7..3da17a39 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.User.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.User.cs
@@ -1,18 +1,19 @@
using Avalonia.Media.Imaging;
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.RequestModels.User;
+using OsuPlayer.Interfaces.Service.Endpoint;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
-public class NorthFoxUserEndpoint
+public class NorthFoxUserEndpoint : IOsuPlayerApiUserEndpoint
{
private readonly AbstractApiBase _apiBase;
-
+
public NorthFoxUserEndpoint(AbstractApiBase apiBase)
{
_apiBase = apiBase;
}
-
+
#region DELETE Requests
public async Task DeleteUser()
@@ -38,17 +39,21 @@ public async Task DeleteUser()
if (Constants.OfflineMode)
return default;
+ var url = new Uri($"{_apiBase.Url}User/getProfilePicture?id={uniqueId}");
+
+ _apiBase.loggingService.Log($"Requesting => {_apiBase.ApiName} => {url}");
+
try
{
using var client = new HttpClient();
- var data = await client.GetAsync(new Uri($"{_apiBase.Url}User/getProfilePicture?id={uniqueId}"));
+ var data = await client.GetAsync(url);
return new Bitmap(await data.Content.ReadAsStreamAsync());
}
catch (Exception ex)
{
- _apiBase.ParseWebException(ex);
+ _apiBase.ParseWebException(ex, url);
return default;
}
@@ -66,6 +71,8 @@ public async Task DeleteUser()
using var client = new HttpClient();
+ _apiBase.loggingService.Log($"Requesting => {_apiBase.ApiName} => {bannerUrl}");
+
try
{
var data = await client.GetAsync(bannerUrl);
diff --git a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.UserStatistics.cs b/OsuPlayer.Network/API/NorthFox/NorthFox.UserStatistics.cs
similarity index 93%
rename from OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.UserStatistics.cs
rename to OsuPlayer.Network/API/NorthFox/NorthFox.UserStatistics.cs
index b801cdb4..9a74c67c 100644
--- a/OsuPlayer.Network/API/Service/NorthFox/Endpoints/NorthFox.UserStatistics.cs
+++ b/OsuPlayer.Network/API/NorthFox/NorthFox.UserStatistics.cs
@@ -1,7 +1,7 @@
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.RequestModels.Statistics;
-namespace OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+namespace OsuPlayer.Network.API.NorthFox;
public class NorthFoxUserStatisticsEndpoint
{
diff --git a/OsuPlayer.Network/Discord/DiscordClient.cs b/OsuPlayer.Network/Discord/DiscordClient.cs
index 965c17f1..11ae3d3c 100644
--- a/OsuPlayer.Network/Discord/DiscordClient.cs
+++ b/OsuPlayer.Network/Discord/DiscordClient.cs
@@ -1,20 +1,22 @@
using System.Diagnostics;
-using System.Net;
using System.Reflection;
using System.Text;
using DiscordRPC;
-using DiscordRPC.Logging;
using DiscordRPC.Message;
using Nein.Extensions;
-using OsuPlayer.Network.Online;
+using OsuPlayer.Interfaces.Service;
+using Splat;
+using ConsoleLogger = DiscordRPC.Logging.ConsoleLogger;
+using LogLevel = DiscordRPC.Logging.LogLevel;
namespace OsuPlayer.Network.Discord;
public class DiscordClient
{
private const string ApplicationId = "506435812397940736";
- private readonly DiscordRpcClient _client;
private const string DefaultImageKey = "logo";
+ private readonly DiscordRpcClient _client;
+ private readonly IProfileManagerService _profileManager;
private readonly string _defaultOsuThumbnailUrl = "https://assets.ppy.sh/beatmaps/{0}/covers/list.jpg";
///
@@ -22,8 +24,13 @@ public class DiscordClient
///
private readonly Assets _defaultAssets;
- public DiscordClient()
+ public DiscordClient() : this(Locator.Current.GetRequiredService())
+ {
+ }
+
+ public DiscordClient(IProfileManagerService profileManager)
{
+ _profileManager = profileManager;
_client = new DiscordRpcClient(ApplicationId);
_defaultAssets = new Assets
@@ -92,7 +99,7 @@ public async Task UpdatePresence(string details, string state, int beatmapSetId
}
var timestamps = durationLeft == null ? null : Timestamps.FromTimeSpan(durationLeft.Value);
-
+
_client.SetPresence(new RichPresence
{
Details = details,
@@ -121,10 +128,10 @@ public async Task UpdatePresence(string details, string state, int beatmapSetId
return null;
return new()
- {
- LargeImageKey = url,
- LargeImageText = $"osu!player v{Assembly.GetEntryAssembly().ToVersionString()}"
- };
+ {
+ LargeImageKey = url,
+ LargeImageText = $"osu!player v{Assembly.GetEntryAssembly().ToVersionString()}"
+ };
}
private Button[]? GetButtons()
@@ -138,12 +145,12 @@ public async Task UpdatePresence(string details, string state, int beatmapSetId
}
};
- if (ProfileManager.User is null || string.IsNullOrWhiteSpace(ProfileManager.User.Name)) return buttons.ToArray();
+ if (_profileManager.User is null || string.IsNullOrWhiteSpace(_profileManager.User.Name)) return buttons.ToArray();
buttons.Add(new Button
{
- Label = $"{ProfileManager.User.Name}'s profile",
- Url = $"https://stats.founntain.dev/user/{Uri.EscapeDataString(ProfileManager.User.Name)}"
+ Label = $"{_profileManager.User.Name}'s profile",
+ Url = $"https://stats.founntain.dev/user/{Uri.EscapeDataString(_profileManager.User.Name)}"
}
);
diff --git a/OsuPlayer.Network/LastFM/Responses/TokenResponse.cs b/OsuPlayer.Network/LastFM/Responses/TokenResponse.cs
deleted file mode 100644
index 14efd063..00000000
--- a/OsuPlayer.Network/LastFM/Responses/TokenResponse.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace OsuPlayer.Network.LastFM.Responses;
-
-public record TokenResponse(string Token);
\ No newline at end of file
diff --git a/OsuPlayer.Network/LastFM/LastFmApi.cs b/OsuPlayer.Network/LastFm/LastFmApi.cs
similarity index 90%
rename from OsuPlayer.Network/LastFM/LastFmApi.cs
rename to OsuPlayer.Network/LastFm/LastFmApi.cs
index cdcb2c45..c6ded02b 100644
--- a/OsuPlayer.Network/LastFM/LastFmApi.cs
+++ b/OsuPlayer.Network/LastFm/LastFmApi.cs
@@ -2,14 +2,19 @@
using System.Text;
using System.Xml;
using Nein.Extensions;
+using OsuPlayer.Data.LazerModels.Extensions;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Storage.Config;
-using OsuPlayer.IO.Storage.LazerModels.Extensions;
-using OsuPlayer.Network.LastFM.Responses;
+using OsuPlayer.Network.LastFm.Responses;
+using OsuPlayer.Services;
+using Splat;
-namespace OsuPlayer.Network.LastFM;
+namespace OsuPlayer.Network.LastFm;
-public class LastFmApi : WebRequestBase
+public class LastFmApi : WebRequestBase, ILastFmApiService
{
+ private readonly ILoggingService _loggingService;
+
///
/// The Last.FM API-Key of the user
///
@@ -29,6 +34,8 @@ public class LastFmApi : WebRequestBase
public LastFmApi()
{
+ _loggingService = Locator.Current.GetRequiredService();
+
BaseUrl = "http://ws.audioscrobbler.com/2.0/?format=json";
using var config = new Config();
@@ -38,15 +45,6 @@ public LastFmApi()
_authToken = string.Empty;
}
- public LastFmApi(string apiKey, string secret)
- {
- _apiKey = apiKey;
- _secret = secret;
- _authToken = string.Empty;
-
- BaseUrl = "http://ws.audioscrobbler.com/2.0/?format=json";
- }
-
public void SetApiKeyAndSecret(string apiKey, string secret)
{
_apiKey = apiKey;
@@ -62,7 +60,8 @@ public async Task Scrobble(string title, string artist)
{
if (string.IsNullOrWhiteSpace(_sessionKey))
{
- Console.WriteLine("can't scrobble to the last.fm api, because there isn't a valid session key");
+ _loggingService.Log("Can't scrobble to the last.fm api, because there isn't a valid session key", LogType.Warning);
+
return;
}
@@ -91,6 +90,7 @@ public async Task SaveSessionKeyAsync()
config.Container.LastFmApiKey = _apiKey;
config.Container.LastFmSecret = _secret;
}
+
///
/// Loads the last.fm Session Key from the users file system
///
@@ -104,7 +104,7 @@ public bool LoadSessionKey()
return !string.IsNullOrWhiteSpace(_sessionKey);
}
-
+
///
/// Loads the last.fm Session Key from the users file system asynchronously
///
@@ -174,20 +174,15 @@ public async Task GetSessionKey()
/// a
private async Task SessionRequest(string route)
{
+ var baseUrl = $"http://ws.audioscrobbler.com/2.0/?api_key={_apiKey}";
+ var url = new Uri($"{baseUrl}{route}");
+
try
{
using var client = new HttpClient();
- var baseUrl = $"http://ws.audioscrobbler.com/2.0/?api_key={_apiKey}";
-
- var url = new Uri($"{baseUrl}{route}");
-
var req = new HttpRequestMessage(HttpMethod.Get, url);
-
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
-
var respString = await result.Content.ReadAsStringAsync();
var xmlDoc = new XmlDocument();
@@ -200,7 +195,7 @@ public async Task GetSessionKey()
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
diff --git a/OsuPlayer.Network/LastFM/Responses/SessionResponse.cs b/OsuPlayer.Network/LastFm/Responses/SessionResponse.cs
similarity index 59%
rename from OsuPlayer.Network/LastFM/Responses/SessionResponse.cs
rename to OsuPlayer.Network/LastFm/Responses/SessionResponse.cs
index 4a2db73d..65c8339f 100644
--- a/OsuPlayer.Network/LastFM/Responses/SessionResponse.cs
+++ b/OsuPlayer.Network/LastFm/Responses/SessionResponse.cs
@@ -1,3 +1,3 @@
-namespace OsuPlayer.Network.LastFM.Responses;
+namespace OsuPlayer.Network.LastFm.Responses;
public record SessionResponse(string? Name, string Key, int Subscriber);
\ No newline at end of file
diff --git a/OsuPlayer.Network/LastFm/Responses/TokenResponse.cs b/OsuPlayer.Network/LastFm/Responses/TokenResponse.cs
new file mode 100644
index 00000000..fbae3c3a
--- /dev/null
+++ b/OsuPlayer.Network/LastFm/Responses/TokenResponse.cs
@@ -0,0 +1,3 @@
+namespace OsuPlayer.Network.LastFm.Responses;
+
+public record TokenResponse(string Token);
\ No newline at end of file
diff --git a/OsuPlayer.Network/Online/ProfileManager.cs b/OsuPlayer.Network/Online/ProfileManager.cs
deleted file mode 100644
index 788da41d..00000000
--- a/OsuPlayer.Network/Online/ProfileManager.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
-using Splat;
-
-namespace OsuPlayer.Network.Online;
-
-public class ProfileManager
-{
- public static User? User = User ?? new User();
-
- public static async Task Login(string username, string password)
- {
- var result = await Locator.Current.GetService().LoginAndSaveAuthToken(username, password);
-
- // If login failed, we set the user to its default value
- if (result == default)
- {
- User = default;
-
- return;
- }
-
- User = new User(result);
- }
-
- public static async Task Login(string token)
- {
- if (string.IsNullOrWhiteSpace(token)) return;
-
- var result = await Locator.Current.GetService().LoginWithTokenAndSaveNewToken(token);
-
- // If login via token failed, we set the User to its default value
- if (result == default)
- {
- User = default;
-
- return;
- }
-
- User = new User(result);
- }
-}
\ No newline at end of file
diff --git a/OsuPlayer.Network/OsuPlayer.Network.csproj b/OsuPlayer.Network/OsuPlayer.Network.csproj
index aebc6234..e533e183 100644
--- a/OsuPlayer.Network/OsuPlayer.Network.csproj
+++ b/OsuPlayer.Network/OsuPlayer.Network.csproj
@@ -17,7 +17,7 @@
-
+
-
+
\ No newline at end of file
diff --git a/OsuPlayer.Network/WebRequestBase.cs b/OsuPlayer.Network/WebRequestBase.cs
index f1a39eee..94625f44 100644
--- a/OsuPlayer.Network/WebRequestBase.cs
+++ b/OsuPlayer.Network/WebRequestBase.cs
@@ -1,59 +1,64 @@
using System.Net;
using System.Text;
using Newtonsoft.Json;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Services;
+using Splat;
namespace OsuPlayer.Network;
public class WebRequestBase : IWebRequest
{
+ private readonly ILoggingService _loggingService;
protected string BaseUrl;
- protected CancellationTokenSource CancellationTokenSource = new();
+ protected readonly CancellationTokenSource CancellationTokenSource = new();
- public WebRequestBase()
+ protected WebRequestBase() :this(string.Empty)
{
- BaseUrl = string.Empty;
}
public WebRequestBase(string baseUrl)
{
BaseUrl = baseUrl;
+
+ _loggingService = Locator.Current.GetService();
}
-
- protected void ParseWebException(Exception ex)
+
+ protected void ParseWebException(Exception ex, Uri url)
{
if (ex.GetType() != typeof(WebException)) return;
var webEx = (WebException) ex;
- if (webEx.Status != WebExceptionStatus.ConnectFailure && webEx.Status != WebExceptionStatus.Timeout) return;
+ _loggingService.Log($"Error while requesting {url}: {webEx.Message}", LogType.Error, webEx);
}
public virtual async Task GetRequest(string route, TRequest? data = default)
{
+ var url = new Uri($"{BaseUrl}{route}");
+
+ _loggingService.Log($"Request => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{BaseUrl}{route}");
-
var req = new HttpRequestMessage(HttpMethod.Get, url);
if ( data != null )
req.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var respString = await result.Content.ReadAsStringAsync();
-
+
var response = JsonConvert.DeserializeObject(respString);
return response;
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
@@ -61,19 +66,21 @@ public virtual async Task GetRequest(string rout
public async Task GetRequestWithHttpResponseMessage(string route)
{
+ var url = new Uri($"{BaseUrl}{route}");
+
+ _loggingService.Log($"Request => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{BaseUrl}{route}");
-
var req = new HttpRequestMessage(HttpMethod.Get, url);
-
+
return await client.SendAsync(req, CancellationTokenSource.Token);
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -81,12 +88,14 @@ public async Task GetRequestWithHttpResponseMessage(string
public virtual async Task PostRequest(string route, TRequest? data = default)
{
+ var url = new Uri($"{BaseUrl}{route}");
+
+ _loggingService.Log($"Request => {url}");
+
try
{
using var client = new HttpClient();
- var url = new Uri($"{BaseUrl}{route}");
-
var req = new HttpRequestMessage(HttpMethod.Post, url);
if(data != null)
@@ -97,8 +106,6 @@ public virtual async Task PostRequest(string rou
req.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
}
- // CancelCancellationToken();
-
var result = await client.SendAsync(req, CancellationTokenSource.Token);
var response = JsonConvert.DeserializeObject(await result.Content.ReadAsStringAsync());
@@ -107,7 +114,7 @@ public virtual async Task PostRequest(string rou
}
catch (Exception ex)
{
- ParseWebException(ex);
+ ParseWebException(ex, url);
return default;
}
diff --git a/OsuPlayer/Modules/Services/ApiStatisticsProvider.cs b/OsuPlayer.Services/ApiStatisticsService.cs
similarity index 50%
rename from OsuPlayer/Modules/Services/ApiStatisticsProvider.cs
rename to OsuPlayer.Services/ApiStatisticsService.cs
index f7e8636f..8ddcf3e4 100644
--- a/OsuPlayer/Modules/Services/ApiStatisticsProvider.cs
+++ b/OsuPlayer.Services/ApiStatisticsService.cs
@@ -1,27 +1,37 @@
using System.ComponentModel;
-using System.Threading.Tasks;
using Avalonia.Threading;
using LiveChartsCore.Defaults;
using Nein.Extensions;
+using Nein.Extensions.Bindables;
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.Enums;
using OsuPlayer.Api.Data.API.RequestModels.User;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Interfaces.Service;
using Splat;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Services;
-public class ApiStatisticsProvider : IStatisticsProvider
+public class ApiStatisticsService : OsuPlayerService, IStatisticsProvider
{
public BindableList GraphValues { get; } = new();
+
+ public override string ServiceName => "API_STATISTICS_SERVICE";
public event PropertyChangedEventHandler? UserDataChanged;
+ private readonly IProfileManagerService _profileManager;
+
+ public ApiStatisticsService(IProfileManagerService profileManager)
+ {
+ _profileManager = profileManager;
+ }
+
public async Task UpdateOnlineStatus(UserOnlineStatusType statusType, string? song = null, string? checksum = null)
{
- if (ProfileManager.User == default || ProfileManager.User.UniqueId == Guid.Empty)
+ if (_profileManager.User == default || _profileManager.User.UniqueId == Guid.Empty)
return;
- await Locator.Current.GetService().User.SetOnlineStatus(new UserOnlineStatusModel
+ await Locator.Current.GetRequiredService().User.SetOnlineStatus(new UserOnlineStatusModel
{
StatusType = statusType,
Song = song,
@@ -31,13 +41,13 @@ await Locator.Current.GetService().User.SetOnlineStatus(new UserOnline
public async Task UpdateXp(string hash, double timeListened, double channelLength)
{
- if (ProfileManager.User == default) return;
+ if (_profileManager.User == default) return;
- var currentTotalXp = ProfileManager.User.TotalXp;
+ var currentTotalXp = _profileManager.User.TotalXp;
var time = timeListened / 1000;
- var response = await Locator.Current.GetService().User.UpdateXp(new UpdateXpModel
+ var response = await Locator.Current.GetRequiredService().User.UpdateXp(new UpdateXpModel
{
SongChecksum = hash,
ChannelLength = channelLength,
@@ -46,25 +56,29 @@ public async Task UpdateXp(string hash, double timeListened, double channelLengt
if (response == default) return;
- ProfileManager.User = response.ConvertObjectToJson();
+ _profileManager.User = response.ConvertObjectToJson();
var xpEarned = response.TotalXp - currentTotalXp;
GraphValues.Add(new ObservableValue(xpEarned));
await Dispatcher.UIThread.InvokeAsync(() => UserDataChanged?.Invoke(this, new PropertyChangedEventArgs("Xp")));
+
+ LogToConsole($"Successfully updated XP for {_profileManager.User?.Name ?? string.Empty}. Earned {xpEarned} XP.");
}
public async Task UpdateSongsPlayed(int beatmapSetId)
{
- if (ProfileManager.User == default) return;
+ if (_profileManager.User == default) return;
- var response = await Locator.Current.GetService().User.UpdateSongsPlayed(1, beatmapSetId);
+ var response = await Locator.Current.GetRequiredService().User.UpdateSongsPlayed(1, beatmapSetId);
if (response == default) return;
- ProfileManager.User = response.ConvertObjectToJson();
+ _profileManager.User = response.ConvertObjectToJson();
await Dispatcher.UIThread.InvokeAsync(() => UserDataChanged?.Invoke(this, new PropertyChangedEventArgs("SongsPlayed")));
+
+ LogToConsole($"Successfully updated songs played for {_profileManager.User?.Name ?? string.Empty}");
}
}
\ No newline at end of file
diff --git a/OsuPlayer.Services/DbReaderFactory.cs b/OsuPlayer.Services/DbReaderFactory.cs
new file mode 100644
index 00000000..06fa94ce
--- /dev/null
+++ b/OsuPlayer.Services/DbReaderFactory.cs
@@ -0,0 +1,32 @@
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Data.Enums;
+using OsuPlayer.IO.DbReader;
+
+namespace OsuPlayer.Services;
+
+public class DbReaderFactory : OsuPlayerService, IDbReaderFactory
+{
+ public override string ServiceName => "DBREADER_FACTORY_SERVICE";
+
+ public DbCreationType Type { get; set; }
+
+ public IDatabaseReader? CreateDatabaseReader(string path)
+ {
+ switch (Type)
+ {
+ case DbCreationType.OsuDb:
+ var dbLoc = Path.Combine(path, "osu!.db");
+
+ if (!File.Exists(dbLoc)) return null;
+
+ var file = File.OpenRead(dbLoc);
+
+ return new OsuDbReader(file, path, this);
+ case DbCreationType.Realm:
+ return new RealmReader(path, this);
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer.Services/HistoryService.cs b/OsuPlayer.Services/HistoryService.cs
new file mode 100644
index 00000000..f6f2f3f5
--- /dev/null
+++ b/OsuPlayer.Services/HistoryService.cs
@@ -0,0 +1,37 @@
+using Nein.Extensions.Bindables;
+using OsuPlayer.Data.DataModels.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Interfaces.Service;
+
+namespace OsuPlayer.Services;
+
+public class HistoryService : OsuPlayerService, IHistoryProvider
+{
+ public HistoricalMapEntryComparer Comparer { get; } = new();
+ public BindableList History { get; } = new();
+
+ public override string ServiceName => "HISTORY_SERVICE";
+
+ public void AddOrUpdateMapEntry(IMapEntryBase? mapEntry)
+ {
+ if (mapEntry == default) return;
+
+ var historicalMapEntry = new HistoricalMapEntry(mapEntry);
+
+ var foundEntry = History.FirstOrDefault(entry => Comparer.Equals(entry, historicalMapEntry));
+
+ if (foundEntry != default)
+ History.Remove(foundEntry);
+
+ History.Add(historicalMapEntry);
+
+ LogToConsole($"Added or updated map entry {mapEntry.GetSongName()} ({mapEntry.Hash}) to history.");
+ }
+
+ public void ClearHistory()
+ {
+ History.Clear();
+
+ LogToConsole($"Cleared listening history.");
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer.Services/LastFmService.cs b/OsuPlayer.Services/LastFmService.cs
new file mode 100644
index 00000000..4b08d988
--- /dev/null
+++ b/OsuPlayer.Services/LastFmService.cs
@@ -0,0 +1,25 @@
+using OsuPlayer.Interfaces.Service;
+
+namespace OsuPlayer.Services;
+
+public class LastFmService : OsuPlayerService, ILastFmApiService
+{
+ private readonly ILastFmApiService _lastFmApiService;
+
+ public override string ServiceName => "LASTFM_SERVICE";
+
+ public LastFmService( ILastFmApiService lastFmApiService )
+ {
+ _lastFmApiService = lastFmApiService;
+ }
+
+ public void AuthorizeToken() => _lastFmApiService.AuthorizeToken();
+ public void SetApiKeyAndSecret(string apiKey, string secret) => _lastFmApiService.SetApiKeyAndSecret(apiKey, secret);
+ public bool LoadSessionKey() => _lastFmApiService.LoadSessionKey();
+ public bool IsAuthorized() => _lastFmApiService.IsAuthorized();
+ public Task GetSessionKey() => _lastFmApiService.GetSessionKey();
+ public Task SaveSessionKeyAsync() => _lastFmApiService.SaveSessionKeyAsync();
+ public Task Scrobble(string title, string artist) => _lastFmApiService.Scrobble(title, artist);
+ public Task LoadSessionKeyAsync() => _lastFmApiService.LoadSessionKeyAsync();
+ public Task GetAuthToken() => _lastFmApiService.GetAuthToken();
+}
\ No newline at end of file
diff --git a/OsuPlayer.Services/LoggingService.cs b/OsuPlayer.Services/LoggingService.cs
new file mode 100644
index 00000000..65bd48d7
--- /dev/null
+++ b/OsuPlayer.Services/LoggingService.cs
@@ -0,0 +1,10 @@
+using OsuPlayer.Interfaces.Service;
+
+namespace OsuPlayer.Services;
+
+public class LoggingService : OsuPlayerService, ILoggingService
+{
+ public override string ServiceName => "LOGGING_SERVICE";
+
+ public void Log(string message, LogType logType = LogType.Info, object? data = null) => LogToConsole(message, logType, data);
+}
\ No newline at end of file
diff --git a/OsuPlayer.Services/OsuPlayer.Services.csproj b/OsuPlayer.Services/OsuPlayer.Services.csproj
new file mode 100644
index 00000000..5e195cac
--- /dev/null
+++ b/OsuPlayer.Services/OsuPlayer.Services.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net7.0
+ enable
+ annotations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsuPlayer.Services/OsuPlayerService.cs b/OsuPlayer.Services/OsuPlayerService.cs
new file mode 100644
index 00000000..74b9f4cb
--- /dev/null
+++ b/OsuPlayer.Services/OsuPlayerService.cs
@@ -0,0 +1,87 @@
+using System.Text;
+using System.Text.Json;
+using OsuPlayer.Interfaces.Service;
+
+namespace OsuPlayer.Services;
+
+public abstract class OsuPlayerService : IOsuPlayerService
+{
+ public abstract string ServiceName { get; }
+
+ protected OsuPlayerService()
+ {
+ try
+ {
+ Console.OutputEncoding = Encoding.UTF8;
+
+ LogToConsole("Service initialized.", LogType.Success, includeLogTypeTag: false);
+ }
+ catch (Exception _)
+ {
+ LogToConsole($"Service initialized, but couldn't initialize with encoding {Encoding.UTF8.EncodingName}.", LogType.Warning, includeLogTypeTag: false);
+ }
+ }
+
+ ~OsuPlayerService() => LogToConsole("Service deinitialized.", LogType.Warning, includeLogTypeTag: false);
+
+ public string ServiceTag() => $"[{ServiceName}] ";
+
+ protected void LogToConsole(string message, LogType logType = LogType.Info, object? data = null, bool includeLogTypeTag = true)
+ {
+ string outputMessage;
+
+ if (data == null)
+ outputMessage = $"{ServiceTag()}{(includeLogTypeTag ? GetLogTypeIcon(logType) + " " : string.Empty)}{message}";
+ else
+ outputMessage =
+ $"{ServiceTag()}{(includeLogTypeTag ? GetLogTypeIcon(logType) + " " : string.Empty)}{message} - {JsonSerializer.Serialize(data)}";
+
+ switch (logType)
+ {
+ case LogType.Info:
+ Console.ResetColor();
+
+ break;
+ case LogType.Success:
+ Console.BackgroundColor = ConsoleColor.DarkGreen;
+ Console.ForegroundColor = ConsoleColor.White;
+
+ break;
+ case LogType.Warning:
+ Console.BackgroundColor = ConsoleColor.DarkYellow;
+ Console.ForegroundColor = ConsoleColor.White;
+
+ break;
+ case LogType.Error:
+ Console.BackgroundColor = ConsoleColor.DarkRed;
+ Console.ForegroundColor = ConsoleColor.White;
+
+ break;
+ case LogType.Debug:
+ Console.BackgroundColor = ConsoleColor.DarkMagenta;
+ Console.ForegroundColor = ConsoleColor.White;
+
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(logType), logType, null);
+ }
+
+ Console.WriteLine(outputMessage);
+
+ // Resetting the colors, so subsequent logs don't have the same colors.
+ Console.ResetColor();
+ }
+
+ private string GetLogTypeIcon(LogType logType)
+ {
+ return logType switch
+ {
+ LogType.Info => "ℹ️",
+ LogType.Success => "✅",
+ LogType.Warning => "⚠️",
+ LogType.Error => "❌",
+ LogType.Debug => "🐛",
+ _ => throw new ArgumentOutOfRangeException(nameof(logType), logType, null)
+ };
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/Services/OsuSongSourceProvider.cs b/OsuPlayer.Services/OsuSongSourceService.cs
similarity index 78%
rename from OsuPlayer/Modules/Services/OsuSongSourceProvider.cs
rename to OsuPlayer.Services/OsuSongSourceService.cs
index 5b07ed2e..3adfbc03 100644
--- a/OsuPlayer/Modules/Services/OsuSongSourceProvider.cs
+++ b/OsuPlayer.Services/OsuSongSourceService.cs
@@ -1,10 +1,12 @@
-using DynamicData;
-using OsuPlayer.IO.DbReader.Interfaces;
+using System.Collections.ObjectModel;
+using DynamicData;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Importer;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Services;
-public class OsuSongSourceProvider : ISongSourceProvider
+public class OsuSongSourceService : OsuPlayerService, ISongSourceProvider
{
private readonly ReadOnlyObservableCollection? _songSourceList;
@@ -12,7 +14,9 @@ public class OsuSongSourceProvider : ISongSourceProvider
public IObservable>? Songs { get; }
public ReadOnlyObservableCollection? SongSourceList => _songSourceList;
- public OsuSongSourceProvider(ISortProvider? sortProvider = null)
+ public override string ServiceName => "OSU_SONGSOURCE_SERVICE";
+
+ public OsuSongSourceService(ISortProvider? sortProvider = null)
{
if (sortProvider != null)
{
diff --git a/OsuPlayer.Services/ProfileManagerServiceService.cs b/OsuPlayer.Services/ProfileManagerServiceService.cs
new file mode 100644
index 00000000..15b9e2a8
--- /dev/null
+++ b/OsuPlayer.Services/ProfileManagerServiceService.cs
@@ -0,0 +1,43 @@
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Interfaces.Service;
+using Splat;
+
+namespace OsuPlayer.Services;
+
+public class ProfileManagerServiceService : IProfileManagerService
+{
+ public User? User { get; set; }
+
+ public async Task Login(string username, string password)
+ {
+ var result = await Locator.Current.GetService().LoginAndSaveAuthToken(username, password);
+
+ // If login failed, we set the user to its default value
+ if (result == default)
+ {
+ User = default;
+
+ return;
+ }
+
+ User = new User(result);
+ }
+
+ public async Task Login(string token)
+ {
+ if (string.IsNullOrWhiteSpace(token)) return;
+
+ var result = await Locator.Current.GetService().LoginWithTokenAndSaveNewToken(token);
+
+ // If login via token failed, we set the User to its default value
+ if (result == default)
+ {
+ User = default;
+
+ return;
+ }
+
+ User = new User(result);
+ }
+}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/ShuffleImpl/BalancedShuffler.cs b/OsuPlayer.Services/ShuffleImpl/BalancedShuffler.cs
similarity index 88%
rename from OsuPlayer/Modules/ShuffleImpl/BalancedShuffler.cs
rename to OsuPlayer.Services/ShuffleImpl/BalancedShuffler.cs
index ae43dc53..095cd147 100644
--- a/OsuPlayer/Modules/ShuffleImpl/BalancedShuffler.cs
+++ b/OsuPlayer.Services/ShuffleImpl/BalancedShuffler.cs
@@ -1,11 +1,12 @@
using OsuPlayer.Data.OsuPlayer.Enums;
+using OsuPlayer.Interfaces.Service;
-namespace OsuPlayer.Modules.ShuffleImpl;
+namespace OsuPlayer.Services.ShuffleImpl;
///
/// This shuffle algorithm performs a full reshuffle of the song list so there aren't any duplicates and biases.
///
-public class BalancedShuffler : IShuffleImpl
+public class BalancedShuffler : OsuPlayerService, IShuffleImpl
{
private readonly List _shuffledIndexes = new();
private int _currentIndex;
@@ -15,6 +16,8 @@ public class BalancedShuffler : IShuffleImpl
public string Name => "Balanced Shuffle";
public string Description => "Shuffles the entire list of songs so there aren't any duplicates and biases.";
+ public override string ServiceName => "BALANCED_SHUFFLE_SERVICE";
+
public void Init(int maxRange)
{
if (_maxRange == maxRange) return;
diff --git a/OsuPlayer/Modules/ShuffleImpl/RngHistoryShuffler.cs b/OsuPlayer.Services/ShuffleImpl/RngHistoryShuffler.cs
similarity index 94%
rename from OsuPlayer/Modules/ShuffleImpl/RngHistoryShuffler.cs
rename to OsuPlayer.Services/ShuffleImpl/RngHistoryShuffler.cs
index f40c0d18..40a19804 100644
--- a/OsuPlayer/Modules/ShuffleImpl/RngHistoryShuffler.cs
+++ b/OsuPlayer.Services/ShuffleImpl/RngHistoryShuffler.cs
@@ -1,13 +1,14 @@
using OsuPlayer.Data.OsuPlayer.Enums;
+using OsuPlayer.Interfaces.Service;
-namespace OsuPlayer.Modules.ShuffleImpl;
+namespace OsuPlayer.Services.ShuffleImpl;
///
/// This shuffle implementation is mostly the same as but adds a 10 depth history buffer so one
/// can go back to the previous song.
/// This also has a security check to prevent the same song from being played twice in a row.
///
-public class RngHistoryShuffler : IShuffleImpl
+public class RngHistoryShuffler : OsuPlayerService, IShuffleImpl
{
private readonly int?[] _shuffleHistory = new int?[10];
private int _currentIndex;
@@ -18,10 +19,9 @@ public class RngHistoryShuffler : IShuffleImpl
public string Name => "Random Shuffle (with history)";
public string Description => "Randomly picks a song from the list with a history buffer of 10 songs.";
- public void Init(int maxRange)
- {
- _maxRange = maxRange;
- }
+ public override string ServiceName => "RNG_HISTORY_SHUFFLE_SERVICE";
+
+ public void Init(int maxRange) => _maxRange = maxRange;
public int DoShuffle(int currentIndex, ShuffleDirection direction)
{
diff --git a/OsuPlayer/Modules/ShuffleImpl/RngShuffler.cs b/OsuPlayer.Services/ShuffleImpl/RngShuffler.cs
similarity index 56%
rename from OsuPlayer/Modules/ShuffleImpl/RngShuffler.cs
rename to OsuPlayer.Services/ShuffleImpl/RngShuffler.cs
index ca9cbb48..9b4d2552 100644
--- a/OsuPlayer/Modules/ShuffleImpl/RngShuffler.cs
+++ b/OsuPlayer.Services/ShuffleImpl/RngShuffler.cs
@@ -1,31 +1,25 @@
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Extensions;
+using OsuPlayer.Interfaces.Service;
-namespace OsuPlayer.Modules.ShuffleImpl;
+namespace OsuPlayer.Services.ShuffleImpl;
///
/// This shuffle implementation will randomly select a song each time with no further logic.
///
[DefaultImplAttr]
-public class RngShuffler : IShuffleImpl
+public class RngShuffler : OsuPlayerService, IShuffleImpl
{
private int _maxRange = -1;
public string Name => "Random Shuffle";
public string Description => "Randomly select a song each time with no further logic.";
- public void Init(int maxRange)
- {
- _maxRange = maxRange;
- }
+ public override string ServiceName => "RNG_SHUFFLE_SERVICE";
- public int DoShuffle(int currentIndex, ShuffleDirection direction)
- {
- return Random.Shared.Next(_maxRange);
- }
+ public void Init(int maxRange) => _maxRange = maxRange;
- public override string ToString()
- {
- return Name;
- }
+ public int DoShuffle(int currentIndex, ShuffleDirection direction) => Random.Shared.Next(_maxRange);
+
+ public override string ToString() => Name;
}
\ No newline at end of file
diff --git a/OsuPlayer/Modules/Services/ShuffleServiceProvider.cs b/OsuPlayer.Services/ShuffleService.cs
similarity index 82%
rename from OsuPlayer/Modules/Services/ShuffleServiceProvider.cs
rename to OsuPlayer.Services/ShuffleService.cs
index 6986d83a..d8e9dda7 100644
--- a/OsuPlayer/Modules/Services/ShuffleServiceProvider.cs
+++ b/OsuPlayer.Services/ShuffleService.cs
@@ -1,17 +1,20 @@
using OsuPlayer.Extensions;
-using OsuPlayer.Modules.ShuffleImpl;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.IO.Storage.Config;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Services;
///
/// Provides a service for shuffle implementation registering the services using Splat.
///
-public class ShuffleServiceProvider : IShuffleServiceProvider
+public class ShuffleService : OsuPlayerService, IShuffleServiceProvider
{
public List ShuffleAlgorithms { get; }
public IShuffleImpl? ShuffleImpl { get; private set; }
- public ShuffleServiceProvider()
+ public override string ServiceName => "SHUFFLE_SERVICE";
+
+ public ShuffleService()
{
using var config = new Config();
diff --git a/OsuPlayer/Modules/Services/SortProvider.cs b/OsuPlayer.Services/SortService.cs
similarity index 82%
rename from OsuPlayer/Modules/Services/SortProvider.cs
rename to OsuPlayer.Services/SortService.cs
index daaab9fe..7431974c 100644
--- a/OsuPlayer/Modules/Services/SortProvider.cs
+++ b/OsuPlayer.Services/SortService.cs
@@ -1,16 +1,21 @@
using DynamicData;
+using Nein.Extensions.Bindables;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Interfaces.Service;
-namespace OsuPlayer.Modules.Services;
+namespace OsuPlayer.Services;
-public class SortProvider : ISortProvider
+public class SortService : OsuPlayerService, ISortProvider
{
public IObservable>? SortedSongs { get; set; }
public Bindable SortingModeBindable { get; } = new();
public ObservableSorter SortingModeObservable { get; } = new();
- public SortProvider()
+ public override string ServiceName => "SORT_SERVICE";
+
+ public SortService()
{
SortingModeBindable.BindValueChanged(d => SortingModeObservable.UpdateComparer(new MapSorter(d.NewValue)), true, true);
}
diff --git a/OsuPlayer.Tests/IOTests/ConfigTests.cs b/OsuPlayer.Tests/IOTests/ConfigTests.cs
index 73645ab8..1168279f 100644
--- a/OsuPlayer.Tests/IOTests/ConfigTests.cs
+++ b/OsuPlayer.Tests/IOTests/ConfigTests.cs
@@ -3,7 +3,7 @@
using NUnit.Framework;
using OsuPlayer.IO.Storage.Config;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.IOTests;
public class ConfigTests
{
diff --git a/OsuPlayer.Tests/IOTests/DirectoryManagerTests.cs b/OsuPlayer.Tests/IOTests/DirectoryManagerTests.cs
index b6dac2cc..83df95b1 100644
--- a/OsuPlayer.Tests/IOTests/DirectoryManagerTests.cs
+++ b/OsuPlayer.Tests/IOTests/DirectoryManagerTests.cs
@@ -2,7 +2,7 @@
using NUnit.Framework;
using OsuPlayer.IO;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.IOTests;
public class DirectoryManagerTests
{
diff --git a/OsuPlayer.Tests/IOTests/PlaylistStorageTests.cs b/OsuPlayer.Tests/IOTests/PlaylistStorageTests.cs
index dc4f8db8..a337f39e 100644
--- a/OsuPlayer.Tests/IOTests/PlaylistStorageTests.cs
+++ b/OsuPlayer.Tests/IOTests/PlaylistStorageTests.cs
@@ -6,7 +6,7 @@
using OsuPlayer.Data.OsuPlayer.StorageModels;
using OsuPlayer.IO.Storage.Playlists;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.IOTests;
public class PlaylistStorageTests
{
diff --git a/OsuPlayer.Tests/IOTests/PlaylistTests.cs b/OsuPlayer.Tests/IOTests/PlaylistTests.cs
index 0526fda3..cb88e5e0 100644
--- a/OsuPlayer.Tests/IOTests/PlaylistTests.cs
+++ b/OsuPlayer.Tests/IOTests/PlaylistTests.cs
@@ -5,7 +5,7 @@
using OsuPlayer.Data.OsuPlayer.StorageModels;
using OsuPlayer.IO.Storage.Playlists;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.IOTests;
public class PlaylistTests
{
diff --git a/OsuPlayer.Tests/NetworkTests/OnlineTests.cs b/OsuPlayer.Tests/NetworkTests/OnlineTests.cs
index 1b8803fb..4f97241d 100644
--- a/OsuPlayer.Tests/NetworkTests/OnlineTests.cs
+++ b/OsuPlayer.Tests/NetworkTests/OnlineTests.cs
@@ -1,9 +1,10 @@
using System;
using NUnit.Framework;
using OsuPlayer.Api.Data.API.Enums;
-using OsuPlayer.Network.Online;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Online;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.NetworkTests;
public class OnlineTests
{
diff --git a/OsuPlayer.Tests/NetworkTests/PasswordManagerTests.cs b/OsuPlayer.Tests/NetworkTests/PasswordManagerTests.cs
index 730789c1..3fda91e2 100644
--- a/OsuPlayer.Tests/NetworkTests/PasswordManagerTests.cs
+++ b/OsuPlayer.Tests/NetworkTests/PasswordManagerTests.cs
@@ -1,7 +1,7 @@
using NUnit.Framework;
using OsuPlayer.Network.Security;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.NetworkTests;
public class PasswordManagerTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/GridFormatterTests.cs b/OsuPlayer.Tests/ValueConverterTests/GridFormatterTests.cs
index eaa32f71..9b2990eb 100644
--- a/OsuPlayer.Tests/ValueConverterTests/GridFormatterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/GridFormatterTests.cs
@@ -3,7 +3,7 @@
using NUnit.Framework;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class GridFormatterTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/PlayPauseConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/PlayPauseConverterTests.cs
index 42707937..a5644909 100644
--- a/OsuPlayer.Tests/ValueConverterTests/PlayPauseConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/PlayPauseConverterTests.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class PlayPauseConverterTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/RepeatConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/RepeatConverterTests.cs
index 55b5bf41..fbf0fa3f 100644
--- a/OsuPlayer.Tests/ValueConverterTests/RepeatConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/RepeatConverterTests.cs
@@ -5,7 +5,7 @@
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class RepeatConverterTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/SettingsUserConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/SettingsUserConverterTests.cs
index 0e07bf6c..8673115b 100644
--- a/OsuPlayer.Tests/ValueConverterTests/SettingsUserConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/SettingsUserConverterTests.cs
@@ -1,10 +1,10 @@
using System;
using System.Globalization;
using NUnit.Framework;
+using OsuPlayer.Data.DataModels;
using OsuPlayer.Extensions.ValueConverters;
-using OsuPlayer.Network.Online;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class SettingsUserConverterTests
{
@@ -47,11 +47,11 @@ public void TestOutputOnNullInput()
// {
// Name = name
// };
- //
+ //
// Assert.IsInstanceOf(_expectedInput, input);
- //
+ //
// var output = _userConverter.Convert(input, _expectedOutput, null, CultureInfo.InvariantCulture);
- //
+ //
// Assert.IsInstanceOf(_expectedOutput, output);
// Assert.AreEqual(input.Name, output);
// }
diff --git a/OsuPlayer.Tests/ValueConverterTests/ShuffleConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/ShuffleConverterTests.cs
index 73796d67..eb6e6e6a 100644
--- a/OsuPlayer.Tests/ValueConverterTests/ShuffleConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/ShuffleConverterTests.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class ShuffleConverterTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/SourceListValueConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/SourceListValueConverterTests.cs
index 5168008c..9ef17cd1 100644
--- a/OsuPlayer.Tests/ValueConverterTests/SourceListValueConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/SourceListValueConverterTests.cs
@@ -6,7 +6,7 @@
using OsuPlayer.Data.OsuPlayer.StorageModels;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class SourceListValueConverterTests
{
diff --git a/OsuPlayer.Tests/ValueConverterTests/VolumeConverterTests.cs b/OsuPlayer.Tests/ValueConverterTests/VolumeConverterTests.cs
index 4a2ef4e9..7f9ccbf8 100644
--- a/OsuPlayer.Tests/ValueConverterTests/VolumeConverterTests.cs
+++ b/OsuPlayer.Tests/ValueConverterTests/VolumeConverterTests.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using OsuPlayer.Extensions.ValueConverters;
-namespace OsuPlayer.Tests;
+namespace OsuPlayer.Tests.ValueConverterTests;
public class VolumeConverterTests
{
diff --git a/OsuPlayer.sln b/OsuPlayer.sln
index cefb97e3..76f1fb48 100644
--- a/OsuPlayer.sln
+++ b/OsuPlayer.sln
@@ -23,6 +23,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0EC9D629
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OsuPlayer.CrashHandler", "OsuPlayer.CrashHandler\OsuPlayer.CrashHandler.csproj", "{99497585-DB09-4427-8813-88CE41BB392E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OsuPlayer.Services", "OsuPlayer.Services\OsuPlayer.Services.csproj", "{704B3DBB-458D-4C83-818D-3BE403AA433B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OsuPlayer.Interfaces", "OsuPlayer.Interfaces\OsuPlayer.Interfaces.csproj", "{959F77A7-DC5D-4C01-8291-2660683C099C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -61,6 +65,14 @@ Global
{99497585-DB09-4427-8813-88CE41BB392E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99497585-DB09-4427-8813-88CE41BB392E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99497585-DB09-4427-8813-88CE41BB392E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {704B3DBB-458D-4C83-818D-3BE403AA433B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {704B3DBB-458D-4C83-818D-3BE403AA433B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {704B3DBB-458D-4C83-818D-3BE403AA433B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {704B3DBB-458D-4C83-818D-3BE403AA433B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {959F77A7-DC5D-4C01-8291-2660683C099C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {959F77A7-DC5D-4C01-8291-2660683C099C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {959F77A7-DC5D-4C01-8291-2660683C099C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {959F77A7-DC5D-4C01-8291-2660683C099C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0034AEFA-ED66-47FA-AA37-1AB01F371AAF} = {AF8CA35D-63B3-4B8B-95B1-4717C57ED0E1}
@@ -69,5 +81,7 @@ Global
{5C528D33-1973-412A-8068-8397B7BE5897} = {AF8CA35D-63B3-4B8B-95B1-4717C57ED0E1}
{D428D0A2-A166-4522-98CF-6365261E2C8F} = {AF8CA35D-63B3-4B8B-95B1-4717C57ED0E1}
{BA344BAD-2E55-4617-B2E0-926D67D8BBA8} = {0EC9D629-BCAE-4603-9ACA-8479877FA198}
+ {704B3DBB-458D-4C83-818D-3BE403AA433B} = {AF8CA35D-63B3-4B8B-95B1-4717C57ED0E1}
+ {959F77A7-DC5D-4C01-8291-2660683C099C} = {AF8CA35D-63B3-4B8B-95B1-4717C57ED0E1}
EndGlobalSection
EndGlobal
diff --git a/OsuPlayer/Modules/Audio/Engine/BassEngine.cs b/OsuPlayer/Modules/Audio/Engine/BassEngine.cs
index 980c7cda..72ad08cc 100644
--- a/OsuPlayer/Modules/Audio/Engine/BassEngine.cs
+++ b/OsuPlayer/Modules/Audio/Engine/BassEngine.cs
@@ -4,16 +4,30 @@
using ManagedBass.DirectX8;
using ManagedBass.Fx;
using OsuPlayer.Data.OsuPlayer.Classes;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Storage.Equalizer;
using OsuPlayer.Modules.Audio.Interfaces;
+using OsuPlayer.Services;
namespace OsuPlayer.Modules.Audio.Engine;
///
/// Audio engine for the osu!player using
///
-public sealed class BassEngine : IAudioEngine
+public sealed class BassEngine : OsuPlayerService, IAudioEngine
{
+ public override string ServiceName => "BASS_ENGINE";
+
+ public List AvailableAudioDevices { get; } = new();
+ public IAudioEngine.ChannelReachedEndHandler? ChannelReachedEnd { private get; set; }
+ public BindableArray EqGains { get; } = new(10, 1);
+
+ public Bindable ChannelLength { get; } = new();
+ public Bindable ChannelPosition { get; } = new();
+ public Bindable Volume { get; } = new();
+ public Bindable IsPlaying { get; } = new();
+ public Bindable PlaybackSpeed { get; } = new();
+
private readonly SyncProcedure _endTrackSyncProc;
private readonly DispatcherTimer _positionTimer = new(DispatcherPriority.ApplicationIdle);
@@ -27,16 +41,6 @@ public sealed class BassEngine : IAudioEngine
private double _playbackSpeed;
private int _sampleFrequency = 44100;
- public List AvailableAudioDevices { get; } = new();
- public IAudioEngine.ChannelReachedEndHandler? ChannelReachedEnd { private get; set; }
- public BindableArray EqGains { get; } = new(10, 1);
-
- public Bindable ChannelLength { get; } = new();
- public Bindable ChannelPosition { get; } = new();
- public Bindable Volume { get; } = new();
- public Bindable IsPlaying { get; } = new();
- public Bindable PlaybackSpeed { get; } = new();
-
public bool IsEqEnabled
{
get => _isEqEnabled;
@@ -50,7 +54,7 @@ public bool IsEqEnabled
}
}
- public BassEngine()
+ public BassEngine() : base()
{
_positionTimer.Interval = TimeSpan.FromMilliseconds((double) 1000 / 60);
_positionTimer.Tick += PositionTimer_Tick;
@@ -193,7 +197,7 @@ public void SetDevice(AudioDevice? audioDevice)
using var config = new Config();
config.Container.SelectedAudioDeviceDriver = audioDevices[index].Driver;
- Console.WriteLine($"[BASSENGINE] DEVICE {index} | LOADING PLAYBACK {Bass.LastError}");
+ LogToConsole($"DEVICE {index} | LOADING PLAYBACK {Bass.LastError}");
}
private void SetPlaybackSpeedOptions(double speed)
@@ -232,7 +236,7 @@ private void InitAudioDevices()
{
var success = Bass.Init(counter);
- Console.WriteLine($"[BASSENGINE] INIT DEVICE {deviceInfo} | SUCCESSFUL: {success} | CODE: {Bass.LastError}");
+ LogToConsole($"INIT DEVICE {deviceInfo} | SUCCESSFUL: {success} | CODE: {Bass.LastError}");
if (success) AvailableAudioDevices.Add(deviceInfo);
@@ -346,6 +350,7 @@ private IEnumerable GetAudioDevices()
private void PositionTimer_Tick(object sender, EventArgs e)
{
if (!IsPlaying.Value) return;
+
if (_fxStream == 0)
{
ChannelPosition.Value = 0;
diff --git a/OsuPlayer/Modules/Audio/Interfaces/IPlayer.cs b/OsuPlayer/Modules/Audio/Interfaces/IPlayer.cs
index 3b468c8e..7e9d1e7a 100644
--- a/OsuPlayer/Modules/Audio/Interfaces/IPlayer.cs
+++ b/OsuPlayer/Modules/Audio/Interfaces/IPlayer.cs
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Importer;
namespace OsuPlayer.Modules.Audio.Interfaces;
diff --git a/OsuPlayer/Modules/Audio/Player.cs b/OsuPlayer/Modules/Audio/Player.cs
index cc813c08..5824eb0a 100644
--- a/OsuPlayer/Modules/Audio/Player.cs
+++ b/OsuPlayer/Modules/Audio/Player.cs
@@ -6,19 +6,19 @@
using Nein.Extensions;
using Nein.Extensions.Exceptions;
using OsuPlayer.Api.Data.API.Enums;
+using OsuPlayer.Data.DataModels.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Classes;
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.DataModels.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Importer;
using OsuPlayer.IO.Storage.Blacklist;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.Modules.Audio.Engine;
using OsuPlayer.Modules.Audio.Interfaces;
-using OsuPlayer.Modules.Services;
using OsuPlayer.Network.Discord;
-using OsuPlayer.Network.LastFM;
+using OsuPlayer.Network.LastFm;
namespace OsuPlayer.Modules.Audio;
@@ -35,7 +35,7 @@ public class Player : IPlayer, IImportNotifications
private readonly IStatisticsProvider? _statisticsProvider;
private readonly IHistoryProvider? _historyProvider;
private readonly WindowsMediaTransportControls? _winMediaControls;
- private readonly LastFmApi? _lastFmApi;
+ private readonly ILastFmApiService? _lastFmApi;
private bool _isMuted;
private double _oldVolume;
@@ -53,7 +53,7 @@ public class Player : IPlayer, IImportNotifications
public Bindable RepeatMode { get; } = new();
public BindableList History { get; } = new();
-
+
public List AvailableAudioDevices => _audioEngine.AvailableAudioDevices;
public BindableArray EqGains => _audioEngine.EqGains;
public Bindable Volume => _audioEngine.Volume;
@@ -70,7 +70,8 @@ public bool IsEqEnabled
private List ActivePlaylistSongs { get; set; }
public Player(IAudioEngine audioEngine, ISongSourceProvider songSourceProvider, IShuffleServiceProvider? shuffleProvider = null,
- IStatisticsProvider? statisticsProvider = null, ISortProvider? sortProvider = null, IHistoryProvider? historyProvider = null, LastFmApi? lastFmApi = null)
+ IStatisticsProvider? statisticsProvider = null, ISortProvider? sortProvider = null, IHistoryProvider? historyProvider = null,
+ ILastFmApiService? lastFmApi = null)
{
_audioEngine = audioEngine;
@@ -153,7 +154,7 @@ private void OnRepeatModeChanged(ValueChangedEvent repeatMode)
private void OnCurrentSongChanged(ValueChangedEvent mapEntry)
{
_historyProvider?.AddOrUpdateMapEntry(mapEntry.NewValue);
-
+
using var cfg = new Config();
cfg.Container.LastPlayedSong = mapEntry.NewValue?.Hash;
@@ -163,7 +164,7 @@ private void OnCurrentSongChanged(ValueChangedEvent mapEntry)
if (mapEntry.NewValue is null) return;
var timestamp = TimeSpan.FromSeconds(_audioEngine.ChannelLength.Value * (1 - _audioEngine.PlaybackSpeed.Value));
-
+
_discordClient?.UpdatePresence(mapEntry.NewValue.Title, $"by {mapEntry.NewValue.Artist}", mapEntry.NewValue.BeatmapSetId, durationLeft: timestamp);
}
@@ -219,11 +220,11 @@ public void TriggerBlacklistChanged(PropertyChangedEventArgs e)
public void SetPlaybackSpeed(double speed)
{
_audioEngine.SetPlaybackSpeed(speed);
-
- if(!_audioEngine.IsPlaying.Value) return;
-
+
+ if (!_audioEngine.IsPlaying.Value) return;
+
var timestamp = TimeSpan.FromSeconds(_audioEngine.ChannelLength.Value * (1 - _audioEngine.PlaybackSpeed.Value) - _audioEngine.ChannelPosition.Value);
-
+
_discordClient?.UpdatePresence(CurrentSong.Value.Title, $"by {CurrentSong.Value.Artist}", CurrentSong.Value.BeatmapSetId, durationLeft: timestamp);
}
@@ -259,9 +260,9 @@ public void Play()
_currentSongTimer.Start();
_winMediaControls?.UpdatePlayingStatus(true);
-
+
var timestamp = TimeSpan.FromSeconds(_audioEngine.ChannelLength.Value * (1 - _audioEngine.PlaybackSpeed.Value) - _audioEngine.ChannelPosition.Value);
-
+
_discordClient?.UpdatePresence(CurrentSong.Value.Title, $"by {CurrentSong.Value.Artist}", CurrentSong.Value.BeatmapSetId, durationLeft: timestamp);
}
@@ -271,7 +272,7 @@ public void Pause()
_currentSongTimer.Stop();
_winMediaControls?.UpdatePlayingStatus(false);
-
+
_discordClient?.UpdatePresence(CurrentSong.Value.Title, $"by {CurrentSong.Value.Artist}", CurrentSong.Value.BeatmapSetId);
}
@@ -326,7 +327,6 @@ public async Task TryPlaySongAsync(IMapEntryBase? song, PlayDirection playDirect
{
if (SongSourceProvider.SongSourceList == default || !SongSourceProvider.SongSourceList.Any())
throw new NullOrEmptyException($"{nameof(SongSourceProvider.SongSourceList)} can't be null or empty");
-
if (song == default)
{
await TryStartSongAsync(SongSourceProvider.SongSourceList[0]);
@@ -427,7 +427,7 @@ private async Task TryStartSongAsync(IMapEntryBase song)
await using var config = new Config();
- var fullMapEntry = await song.ReadFullEntry();
+ var fullMapEntry = song.ReadFullEntry();
if (fullMapEntry == default) throw new NullReferenceException();
@@ -485,7 +485,7 @@ private async Task TryStartSongAsync(IMapEntryBase song)
{
if (!config.Container.EnableScrobbling)
return;
-
+
await _lastFmApi?.Scrobble(CurrentSong.Value.Title, CurrentSong.Value.Artist)!;
}
catch (Exception e)
diff --git a/OsuPlayer/Modules/Audio/WindowsMediaTransportControls.cs b/OsuPlayer/Modules/Audio/WindowsMediaTransportControls.cs
index 449b1cb7..118b9da1 100644
--- a/OsuPlayer/Modules/Audio/WindowsMediaTransportControls.cs
+++ b/OsuPlayer/Modules/Audio/WindowsMediaTransportControls.cs
@@ -2,8 +2,8 @@
using Windows.Media.Playback;
using Windows.Storage;
using Windows.Storage.Streams;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.Modules.Audio.Interfaces;
namespace OsuPlayer.Modules.Audio;
diff --git a/OsuPlayer/Modules/Services/HistoryProvider.cs b/OsuPlayer/Modules/Services/HistoryProvider.cs
deleted file mode 100644
index 0372cd80..00000000
--- a/OsuPlayer/Modules/Services/HistoryProvider.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using OsuPlayer.IO.DbReader.DataModels.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
-using OsuPlayer.Modules.Audio.Interfaces;
-
-namespace OsuPlayer.Modules.Services;
-
-public class HistoryProvider : IHistoryProvider
-{
- public HistoricalMapEntryComparer Comparer { get; }
- public BindableList History { get; }
-
- public HistoryProvider()
- {
- Comparer = new HistoricalMapEntryComparer();
- History = new BindableList();
- }
-
- public void AddOrUpdateMapEntry(IMapEntryBase? mapEntry)
- {
- if (mapEntry == default) return;
-
- var historicalMapEntry = new HistoricalMapEntry(mapEntry);
-
- var foundEntry = History.FirstOrDefault(entry => Comparer.Equals(entry, historicalMapEntry));
-
- if (foundEntry != default)
- History.Remove(foundEntry);
-
- History.Add(historicalMapEntry);
- }
-
- public void ClearHistory()
- {
- History.Clear();
- }
-}
\ No newline at end of file
diff --git a/OsuPlayer/OsuPlayer.csproj b/OsuPlayer/OsuPlayer.csproj
index bc7c3f38..4693d490 100644
--- a/OsuPlayer/OsuPlayer.csproj
+++ b/OsuPlayer/OsuPlayer.csproj
@@ -57,8 +57,10 @@
+
+
@@ -146,16 +148,16 @@
BeatmapsView.axaml
- ExportSongsView.axaml
+ ExportSongsView.axaml
- ExportSongsProcessWindow.axaml
+ ExportSongsProcessWindow.axaml
- PlayHistoryView.axaml
+ PlayHistoryView.axaml
- PlayHistoryView.axaml
+ PlayHistoryView.axaml
diff --git a/OsuPlayer/Program.cs b/OsuPlayer/Program.cs
index e55588b2..640f6434 100644
--- a/OsuPlayer/Program.cs
+++ b/OsuPlayer/Program.cs
@@ -3,13 +3,15 @@
using Avalonia.Platform;
using Avalonia.ReactiveUI;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels;
using OsuPlayer.Extensions;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Importer;
using OsuPlayer.Modules.Audio.Engine;
using OsuPlayer.Modules.Audio.Interfaces;
-using OsuPlayer.Modules.Services;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
-using OsuPlayer.Network.LastFM;
+using OsuPlayer.Network.API.NorthFox;
+using OsuPlayer.Network.LastFm;
+using OsuPlayer.Services;
using OsuPlayer.Windows;
using Splat;
@@ -71,16 +73,21 @@ private static AppBuilder BuildAvaloniaApp()
private static void Register(IMutableDependencyResolver services, IReadonlyDependencyResolver resolver, IRuntimePlatform platform)
{
+ services.RegisterLazySingleton(() => new LoggingService());
+
services.RegisterLazySingleton(() => new BassEngine());
- services.RegisterLazySingleton(() => new ShuffleServiceProvider());
- services.RegisterLazySingleton(() => new ApiStatisticsProvider());
- services.RegisterLazySingleton(() => new SortProvider());
- services.RegisterLazySingleton(() => new OsuSongSourceProvider(resolver.GetService()));
- services.RegisterLazySingleton(() => new HistoryProvider());
- services.RegisterLazySingleton(() => new LastFmApi());
+ services.RegisterLazySingleton(() => new DbReaderFactory());
+
+ services.RegisterLazySingleton(() => new ProfileManagerServiceService());
+ services.RegisterLazySingleton(() => new ShuffleService());
+ services.RegisterLazySingleton(() => new ApiStatisticsService(resolver.GetService()));
+ services.RegisterLazySingleton(() => new SortService());
+ services.RegisterLazySingleton(() => new OsuSongSourceService(resolver.GetService()));
+ services.RegisterLazySingleton(() => new HistoryService());
+ services.RegisterLazySingleton(() => new LastFmService(new LastFmApi()));
- services.RegisterLazySingleton(() => new NorthFox());
+ services.RegisterLazySingleton(() => new NorthFox());
services.RegisterLazySingleton(() => new Player(
audioEngine: resolver.GetRequiredService(),
@@ -89,18 +96,20 @@ private static void Register(IMutableDependencyResolver services, IReadonlyDepen
statisticsProvider: resolver.GetRequiredService(),
sortProvider: resolver.GetRequiredService(),
historyProvider: resolver.GetRequiredService(),
- lastFmApi: resolver.GetRequiredService()
+ lastFmApi: resolver.GetRequiredService()
));
services.Register(() => new MainWindowViewModel(
resolver.GetRequiredService(),
resolver.GetRequiredService(),
+ resolver.GetRequiredService(),
resolver.GetService(),
resolver.GetService(),
resolver.GetService(),
resolver.GetService()));
services.RegisterLazySingleton(() => new MainWindow(
- resolver.GetRequiredService()));
+ resolver.GetRequiredService(),
+ resolver.GetRequiredService()));
}
}
\ No newline at end of file
diff --git a/OsuPlayer/Usings.cs b/OsuPlayer/Usings.cs
index 645750a8..ee62d37c 100644
--- a/OsuPlayer/Usings.cs
+++ b/OsuPlayer/Usings.cs
@@ -4,10 +4,8 @@
global using System.Collections.Generic;
global using System.Collections.ObjectModel;
global using Nein.Extensions.Bindables;
-global using OsuPlayer.IO.DbReader.DataModels;
global using OsuPlayer.IO.Storage.Config;
global using OsuPlayer.Modules.Audio;
-global using OsuPlayer.Network.Online;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("OsuPlayer.Tests")]
\ No newline at end of file
diff --git a/OsuPlayer/Views/BeatmapsViewModel.cs b/OsuPlayer/Views/BeatmapsViewModel.cs
index 409c5c78..80f133f4 100644
--- a/OsuPlayer/Views/BeatmapsViewModel.cs
+++ b/OsuPlayer/Views/BeatmapsViewModel.cs
@@ -6,8 +6,9 @@
using OsuPlayer.Api.Data.API.Enums;
using OsuPlayer.Api.Data.API.RequestModels.Beatmap;
using OsuPlayer.Api.Data.API.ResponseModels;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.Modules.Audio.Interfaces;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using OsuPlayer.Network.API.NorthFox;
using ReactiveUI;
using Splat;
@@ -133,14 +134,14 @@ private async void Block(CompositeDisposable disposables)
// If we have beatmaps already loaded and reload the view we don't want to load them again
if (Beatmaps?.Count > 0) return;
- var api = Locator.Current.GetService();
-
await SearchBeatmaps();
}
public async Task SearchBeatmaps(int newPage = 1, int pageSize = 64)
{
- var api = Locator.Current.GetService();
+ var api = Locator.Current.GetService() as NorthFox;
+
+ if (api == default) return new ();
SearchingBeatmaps = true;
diff --git a/OsuPlayer/Views/BlacklistEditorView.axaml b/OsuPlayer/Views/BlacklistEditorView.axaml
index 445530eb..8ec2e53b 100644
--- a/OsuPlayer/Views/BlacklistEditorView.axaml
+++ b/OsuPlayer/Views/BlacklistEditorView.axaml
@@ -5,8 +5,7 @@
xmlns:valueConverters="clr-namespace:OsuPlayer.ValueConverters"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.BlacklistEditorView"
FontWeight="{DynamicResource DefaultFontWeight}">
diff --git a/OsuPlayer/Views/BlacklistEditorView.axaml.cs b/OsuPlayer/Views/BlacklistEditorView.axaml.cs
index fb1ffb05..a85fae6c 100644
--- a/OsuPlayer/Views/BlacklistEditorView.axaml.cs
+++ b/OsuPlayer/Views/BlacklistEditorView.axaml.cs
@@ -4,7 +4,7 @@
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
using Nein.Base;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.IO.Storage.Blacklist;
using OsuPlayer.Windows;
using ReactiveUI;
diff --git a/OsuPlayer/Views/BlacklistEditorViewModel.cs b/OsuPlayer/Views/BlacklistEditorViewModel.cs
index 13437e6a..d7ece5e2 100644
--- a/OsuPlayer/Views/BlacklistEditorViewModel.cs
+++ b/OsuPlayer/Views/BlacklistEditorViewModel.cs
@@ -3,8 +3,8 @@
using Avalonia.Threading;
using DynamicData;
using Nein.Base;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Blacklist;
using OsuPlayer.Modules.Audio.Interfaces;
using ReactiveUI;
diff --git a/OsuPlayer/Views/EditUserView.axaml.cs b/OsuPlayer/Views/EditUserView.axaml.cs
index 6898b41f..3785cdde 100644
--- a/OsuPlayer/Views/EditUserView.axaml.cs
+++ b/OsuPlayer/Views/EditUserView.axaml.cs
@@ -8,7 +8,10 @@
using Avalonia.VisualTree;
using Nein.Extensions;
using OsuPlayer.Api.Data.API.RequestModels.User;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Network.API.NorthFox;
+using OsuPlayer.Services;
using OsuPlayer.UI_Extensions;
using OsuPlayer.Windows;
using ReactiveUI;
@@ -19,9 +22,16 @@ namespace OsuPlayer.Views;
public partial class EditUserView : ReactiveUserControl
{
private MainWindow? _mainWindow;
+ private readonly IProfileManagerService _profileManager;
- public EditUserView()
+ public EditUserView() : this(Locator.Current.GetService())
{
+ }
+
+ public EditUserView(IProfileManagerService profileManager)
+ {
+ _profileManager = profileManager;
+
InitializeComponent();
}
@@ -135,7 +145,7 @@ private async void SaveChanges_OnClick(object? sender, RoutedEventArgs e)
{
if (_mainWindow == default || ViewModel?.CurrentUser == default || string.IsNullOrWhiteSpace(ViewModel?.CurrentUser.Name)) return;
- var api = Locator.Current.GetService();
+ if (Locator.Current.GetService() is not NorthFox api) return;
var tempUser = await api.User.GetUserFromLoginToken();
@@ -192,7 +202,7 @@ await MessageBox.ShowDialogAsync(_mainWindow,
if (ViewModel == null)
{
if (!string.IsNullOrWhiteSpace(editUserModel.User.Name))
- ProfileManager.User = (await api.User.GetUserFromLoginToken())?.ConvertObjectToJson();
+ _profileManager.User = (await api.User.GetUserFromLoginToken())?.ConvertObjectToJson();
if (changedProfilePicture)
await MessageBox.ShowDialogAsync(_mainWindow,
@@ -203,7 +213,7 @@ await MessageBox.ShowDialogAsync(_mainWindow,
ViewModel.NewPassword = string.Empty;
ViewModel.Password = string.Empty;
- ProfileManager.User = ViewModel.CurrentUser.ConvertObjectToJson();
+ _profileManager.User = ViewModel.CurrentUser.ConvertObjectToJson();
var successMessage = "Profile updated successfully!";
@@ -223,7 +233,7 @@ private async Task UpdateProfilePicture()
{
if (_mainWindow == default || ViewModel?.CurrentUser == default || ViewModel?.CurrentProfilePicture == default) return;
- var api = Locator.Current.GetService();
+ if (Locator.Current.GetService() is not NorthFox api) return;
await using var stream = new MemoryStream();
@@ -265,7 +275,7 @@ private async void PreviewBanner_OnClick(object? sender, RoutedEventArgs e)
{
if (ViewModel?.CurrentUser == default) return;
- var banner = await Locator.Current.GetService().User.GetProfileBannerAsync(ViewModel.CurrentUser.CustomBannerUrl);
+ var banner = await Locator.Current.GetService().User.GetProfileBannerAsync(ViewModel.CurrentUser.CustomBannerUrl);
if (banner == default) return;
@@ -276,7 +286,7 @@ private async void ResetBanner_OnClick(object? sender, RoutedEventArgs e)
{
if (ViewModel?.CurrentUser == default || string.IsNullOrWhiteSpace(ViewModel.CurrentUser.Name)) return;
- var api = Locator.Current.GetService();
+ var api = Locator.Current.GetService();
var user = await api.User.GetUserFromLoginToken();
@@ -303,7 +313,7 @@ private async void ResetBanner_OnClick(object? sender, RoutedEventArgs e)
private async void ConfirmDeleteProfile_OnClick(object? sender, RoutedEventArgs e)
{
- if (_mainWindow?.ViewModel == default || ProfileManager.User == default || ViewModel == default) return;
+ if (_mainWindow?.ViewModel == default || _profileManager.User == default || ViewModel == default) return;
if (string.IsNullOrWhiteSpace(ViewModel.ConfirmDeletionPassword))
{
@@ -312,7 +322,7 @@ private async void ConfirmDeleteProfile_OnClick(object? sender, RoutedEventArgs
return;
}
- var response = await Locator.Current.GetService().User.DeleteUser();
+ var response = await Locator.Current.GetService().User.DeleteUser();
if (!response)
{
@@ -321,7 +331,7 @@ private async void ConfirmDeleteProfile_OnClick(object? sender, RoutedEventArgs
return;
}
- ProfileManager.User = default;
+ _profileManager.User = default;
await MessageBox.ShowDialogAsync(_mainWindow, "Profile deleted!\n\nSee you next time!");
diff --git a/OsuPlayer/Views/EditUserViewModel.cs b/OsuPlayer/Views/EditUserViewModel.cs
index 8f024206..c05dc359 100644
--- a/OsuPlayer/Views/EditUserViewModel.cs
+++ b/OsuPlayer/Views/EditUserViewModel.cs
@@ -7,7 +7,9 @@
using Nein.Extensions;
using OsuPlayer.Api.Data.API.EntityModels;
using OsuPlayer.Api.Data.API.RequestModels.Statistics;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Network.API.NorthFox;
+using OsuPlayer.Services;
using ReactiveUI;
using Splat;
@@ -15,6 +17,8 @@ namespace OsuPlayer.Views;
public class EditUserViewModel : BaseViewModel
{
+ private readonly IProfileManagerService _profileManager;
+
private CancellationTokenSource? _bannerCancellationTokenSource;
private string _confirmDeletionPassword = string.Empty;
private Bitmap? _currentProfileBanner;
@@ -24,8 +28,8 @@ public class EditUserViewModel : BaseViewModel
private bool _isDeleteProfilePopupOpen;
private bool _isNewBannerSelected;
private bool _isNewProfilePictureSelected;
- private string _newPassword = string.Empty;
- private string _newUsername = ProfileManager.User?.Name ?? string.Empty;
+ private string? _newPassword;
+ private string? _newUsername;
private string _password = string.Empty;
private CancellationTokenSource? _profilePictureCancellationTokenSource;
private CancellationTokenSource? _topSongsCancellationTokenSource;
@@ -106,18 +110,20 @@ public string NewPassword
public string NewUsername
{
- get => _newUsername;
+ get => _newUsername ??= _profileManager.User?.Name ?? string.Empty;
set => this.RaiseAndSetIfChanged(ref _newUsername, value);
}
- public EditUserViewModel()
+ public EditUserViewModel(IProfileManagerService profileManager)
{
+ _profileManager = profileManager;
+
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
Disposable.Create(() => { }).DisposeWith(disposables);
- CurrentUser = ProfileManager.User;
+ CurrentUser = _profileManager.User;
});
}
@@ -139,7 +145,11 @@ private async void LoadTopSongs()
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
- var stats = await Locator.Current.GetService().Beatmap.GetBeatmapsPlayedByUser(CurrentUser.UniqueId);
+ var api = Locator.Current.GetService() as NorthFox;
+
+ if (api == default) return;
+
+ var stats = await api.Beatmap.GetBeatmapsPlayedByUser(CurrentUser.UniqueId);
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
@@ -171,7 +181,7 @@ public async void LoadProfilePicture()
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
- var profilePicture = await Locator.Current.GetService().User.GetProfilePictureAsync(CurrentUser.UniqueId);
+ var profilePicture = await Locator.Current.GetService().User.GetProfilePictureAsync(CurrentUser.UniqueId);
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
@@ -203,7 +213,7 @@ public async void LoadProfileBanner()
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
- var banner = await Locator.Current.GetService().User.GetProfileBannerAsync(CurrentUser.CustomBannerUrl);
+ var banner = await Locator.Current.GetService().User.GetProfileBannerAsync(CurrentUser.CustomBannerUrl);
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
diff --git a/OsuPlayer/Views/ExportSongsView.axaml b/OsuPlayer/Views/ExportSongsView.axaml
index b820dff8..98e5716b 100644
--- a/OsuPlayer/Views/ExportSongsView.axaml
+++ b/OsuPlayer/Views/ExportSongsView.axaml
@@ -3,8 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.ExportSongsView">
diff --git a/OsuPlayer/Views/ExportSongsView.axaml.cs b/OsuPlayer/Views/ExportSongsView.axaml.cs
index bbcb7e55..d0051908 100644
--- a/OsuPlayer/Views/ExportSongsView.axaml.cs
+++ b/OsuPlayer/Views/ExportSongsView.axaml.cs
@@ -1,20 +1,13 @@
-using System.Text;
-using System.Text.Json.Serialization;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
-using Avalonia.Threading;
using Avalonia.VisualTree;
-using Nein.Extensions;
-using OsuPlayer.IO.DbReader.Interfaces;
-using OsuPlayer.Network;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.UI_Extensions;
using OsuPlayer.Windows;
using ReactiveUI;
-using TagLib;
-using File = System.IO.File;
namespace OsuPlayer.Views;
diff --git a/OsuPlayer/Views/ExportSongsViewModel.cs b/OsuPlayer/Views/ExportSongsViewModel.cs
index d2e1ad3d..01ddcedb 100644
--- a/OsuPlayer/Views/ExportSongsViewModel.cs
+++ b/OsuPlayer/Views/ExportSongsViewModel.cs
@@ -1,8 +1,8 @@
using System.Reactive.Disposables;
using Nein.Base;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Importer;
using OsuPlayer.IO.Storage.Playlists;
using ReactiveUI;
diff --git a/OsuPlayer/Views/HomeSubViews/HomeUserPanelViewModel.cs b/OsuPlayer/Views/HomeSubViews/HomeUserPanelViewModel.cs
index 5af8b21a..4a8eef6b 100644
--- a/OsuPlayer/Views/HomeSubViews/HomeUserPanelViewModel.cs
+++ b/OsuPlayer/Views/HomeSubViews/HomeUserPanelViewModel.cs
@@ -6,8 +6,11 @@
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using Nein.Base;
-using OsuPlayer.Modules.Services;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using OsuPlayer.Data.DataModels;
+using OsuPlayer.Data.DataModels.Interfaces;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Network.API.NorthFox;
+using OsuPlayer.Services;
using ReactiveUI;
using SkiaSharp;
using Splat;
@@ -16,12 +19,13 @@ namespace OsuPlayer.Views.HomeSubViews;
public class HomeUserPanelViewModel : BaseViewModel
{
+ private readonly IProfileManagerService _profileManager;
private readonly BindableList _graphValues = new();
-
+
public bool IsUserNotLoggedIn => CurrentUser == default || CurrentUser?.UniqueId == Guid.Empty;
public bool IsUserLoggedIn => CurrentUser != default && CurrentUser?.UniqueId != Guid.Empty;
-
- public User? CurrentUser => ProfileManager.User;
+
+ public IUser? CurrentUser => _profileManager.User;
public Axis[] Axes { get; set; } =
{
@@ -31,7 +35,7 @@ public class HomeUserPanelViewModel : BaseViewModel
Labels = null
}
};
-
+
private Bitmap? _profilePicture;
public Bitmap? ProfilePicture
@@ -39,13 +43,15 @@ public Bitmap? ProfilePicture
get => _profilePicture;
set => this.RaiseAndSetIfChanged(ref _profilePicture, value);
}
-
+
public ObservableCollection Series { get; set; }
- public HomeUserPanelViewModel(IStatisticsProvider? statisticsProvider)
+ public HomeUserPanelViewModel(IStatisticsProvider? statisticsProvider, IProfileManagerService profileManager)
{
+ _profileManager = profileManager;
+
var statsProvider = statisticsProvider;
-
+
if (statsProvider != null)
{
_graphValues.BindTo(statsProvider.GraphValues);
@@ -58,7 +64,7 @@ public HomeUserPanelViewModel(IStatisticsProvider? statisticsProvider)
statsProvider.UserDataChanged += (_, _) => this.RaisePropertyChanged(nameof(CurrentUser));
}
-
+
Activator = new ViewModelActivator();
this.WhenActivated(Block);
@@ -67,7 +73,7 @@ public HomeUserPanelViewModel(IStatisticsProvider? statisticsProvider)
private async void Block(CompositeDisposable obj)
{
ProfilePicture = await LoadProfilePictureAsync();
-
+
Series = new ObservableCollection
{
new LineSeries
@@ -105,12 +111,12 @@ public async Task LoadUserProfileAsync()
var sessionToken = await File.ReadAllTextAsync("data/session.op");
- await ProfileManager.Login(sessionToken);
+ await _profileManager.Login(sessionToken);
this.RaisePropertyChanged(nameof(IsUserLoggedIn));
this.RaisePropertyChanged(nameof(IsUserNotLoggedIn));
this.RaisePropertyChanged(nameof(CurrentUser));
-
+
ProfilePicture = await LoadProfilePictureAsync();
}
@@ -118,6 +124,6 @@ public async Task LoadUserProfileAsync()
{
if (CurrentUser == default || CurrentUser.UniqueId == Guid.Empty) return default;
- return await Locator.Current.GetService().User.GetProfilePictureAsync(CurrentUser.UniqueId);
+ return await Locator.Current.GetService().User.GetProfilePictureAsync(CurrentUser.UniqueId);
}
}
\ No newline at end of file
diff --git a/OsuPlayer/Views/HomeView.axaml b/OsuPlayer/Views/HomeView.axaml
index bd1da925..2130a332 100644
--- a/OsuPlayer/Views/HomeView.axaml
+++ b/OsuPlayer/Views/HomeView.axaml
@@ -5,9 +5,8 @@
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:views="clr-namespace:OsuPlayer.Views"
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
xmlns:valueConverters="clr-namespace:OsuPlayer.Extensions.ValueConverters;assembly=OsuPlayer.Extensions"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.HomeView"
FontWeight="{DynamicResource DefaultFontWeight}">
@@ -18,10 +17,10 @@
-
-
+
+
-
+
_songsLoading = new();
private readonly ReadOnlyObservableCollection? _sortedSongEntries;
+ private readonly IProfileManagerService _profileManager;
public readonly IPlayer Player;
+
private List? _playlistContextMenuEntries;
private List? _playlists;
private Bitmap? _profilePicture;
@@ -31,7 +35,7 @@ public class HomeViewModel : BaseViewModel
public ReadOnlyObservableCollection? SortedSongEntries => _sortedSongEntries;
public HomeUserPanelViewModel HomeUserPanelView { get; }
-
+
public IMapEntryBase? SelectedSong
{
get => _selectedSong;
@@ -43,7 +47,7 @@ public IMapEntryBase? SelectedSong
public bool SongsLoading => new Config().Container.OsuPath != null && _songsLoading.Value;
- public User? CurrentUser => ProfileManager.User;
+ public User? CurrentUser => _profileManager.User;
public Bitmap? ProfilePicture
{
@@ -58,22 +62,24 @@ public bool DisplayUserStats
get => _displayUserStats;
set => this.RaiseAndSetIfChanged(ref _displayUserStats, value);
}
-
+
public List? PlaylistContextMenuEntries
{
get => _playlistContextMenuEntries;
set => this.RaiseAndSetIfChanged(ref _playlistContextMenuEntries, value);
}
- public HomeViewModel(IPlayer player, IStatisticsProvider? statisticsProvider)
+ public HomeViewModel(IPlayer player, IStatisticsProvider? statisticsProvider, IProfileManagerService profileManager)
{
- HomeUserPanelView = new HomeUserPanelViewModel(statisticsProvider);
-
+ _profileManager = profileManager;
+
+ HomeUserPanelView = new HomeUserPanelViewModel(statisticsProvider, _profileManager);
+
Player = player;
_songsLoading.BindTo(((IImportNotifications) Player).SongsLoading);
_songsLoading.BindValueChanged(_ => this.RaisePropertyChanged(nameof(SongsLoading)));
-
+
player.SongSourceProvider.Songs?.ObserveOn(AvaloniaScheduler.Instance).Bind(out _sortedSongEntries).Subscribe();
this.RaisePropertyChanged(nameof(SortedSongEntries));
diff --git a/OsuPlayer/Views/PlayHistoryView.axaml b/OsuPlayer/Views/PlayHistoryView.axaml
index 0eb30950..9516ae1f 100644
--- a/OsuPlayer/Views/PlayHistoryView.axaml
+++ b/OsuPlayer/Views/PlayHistoryView.axaml
@@ -3,7 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:extensions="clr-namespace:OsuPlayer.IO.DbReader.DataModels.Extensions;assembly=OsuPlayer.IO"
+ xmlns:extensions="clr-namespace:OsuPlayer.Data.DataModels.Extensions;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.PlayHistoryView">
diff --git a/OsuPlayer/Views/PlayHistoryViewModel.cs b/OsuPlayer/Views/PlayHistoryViewModel.cs
index 04a4883a..ce10df22 100644
--- a/OsuPlayer/Views/PlayHistoryViewModel.cs
+++ b/OsuPlayer/Views/PlayHistoryViewModel.cs
@@ -1,6 +1,7 @@
using Nein.Base;
using Nein.Extensions;
-using OsuPlayer.IO.DbReader.DataModels.Extensions;
+using OsuPlayer.Data.DataModels.Extensions;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Importer;
using OsuPlayer.Modules.Audio.Interfaces;
using ReactiveUI;
diff --git a/OsuPlayer/Views/PlayerControlViewModel.cs b/OsuPlayer/Views/PlayerControlViewModel.cs
index 1f7afb7a..aaffa8e9 100644
--- a/OsuPlayer/Views/PlayerControlViewModel.cs
+++ b/OsuPlayer/Views/PlayerControlViewModel.cs
@@ -3,10 +3,10 @@
using Avalonia.Threading;
using Nein.Base;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Data.OsuPlayer.StorageModels;
using OsuPlayer.Extensions.EnumExtensions;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Blacklist;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.Modules.Audio.Interfaces;
diff --git a/OsuPlayer/Views/PlaylistEditorView.axaml b/OsuPlayer/Views/PlaylistEditorView.axaml
index 32aa3628..77a92efb 100644
--- a/OsuPlayer/Views/PlaylistEditorView.axaml
+++ b/OsuPlayer/Views/PlaylistEditorView.axaml
@@ -6,8 +6,7 @@
xmlns:valueConverters="clr-namespace:OsuPlayer.ValueConverters"
xmlns:extensions="clr-namespace:OsuPlayer.Extensions.ValueConverters;assembly=OsuPlayer.Extensions"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.PlaylistEditorView"
FontWeight="{DynamicResource DefaultFontWeight}">
diff --git a/OsuPlayer/Views/PlaylistEditorView.axaml.cs b/OsuPlayer/Views/PlaylistEditorView.axaml.cs
index ec181d40..71a1684d 100644
--- a/OsuPlayer/Views/PlaylistEditorView.axaml.cs
+++ b/OsuPlayer/Views/PlaylistEditorView.axaml.cs
@@ -5,8 +5,8 @@
using Avalonia.VisualTree;
using Nein.Base;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.UI_Extensions;
using OsuPlayer.Windows;
diff --git a/OsuPlayer/Views/PlaylistEditorViewModel.cs b/OsuPlayer/Views/PlaylistEditorViewModel.cs
index db6de530..580e01a3 100644
--- a/OsuPlayer/Views/PlaylistEditorViewModel.cs
+++ b/OsuPlayer/Views/PlaylistEditorViewModel.cs
@@ -4,8 +4,8 @@
using DynamicData;
using Nein.Base;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.Modules.Audio.Interfaces;
using ReactiveUI;
diff --git a/OsuPlayer/Views/PlaylistView.axaml b/OsuPlayer/Views/PlaylistView.axaml
index 8984f828..00f09ed8 100644
--- a/OsuPlayer/Views/PlaylistView.axaml
+++ b/OsuPlayer/Views/PlaylistView.axaml
@@ -3,10 +3,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:storageModels="clr-namespace:OsuPlayer.Data.OsuPlayer.StorageModels;assembly=OsuPlayer.Data"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.PlaylistView"
FontWeight="{DynamicResource DefaultFontWeight}">
diff --git a/OsuPlayer/Views/PlaylistView.axaml.cs b/OsuPlayer/Views/PlaylistView.axaml.cs
index 737ec1b4..be5df20d 100644
--- a/OsuPlayer/Views/PlaylistView.axaml.cs
+++ b/OsuPlayer/Views/PlaylistView.axaml.cs
@@ -6,9 +6,9 @@
using Avalonia.VisualTree;
using Material.Icons.Avalonia;
using Nein.Base;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.UI_Extensions;
using OsuPlayer.Windows;
diff --git a/OsuPlayer/Views/PlaylistViewModel.cs b/OsuPlayer/Views/PlaylistViewModel.cs
index b6caf62a..d46cf2c1 100644
--- a/OsuPlayer/Views/PlaylistViewModel.cs
+++ b/OsuPlayer/Views/PlaylistViewModel.cs
@@ -5,9 +5,9 @@
using Material.Icons.Avalonia;
using Nein.Base;
using Nein.Extensions;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.Modules.Audio.Interfaces;
using ReactiveUI;
diff --git a/OsuPlayer/Views/SearchView.axaml b/OsuPlayer/Views/SearchView.axaml
index d224806b..df090c05 100644
--- a/OsuPlayer/Views/SearchView.axaml
+++ b/OsuPlayer/Views/SearchView.axaml
@@ -3,8 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OsuPlayer.Views"
- xmlns:dataModels="clr-namespace:OsuPlayer.IO.DbReader.DataModels;assembly=OsuPlayer.IO"
- xmlns:interfaces="clr-namespace:OsuPlayer.IO.DbReader.Interfaces;assembly=OsuPlayer.IO"
+ xmlns:interfaces="clr-namespace:OsuPlayer.Data.DataModels.Interfaces;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.SearchView"
FontWeight="{DynamicResource DefaultFontWeight}">
@@ -18,7 +17,8 @@
-
diff --git a/OsuPlayer/Views/SearchView.axaml.cs b/OsuPlayer/Views/SearchView.axaml.cs
index 8d9bd7e4..817d4583 100644
--- a/OsuPlayer/Views/SearchView.axaml.cs
+++ b/OsuPlayer/Views/SearchView.axaml.cs
@@ -2,7 +2,7 @@
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Nein.Base;
-using OsuPlayer.IO.DbReader.Interfaces;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.IO.Storage.Blacklist;
using ReactiveUI;
diff --git a/OsuPlayer/Views/SearchViewModel.cs b/OsuPlayer/Views/SearchViewModel.cs
index 39fc2db9..d5e38f90 100644
--- a/OsuPlayer/Views/SearchViewModel.cs
+++ b/OsuPlayer/Views/SearchViewModel.cs
@@ -4,9 +4,9 @@
using Avalonia.Threading;
using DynamicData;
using Nein.Base;
+using OsuPlayer.Data.DataModels.Interfaces;
using OsuPlayer.Data.OsuPlayer.Classes;
using OsuPlayer.Data.OsuPlayer.StorageModels;
-using OsuPlayer.IO.DbReader.Interfaces;
using OsuPlayer.IO.Storage.Playlists;
using OsuPlayer.Modules.Audio.Interfaces;
using ReactiveUI;
diff --git a/OsuPlayer/Views/SettingsView.axaml b/OsuPlayer/Views/SettingsView.axaml
index 5cede5d3..45f3545c 100644
--- a/OsuPlayer/Views/SettingsView.axaml
+++ b/OsuPlayer/Views/SettingsView.axaml
@@ -321,7 +321,7 @@
-
+
@@ -400,6 +400,17 @@
+
+
+
+
+
+
+
+
diff --git a/OsuPlayer/Views/SettingsView.axaml.cs b/OsuPlayer/Views/SettingsView.axaml.cs
index 85536b45..fd03888b 100644
--- a/OsuPlayer/Views/SettingsView.axaml.cs
+++ b/OsuPlayer/Views/SettingsView.axaml.cs
@@ -3,13 +3,13 @@
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
-using JetBrains.Annotations;
using Nein.Base;
using Nein.Controls;
using Nein.Extensions;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.IO.Importer;
using OsuPlayer.Modules.Audio.Interfaces;
-using OsuPlayer.Network.LastFM;
+using OsuPlayer.Network.LastFm;
using OsuPlayer.UI_Extensions;
using OsuPlayer.Windows;
using ReactiveUI;
@@ -129,25 +129,14 @@ private void OpenEqClick(object? sender, RoutedEventArgs e)
_mainWindow.ViewModel.MainView = _mainWindow.ViewModel.EqualizerView;
}
- private void ReportBug_OnClick(object? sender, RoutedEventArgs e)
- {
- GeneralExtensions.OpenUrl("https://github.com/osu-player/osuplayer/issues/new/choose");
- }
-
- private void JoinDiscord_OnClick(object? sender, RoutedEventArgs e)
- {
- GeneralExtensions.OpenUrl("https://discord.gg/RJQSc5B");
- }
-
- private void ContactUs_OnClick(object? sender, RoutedEventArgs e)
- {
- GeneralExtensions.OpenUrl("https://github.com/osu-player/osuplayer#contact");
- }
-
private void OnUsePitch_Click(object? sender, RoutedEventArgs e)
{
var value = (sender as ToggleSwitch)?.IsChecked;
+ using var config = new Config();
+
+ config.Container.UsePitch = value ?? true;
+
var engine = Locator.Current.GetRequiredService();
engine.UpdatePlaybackMethod();
@@ -156,7 +145,7 @@ private void OnUsePitch_Click(object? sender, RoutedEventArgs e)
private async void LastFmAuth_OnClick(object? sender, RoutedEventArgs e)
{
var window = Locator.Current.GetService();
- var lastFmApi = Locator.Current.GetService();
+ var lastFmApi = Locator.Current.GetService();
await using var config = new Config();
@@ -168,7 +157,7 @@ private async void LastFmAuth_OnClick(object? sender, RoutedEventArgs e)
await MessageBox.ShowDialogAsync(window, "Please enter a API-Key and API-Secret before authorizing");
return;
}
-
+
// We only load the APIKey from the config, as it is the only key that we save
// 1. Because we always need the api key for all the request
// 2. The secret is only used for the first authentication of the token
@@ -185,7 +174,7 @@ private async void LastFmAuth_OnClick(object? sender, RoutedEventArgs e)
lastFmApi.AuthorizeToken();
await MessageBox.ShowDialogAsync(window, "Close this window, when you are done, authenticating in the browser");
-
+
await lastFmApi.GetSessionKey();
await lastFmApi.SaveSessionKeyAsync();
@@ -197,7 +186,7 @@ private async void LastFmAuth_OnClick(object? sender, RoutedEventArgs e)
private void ExportCollectionsClick(object? sender, RoutedEventArgs e)
{
if (_mainWindow?.ViewModel == null) return;
-
+
_mainWindow.ViewModel.MainView = _mainWindow.ViewModel.ExportSongsView;
}
@@ -207,4 +196,12 @@ private void OpenPlayerHistoryClick(object? sender, RoutedEventArgs e)
_mainWindow.ViewModel.MainView = _mainWindow.ViewModel.PlayHistoryView;
}
+
+ private void ReportBug_OnClick(object? sender, RoutedEventArgs e) => GeneralExtensions.OpenUrl("https://github.com/founntain/osuplayer/issues/new/choose");
+
+ private void JoinDiscord_OnClick(object? sender, RoutedEventArgs e) => GeneralExtensions.OpenUrl("https://discord.gg/RJQSc5B");
+
+ private void ContactUs_OnClick(object? sender, RoutedEventArgs e) => GeneralExtensions.OpenUrl("https://github.com/founntain/osuplayer#-contact");
+
+ private void Github_OnClick(object? sender, RoutedEventArgs e) => GeneralExtensions.OpenUrl("https://github.com/founntain/osuplayer");
}
\ No newline at end of file
diff --git a/OsuPlayer/Views/SettingsViewModel.cs b/OsuPlayer/Views/SettingsViewModel.cs
index 1d72698f..aedf8fbf 100644
--- a/OsuPlayer/Views/SettingsViewModel.cs
+++ b/OsuPlayer/Views/SettingsViewModel.cs
@@ -9,12 +9,12 @@
using OsuPlayer.Data.OsuPlayer.Classes;
using OsuPlayer.Data.OsuPlayer.Enums;
using OsuPlayer.Extensions.EnumExtensions;
+using OsuPlayer.Interfaces.Service;
using OsuPlayer.Modules.Audio.Interfaces;
-using OsuPlayer.Modules.Services;
-using OsuPlayer.Modules.ShuffleImpl;
using OsuPlayer.Network;
using OsuPlayer.Network.Data;
-using OsuPlayer.Network.LastFM;
+using OsuPlayer.Network.LastFm;
+using OsuPlayer.Services;
using OsuPlayer.Styles;
using OsuPlayer.Windows;
using ReactiveUI;
@@ -26,6 +26,8 @@ public class SettingsViewModel : BaseViewModel
{
public readonly IPlayer Player;
+ private readonly IProfileManagerService _profileManager;
+
private readonly Bindable _blacklistSkip = new();
private readonly Bindable _playlistEnableOnPlay = new();
private readonly Bindable _sortingMode = new();
@@ -36,8 +38,8 @@ public class SettingsViewModel : BaseViewModel
private bool _enableScrobbling;
private bool _displayBackgroundImage;
private float _backgroundBlurRadius;
- private string _lastFmApiKey;
- private string _lastFmApiSecret;
+ private string _lastFmApiKey = string.Empty;
+ private string _lastFmApiSecret = string.Empty;
private string _osuLocation = string.Empty;
private string _patchnotes = string.Empty;
private string _settingsSearchQ = string.Empty;
@@ -46,10 +48,10 @@ public class SettingsViewModel : BaseViewModel
private KnownColors _selectedBackgroundColor;
private FontWeights _selectedFontWeight;
private StartupSong _selectedStartupSong;
- private BackgroundMode _backgroundMode;
- private ReleaseChannels _selectedReleaseChannel;
private AudioDevice? _selectedAudioDevice;
private IShuffleImpl? _selectedShuffleAlgorithm;
+ private BackgroundMode _backgroundMode;
+ private ReleaseChannels _selectedReleaseChannel;
private IShuffleServiceProvider? _shuffleServiceProvider;
private List? _contributors;
@@ -67,7 +69,7 @@ public bool DisplayUserStats
var mainWindowViewModel = Locator.Current.GetService();
mainWindowViewModel.HomeView.DisplayUserStats = value;
-
+
mainWindowViewModel.HomeView.RaisePropertyChanged(nameof(mainWindowViewModel.HomeView.DisplayUserStats));
}
}
@@ -169,7 +171,7 @@ public string Patchnotes
set => this.RaiseAndSetIfChanged(ref _patchnotes, value);
}
- public UserModel? CurrentUser => ProfileManager.User;
+ public UserModel? CurrentUser => _profileManager.User;
public string OsuLocation
{
@@ -465,10 +467,11 @@ public string SettingsSearchQ
public Controls? SettingsCategories { get; set; }
- public SettingsViewModel(IPlayer player, ISortProvider? sortProvider, IShuffleServiceProvider? shuffleServiceProvider)
+ public SettingsViewModel(IPlayer player, ISortProvider? sortProvider, IShuffleServiceProvider? shuffleServiceProvider, IProfileManagerService profileManager)
{
Player = player;
_shuffleServiceProvider = shuffleServiceProvider;
+ _profileManager = profileManager;
AvailableAudioDevices = Player.AvailableAudioDevices;
@@ -490,7 +493,7 @@ public SettingsViewModel(IPlayer player, ISortProvider? sortProvider, IShuffleSe
_enableScrobbling = config.Container.EnableScrobbling;
_displayUserStats = config.Container.DisplayerUserStats;
- var lastFmApi = Locator.Current.GetService();
+ var lastFmApi = Locator.Current.GetService();
_isLastFmAuthorized = lastFmApi.LoadSessionKey();
diff --git a/OsuPlayer/Views/StatisticsViewModel.cs b/OsuPlayer/Views/StatisticsViewModel.cs
index 0cd98715..acf920b6 100644
--- a/OsuPlayer/Views/StatisticsViewModel.cs
+++ b/OsuPlayer/Views/StatisticsViewModel.cs
@@ -2,7 +2,9 @@
using System.Threading.Tasks;
using System.Timers;
using Nein.Base;
-using OsuPlayer.Network.API.Service.NorthFox.Endpoints;
+using Nein.Extensions;
+using OsuPlayer.Interfaces.Service;
+using OsuPlayer.Network.API.NorthFox;
using ReactiveUI;
using Splat;
@@ -122,7 +124,9 @@ private void UpdateDate()
private async Task UpdateApiStatistics()
{
- var statistics = await Locator.Current.GetService().ApiStatistics.GetApiStatistics();
+ if (Locator.Current.GetRequiredService() is not NorthFox api) return;
+
+ var statistics = await api.ApiStatistics.GetApiStatistics();
if (statistics == null) return;
@@ -136,12 +140,16 @@ private async Task UpdateApiStatistics()
private async Task UpdateStorageAmount()
{
- MbUsed = (float) await Locator.Current.GetService().ApiStatistics.GetStorageAmount();
+ if (Locator.Current.GetRequiredService() is not NorthFox api) return;
+
+ MbUsed = (float) await api.ApiStatistics.GetStorageAmount();
}
private async Task UpdateBeatmapCount()
{
- var apiStatistics = await Locator.Current.GetService().ApiStatistics.GetApiStatistics();
+ if (Locator.Current.GetRequiredService() is not NorthFox api) return;
+
+ var apiStatistics = await api.ApiStatistics.GetApiStatistics();
if (apiStatistics == null) return;
diff --git a/OsuPlayer/Views/UserView.axaml b/OsuPlayer/Views/UserView.axaml
index 12c4b7f1..30dfef3b 100644
--- a/OsuPlayer/Views/UserView.axaml
+++ b/OsuPlayer/Views/UserView.axaml
@@ -2,13 +2,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:online="clr-namespace:OsuPlayer.Network.Online;assembly=OsuPlayer.Network"
xmlns:views="clr-namespace:OsuPlayer.Views"
xmlns:valueConverters="clr-namespace:OsuPlayer.Extensions.ValueConverters;assembly=OsuPlayer.Extensions"
xmlns:avalonia="clr-namespace:LiveChartsCore.SkiaSharpView.Avalonia;assembly=LiveChartsCore.SkiaSharpView.Avalonia"
xmlns:statistics="clr-namespace:OsuPlayer.Api.Data.API.RequestModels.Statistics;assembly=OsuPlayer.Api.Data"
xmlns:avalonia1="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:entityModels="clr-namespace:OsuPlayer.Api.Data.API.EntityModels;assembly=OsuPlayer.Api.Data"
+ xmlns:dataModels="clr-namespace:OsuPlayer.Data.DataModels;assembly=OsuPlayer.Data"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OsuPlayer.Views.UserView"
FontWeight="{DynamicResource DefaultFontWeight}">
@@ -32,7 +32,7 @@