├── OsuPlayer.NativeLibs
├── _._
├── image
│ └── icon.png
├── docs
│ └── README.md
├── runtimes
│ ├── win-x64
│ │ └── native
│ │ │ ├── bass.dll
│ │ │ ├── bass_fx.dll
│ │ │ ├── bassenc.dll
│ │ │ └── bassenc_mp3.dll
│ ├── win-x86
│ │ └── native
│ │ │ ├── bass.dll
│ │ │ ├── bass_fx.dll
│ │ │ ├── bassenc.dll
│ │ │ └── bassenc_mp3.dll
│ ├── linux-x64
│ │ └── native
│ │ │ ├── libbass.so
│ │ │ ├── libbass_fx.so
│ │ │ ├── libbassenc.so
│ │ │ └── libbassenc_mp3.so
│ ├── linux-x86
│ │ └── native
│ │ │ ├── libbass.so
│ │ │ ├── libbass_fx.so
│ │ │ ├── libbassenc.so
│ │ │ └── libbassenc_mp3.so
│ └── osx-x64
│ │ └── native
│ │ ├── libbass.dylib
│ │ ├── libbass_fx.dylib
│ │ ├── libbassenc.dylib
│ │ └── libbassenc_mp3.dylib
└── OsuPlayer.NativeLibs.csproj
├── OsuPlayer.IO
├── Realm.dll
├── Realm.Fody.dll
├── FodyWeavers.xml
├── DirectoryManager.cs
├── Storage
│ ├── Config
│ │ └── Config.cs
│ ├── Equalizer
│ │ └── EqStorage.cs
│ ├── Playlists
│ │ └── PlaylistStorage.cs
│ └── Blacklist
│ │ └── Blacklist.cs
├── Importer
│ ├── IImportNotifications.cs
│ ├── ISongSourceProvider.cs
│ └── CollectionImporter.cs
└── OsuPlayer.IO.csproj
├── OsuPlayer
├── Resources
│ ├── x96.ico
│ ├── defaultBg.jpg
│ ├── playerLogo.png
│ └── logo_outline.png
├── Modules
│ ├── Audio
│ │ └── Interfaces
│ │ │ ├── ICommonFeatures.cs
│ │ │ ├── IHasDiscordRpc.cs
│ │ │ ├── IPlayModes.cs
│ │ │ ├── IHasBlacklist.cs
│ │ │ ├── ISettableAudioDevices.cs
│ │ │ ├── IAudioEngine.cs
│ │ │ ├── IHasPlaylists.cs
│ │ │ ├── IHasEffects.cs
│ │ │ ├── ICanOpenFiles.cs
│ │ │ ├── IAudioControls.cs
│ │ │ └── IPlayer.cs
│ └── BitmapExtensions.cs
├── Usings.cs
├── Views
│ ├── PartyViewModel.cs
│ ├── TopBarViewModel.cs
│ ├── StatisticsView.axaml.cs
│ ├── PartyView.axaml.cs
│ ├── PlayHistoryView.axaml.cs
│ ├── UpdateViewModel.cs
│ ├── Navigation
│ │ └── NavigationFactory.cs
│ ├── SearchView.axaml.cs
│ ├── PartyView.axaml
│ ├── CustomControls
│ │ ├── AudioVisualizerView.axaml
│ │ └── AudioVisualizerView.axaml.cs
│ ├── HomeSubViews
│ │ └── HomeUserPanelView.axaml.cs
│ ├── UpdateView.axaml.cs
│ ├── PlayHistoryViewModel.cs
│ ├── HomeView.axaml.cs
│ ├── UpdateView.axaml
│ ├── TopBarView.axaml.cs
│ └── ExportSongsView.axaml.cs
├── Windows
│ ├── LoginWindowViewModel.cs
│ ├── FullscreenWindow.axaml.cs
│ ├── CreateProfileWindowViewModel.cs
│ ├── FullscreenWindow.axaml
│ ├── ExportSongsProcessWindowViewModel.cs
│ └── FullscreenWindowViewModel.cs
├── Styles
│ ├── FluentDark.axaml
│ └── Accents
│ │ └── AccentColors.axaml
├── App.axaml.cs
├── ValueConverters
│ └── PlaylistValueConverter.cs
└── UI Extensions
│ ├── MessageBoxWindow.axaml.cs
│ ├── MessageBoxViewModel.cs
│ ├── MessageBox.cs
│ └── MessageBoxWindow.axaml
├── .gitignore
├── .idea
└── .idea.OsuPlayer
│ └── .idea
│ ├── dictionaries
│ └── engel.xml
│ ├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
│ ├── encodings.xml
│ ├── sqldialects.xml
│ ├── vcs.xml
│ ├── indexLayout.xml
│ └── .gitignore
├── OsuPlayer.Data
├── Enums
│ ├── DbCreationType.cs
│ └── LogType.cs
├── OsuPlayer
│ ├── Enums
│ │ ├── PlayState.cs
│ │ ├── ReleaseChannels.cs
│ │ ├── RepeatMode.cs
│ │ ├── ShuffleDirection.cs
│ │ ├── PlayDirection.cs
│ │ ├── StartupSong.cs
│ │ ├── BackgroundMode.cs
│ │ ├── SortingMode.cs
│ │ └── FontWeights.cs
│ ├── Classes
│ │ ├── VersionModel.cs
│ │ ├── AddToPlaylistContextMenuEntry.cs
│ │ ├── AudioDevice.cs
│ │ └── EqPreset.cs
│ └── StorageModels
│ │ ├── IStorableContainer.cs
│ │ ├── BlacklistContainer.cs
│ │ ├── EqContainer.cs
│ │ ├── PlaylistContainer.cs
│ │ └── Playlist.cs
├── DataModels
│ ├── IDbReaderFactory.cs
│ ├── Online
│ │ ├── News.cs
│ │ ├── Article.cs
│ │ ├── UserColors.cs
│ │ └── OnlineUserStatusModelExtended.cs
│ ├── OsuCollection.cs
│ ├── Extensions
│ │ ├── HistoricalMapEntryComparer.cs
│ │ └── HistoricalMapEntry.cs
│ ├── Interfaces
│ │ ├── IMapEntry.cs
│ │ ├── IUser.cs
│ │ ├── IDatabaseReader.cs
│ │ └── IMapEntryBase.cs
│ ├── RealmMapEntry.cs
│ ├── ObservableSorter.cs
│ └── DbMapEntry.cs
├── LazerModels
│ ├── Files
│ │ ├── INamedFile.cs
│ │ ├── IHasRealmFiles.cs
│ │ ├── IFileInfo.cs
│ │ ├── RealmFile.cs
│ │ ├── IHasNamedFiles.cs
│ │ ├── IHasGuidPrimaryKey.cs
│ │ ├── INamedFileUsage.cs
│ │ └── RealmNamedFileUsage.cs
│ ├── Beatmaps
│ │ ├── BeatmapOnlineStatus.cs
│ │ ├── ScoreRank.cs
│ │ ├── IRulesetInfo.cs
│ │ ├── BeatmapDifficulty.cs
│ │ ├── IScoreInfo.cs
│ │ ├── IBeatmapSetInfo.cs
│ │ ├── IBeatmapInfo.cs
│ │ └── BeatmapMetadata.cs
│ ├── Interfaces
│ │ ├── IUser.cs
│ │ ├── IHasOnlineID.cs
│ │ └── IMappingOperationOptions.cs
│ ├── Extensions
│ │ ├── ScoreInfoExtensions.cs
│ │ ├── CollectionExtensions.cs
│ │ ├── BeatmapInfoExtionsions.cs
│ │ └── BeatmapMetadataInfoExtensions.cs
│ ├── RealmUser.cs
│ └── Collections
│ │ └── BeatmapCollection.cs
└── OsuPlayer.Data.csproj
├── OsuPlayer.Network
├── LastFm
│ └── Responses
│ │ ├── TokenResponse.cs
│ │ └── SessionResponse.cs
├── Data
│ └── OsuPlayerContributor.cs
├── Constants.cs
├── IWebRequest.cs
├── UpdateResponse.cs
├── API
│ └── NorthFox
│ │ ├── NorthFox.Event.cs
│ │ ├── NorthFox.Activity.cs
│ │ ├── NorthFox.ApiStatistics.cs
│ │ ├── NorthFox.UserStatistics.cs
│ │ ├── NorthFox.Beatmap.cs
│ │ └── NorthFox.Badge.cs
└── OsuPlayer.Network.csproj
├── OsuPlayer.Interfaces
├── Service
│ ├── IOsuPlayerService.cs
│ ├── ILoggingService.cs
│ ├── IProfileManagerService.cs
│ ├── IDiscordService.cs
│ ├── IOsuPlayerApiService.cs
│ ├── ILastFmApiService.cs
│ ├── IHistoryProvider.cs
│ ├── IShuffleServiceProvider.cs
│ ├── ISortProvider.cs
│ ├── Endpoint
│ │ └── IOsuPlayerApiUserEndpoint.cs
│ ├── IShuffleImpl.cs
│ └── IStatisticsProvider.cs
└── OsuPlayer.Interfaces.csproj
├── OsuPlayer.Extensions
├── StringExtensions.cs
├── EnumExtensions
│ ├── KnownColorsExtensions.cs
│ └── FontWeightExtensions.cs
├── FilePickerFileTypesExtensions.cs
├── DefaultImplAttr.cs
├── ValueConverters
│ ├── OsuProfileConverter.cs
│ ├── UsernameConverter.cs
│ ├── SettingsUserConverter.cs
│ ├── PlayPauseConverter.cs
│ ├── IsCurrentSongInPlaylistConverter.cs
│ ├── ShuffleConverter.cs
│ ├── BeatmapModelFullSongNameConverter.cs
│ ├── BeatmapModelLastPlayedConverter.cs
│ ├── BeatmapModelMostPlayedConverter.cs
│ ├── BeatmapModelTimesPlayedConverter.cs
│ ├── DecimalFormatter.cs
│ ├── IsCurrentSongOnBlacklistConverter.cs
│ ├── LastFmToAuthConverter.cs
│ ├── SourceListValueConverter.cs
│ ├── IconNameToIconKindConverter.cs
│ ├── VolumeConverter.cs
│ ├── GridFormatter.cs
│ └── RepeatConverter.cs
├── OsuPlayer.Extensions.csproj
├── ObjectExtensions
│ └── BeatmapModelExtensions.cs
└── UnhandledExceptionHandler.cs
├── OsuPlayer.Services
├── LoggingService.cs
├── ShuffleImpl
│ ├── RngShuffler.cs
│ └── BalancedShuffler.cs
├── OsuPlayer.Services.csproj
├── LastFmService.cs
├── ProfileManagerService.cs
├── HistoryService.cs
├── DbReaderFactory.cs
├── ShuffleService.cs
├── OsuSongSourceService.cs
└── SortService.cs
├── OsuPlayer.CrashHandler
├── CrashHandlerMainWindowViewModel.cs
├── App.axaml
├── App.axaml.cs
├── Program.cs
├── CrashHandlerMainWindow.axaml.cs
└── CrashHandlerMainWindow.axaml
├── OsuPlayer.Tests
├── NetworkTests
│ └── PasswordManagerTests.cs
├── IOTests
│ └── DirectoryManagerTests.cs
├── FormatTimeTests.cs
├── OsuPlayer.Tests.csproj
└── ValueConverterTests
│ ├── ShuffleConverterTests.cs
│ ├── PlayPauseConverterTests.cs
│ └── SourceListValueConverterTests.cs
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── dotnet.yml
├── OsuPlayer.Updater
└── OsuPlayer.Updater.csproj
├── .run
├── OsuPlayer.Tests.run.xml
├── OsuPlayer.CrashHandler.run.xml
├── OsuPlayer With Environment Variables.run.xml
├── OsuPlayer _ Live API.run.xml
├── OsuPlayer _ Local API.run.xml
└── OsuPlayer _ Sandbox API.run.xml
└── LICENSE
/OsuPlayer.NativeLibs/_._:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OsuPlayer.IO/Realm.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.IO/Realm.dll
--------------------------------------------------------------------------------
/OsuPlayer.IO/Realm.Fody.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.IO/Realm.Fody.dll
--------------------------------------------------------------------------------
/OsuPlayer/Resources/x96.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer/Resources/x96.ico
--------------------------------------------------------------------------------
/OsuPlayer/Resources/defaultBg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer/Resources/defaultBg.jpg
--------------------------------------------------------------------------------
/OsuPlayer/Resources/playerLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer/Resources/playerLogo.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | obj/
3 | /packages/
4 | riderModule.iml
5 | /_ReSharper.Caches/
6 | OsuPlayer.sln.DotSettings.user
7 | .name
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/image/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/image/icon.png
--------------------------------------------------------------------------------
/OsuPlayer/Resources/logo_outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer/Resources/logo_outline.png
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/dictionaries/engel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/Enums/DbCreationType.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.Enums;
2 |
3 | public enum DbCreationType
4 | {
5 | OsuDb,
6 | Realm
7 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/LastFm/Responses/TokenResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Network.LastFm.Responses;
2 |
3 | public record TokenResponse(string Token);
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/PlayState.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum PlayState
4 | {
5 | Playing,
6 | Paused
7 | }
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/docs/README.md:
--------------------------------------------------------------------------------
1 | All rights belong to the respective owners at https://www.un4seen.com/.
2 |
3 | Contains the bass libraries for win and linux.
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x64/native/bass.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x64/native/bass.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x86/native/bass.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x86/native/bass.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x64/native/bass_fx.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x64/native/bass_fx.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x64/native/bassenc.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x64/native/bassenc.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x86/native/bass_fx.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x86/native/bass_fx.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x86/native/bassenc.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x86/native/bassenc.dll
--------------------------------------------------------------------------------
/OsuPlayer.IO/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbass.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbass.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbass.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbass.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbass.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbass.dylib
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbass_fx.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbass_fx.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbassenc.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbassenc.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbass_fx.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbass_fx.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbassenc.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbassenc.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbass_fx.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbass_fx.dylib
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbassenc.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbassenc.dylib
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x64/native/bassenc_mp3.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x64/native/bassenc_mp3.dll
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/win-x86/native/bassenc_mp3.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/win-x86/native/bassenc_mp3.dll
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/ReleaseChannels.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum ReleaseChannels
4 | {
5 | Stable = 0,
6 | PreReleases = 1
7 | }
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbassenc_mp3.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x64/native/libbassenc_mp3.so
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbassenc_mp3.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/linux-x86/native/libbassenc_mp3.so
--------------------------------------------------------------------------------
/OsuPlayer.Network/LastFm/Responses/SessionResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Network.LastFm.Responses;
2 |
3 | public record SessionResponse(string? Name, string Key, int Subscriber);
--------------------------------------------------------------------------------
/OsuPlayer.Data/Enums/LogType.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Services;
2 |
3 | public enum LogType
4 | {
5 | Info,
6 | Success,
7 | Warning,
8 | Error,
9 | Debug
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/RepeatMode.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum RepeatMode
4 | {
5 | NoRepeat,
6 | Playlist,
7 | SingleSong
8 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/ShuffleDirection.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum ShuffleDirection
4 | {
5 | Backwards = -1,
6 | Forward = 1
7 | }
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbassenc_mp3.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Founntain/osuplayer/HEAD/OsuPlayer.NativeLibs/runtimes/osx-x64/native/libbassenc_mp3.dylib
--------------------------------------------------------------------------------
/OsuPlayer.Network/Data/OsuPlayerContributor.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media.Imaging;
2 |
3 | namespace OsuPlayer.Network.Data;
4 |
5 | public record OsuPlayerContributor(string Name, Bitmap? Avatar);
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/PlayDirection.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum PlayDirection
4 | {
5 | Backwards = -1,
6 | Normal = 0,
7 | Forward = 1
8 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/StartupSong.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum StartupSong
4 | {
5 | FirstSong = 0,
6 | LastPlayed = 1,
7 | RandomSong = 2
8 | }
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/sqldialects.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IOsuPlayerService.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Interfaces.Service;
2 |
3 | public interface IOsuPlayerService
4 | {
5 | protected abstract string ServiceName { get; }
6 | protected abstract string ServiceTag();
7 | }
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/ILoggingService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Services;
2 |
3 | namespace OsuPlayer.Interfaces.Service;
4 |
5 | public interface ILoggingService
6 | {
7 | public void Log(string message, LogType logType = LogType.Info, object? data = null);
8 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Extensions;
2 |
3 | public static class StringExtensions
4 | {
5 | public static string? IsNullOrWhiteSpaceWithFallback(this string? str, string? fallback) => string.IsNullOrWhiteSpace(str) ? fallback : str;
6 | }
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/OsuPlayer.IO/DirectoryManager.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.IO;
2 |
3 | public static class DirectoryManager
4 | {
5 | public static void GenerateMissingDirectories()
6 | {
7 | if (!Directory.Exists("data"))
8 | Directory.CreateDirectory("data");
9 | }
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Network;
2 |
3 | ///
4 | /// Global constants for the application
5 | ///
6 | public static class Constants
7 | {
8 | public static bool OfflineMode { get; set; }
9 | public static bool Localhost { get; set; } = false;
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Classes/VersionModel.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Classes;
2 |
3 | public sealed class VersionModel
4 | {
5 | public DateTime Version { get; set; }
6 |
7 | public new string ToString()
8 | {
9 | return Version.ToString("yyyy.Mdd.Hmm.s");
10 | }
11 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/IWebRequest.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Network;
2 |
3 | public interface IWebRequest
4 | {
5 | public Task GetRequest(string route, TRequest? data = default);
6 | public Task PostRequest(string route, TRequest? data = default);
7 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/ICommonFeatures.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Modules.Audio.Interfaces;
2 |
3 | ///
4 | /// This interface is used to provide a common feature set used by the audio component.
5 | ///
6 | public interface ICommonFeatures : IAudioControls, ISettableAudioDevices, IHasEffects
7 | {
8 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/StorageModels/IStorableContainer.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.StorageModels;
2 |
3 | ///
4 | /// This interface represents a implementing type which is given to
5 | ///
6 | public interface IStorableContainer
7 | {
8 | public IStorableContainer Init();
9 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/IDbReaderFactory.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels.Interfaces;
2 | using OsuPlayer.Data.Enums;
3 |
4 | namespace OsuPlayer.Data.DataModels;
5 |
6 | public interface IDbReaderFactory
7 | {
8 | public DbCreationType Type { get; set; }
9 |
10 | public IDatabaseReader CreateDatabaseReader(string path);
11 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IProfileManagerService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels;
2 |
3 | namespace OsuPlayer.Interfaces.Service;
4 |
5 | public interface IProfileManagerService
6 | {
7 | public User? User { get; set; }
8 |
9 | public Task Login(string username, string password);
10 | public Task Login(string token);
11 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/BackgroundMode.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | public enum BackgroundMode
4 | {
5 | // SolidColor = WindowTransparencyLevel.None,
6 | // AcrylicBlur = WindowTransparencyLevel.AcrylicBlur,
7 | // Mica = WindowTransparencyLevel.Mica
8 | SolidColor,
9 | AcrylicBlur,
10 | Mica,
11 | }
--------------------------------------------------------------------------------
/.idea/.idea.OsuPlayer/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /contentModel.xml
6 | /modules.xml
7 | /projectSettingsUpdater.xml
8 | /.idea.OsuPlayer.iml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/INamedFile.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Files;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface INamedFile
6 | {
7 | string Filename { get; set; }
8 |
9 | RealmFile File { get; set; }
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/EnumExtensions/KnownColorsExtensions.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media;
2 | using OsuPlayer.Data.OsuPlayer.Enums;
3 |
4 | namespace OsuPlayer.Extensions.EnumExtensions;
5 |
6 | public static class KnownColorsExtensions
7 | {
8 | public static Color ToColor(this KnownColors color)
9 | {
10 | return Color.FromUInt32((uint) color);
11 | }
12 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/FilePickerFileTypesExtensions.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Platform.Storage;
2 |
3 | namespace OsuPlayer.Extensions;
4 |
5 | public class FilePickerFileTypesExtensions {
6 | public static FilePickerFileType OsuDb { get; } = new("osu! db files")
7 | {
8 | Patterns = new[] { "osu!.db", "client.realm", },
9 | MimeTypes = null
10 | };
11 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IHasDiscordRpc.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Modules.Audio.Interfaces;
2 |
3 | ///
4 | /// This interface provides discord rpc capabilities.
5 | ///
6 | public interface IHasDiscordRpc
7 | {
8 | ///
9 | /// Disposes the discord client.
10 | ///
11 | public void DisposeDiscordClient();
12 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IDiscordService.cs:
--------------------------------------------------------------------------------
1 | using DiscordRPC;
2 |
3 | namespace OsuPlayer.Interfaces.Service;
4 |
5 | public interface IDiscordService
6 | {
7 | public void Initialize();
8 | public void DeInitialize();
9 | public Task UpdatePresence(string details, string state, int beatmapSetId = 0, Assets? assets = null, TimeSpan? durationLeft = null);
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/IHasRealmFiles.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Files;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface IHasRealmFiles
6 | {
7 | IList Files { get; }
8 |
9 | string Hash { get; set; }
10 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/SortingMode.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | ///
4 | /// An enum representing possible sorting modes for the song list
5 | ///
6 | /// Available sorting modes: Title, Artist, SetId
7 | ///
8 | ///
9 | public enum SortingMode
10 | {
11 | Title = 0,
12 | Artist = 1,
13 | SetId = 2
14 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/StorageModels/BlacklistContainer.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
2 |
3 | namespace OsuPlayer.Data.OsuPlayer.StorageModels;
4 |
5 | public class BlacklistContainer : IStorableContainer
6 | {
7 | public HashSet Songs { get; set; } = new();
8 |
9 | public IStorableContainer Init()
10 | {
11 | return this;
12 | }
13 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/LoggingService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Interfaces.Service;
2 |
3 | namespace OsuPlayer.Services;
4 |
5 | public class LoggingService : OsuPlayerService, ILoggingService
6 | {
7 | public override string ServiceName => "LOGGING_SERVICE";
8 |
9 | public void Log(string message, LogType logType = LogType.Info, object? data = null) => LogToConsole(message, logType, data);
10 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IPlayModes.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | namespace OsuPlayer.Modules.Audio.Interfaces;
4 |
5 | ///
6 | /// This interface provides different play modes for the player.
7 | ///
8 | public interface IPlayModes
9 | {
10 | public Bindable IsShuffle { get; }
11 | public Bindable RepeatMode { get; }
12 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/IFileInfo.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Files;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface IFileInfo
6 | {
7 | ///
8 | /// SHA-256 hash of the file content.
9 | ///
10 | string Hash { get; }
11 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Classes/AddToPlaylistContextMenuEntry.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Classes;
2 |
3 | public class AddToPlaylistContextMenuEntry
4 | {
5 | public string Name { get; set; }
6 | public Action Action { get; set; }
7 |
8 | public AddToPlaylistContextMenuEntry(string name, Action action)
9 | {
10 | Name = name;
11 | Action = action;
12 | }
13 | }
--------------------------------------------------------------------------------
/OsuPlayer/Usings.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.IO;
3 | global using System.Linq;
4 | global using System.Collections.Generic;
5 | global using System.Collections.ObjectModel;
6 | global using Nein.Extensions.Bindables;
7 | global using OsuPlayer.IO.Storage.Config;
8 | global using OsuPlayer.Modules.Audio;
9 | using System.Runtime.CompilerServices;
10 |
11 | [assembly: InternalsVisibleTo("OsuPlayer.Tests")]
--------------------------------------------------------------------------------
/OsuPlayer/Views/PartyViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using Nein.Base;
3 | using ReactiveUI;
4 |
5 | namespace OsuPlayer.Views;
6 |
7 | public class PartyViewModel : BaseViewModel
8 | {
9 | public PartyViewModel()
10 | {
11 | Activator = new ViewModelActivator();
12 | this.WhenActivated(disposables => { Disposable.Create(() => { }).DisposeWith(disposables); });
13 | }
14 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/TopBarViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using Nein.Base;
3 | using ReactiveUI;
4 |
5 | namespace OsuPlayer.Views;
6 |
7 | public class TopBarViewModel : BaseViewModel
8 | {
9 | public TopBarViewModel()
10 | {
11 | Activator = new ViewModelActivator();
12 | this.WhenActivated(disposables => { Disposable.Create(() => { }).DisposeWith(disposables); });
13 | }
14 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/CrashHandlerMainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using Nein.Base;
2 | using ReactiveUI;
3 |
4 | namespace OsuPlayer.CrashHandler;
5 |
6 | public class CrashHandlerMainWindowViewModel : BaseWindowViewModel
7 | {
8 | private string _crashLog = string.Empty;
9 |
10 | public string CrashLog
11 | {
12 | get => _crashLog;
13 | set => this.RaiseAndSetIfChanged(ref _crashLog, value);
14 | }
15 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/RealmFile.cs:
--------------------------------------------------------------------------------
1 | using Realms;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Files;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | [MapTo("File")]
8 | public class RealmFile : RealmObject, IFileInfo
9 | {
10 | [PrimaryKey]
11 | public string Hash { get; set; } = string.Empty;
12 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/IHasNamedFiles.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Files;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface IHasNamedFiles
6 | {
7 | ///
8 | /// All files used by this model.
9 | ///
10 | IEnumerable Files { get; }
11 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/IHasGuidPrimaryKey.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using Realms;
3 |
4 | namespace OsuPlayer.Data.LazerModels.Files;
5 |
6 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
7 | // See the LICENCE file in the repository root for full licence text.
8 | public interface IHasGuidPrimaryKey
9 | {
10 | [JsonIgnore]
11 | [PrimaryKey]
12 | Guid ID { get; }
13 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/DefaultImplAttr.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Extensions;
2 |
3 | ///
4 | /// This attribute defines the default implementation of a service to use if no other is specified explicitly.
5 | ///
6 | public class DefaultImplAttr : Attribute
7 | {
8 | ///
9 | /// Creates a new instance of the class.
10 | ///
11 | public DefaultImplAttr()
12 | {
13 | }
14 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/StatisticsView.axaml.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using Nein.Base;
3 |
4 | namespace OsuPlayer.Views;
5 |
6 | public partial class StatisticsView : ReactiveControl
7 | {
8 | public StatisticsView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private void Block(CompositeDisposable disposables)
14 | {
15 | Disposable.Create(() => { }).DisposeWith(disposables);
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IOsuPlayerApiService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 | using OsuPlayer.Interfaces.Service.Endpoint;
3 |
4 | namespace OsuPlayer.Interfaces.Service;
5 |
6 | public interface IOsuPlayerApiService
7 | {
8 | public IOsuPlayerApiUserEndpoint User { get; set; }
9 |
10 | public Task LoginAndSaveAuthToken(string username, string password);
11 | public Task LoginWithTokenAndSaveNewToken(string token);
12 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Storage/Config/Config.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.StorageModels;
2 |
3 | namespace OsuPlayer.IO.Storage.Config;
4 |
5 | public class Config : Storable
6 | {
7 | private static ConfigContainer? _configContainer;
8 |
9 | public override string Path => System.IO.Path.Combine("data", "config.json");
10 |
11 | public Config()
12 | {
13 | _configContainer ??= Read();
14 |
15 | Container = _configContainer;
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Storage/Equalizer/EqStorage.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.StorageModels;
2 |
3 | namespace OsuPlayer.IO.Storage.Equalizer;
4 |
5 | public class EqStorage : Storable
6 | {
7 | private static EqContainer? _eqContainer;
8 |
9 | public override string Path => System.IO.Path.Combine("data", "eqPresets.json");
10 |
11 | public EqStorage()
12 | {
13 | _eqContainer ??= Read();
14 |
15 | Container = _eqContainer;
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Online/News.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace OsuPlayer.Data.DataModels.Online;
4 |
5 | public sealed class News
6 | {
7 | public DateTime CreationTime { get; set; }
8 |
9 | public string CreationTimeString =>
10 | $"Written on {CreationTime.ToString("dddd HH:mm, dd MMMM yyyy", new CultureInfo("en-us"))} by {Creator}";
11 |
12 | public string Creator { get; set; }
13 | public string Title { get; set; }
14 | public string Content { get; set; }
15 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapOnlineStatus.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public enum BeatmapOnlineStatus
6 | {
7 | None = -3,
8 |
9 | Graveyard = -2,
10 |
11 | WIP = -1,
12 |
13 | Pending = 0,
14 |
15 | Ranked = 1,
16 |
17 | Approved = 2,
18 |
19 | Qualified = 3,
20 |
21 | Loved = 4
22 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Online/Article.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace OsuPlayer.Data.DataModels.Online;
4 |
5 | public sealed class Article
6 | {
7 | public DateTime CreationTime { get; set; }
8 |
9 | public string CreationTimeString =>
10 | $"Written on {CreationTime.ToString("dddd HH:mm, dd MMMM yyyy", new CultureInfo("en-us"))} by {Creator}";
11 |
12 | public string Creator { get; set; }
13 | public string Title { get; set; }
14 | public string Content { get; set; }
15 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/INamedFileUsage.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Files;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface INamedFileUsage
6 | {
7 | ///
8 | /// The underlying file on disk.
9 | ///
10 | IFileInfo File { get; }
11 |
12 | ///
13 | /// The filename for this usage.
14 | ///
15 | string Filename { get; }
16 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/NetworkTests/PasswordManagerTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using OsuPlayer.Network.Security;
3 |
4 | namespace OsuPlayer.Tests.NetworkTests;
5 |
6 | public class PasswordManagerTests
7 | {
8 | [TestCase("", false)]
9 | [TestCase("Test", false)]
10 | [TestCase("Test123!_?", true)]
11 | public void PasswordManagerTest(string pw, bool expected)
12 | {
13 | var result = PasswordManager.CheckIfPasswordMeetsRequirements(pw);
14 |
15 | Assert.That(result, Is.EqualTo(expected));
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/IOTests/DirectoryManagerTests.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using NUnit.Framework;
3 | using OsuPlayer.IO;
4 |
5 | namespace OsuPlayer.Tests.IOTests;
6 |
7 | public class DirectoryManagerTests
8 | {
9 | [Test]
10 | public void GenerateMissingDirectories()
11 | {
12 | Assert.DoesNotThrow(() =>
13 | {
14 | if (Directory.Exists("data"))
15 | Directory.Delete("data", true);
16 | });
17 |
18 | Assert.DoesNotThrow(DirectoryManager.GenerateMissingDirectories);
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/App.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/ILastFmApiService.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Interfaces.Service;
2 |
3 | public interface ILastFmApiService
4 | {
5 | public void SetApiKeyAndSecret(string apiKey, string secret);
6 | public Task Scrobble(string title, string artist);
7 | public bool LoadSessionKey();
8 | public Task LoadSessionKeyAsync();
9 | public bool IsAuthorized();
10 | public Task GetAuthToken();
11 | public void AuthorizeToken();
12 | public Task GetSessionKey();
13 | public Task SaveSessionKeyAsync();
14 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/PartyView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Interactivity;
3 | using Material.Icons;
4 | using Material.Icons.Avalonia;
5 | using Nein.Extensions;
6 |
7 | namespace OsuPlayer.Views;
8 |
9 | public partial class PartyView : UserControl
10 | {
11 | public PartyView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | private void Button_OnClick(object? sender, RoutedEventArgs e)
17 | {
18 | GeneralExtensions.OpenUrl("https://github.com/osu-player/osuplayer/issues/70");
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/OsuCollection.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.DataModels;
2 |
3 | ///
4 | /// Represents a collection from osu!
5 | ///
6 | public class OsuCollection
7 | {
8 | public string Name { get; set; } = string.Empty;
9 | public List BeatmapHashes { get; private set; } = new();
10 |
11 | public OsuCollection()
12 | {
13 | }
14 |
15 | public OsuCollection(string name, List beatmapHashes)
16 | {
17 | Name = name;
18 | BeatmapHashes = beatmapHashes;
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/UpdateResponse.cs:
--------------------------------------------------------------------------------
1 | using Octokit;
2 |
3 | namespace OsuPlayer.Network;
4 |
5 | ///
6 | /// A data structure for an update.
7 | ///
8 | public sealed class UpdateResponse
9 | {
10 | public bool IsNewVersionAvailable { get; set; }
11 | public bool IsPrerelease { get; set; }
12 | public string? HtmlUrl { get; set; }
13 | public string? Version { get; set; }
14 | public string? PatchNotes { get; set; }
15 | public DateTimeOffset? ReleaseDate { get; set; }
16 | public IReadOnlyList? Assets { get; set; }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IHistoryProvider.cs:
--------------------------------------------------------------------------------
1 | using Nein.Extensions.Bindables;
2 | using OsuPlayer.Data.DataModels.Extensions;
3 | using OsuPlayer.Data.DataModels.Interfaces;
4 |
5 | namespace OsuPlayer.Interfaces.Service;
6 |
7 | ///
8 | /// This interface provides historic capabilities
9 | ///
10 | public interface IHistoryProvider
11 | {
12 | public HistoricalMapEntryComparer Comparer { get; }
13 | public BindableList History { get; }
14 |
15 | void AddOrUpdateMapEntry(IMapEntryBase mapEntry);
16 | void ClearHistory();
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntryComparer.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.DataModels.Extensions;
2 |
3 | public class HistoricalMapEntryComparer : IEqualityComparer
4 | {
5 | public bool Equals(HistoricalMapEntry? x, HistoricalMapEntry? y)
6 | {
7 | if (x == null && y == null) return true;
8 | if (x == null || y == null) return false;
9 |
10 | return x.MapEntry.Hash == y.MapEntry.Hash;
11 | }
12 |
13 | public int GetHashCode(HistoricalMapEntry obj)
14 | {
15 | return obj.MapEntry.GetHashCode();
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer/Windows/LoginWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using Nein.Base;
2 | using ReactiveUI;
3 |
4 | namespace OsuPlayer.Windows;
5 |
6 | public class LoginWindowViewModel : BaseWindowViewModel
7 | {
8 | private string _password = string.Empty;
9 | private string _username = string.Empty;
10 |
11 | public string Username
12 | {
13 | get => _username;
14 | set => this.RaiseAndSetIfChanged(ref _username, value);
15 | }
16 |
17 | public string Password
18 | {
19 | get => _password;
20 | set => this.RaiseAndSetIfChanged(ref _password, value);
21 | }
22 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Interfaces/IMapEntry.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.DataModels.Interfaces;
2 |
3 | public interface IMapEntry : IMapEntryBase
4 | {
5 | public string AudioFileName { get; }
6 | public string FolderName { get; }
7 | public string FolderPath { get; }
8 | public string FullPath { get; }
9 |
10 | ///
11 | /// Gets the background image of this
12 | ///
13 | /// the path of the background found. Returns null if the map doesn't have a background
14 | public Task FindBackground();
15 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IHasBlacklist.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace OsuPlayer.Modules.Audio.Interfaces;
4 |
5 | ///
6 | /// This interface provides blacklist capability.
7 | ///
8 | public interface IHasBlacklist
9 | {
10 | public Bindable BlacklistSkip { get; }
11 |
12 | public event PropertyChangedEventHandler? BlacklistChanged;
13 |
14 | ///
15 | /// Triggers if the blacklist got changed
16 | ///
17 | ///
18 | public void TriggerBlacklistChanged(PropertyChangedEventArgs e);
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Interfaces/IUser.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Interfaces;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface IUser : IHasOnlineID, IEquatable
6 | {
7 | string Username { get; }
8 |
9 | bool IsBot { get; }
10 |
11 | bool IEquatable.Equals(IUser? other)
12 | {
13 | if (other == null)
14 | return false;
15 |
16 | return OnlineID == other.OnlineID && Username == other.Username;
17 | }
18 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/OsuProfileConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 |
4 | namespace OsuPlayer.Extensions.ValueConverters;
5 |
6 | public class OsuProfileConverter : IValueConverter
7 | {
8 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
9 | {
10 | return !string.IsNullOrWhiteSpace(value?.ToString());
11 | }
12 |
13 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
14 | {
15 | throw new NotImplementedException();
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IShuffleServiceProvider.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Interfaces.Service;
2 |
3 | ///
4 | /// This interface provides a service provider for shuffle implementations.
5 | ///
6 | public interface IShuffleServiceProvider
7 | {
8 | public List ShuffleAlgorithms { get; }
9 | public IShuffleImpl? ShuffleImpl { get; }
10 |
11 | ///
12 | /// Sets the shuffle algorithm.
13 | ///
14 | /// The to set.
15 | public void SetShuffleImpl(IShuffleImpl? algorithm);
16 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 |
5 | namespace OsuPlayer.CrashHandler;
6 |
7 | public class App : Application
8 | {
9 | public override void Initialize()
10 | {
11 | AvaloniaXamlLoader.Load(this);
12 | }
13 |
14 | public override void OnFrameworkInitializationCompleted()
15 | {
16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) desktop.MainWindow = new CrashHandlerMainWindow();
17 |
18 | base.OnFrameworkInitializationCompleted();
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/ISortProvider.cs:
--------------------------------------------------------------------------------
1 | using DynamicData;
2 | using Nein.Extensions.Bindables;
3 | using OsuPlayer.Data.DataModels;
4 | using OsuPlayer.Data.DataModels.Interfaces;
5 | using OsuPlayer.Data.OsuPlayer.Enums;
6 |
7 | namespace OsuPlayer.Interfaces.Service;
8 |
9 | public interface ISortProvider
10 | {
11 | public IObservable>? SortedSongs { get; set; }
12 | public Bindable SortingModeBindable { get; }
13 | public ObservableSorter SortingModeObservable { get; }
14 |
15 | public IComparable CustomSorter(IMapEntryBase map, SortingMode sortingMode);
16 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/ISettableAudioDevices.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Classes;
2 |
3 | namespace OsuPlayer.Modules.Audio.Interfaces;
4 |
5 | ///
6 | /// This interface provides changeable audio device capability.
7 | ///
8 | public interface ISettableAudioDevices
9 | {
10 | public List AvailableAudioDevices { get; }
11 |
12 | ///
13 | /// Set the audio device to use as the output.
14 | ///
15 | /// The to use
16 | public void SetDevice(AudioDevice? audioDevice);
17 | }
--------------------------------------------------------------------------------
/OsuPlayer/Styles/FluentDark.axaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OsuPlayer/Windows/FullscreenWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Nein.Base;
3 | using Nein.Extensions;
4 | using OsuPlayer.Modules.Audio.Interfaces;
5 | using Splat;
6 |
7 | namespace OsuPlayer.Windows;
8 |
9 | public partial class FullscreenWindow : ReactiveWindow
10 | {
11 | public FullscreenWindow()
12 | {
13 | InitializeComponent();
14 |
15 | DataContext = new FullscreenWindowViewModel(Locator.Current.GetRequiredService());
16 | }
17 |
18 | private void InitializeComponent()
19 | {
20 | AvaloniaXamlLoader.Load(this);
21 | }
22 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/PlayHistoryView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Input;
2 | using Nein.Base;
3 |
4 | namespace OsuPlayer.Views;
5 |
6 | public partial class PlayHistoryView : ReactiveControl
7 | {
8 | public PlayHistoryView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private async void HistoryListBox_OnDoubleTapped(object? sender, TappedEventArgs e)
14 | {
15 | var mapEntryFromHash = ViewModel.SongSourceProvider.GetMapEntryFromHash(ViewModel.SelectedHistoricalMapEntry?.MapEntry.Hash);
16 |
17 | await ViewModel.Player.TryPlaySongAsync(mapEntryFromHash);
18 | }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/UsernameConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 |
4 | namespace OsuPlayer.Extensions.ValueConverters;
5 |
6 | public class UsernameConverter : IValueConverter
7 | {
8 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
9 | {
10 | return string.IsNullOrWhiteSpace(value?.ToString()) ? "Not logged in" : value;
11 | }
12 |
13 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
14 | {
15 | throw new NotImplementedException();
16 | }
17 | }
--------------------------------------------------------------------------------
/OsuPlayer/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 | using OsuPlayer.Windows;
5 | using Splat;
6 |
7 | namespace OsuPlayer;
8 |
9 | public class App : Application
10 | {
11 | public override void Initialize()
12 | {
13 | AvaloniaXamlLoader.Load(this);
14 | }
15 |
16 | public override void OnFrameworkInitializationCompleted()
17 | {
18 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) desktop.MainWindow = Locator.Current.GetService();
19 |
20 | base.OnFrameworkInitializationCompleted();
21 | }
22 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/UpdateViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using Nein.Base;
3 | using OsuPlayer.Network;
4 | using ReactiveUI;
5 |
6 | namespace OsuPlayer.Views;
7 |
8 | public class UpdateViewModel : BaseViewModel
9 | {
10 | private UpdateResponse? _update;
11 |
12 | public UpdateResponse? Update
13 | {
14 | get => _update;
15 | set => this.RaiseAndSetIfChanged(ref _update, value);
16 | }
17 |
18 | public UpdateViewModel()
19 | {
20 | Activator = new ViewModelActivator();
21 |
22 | this.WhenActivated(disposables => { Disposable.Create(() => { }).DisposeWith(disposables); });
23 | }
24 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Extensions/ScoreInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Beatmaps;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Extensions;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public static class ScoreInfoExtensions
8 | {
9 | ///
10 | /// A user-presentable display title representing this score.
11 | ///
12 | public static string GetDisplayTitle(this IScoreInfo scoreInfo)
13 | {
14 | return $"{scoreInfo.User.Username} playing {scoreInfo.Beatmap.GetDisplayTitle()}";
15 | }
16 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IAudioEngine.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace OsuPlayer.Modules.Audio.Interfaces;
4 |
5 | ///
6 | /// This interface wraps all sub-interfaces used by the audio engine.
7 | ///
8 | public interface IAudioEngine : ICanOpenFiles, ICommonFeatures
9 | {
10 | public delegate Task ChannelReachedEndHandler();
11 |
12 | public Bindable ChannelLength { get; }
13 | public Bindable ChannelPosition { get; }
14 | public Bindable PlaybackSpeed { get; }
15 | public ChannelReachedEndHandler ChannelReachedEnd { set; }
16 |
17 | public float[] GetVisualizationData();
18 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Online/UserColors.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media;
2 |
3 | namespace OsuPlayer.Data.DataModels.Online;
4 |
5 | ///
6 | /// A list of all available role colors
7 | ///
8 | public static class UserColors
9 | {
10 | public static Brush Staff => new SolidColorBrush(Color.FromRgb(46, 224, 94));
11 | public static Brush Developer => new SolidColorBrush(Color.FromRgb(255, 0, 152));
12 | public static Brush Tester => new SolidColorBrush(Color.FromRgb(0, 191, 255));
13 | public static Brush Donator => new SolidColorBrush(Color.FromRgb(255, 215, 0));
14 | public static Brush User => new SolidColorBrush(Color.FromRgb(255, 255, 255));
15 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Storage/Playlists/PlaylistStorage.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.StorageModels;
2 |
3 | namespace OsuPlayer.IO.Storage.Playlists;
4 |
5 | ///
6 | /// The PlaylistStorage reads and writes playlist data to the playlists.json file located in the data folder.
7 | ///
8 | public sealed class PlaylistStorage : Storable
9 | {
10 | private static PlaylistContainer? _playlistContainer;
11 |
12 | public override string Path => System.IO.Path.Combine("data", "playlists.json");
13 |
14 | public PlaylistStorage()
15 | {
16 | _playlistContainer ??= Read();
17 |
18 | Container = _playlistContainer;
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/ScoreRank.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public enum ScoreRank
8 | {
9 | [Description(@"D")]
10 | D,
11 |
12 | [Description(@"C")]
13 | C,
14 |
15 | [Description(@"B")]
16 | B,
17 |
18 | [Description(@"A")]
19 | A,
20 |
21 | [Description(@"S")]
22 | S,
23 |
24 | [Description(@"S+")]
25 | SH,
26 |
27 | [Description(@"SS")]
28 | X,
29 |
30 | [Description(@"SS+")]
31 | XH
32 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Extensions/CollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Extensions;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public static class CollectionExtensions
6 | {
7 | public static void AddRange(this ICollection collection, IEnumerable items)
8 | {
9 | // List has a potentially more optimal path to adding a range.
10 | if (collection is List list)
11 | list.AddRange(items);
12 | else
13 | foreach (var obj in items)
14 | collection.Add(obj);
15 | }
16 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Storage/Blacklist/Blacklist.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels.Interfaces;
2 | using OsuPlayer.Data.OsuPlayer.StorageModels;
3 |
4 | namespace OsuPlayer.IO.Storage.Blacklist;
5 |
6 | public sealed class Blacklist : Storable
7 | {
8 | private static BlacklistContainer? _blacklistContainer;
9 |
10 | public override string? Path => System.IO.Path.Combine("data", "blacklist.json");
11 |
12 | public Blacklist()
13 | {
14 | _blacklistContainer ??= Read();
15 |
16 | Container = _blacklistContainer;
17 | }
18 |
19 | public bool Contains(IMapEntryBase? map)
20 | {
21 | return Container.Songs.Contains(map?.Hash);
22 | }
23 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/Navigation/NavigationFactory.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using FluentAvalonia.UI.Controls;
3 |
4 | namespace OsuPlayer.Views.Navigation;
5 |
6 | public class NavigationFactory : INavigationPageFactory
7 | {
8 | public Control GetPage(Type srcType)
9 | {
10 | return null;
11 | }
12 |
13 | public Control GetPageFromObject(object target)
14 | {
15 | switch (target)
16 | {
17 | case HomeViewModel:
18 | return new HomeView();
19 | case PlaylistViewModel:
20 | return new PlaylistView();
21 | default:
22 | throw new ArgumentException();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/StorageModels/EqContainer.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Classes;
2 |
3 | namespace OsuPlayer.Data.OsuPlayer.StorageModels;
4 |
5 | public class EqContainer : IStorableContainer
6 | {
7 | public Guid? LastUsedEqId { get; set; }
8 |
9 | public List? EqPresets { get; set; }
10 |
11 | public IStorableContainer Init()
12 | {
13 | EqPresets ??= new List();
14 | EqPresets.Add(EqPreset.Flat);
15 | EqPresets.Add(EqPreset.Custom);
16 | EqPresets.Add(EqPreset.Classic);
17 | EqPresets.Add(EqPreset.LaptopSpeaker);
18 |
19 | LastUsedEqId ??= EqPresets.First().Id;
20 |
21 | return this;
22 | }
23 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/SettingsUserConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using OsuPlayer.Api.Data.API.EntityModels;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class SettingsUserConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is UserModel user)
12 | return user.Name;
13 |
14 | return "Not logged in";
15 | }
16 |
17 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
18 | {
19 | throw new NotImplementedException();
20 | }
21 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Importer/IImportNotifications.cs:
--------------------------------------------------------------------------------
1 | using Nein.Extensions.Bindables;
2 |
3 | namespace OsuPlayer.IO.Importer;
4 |
5 | ///
6 | /// This interface provides a way to receive import notifications
7 | ///
8 | public interface IImportNotifications
9 | {
10 | public Bindable SongsLoading { get; }
11 |
12 | ///
13 | /// Is called when importing songs started
14 | ///
15 | public void OnImportStarted();
16 |
17 | ///
18 | /// Is called when importing songs finished
19 | ///
20 | /// Indicates whether the import was successful or not
21 | public void OnImportFinished(bool success);
22 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IHasPlaylists.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using OsuPlayer.Data.OsuPlayer.StorageModels;
3 |
4 | namespace OsuPlayer.Modules.Audio.Interfaces;
5 |
6 | ///
7 | /// This interface provides playlist capability.
8 | ///
9 | public interface IHasPlaylists
10 | {
11 | public Bindable SelectedPlaylist { get; }
12 | public Bindable PlaylistEnableOnPlay { get; }
13 |
14 | public event PropertyChangedEventHandler? PlaylistChanged;
15 |
16 | ///
17 | /// Triggers if the playlist got changed
18 | ///
19 | ///
20 | public void TriggerPlaylistChanged(PropertyChangedEventArgs e);
21 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[REQUEST] "
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/PlayPauseConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class PlayPauseConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is bool val) return val ? MaterialIconKind.Pause : MaterialIconKind.PlayArrow;
12 |
13 | return MaterialIconKind.QuestionMark;
14 | }
15 |
16 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
17 | {
18 | throw new NotImplementedException();
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/IsCurrentSongInPlaylistConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class IsCurrentSongInPlaylistConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | var x = value != null && (bool) value;
12 |
13 | return x ? MaterialIconKind.Heart : MaterialIconKind.HeartOutline;
14 | }
15 |
16 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
17 | {
18 | throw new NotImplementedException();
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/ShuffleConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class ShuffleConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is bool val) return val ? MaterialIconKind.Shuffle : MaterialIconKind.ShuffleDisabled;
12 |
13 | return MaterialIconKind.QuestionMark;
14 | }
15 |
16 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
17 | {
18 | throw new NotImplementedException();
19 | }
20 | }
--------------------------------------------------------------------------------
/OsuPlayer/Styles/Accents/AccentColors.axaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | #B200FF
6 | #9f05e1
7 | #8f06cb
8 | #7c05af
9 | #be29ff
10 | #c849ff
11 | #d676ff
12 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Online/OnlineUserStatusModelExtended.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 | using OsuPlayer.Api.Data.API.Enums;
3 |
4 | namespace OsuPlayer.Data.DataModels.Online;
5 |
6 | public sealed class OnlineUserStatusModelExtended : UserOnlineStatusModel
7 | {
8 | public string Status => GetStatusDisplay();
9 |
10 | public string GetStatusDisplay()
11 | {
12 | switch (StatusType)
13 | {
14 | case UserOnlineStatusType.Listening:
15 | return $"Listening to {Song}";
16 | case UserOnlineStatusType.InParty:
17 | return $"Dancing in a party to {Song}";
18 | default:
19 | return "Idle";
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.Event.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 |
3 | namespace OsuPlayer.Network.API.NorthFox;
4 |
5 | public class NorthFoxEventEndpoint
6 | {
7 | private readonly AbstractApiBase _apiBase;
8 |
9 | public NorthFoxEventEndpoint(AbstractApiBase apiBase)
10 | {
11 | _apiBase = apiBase;
12 | }
13 |
14 | #region GET Requests
15 |
16 | public async Task?> GetAllEvents()
17 | {
18 | return await _apiBase.Get("Event");
19 | }
20 |
21 | public async Task GetEvent(Guid uniqueId)
22 | {
23 | return await _apiBase.GetById("Event", uniqueId);
24 | }
25 |
26 | #endregion
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Updater/OsuPlayer.Updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0; net8.0-windows10.0.17763.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 | ..\OsuPlayer\bin\Debug\
13 |
14 |
15 |
16 | ..\OsuPlayer\bin\Release\
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IHasEffects.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Modules.Audio.Interfaces;
2 |
3 | ///
4 | /// This interface provides audio effects capability.
5 | ///
6 | public interface IHasEffects
7 | {
8 | public BindableArray EqGains { get; }
9 | public bool IsEqEnabled { get; set; }
10 |
11 | ///
12 | /// Sets the playback speed (including pitch)
13 | ///
14 | /// The speed to set
15 | public void SetPlaybackSpeed(double speed);
16 |
17 | ///
18 | /// Triggers a Method change. Usually this should only be called when toggling pitch or other FX settings
19 | ///
20 | public void UpdatePlaybackMethod();
21 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.Activity.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 |
3 | namespace OsuPlayer.Network.API.NorthFox;
4 |
5 | public class NorthFoxActivityEndpoint
6 | {
7 | private readonly AbstractApiBase _apiBase;
8 |
9 | public NorthFoxActivityEndpoint(AbstractApiBase apiBase)
10 | {
11 | _apiBase = apiBase;
12 | }
13 |
14 | #region GET Requests
15 |
16 | public async Task?> GetAllActivities()
17 | {
18 | return await _apiBase.Get("Activity");
19 | }
20 |
21 | public async Task GetActivity(Guid uniqueId)
22 | {
23 | return await _apiBase.GetById("Activity", uniqueId);
24 | }
25 |
26 | #endregion
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/BeatmapModelFullSongNameConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using OsuPlayer.Api.Data.API.EntityModels;
4 | using OsuPlayer.Extensions.ObjectExtensions;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class BeatmapModelFullSongNameConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | return value is not BeatmapModel beatmapModel ? string.Empty : beatmapModel.FullSongName();
13 | }
14 |
15 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/BeatmapModelLastPlayedConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using OsuPlayer.Api.Data.API.EntityModels;
4 | using OsuPlayer.Extensions.ObjectExtensions;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class BeatmapModelLastPlayedConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | return value is not BeatmapModel beatmapModel ? string.Empty : beatmapModel.LastPlayedString();
13 | }
14 |
15 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/BeatmapModelMostPlayedConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using OsuPlayer.Api.Data.API.EntityModels;
4 | using OsuPlayer.Extensions.ObjectExtensions;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class BeatmapModelMostPlayedConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | return value is not BeatmapModel beatmapModel ? string.Empty : beatmapModel.MostPlayedString();
13 | }
14 |
15 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/BeatmapModelTimesPlayedConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using OsuPlayer.Api.Data.API.EntityModels;
4 | using OsuPlayer.Extensions.ObjectExtensions;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class BeatmapModelTimesPlayedConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | return value is not BeatmapModel beatmapModel ? string.Empty : beatmapModel.TimesPlayedString();
13 | }
14 |
15 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/DecimalFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 |
4 | namespace OsuPlayer.Extensions.ValueConverters;
5 |
6 | public class DecimalFormatter : IValueConverter
7 | {
8 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
9 | {
10 | if (targetType != typeof(string)) return null;
11 |
12 | if (value is not IFormattable number) return "";
13 |
14 | var format = number.ToString("N0", CultureInfo.CurrentCulture);
15 |
16 | return format;
17 | }
18 |
19 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
20 | {
21 | throw new NotImplementedException();
22 | }
23 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/IsCurrentSongOnBlacklistConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class IsCurrentSongOnBlacklistConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is not bool x)
12 | return MaterialIconKind.QuestionMark;
13 |
14 | return x ? MaterialIconKind.HeartBroken : MaterialIconKind.HeartBrokenOutline;
15 | }
16 |
17 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
18 | {
19 | throw new NotImplementedException();
20 | }
21 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.ApiStatistics.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.Models;
2 |
3 | namespace OsuPlayer.Network.API.NorthFox;
4 |
5 | public class NorthFoxApiStatisticsEndpoint
6 | {
7 | private readonly AbstractApiBase _apiBase;
8 |
9 | public NorthFoxApiStatisticsEndpoint(AbstractApiBase apiBase)
10 | {
11 | _apiBase = apiBase;
12 | }
13 |
14 | #region GET Requests
15 |
16 | public async Task GetApiStatistics()
17 | {
18 | return await _apiBase.GetRequestAsync("ApiStatistics", "get");
19 | }
20 |
21 | public async Task GetStorageAmount()
22 | {
23 | return await _apiBase.GetRequestAsync("ApiStatistics", "getStorageAmount");
24 | }
25 |
26 | #endregion
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/RealmUser.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Interfaces;
2 | using Realms;
3 |
4 | namespace OsuPlayer.Data.LazerModels;
5 |
6 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
7 | // See the LICENCE file in the repository root for full licence text.
8 | public class RealmUser : EmbeddedObject, IUser, IEquatable
9 | {
10 | public int OnlineID { get; set; } = 1;
11 |
12 | public string Username { get; set; } = string.Empty;
13 |
14 | public bool IsBot => false;
15 |
16 | public bool Equals(RealmUser other)
17 | {
18 | if (ReferenceEquals(null, other)) return false;
19 | if (ReferenceEquals(this, other)) return true;
20 |
21 | return OnlineID == other.OnlineID && Username == other.Username;
22 | }
23 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/LastFmToAuthConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Avalonia.Media;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class LastFmToAuthConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | var isAuthorized = value != null && (bool) value;
12 |
13 | return isAuthorized
14 | ? new SolidColorBrush(Color.FromRgb(0, 200, 0))
15 | : new SolidColorBrush(Color.FromRgb(255, 204, 34));
16 | }
17 |
18 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
19 | {
20 | throw new NotImplementedException();
21 | }
22 | }
--------------------------------------------------------------------------------
/OsuPlayer/Windows/CreateProfileWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using Nein.Base;
2 | using ReactiveUI;
3 |
4 | namespace OsuPlayer.Windows;
5 |
6 | public class CreateProfileWindowViewModel : BaseWindowViewModel
7 | {
8 | private bool _isTosChecked;
9 | private string _password = string.Empty;
10 | private string _username = string.Empty;
11 |
12 | public string Username
13 | {
14 | get => _username;
15 | set => this.RaiseAndSetIfChanged(ref _username, value);
16 | }
17 |
18 | public string Password
19 | {
20 | get => _password;
21 | set => this.RaiseAndSetIfChanged(ref _password, value);
22 | }
23 |
24 | public bool IsTosChecked
25 | {
26 | get => _isTosChecked;
27 | set => this.RaiseAndSetIfChanged(ref _isTosChecked, value);
28 | }
29 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG] "
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. Windows, OSX or Linux]
28 | - Version [e.g. 22]
29 |
30 | **Additional context**
31 | Add any other context about the problem here.
32 |
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/ICanOpenFiles.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Modules.Audio.Interfaces;
2 |
3 | ///
4 | /// This interface provides method(s) regarding opening and closing audio files.
5 | ///
6 | public interface ICanOpenFiles
7 | {
8 | ///
9 | /// Opens an audio file and creates a stream handle containing the decoded audio stream to play
10 | ///
11 | /// the path to the audio file to be opened
12 | /// true if opening succeeded, false else
13 | /// if the sync handle could not be created
14 | public bool OpenFile(string path);
15 |
16 | ///
17 | /// Closes the current audio file stream handle
18 | ///
19 | public void CloseFile();
20 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/StorageModels/PlaylistContainer.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.StorageModels;
2 |
3 | ///
4 | /// A playlist container with a list
5 | ///
6 | public class PlaylistContainer : IStorableContainer
7 | {
8 | public IList? Playlists { get; set; }
9 |
10 | ///
11 | /// Indicates an init of the creating a new empty favorites
12 | ///
13 | /// the current object
14 | public IStorableContainer Init()
15 | {
16 | Playlists = new List
17 | {
18 | new()
19 | {
20 | Name = "Favorites"
21 | }
22 | };
23 | return this;
24 | }
25 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/SourceListValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using DynamicData;
4 | using OsuPlayer.Data.OsuPlayer.StorageModels;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class SourceListValueConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | return value switch
13 | {
14 | null => new List(),
15 | SourceList val => val.Items.ToList(),
16 | _ => new List()
17 | };
18 | }
19 |
20 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
21 | {
22 | throw new NotImplementedException();
23 | }
24 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Classes/AudioDevice.cs:
--------------------------------------------------------------------------------
1 | using ManagedBass;
2 |
3 | namespace OsuPlayer.Data.OsuPlayer.Classes;
4 |
5 | ///
6 | /// Wrapper class for
7 | ///
8 | public sealed class AudioDevice
9 | {
10 | private DeviceInfo DeviceInfo { get; }
11 | public string DeviceName => DeviceInfo.Name;
12 | public bool IsEnabled => DeviceInfo.IsEnabled;
13 | public bool IsDefault => DeviceInfo.IsDefault;
14 | public bool IsInitialized => DeviceInfo.IsInitialized;
15 | public string Driver => DeviceInfo.Driver;
16 | public string DeviceToString => DeviceInfo.ToString();
17 |
18 | public AudioDevice(DeviceInfo deviceInfo)
19 | {
20 | DeviceInfo = deviceInfo;
21 | }
22 |
23 | public override string ToString()
24 | {
25 | return DeviceName;
26 | }
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.ReactiveUI;
4 |
5 | namespace OsuPlayer.CrashHandler;
6 |
7 | internal class Program
8 | {
9 | // Initialization code. Don't use any Avalonia, third-party APIs or any
10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
11 | // yet and stuff might break.
12 | [STAThread]
13 | public static void Main(string[] args)
14 | {
15 | BuildAvaloniaApp()
16 | .StartWithClassicDesktopLifetime(args);
17 | }
18 |
19 | // Avalonia configuration, don't remove; also used by visual designer.
20 | public static AppBuilder BuildAvaloniaApp()
21 | {
22 | return AppBuilder.Configure()
23 | .UsePlatformDetect()
24 | .LogToTrace()
25 | .UseReactiveUI();
26 | }
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/IconNameToIconKindConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class IconNameToIconKindConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is not string s) return MaterialIconKind.Error;
12 |
13 | try
14 | {
15 | return Enum.Parse(s);
16 | }
17 | catch (Exception ex)
18 | {
19 | return MaterialIconKind.Error;
20 | }
21 | }
22 |
23 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
24 | {
25 | throw new NotImplementedException();
26 | }
27 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IAudioControls.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Modules.Audio.Interfaces;
2 |
3 | ///
4 | /// This interface provides basic audio control functions.
5 | ///
6 | public interface IAudioControls
7 | {
8 | public Bindable IsPlaying { get; }
9 | public Bindable Volume { get; }
10 |
11 | ///
12 | /// Pauses the current song if playing or plays again if paused
13 | ///
14 | public void PlayPause();
15 |
16 | ///
17 | /// Sets the playing state to Playing
18 | ///
19 | public void Play();
20 |
21 | ///
22 | /// Sets the playing state to Pause
23 | ///
24 | public void Pause();
25 |
26 | ///
27 | /// Stops the current song and disposes the audio stream
28 | ///
29 | public void Stop();
30 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/RealmMapEntry.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels.Interfaces;
2 |
3 | namespace OsuPlayer.Data.DataModels;
4 |
5 | ///
6 | /// a full beatmap entry with optionally used data
7 | /// only created on a call
8 | ///
9 | public class RealmMapEntry : RealmMapEntryBase, IMapEntry
10 | {
11 | public string BackgroundFileLocation { get; init; } = string.Empty;
12 | public string AudioFileName { get; init; } = string.Empty;
13 | public string FolderName { get; init; } = string.Empty;
14 | public string FolderPath { get; init; } = string.Empty;
15 | public string FullPath { get; init; } = string.Empty;
16 |
17 | public Task FindBackground()
18 | {
19 | return Task.FromResult(File.Exists(BackgroundFileLocation) ? BackgroundFileLocation : null);
20 | }
21 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/FormatTimeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Nein.Extensions;
3 | using NUnit.Framework;
4 |
5 | // ReSharper disable RedundantExplicitParamsArrayCreation
6 |
7 | namespace OsuPlayer.Tests;
8 |
9 | public class FormatTimeTests
10 | {
11 | [TestCase(new object[]
12 | {
13 | 0, 1, 30, "1:30"
14 | })]
15 | [TestCase(new object[]
16 | {
17 | 0, 10, 30, "10:30"
18 | })]
19 | [TestCase(new object[]
20 | {
21 | 1, 1, 30, "1:01:30"
22 | })]
23 | public void TestTimeFormat(object[] input)
24 | {
25 | var hours = (int) input[0];
26 | var minutes = (int) input[1];
27 | var seconds = (int) input[2];
28 | var expectedString = input[3];
29 | var actualString = new TimeSpan(hours, minutes, seconds).FormatTime();
30 | Assert.That(actualString, Is.EqualTo(expectedString));
31 | }
32 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Extensions/BeatmapInfoExtionsions.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Beatmaps;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Extensions;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public static class BeatmapInfoExtionsions
8 | {
9 | ///
10 | /// A user-presentable display title representing this beatmap.
11 | ///
12 | public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo)
13 | {
14 | return $"{beatmapInfo.Metadata.GetDisplayTitle()} {GetVersionString(beatmapInfo)}".Trim();
15 | }
16 |
17 | private static string GetVersionString(IBeatmapInfo beatmapInfo)
18 | {
19 | return string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
20 | }
21 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Interfaces/IHasOnlineID.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable InconsistentNaming
2 |
3 | namespace OsuPlayer.Data.LazerModels.Interfaces;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public interface IHasOnlineID
8 | where T : IEquatable
9 | {
10 | ///
11 | /// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID (except in
12 | /// special cases where autoincrement is not used, like rulesets).
13 | ///
14 | ///
15 | /// Generally we use -1 when specifying "missing" in code, but values of 0 are also considered missing as the online source
16 | /// is generally a MySQL autoincrement value, which can never be 0.
17 | ///
18 | T OnlineID { get; }
19 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/VolumeConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 |
5 | namespace OsuPlayer.Extensions.ValueConverters;
6 |
7 | public class VolumeConverter : IValueConverter
8 | {
9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
10 | {
11 | if (value is not double val) return MaterialIconKind.QuestionMark;
12 |
13 | return val switch
14 | {
15 | 0 => MaterialIconKind.VolumeMute,
16 | < 33 => MaterialIconKind.VolumeLow,
17 | < 66 => MaterialIconKind.VolumeMedium,
18 | _ => MaterialIconKind.VolumeHigh
19 | };
20 | }
21 |
22 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
23 | {
24 | throw new NotImplementedException();
25 | }
26 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/OsuPlayer.Extensions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | annotations
7 | en
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/OsuPlayer.Services/ShuffleImpl/RngShuffler.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Enums;
2 | using OsuPlayer.Extensions;
3 | using OsuPlayer.Interfaces.Service;
4 |
5 | namespace OsuPlayer.Services.ShuffleImpl;
6 |
7 | ///
8 | /// This shuffle implementation will randomly select a song each time with no further logic.
9 | ///
10 | [DefaultImplAttr]
11 | public class RngShuffler : OsuPlayerService, IShuffleImpl
12 | {
13 | private int _maxRange = -1;
14 |
15 | public string Name => "Random Shuffle";
16 | public string Description => "Randomly select a song each time with no further logic.";
17 |
18 | public override string ServiceName => "RNG_SHUFFLE_SERVICE";
19 |
20 | public void Init(int maxRange) => _maxRange = maxRange;
21 |
22 | public int DoShuffle(int currentIndex, ShuffleDirection direction) => Random.Shared.Next(_maxRange);
23 |
24 | public override string ToString() => Name;
25 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ObjectExtensions/BeatmapModelExtensions.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 |
3 | namespace OsuPlayer.Extensions.ObjectExtensions;
4 |
5 | public static class BeatmapModelExtensions
6 | {
7 | public static string FullSongName(this BeatmapModel b) => $"{b.Artist} - {b.Title}";
8 | public static string FullSongNameUnicode(this BeatmapModel b) => $"{b.ArtistUnicode} - {b.TitleUnicode}";
9 | public static string TimesPlayedString(this BeatmapModel b) => $"{b.TimesPlayed}x played";
10 | public static string LastPlayedString(this BeatmapModel b) => string.IsNullOrEmpty(b.LastPlayedBy?.Name)
11 | ? "Last played by an unknown user"
12 | : $"Last played by {b.LastPlayedBy.Name}";
13 | public static string MostPlayedString(this BeatmapModel b) => b.MostPlayedBy == null
14 | ? string.Empty
15 | : $"{b.MostPlayedBy.Item1} played it most with {b.MostPlayedBy.Item2} times";
16 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/GridFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 |
4 | namespace OsuPlayer.Extensions.ValueConverters;
5 |
6 | public class GridFormatter : IValueConverter
7 | {
8 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
9 | {
10 | if (value is not double or int) return 0.0;
11 |
12 | var width = System.Convert.ToDouble(value);
13 |
14 | if (parameter is not string) return 0.0;
15 |
16 | var targetWidth = System.Convert.ToDouble(parameter);
17 |
18 | if (targetWidth <= 0) return 0.0;
19 |
20 | var columns = Math.Ceiling(width / targetWidth);
21 |
22 | return width / columns;
23 | }
24 |
25 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
26 | {
27 | throw new NotImplementedException();
28 | }
29 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/SearchView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Input;
3 | using Avalonia.Interactivity;
4 | using Nein.Base;
5 | using OsuPlayer.Data.DataModels.Interfaces;
6 | using OsuPlayer.IO.Storage.Blacklist;
7 |
8 | namespace OsuPlayer.Views;
9 |
10 | public partial class SearchView : ReactiveControl
11 | {
12 | public SearchView()
13 | {
14 | InitializeComponent();
15 | }
16 |
17 | private async void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e)
18 | {
19 | var list = sender as ListBox;
20 | var song = list!.SelectedItem as IMapEntryBase;
21 |
22 | await ViewModel.Player.TryPlaySongAsync(song);
23 | }
24 |
25 | private void AddToBlacklist_OnClick(object? sender, RoutedEventArgs e)
26 | {
27 | using var blacklist = new Blacklist();
28 |
29 | blacklist.Container.Songs.Add(ViewModel.SelectedSong?.Hash);
30 | }
31 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/OsuPlayer.Interfaces.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/OsuPlayer/ValueConverters/PlaylistValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Nein.Extensions;
4 | using OsuPlayer.IO.Importer;
5 | using Splat;
6 |
7 | namespace OsuPlayer.ValueConverters;
8 |
9 | ///
10 | /// This ValueConverter is in the OsuPlayer Project, because we need access to the Audio class
11 | /// to convert the checksum to a MapEntry
12 | ///
13 | public class PlaylistValueConverter : IValueConverter
14 | {
15 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
16 | {
17 | return value != default ? Locator.Current.GetRequiredService().GetMapEntriesFromHash((ICollection) value, out _) : default;
18 | }
19 |
20 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
21 | {
22 | throw new NotImplementedException();
23 | }
24 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer.Data.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | annotations
7 | en
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ..\OsuPlayer.IO\Realm.dll
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/IRulesetInfo.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Interfaces;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public interface IRulesetInfo : IHasOnlineID, IEquatable, IComparable
8 | {
9 | ///
10 | /// The user-exposed name of this ruleset.
11 | ///
12 | string Name { get; }
13 |
14 | ///
15 | /// An acronym defined by the ruleset that can be used as a permanent identifier.
16 | ///
17 | string ShortName { get; }
18 |
19 | ///
20 | /// A string representation of this ruleset, to be used with reflection to instantiate the ruleset represented by this
21 | /// metadata.
22 | ///
23 | string InstantiationInfo { get; }
24 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Files/RealmNamedFileUsage.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 | using Realms;
3 |
4 | namespace OsuPlayer.Data.LazerModels.Files;
5 |
6 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
7 | // See the LICENCE file in the repository root for full licence text.
8 | public class RealmNamedFileUsage : EmbeddedObject, INamedFile, INamedFileUsage
9 | {
10 | public RealmFile File { get; set; } = null!;
11 |
12 | // [Indexed] cannot be used on `EmbeddedObject`s as it only applies to top-level queries. May need to reconsider this if performance becomes a concern.
13 | public string Filename { get; set; } = null!;
14 |
15 | IFileInfo INamedFileUsage.File => File;
16 |
17 | public RealmNamedFileUsage(RealmFile file, string filename)
18 | {
19 | File = file;
20 | Filename = filename;
21 | }
22 |
23 | [UsedImplicitly]
24 | private RealmNamedFileUsage()
25 | {
26 | }
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/OsuPlayer.Services.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | annotations
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Extensions/BeatmapMetadataInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Beatmaps;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Extensions;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public static class BeatmapMetadataInfoExtensions
8 | {
9 | ///
10 | /// A user-presentable display title representing this metadata.
11 | ///
12 | public static string GetDisplayTitle(this IBeatmapMetadataInfo metadataInfo)
13 | {
14 | var author = string.IsNullOrEmpty(metadataInfo.Author.Username) ? string.Empty : $" ({metadataInfo.Author.Username})";
15 |
16 | var artist = string.IsNullOrEmpty(metadataInfo.Artist) ? "unknown artist" : metadataInfo.Artist;
17 | var title = string.IsNullOrEmpty(metadataInfo.Title) ? "unknown title" : metadataInfo.Title;
18 |
19 | return $"{artist} - {title}{author}".Trim();
20 | }
21 | }
--------------------------------------------------------------------------------
/OsuPlayer/UI Extensions/MessageBoxWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Media;
3 | using Avalonia.ReactiveUI;
4 |
5 | namespace OsuPlayer.UI_Extensions;
6 |
7 | public partial class MessageBoxWindow : ReactiveWindow
8 | {
9 | public MessageBoxWindow()
10 | {
11 | InitializeComponent();
12 |
13 | ViewModel = new MessageBoxViewModel();
14 |
15 | var config = new Config();
16 |
17 | TransparencyLevelHint = new[] { WindowTransparencyLevel.Mica, WindowTransparencyLevel.AcrylicBlur, WindowTransparencyLevel.None };
18 | FontFamily = config.Container.Font ?? FontManager.Current.DefaultFontFamily;
19 | }
20 |
21 | public MessageBoxWindow(string text, string? title)
22 | {
23 | InitializeComponent();
24 |
25 | ViewModel = new MessageBoxViewModel(this, text, title);
26 |
27 | var config = new Config();
28 | // TransparencyLevelHint = (WindowTransparencyLevel) config.Container.BackgroundMode;
29 | }
30 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/Endpoint/IOsuPlayerApiUserEndpoint.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media.Imaging;
2 | using OsuPlayer.Api.Data.API.EntityModels;
3 | using OsuPlayer.Api.Data.API.RequestModels.User;
4 |
5 | namespace OsuPlayer.Interfaces.Service.Endpoint;
6 |
7 | public interface IOsuPlayerApiUserEndpoint
8 | {
9 | Task UpdateSongsPlayed(int amount, int beatmapSetId = -1);
10 | Task UpdateXp(UpdateXpModel updateXpModel);
11 | Task SetOnlineStatus(UserOnlineStatusModel data);
12 | Task GetProfilePictureAsync(Guid currentUserUniqueId);
13 | Task GetUserFromLoginToken();
14 | Task EditUser(EditUserModel editUserModel);
15 | Task SaveProfilePicture(byte[] data);
16 | Task GetProfileBannerAsync(string? bannerUrl);
17 | Task DeleteUser();
18 | Task?> GetAllUsers();
19 | Task?> GetActivityOfUser(Guid selectedUserUniqueId);
20 | Task Register(AddUserModel addUserModel);
21 | }
--------------------------------------------------------------------------------
/.run/OsuPlayer.Tests.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/OsuPlayer/Views/PartyView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
12 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/OsuPlayer.Network/OsuPlayer.Network.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | enable
5 | annotations
6 | en
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapDifficulty.cs:
--------------------------------------------------------------------------------
1 | using Realms;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | [MapTo("BeatmapDifficulty")]
8 | public class BeatmapDifficulty : EmbeddedObject, IBeatmapDifficultyInfo
9 | {
10 | ///
11 | /// The default value used for all difficulty settings except and
12 | /// .
13 | ///
14 | public const float DEFAULT_DIFFICULTY = 5;
15 |
16 | public float DrainRate { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
17 | public float CircleSize { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
18 | public float OverallDifficulty { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
19 | public float ApproachRate { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
20 |
21 | public double SliderMultiplier { get; set; } = 1;
22 | public double SliderTickRate { get; set; } = 1;
23 | }
--------------------------------------------------------------------------------
/OsuPlayer/UI Extensions/MessageBoxViewModel.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Nein.Base;
3 | using ReactiveUI;
4 |
5 | namespace OsuPlayer.UI_Extensions;
6 |
7 | public class MessageBoxViewModel : BaseWindowViewModel
8 | {
9 | private readonly Window _window;
10 | private string _messageBoxText;
11 |
12 | private string _messageBoxTitle;
13 |
14 | public string MessageBoxTitle
15 | {
16 | get => _messageBoxTitle;
17 | set => this.RaiseAndSetIfChanged(ref _messageBoxTitle, value);
18 | }
19 |
20 | public string MessageBoxText
21 | {
22 | get => _messageBoxText;
23 | set => this.RaiseAndSetIfChanged(ref _messageBoxText, value);
24 | }
25 |
26 | public MessageBoxViewModel()
27 | {
28 | }
29 |
30 | public MessageBoxViewModel(Window window, string messageBoxText, string? messageBoxTitle = null)
31 | {
32 | _window = window;
33 | MessageBoxText = messageBoxText;
34 | MessageBoxTitle = messageBoxTitle ?? "Hey, listen!";
35 | }
36 |
37 | public void CloseMessageBox()
38 | {
39 | _window.Close();
40 | }
41 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Founntain
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.UserStatistics.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 | using OsuPlayer.Api.Data.API.RequestModels.Statistics;
3 |
4 | namespace OsuPlayer.Network.API.NorthFox;
5 |
6 | public class NorthFoxUserStatisticsEndpoint
7 | {
8 | private readonly AbstractApiBase _apiBase;
9 |
10 | public NorthFoxUserStatisticsEndpoint(AbstractApiBase apiBase)
11 | {
12 | _apiBase = apiBase;
13 | }
14 |
15 | #region POST Requests
16 |
17 | public async Task AddUserStatistic(PostUserStatisticModel data)
18 | {
19 | return await _apiBase.PostRequestAsync("UserStatistics", "add", data);
20 | }
21 |
22 | #endregion
23 |
24 | #region GET Requests
25 |
26 | public async Task?> GetAllUserStatistics()
27 | {
28 | return await _apiBase.Get("UserStatistics");
29 | }
30 |
31 | public async Task GetAllUserStatistics(Guid uniqueId)
32 | {
33 | return await _apiBase.GetById("UserStatistics", uniqueId);
34 | }
35 |
36 | #endregion
37 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/CustomControls/AudioVisualizerView.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/OsuPlayer/Views/HomeSubViews/HomeUserPanelView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Interactivity;
2 | using Avalonia.Markup.Xaml;
3 | using Avalonia.ReactiveUI;
4 | using Avalonia.VisualTree;
5 | using OsuPlayer.Windows;
6 | using ReactiveUI;
7 |
8 | namespace OsuPlayer.Views.HomeSubViews;
9 |
10 | public partial class HomeUserPanelView : ReactiveUserControl
11 | {
12 | private FluentAppWindow _mainWindow;
13 |
14 | public HomeUserPanelView()
15 | {
16 | InitializeComponent();
17 |
18 | this.WhenActivated(_ =>
19 | {
20 | if (this.GetVisualRoot() is FluentAppWindow mainWindow)
21 | _mainWindow = mainWindow;
22 | });
23 | }
24 |
25 | private void GoToSettings_Click(object? sender, RoutedEventArgs e)
26 | {
27 | if (_mainWindow.ViewModel == default) return;
28 |
29 | _mainWindow.ViewModel.SettingsView.SettingsSearchQ = "Display User Statistics";
30 | _mainWindow.ViewModel.MainView = _mainWindow.ViewModel.SettingsView;
31 | _mainWindow.ViewModel.RaisePropertyChanged(nameof(_mainWindow.ViewModel.SettingsView.SettingsSearchQ));
32 | }
33 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/IScoreInfo.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Files;
2 | using OsuPlayer.Data.LazerModels.Interfaces;
3 |
4 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
5 |
6 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
7 | // See the LICENCE file in the repository root for full licence text.
8 | public interface IScoreInfo : IHasOnlineID, IHasNamedFiles
9 | {
10 | IUser User { get; }
11 |
12 | long TotalScore { get; }
13 |
14 | int MaxCombo { get; }
15 |
16 | double Accuracy { get; }
17 |
18 | bool HasReplay { get; }
19 |
20 | DateTimeOffset Date { get; }
21 |
22 | double? PP { get; }
23 |
24 | IBeatmapInfo Beatmap { get; }
25 |
26 | IRulesetInfo Ruleset { get; }
27 |
28 | ScoreRank Rank { get; }
29 |
30 | // Mods is currently missing from this interface as the `IMod` class has properties which can't be fulfilled by `APIMod`,
31 | // but also doesn't expose `Settings`. We can consider how to implement this in the future if required.
32 |
33 | // Statistics is also missing. This can be reconsidered once changes in serialisation have been completed.
34 | }
--------------------------------------------------------------------------------
/.run/OsuPlayer.CrashHandler.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Extensions/HistoricalMapEntry.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels.Interfaces;
2 |
3 | namespace OsuPlayer.Data.DataModels.Extensions;
4 |
5 | public class HistoricalMapEntry : IComparable
6 | {
7 | public IMapEntryBase MapEntry { get; }
8 | public DateTimeOffset TimePlayed { get; }
9 |
10 | public string TimePlayedString => $"Last Played: {TimePlayed:G}";
11 |
12 | public HistoricalMapEntry(IMapEntryBase mapEntry) : this(mapEntry, DateTimeOffset.Now)
13 | {
14 | }
15 |
16 | public HistoricalMapEntry(IMapEntryBase mapEntry, DateTimeOffset timePlayed)
17 | {
18 | MapEntry = mapEntry;
19 | TimePlayed = timePlayed;
20 | }
21 |
22 | public int CompareTo(HistoricalMapEntry other)
23 | {
24 | return TimePlayed.CompareTo(other.TimePlayed);
25 | }
26 |
27 | public override bool Equals(object? obj)
28 | {
29 | if (obj is HistoricalMapEntry other)
30 | {
31 | return MapEntry.Hash == other.MapEntry.Hash;
32 | }
33 |
34 | return false;
35 | }
36 |
37 | public override int GetHashCode()
38 | {
39 | return MapEntry.GetHashCode();
40 | }
41 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IShuffleImpl.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Enums;
2 |
3 | namespace OsuPlayer.Interfaces.Service;
4 |
5 | ///
6 | /// This interface is used as a base for all shuffle algorithm implementations.
7 | ///
8 | public interface IShuffleImpl
9 | {
10 | public string Name { get; }
11 | public string Description { get; }
12 |
13 | ///
14 | /// Inits the shuffler with the given parameters. This must be called before each time to ensure
15 | /// the shuffler is initialized with valid params.
16 | ///
17 | /// The max index range the shuffler will return with
18 | void Init(int maxRange);
19 |
20 | ///
21 | /// Provides a method to generate a shuffled index based on simple parameters.
22 | ///
23 | /// The current song index the shuffle algorithm is based on
24 | /// The to shuffle to
25 | /// a random generated (shuffled) index
26 | int DoShuffle(int currentIndex, ShuffleDirection direction);
27 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Interfaces/IUser.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media;
2 | using OsuPlayer.Api.Data.API.EntityModels;
3 |
4 | namespace OsuPlayer.Data.DataModels.Interfaces;
5 |
6 | public interface IUser
7 | {
8 | public Guid UniqueId { get; }
9 |
10 | public int Xp { get; set; }
11 | public int XpNeededForNextLevel { get; }
12 | public int Level { get; set; }
13 |
14 | public string XpFormattedString { get; }
15 | public string TotalXpFormattedString { get; }
16 | public string SongsPlayedFormattedString { get; }
17 |
18 | public string SongsPlayedComplexString { get; }
19 | public string LevelAndTotalXpString { get; }
20 | public string LevelProgressString { get; }
21 | public Brush RoleColor { get; }
22 | public string RoleString { get; }
23 | public string DescriptionTitleString { get; }
24 | public string LevelString { get; }
25 | public string JoinDateString { get; }
26 | public string TotalXpString { get; }
27 |
28 | public List Badges { get; set; }
29 |
30 | public int GetXpNeededForNextLevel();
31 | public static abstract int GetXpNeededForNextLevel(int level);
32 | public Brush GetRoleColorBrush();
33 | public string GetRoleString();
34 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/LastFmService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Interfaces.Service;
2 |
3 | namespace OsuPlayer.Services;
4 |
5 | public class LastFmService : OsuPlayerService, ILastFmApiService
6 | {
7 | private readonly ILastFmApiService _lastFmApiService;
8 |
9 | public override string ServiceName => "LASTFM_SERVICE";
10 |
11 | public LastFmService( ILastFmApiService lastFmApiService )
12 | {
13 | _lastFmApiService = lastFmApiService;
14 | }
15 |
16 | public void AuthorizeToken() => _lastFmApiService.AuthorizeToken();
17 | public void SetApiKeyAndSecret(string apiKey, string secret) => _lastFmApiService.SetApiKeyAndSecret(apiKey, secret);
18 | public bool LoadSessionKey() => _lastFmApiService.LoadSessionKey();
19 | public bool IsAuthorized() => _lastFmApiService.IsAuthorized();
20 | public Task GetSessionKey() => _lastFmApiService.GetSessionKey();
21 | public Task SaveSessionKeyAsync() => _lastFmApiService.SaveSessionKeyAsync();
22 | public Task Scrobble(string title, string artist) => _lastFmApiService.Scrobble(title, artist);
23 | public Task LoadSessionKeyAsync() => _lastFmApiService.LoadSessionKeyAsync();
24 | public Task GetAuthToken() => _lastFmApiService.GetAuthToken();
25 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/ProfileManagerService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels;
2 | using OsuPlayer.Interfaces.Service;
3 | using Splat;
4 |
5 | namespace OsuPlayer.Services;
6 |
7 | public class ProfileManagerService : IProfileManagerService
8 | {
9 | public User? User { get; set; }
10 |
11 | public async Task Login(string username, string password)
12 | {
13 | var result = await Locator.Current.GetService().LoginAndSaveAuthToken(username, password);
14 |
15 | // If login failed, we set the user to its default value
16 | if (result == default)
17 | {
18 | User = default;
19 |
20 | return;
21 | }
22 |
23 | User = new User(result);
24 | }
25 |
26 | public async Task Login(string token)
27 | {
28 | if (string.IsNullOrWhiteSpace(token)) return;
29 |
30 | var result = await Locator.Current.GetService().LoginWithTokenAndSaveNewToken(token);
31 |
32 | // If login via token failed, we set the User to its default value
33 | if (result == default)
34 | {
35 | User = default;
36 |
37 | return;
38 | }
39 |
40 | User = new User(result);
41 | }
42 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/HistoryService.cs:
--------------------------------------------------------------------------------
1 | using Nein.Extensions.Bindables;
2 | using OsuPlayer.Data.DataModels.Extensions;
3 | using OsuPlayer.Data.DataModels.Interfaces;
4 | using OsuPlayer.Interfaces.Service;
5 |
6 | namespace OsuPlayer.Services;
7 |
8 | public class HistoryService : OsuPlayerService, IHistoryProvider
9 | {
10 | public HistoricalMapEntryComparer Comparer { get; } = new();
11 | public BindableList History { get; } = new();
12 |
13 | public override string ServiceName => "HISTORY_SERVICE";
14 |
15 | public void AddOrUpdateMapEntry(IMapEntryBase? mapEntry)
16 | {
17 | if (mapEntry == default) return;
18 |
19 | var historicalMapEntry = new HistoricalMapEntry(mapEntry);
20 |
21 | var foundEntry = History.FirstOrDefault(entry => Comparer.Equals(entry, historicalMapEntry));
22 |
23 | if (foundEntry != default)
24 | History.Remove(foundEntry);
25 |
26 | History.Add(historicalMapEntry);
27 |
28 | LogToConsole($"Added or updated map entry {mapEntry.GetSongName()} ({mapEntry.Hash}) to history.");
29 | }
30 |
31 | public void ClearHistory()
32 | {
33 | History.Clear();
34 |
35 | LogToConsole($"Cleared listening history.");
36 | }
37 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/ValueConverters/RepeatConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Avalonia.Data.Converters;
3 | using Material.Icons;
4 | using OsuPlayer.Data.OsuPlayer.Enums;
5 |
6 | namespace OsuPlayer.Extensions.ValueConverters;
7 |
8 | public class RepeatConverter : IValueConverter
9 | {
10 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
11 | {
12 | if (value is not RepeatMode val) return MaterialIconKind.QuestionMark;
13 |
14 | if (targetType == typeof(MaterialIconKind))
15 | return val switch
16 | {
17 | RepeatMode.NoRepeat => MaterialIconKind.RepeatOff,
18 | RepeatMode.Playlist => MaterialIconKind.Repeat,
19 | RepeatMode.SingleSong => MaterialIconKind.RepeatOnce,
20 | _ => MaterialIconKind.RepeatOff
21 | };
22 |
23 | if (targetType == typeof(int))
24 | return val == RepeatMode.Playlist ? 400 : int.MaxValue;
25 |
26 | return targetType == typeof(bool) && val == RepeatMode.Playlist;
27 | }
28 |
29 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
30 | {
31 | throw new NotImplementedException();
32 | }
33 | }
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: Build & Unit Tests
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | test:
11 | name: Run Tests
12 | runs-on: ${{ matrix.os.fullname}}
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | os:
17 | - { prettyname: Windows, fullname: windows-latest }
18 | - { prettyname: macOS, fullname: macos-latest }
19 | - { prettyname: Linux, fullname: ubuntu-latest }
20 | timeout-minutes: 60
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v2
24 |
25 | - name: Install .NET 8.0.x
26 | uses: actions/setup-dotnet@v1
27 | with:
28 | dotnet-version: 8.0.x
29 |
30 | - name: Build
31 | run: dotnet build -c Debug
32 |
33 | - name: Test
34 | run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{ matrix.os.prettyname }}.trx"
35 | shell: pwsh
36 |
37 | - name: Updload Test Results
38 | uses: actions/upload-artifact@v4
39 | if: ${{ always() }}
40 | with:
41 | name: osuplayer-test-results-${{ matrix.os.prettyname }}
42 | path: ${{ github.workspace }}/TestResults/TestResults-${{ matrix.os.prettyname }}.trx
--------------------------------------------------------------------------------
/OsuPlayer/Modules/BitmapExtensions.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media.Imaging;
2 | using SkiaSharp;
3 |
4 | namespace OsuPlayer.Modules;
5 |
6 | public static class BitmapExtensions
7 | {
8 | public static Bitmap BlurBitmap(string imagePath, float blurRadius = 10f, float opacity = 1f, int quality = 80)
9 | {
10 | using var stream = File.OpenRead(imagePath);
11 | using var skBitmap = SKBitmap.Decode(stream);
12 |
13 | var blurSigma = blurRadius / 2;
14 | var blurFilter = SKImageFilter.CreateBlur(blurRadius, blurSigma);
15 |
16 | var paint = new SKPaint
17 | {
18 | ImageFilter = blurFilter,
19 | Color = new SKColor(alpha: (byte)(255 * opacity), red: 0, green: 0, blue: 0)
20 | };
21 |
22 | using var surface = SKSurface.Create(new SKImageInfo(skBitmap.Width, skBitmap.Height));
23 | var canvas = surface.Canvas;
24 |
25 | // Draw the original image with the blur effect
26 | canvas.DrawBitmap(skBitmap, 0, 0, paint);
27 |
28 | using var image = surface.Snapshot();
29 | using var outputStream = new MemoryStream();
30 |
31 | image.Encode(SKEncodedImageFormat.Png, quality).SaveTo(outputStream);
32 | outputStream.Position = 0;
33 |
34 | return new Bitmap(outputStream);
35 | }
36 | }
--------------------------------------------------------------------------------
/.run/OsuPlayer With Environment Variables.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.run/OsuPlayer _ Live API.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.run/OsuPlayer _ Local API.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.run/OsuPlayer _ Sandbox API.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/OsuPlayer.Services/DbReaderFactory.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels;
2 | using OsuPlayer.Data.DataModels.Interfaces;
3 | using OsuPlayer.Data.Enums;
4 | using OsuPlayer.Interfaces.Service;
5 | using OsuPlayer.IO.DbReader;
6 | using Splat;
7 |
8 | namespace OsuPlayer.Services;
9 |
10 | public class DbReaderFactory : OsuPlayerService, IDbReaderFactory
11 | {
12 | public override string ServiceName => "DBREADER_FACTORY_SERVICE";
13 |
14 | public DbCreationType Type { get; set; }
15 |
16 | public IDatabaseReader? CreateDatabaseReader(string path)
17 | {
18 | var loggingService = Locator.Current.GetService();
19 |
20 | switch (Type)
21 | {
22 | case DbCreationType.OsuDb:
23 | var dbLoc = Path.Combine(path, "osu!.db");
24 |
25 | if (!File.Exists(dbLoc)) return null;
26 |
27 | var file = File.OpenRead(dbLoc);
28 |
29 | LogToConsole($"Using osu!.db import for path {path}");
30 |
31 | return new OsuDbReader(file, path, this);
32 | case DbCreationType.Realm:
33 | LogToConsole($"Using client.realm importer for path {path}");
34 |
35 | return new RealmReader(path, this);
36 | default:
37 | throw new ArgumentOutOfRangeException();
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapSetInfo.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Files;
2 | using OsuPlayer.Data.LazerModels.Interfaces;
3 |
4 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
5 |
6 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
7 | // See the LICENCE file in the repository root for full licence text.
8 | public interface IBeatmapSetInfo : IHasOnlineID, IEquatable, IHasNamedFiles
9 | {
10 | ///
11 | /// The date when this beatmap was imported.
12 | ///
13 | DateTimeOffset DateAdded { get; }
14 |
15 | ///
16 | /// The best-effort metadata representing this set. In the case metadata differs between contained beatmaps, one is
17 | /// arbitrarily chosen.
18 | ///
19 | IBeatmapMetadataInfo Metadata { get; }
20 |
21 | ///
22 | /// All beatmaps contained in this set.
23 | ///
24 | IEnumerable Beatmaps { get; }
25 |
26 | ///
27 | /// The maximum star difficulty of all beatmaps in this set.
28 | ///
29 | double MaxStarDifficulty { get; }
30 |
31 | ///
32 | /// The maximum playable length in milliseconds of all beatmaps in this set.
33 | ///
34 | double MaxLength { get; }
35 |
36 | ///
37 | /// The maximum BPM of all beatmaps in this set.
38 | ///
39 | double MaxBPM { get; }
40 | }
--------------------------------------------------------------------------------
/OsuPlayer/Modules/Audio/Interfaces/IPlayer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using OsuPlayer.Data.DataModels.Interfaces;
3 | using OsuPlayer.Data.OsuPlayer.Enums;
4 | using OsuPlayer.IO.Importer;
5 |
6 | namespace OsuPlayer.Modules.Audio.Interfaces;
7 |
8 | ///
9 | /// This interface represents an audio player which should use the as an underlying base.
10 | ///
11 | public interface IPlayer : ICommonFeatures, IPlayModes, IHasPlaylists, IHasBlacklist, IHasDiscordRpc
12 | {
13 | public ISongSourceProvider SongSourceProvider { get; }
14 | public Bindable CurrentSong { get; }
15 | public Bindable CurrentSongImage { get; }
16 | public int CurrentIndex { get; }
17 |
18 | ///
19 | /// Toggles mute of the volume
20 | ///
21 | public void ToggleMute();
22 |
23 | ///
24 | /// Plays the next song in the list.
25 | ///
26 | /// The for the next song
27 | public Task NextSong(PlayDirection playDirection);
28 |
29 | ///
30 | /// Enqueues a specific song to play
31 | ///
32 | /// The song to enqueue
33 | /// The direction we went in the playlist. Mostly used by the Next and Prev method
34 | public Task TryPlaySongAsync(IMapEntryBase? song, PlayDirection playDirection = PlayDirection.Normal);
35 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/UpdateView.axaml.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Runtime.InteropServices;
3 | using Avalonia.Interactivity;
4 | using Nein.Base;
5 | using Nein.Extensions;
6 | using OsuPlayer.UI_Extensions;
7 | using OsuPlayer.Windows;
8 | using Splat;
9 |
10 | namespace OsuPlayer.Views;
11 |
12 | public partial class UpdateView : ReactiveControl
13 | {
14 | public UpdateView()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void Button_OnClick(object? sender, RoutedEventArgs e)
20 | {
21 | if (ViewModel?.Update?.HtmlUrl == default) return;
22 |
23 | GeneralExtensions.OpenUrl(ViewModel.Update.HtmlUrl);
24 | }
25 |
26 | private async void Update_OnClick(object? sender, RoutedEventArgs e)
27 | {
28 | var asset = ViewModel.Update?.Assets?.FirstOrDefault(x => x.Name.Contains(RuntimeInformation.RuntimeIdentifier));
29 |
30 | if (asset == default)
31 | {
32 | await MessageBox.ShowDialogAsync(Locator.Current.GetRequiredService(),
33 | "No update for you os found, please visit github for manual update.", "Update binary not found!");
34 |
35 | return;
36 | }
37 |
38 | var processStartInfo = new ProcessStartInfo("dotnet", [
39 | "OsuPlayer.Updater.dll", asset.BrowserDownloadUrl
40 | ]);
41 |
42 | Process.Start(processStartInfo);
43 |
44 | Locator.Current.GetRequiredService().Close();
45 | }
46 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Enums/FontWeights.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media;
2 |
3 | namespace OsuPlayer.Data.OsuPlayer.Enums;
4 |
5 | ///
6 | /// Defines a set of predefined font weights.
7 | ///
8 | ///
9 | /// As well as the values defined by this enumeration you can also pass any integer value by
10 | /// casting it to , e.g. (FontWeight)550.
11 | ///
12 | public enum FontWeights
13 | {
14 | ///
15 | /// Specifies a "thin" font weight.
16 | ///
17 | Thin = 100,
18 |
19 | ///
20 | /// Specifies a "extralight" font weight.
21 | ///
22 | ExtraLight = 200,
23 |
24 | ///
25 | /// Specifies a "light" font weight.
26 | ///
27 | Light = 300,
28 |
29 | ///
30 | /// Specifies a "regular" font weight.
31 | ///
32 | Regular = 400,
33 |
34 | ///
35 | /// Specifies a "medium" font weight.
36 | ///
37 | Medium = 500,
38 |
39 | ///
40 | /// Specifies a "semibold" font weight.
41 | ///
42 | SemiBold = 600,
43 |
44 | ///
45 | /// Specifies a "bold" font weight.
46 | ///
47 | Bold = 700,
48 |
49 | ///
50 | /// Specifies an "extra bold" font weight.
51 | ///
52 | ExtraBold = 800,
53 |
54 | ///
55 | /// Specifies an "black" font weight.
56 | ///
57 | Black = 900
58 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/OsuPlayer.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows10.0.17763.0
5 | annotations
6 | true
7 | false
8 | en
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | all
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/OsuPlayer/Windows/FullscreenWindow.axaml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/OsuPlayer.IO/OsuPlayer.IO.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | annotations
7 | en
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | native
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Realm.dll
32 |
33 |
34 | Realm.Fody.dll
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/OsuPlayer/Windows/ExportSongsProcessWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using Nein.Base;
2 | using OsuPlayer.Data.DataModels.Interfaces;
3 | using ReactiveUI;
4 |
5 | namespace OsuPlayer.Windows;
6 |
7 | public class ExportSongsProcessWindowViewModel : BaseWindowViewModel
8 | {
9 | private int _exportingSongsProgress;
10 | private int _exportTotalSongs;
11 | private string _exportString = string.Empty;
12 | private bool _isExportRunning;
13 | private ICollection _songs = new List();
14 |
15 | public ICollection Songs
16 | {
17 | get => _songs;
18 | set => this.RaiseAndSetIfChanged(ref _songs, value);
19 | }
20 |
21 | public int ExportTotalSongs
22 | {
23 | get => _exportTotalSongs;
24 | set => this.RaiseAndSetIfChanged(ref _exportTotalSongs, value);
25 | }
26 |
27 | public int ExportingSongsProgress
28 | {
29 | get => _exportingSongsProgress;
30 | set => this.RaiseAndSetIfChanged(ref _exportingSongsProgress, value);
31 | }
32 |
33 | public string ExportString
34 | {
35 | get => _exportString;
36 | set => this.RaiseAndSetIfChanged(ref _exportString, value);
37 | }
38 |
39 | public bool IsExportRunning
40 | {
41 | get => _isExportRunning;
42 | set => this.RaiseAndSetIfChanged(ref _isExportRunning, value);
43 | }
44 |
45 | public ExportSongsProcessWindowViewModel()
46 | {
47 | }
48 |
49 | public ExportSongsProcessWindowViewModel(ICollection songs)
50 | {
51 | Songs = songs;
52 | }
53 | }
--------------------------------------------------------------------------------
/OsuPlayer.Interfaces/Service/IStatisticsProvider.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using LiveChartsCore.Defaults;
3 | using Nein.Extensions.Bindables;
4 | using OsuPlayer.Api.Data.API.Enums;
5 |
6 | namespace OsuPlayer.Interfaces.Service;
7 |
8 | public interface IStatisticsProvider
9 | {
10 | public BindableList GraphValues { get; }
11 |
12 | public event PropertyChangedEventHandler? UserDataChanged;
13 |
14 | ///
15 | /// Updates the online status of the user.
16 | ///
17 | /// The to be set
18 | /// the currently playing song name
19 | /// the md5 hash of the playing song
20 | ///
21 | public Task UpdateOnlineStatus(UserOnlineStatusType statusType, string? song = null, string? checksum = null);
22 |
23 | ///
24 | /// Updates the user's xp.
25 | ///
26 | /// The md5 hash of the song which gave the xp
27 | /// Time listened in milliseconds
28 | /// The total song length in seconds
29 | ///
30 | public Task UpdateXp(string hash, double timeListened, double channelLength);
31 |
32 | ///
33 | /// Updates the amount of times the user has played a song.
34 | ///
35 | /// The beatmap set id of the song played
36 | ///
37 | public Task UpdateSongsPlayed(int beatmapSetId);
38 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/PlayHistoryViewModel.cs:
--------------------------------------------------------------------------------
1 | using Nein.Base;
2 | using Nein.Extensions;
3 | using OsuPlayer.Data.DataModels.Extensions;
4 | using OsuPlayer.Interfaces.Service;
5 | using OsuPlayer.IO.Importer;
6 | using OsuPlayer.Modules.Audio.Interfaces;
7 | using ReactiveUI;
8 |
9 | namespace OsuPlayer.Views;
10 |
11 | public class PlayHistoryViewModel : BaseViewModel
12 | {
13 | public readonly ISongSourceProvider SongSourceProvider;
14 |
15 | private ObservableCollection? _history;
16 |
17 | private HistoricalMapEntry? _selectedHistoricalMapEntry;
18 |
19 | public HistoricalMapEntry? SelectedHistoricalMapEntry
20 | {
21 | get => _selectedHistoricalMapEntry;
22 | set => this.RaiseAndSetIfChanged(ref _selectedHistoricalMapEntry, value);
23 | }
24 |
25 | public ObservableCollection? History
26 | {
27 | get => _history;
28 | set => this.RaiseAndSetIfChanged(ref _history, value);
29 | }
30 |
31 | public IPlayer Player { get; set; }
32 |
33 | public PlayHistoryViewModel(IPlayer player, IHistoryProvider? historyProvider, ISongSourceProvider songSourceProvider)
34 | {
35 | Player = player;
36 | SongSourceProvider = songSourceProvider;
37 |
38 | historyProvider?.History.BindCollectionChanged((_, _) =>
39 | {
40 | // We first sort them descending by time played, then by song name alphabetically
41 | History = historyProvider.History.OrderByDescending(x => x.TimePlayed).ThenBy(x => x.MapEntry.SongName).ToObservableCollection();
42 | });
43 |
44 | Activator = new ViewModelActivator();
45 | }
46 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.Beatmap.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 | using OsuPlayer.Api.Data.API.RequestModels.Beatmap;
3 | using OsuPlayer.Api.Data.API.RequestModels.Statistics;
4 | using OsuPlayer.Api.Data.API.ResponseModels;
5 |
6 | namespace OsuPlayer.Network.API.NorthFox;
7 |
8 | public class NorthFoxBeatmapEndpoint
9 | {
10 | private readonly AbstractApiBase _apiBase;
11 |
12 | public NorthFoxBeatmapEndpoint(AbstractApiBase apiBase)
13 | {
14 | _apiBase = apiBase;
15 | }
16 |
17 | #region POST Requests
18 |
19 | public async Task> AddBeatmap(List beatmapsToAdd)
20 | {
21 | return await _apiBase.PostRequestAsync>("Beatmap", "add", beatmapsToAdd);
22 | }
23 |
24 | #endregion
25 |
26 | #region GET Requests
27 |
28 | public async Task?> GetAllBeatmaps()
29 | {
30 | return await _apiBase.Get("Beatmap");
31 | }
32 |
33 | public async Task GetBeatmap(Guid uniqueId)
34 | {
35 | return await _apiBase.GetById("Beatmap", uniqueId);
36 | }
37 |
38 | public async Task GetBeatmapsPaged(SearchBeatmapModel model)
39 | {
40 | return await _apiBase.PostRequestAsync("Beatmap", "getBeatmaps", model);
41 | }
42 |
43 | public async Task GetBeatmapsPlayedByUser(Guid uniqueId, int amount = 0)
44 | {
45 | return await _apiBase.GetRequestWithParameterAsync("Beatmap", "beatmapsPlayedByUser", $"id={uniqueId}&amount={amount}");
46 | }
47 |
48 | #endregion
49 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Interfaces/IDatabaseReader.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.DataModels.Interfaces;
2 |
3 | ///
4 | /// Interface used by the database readers used to read the osu databases.
5 | ///
6 | public interface IDatabaseReader : IDisposable
7 | {
8 | ///
9 | /// Reads all beatmaps from the database.
10 | ///
11 | /// a list of s
12 | public Task?> ReadBeatmaps();
13 |
14 | ///
15 | /// Get all beatmap hashes from the database.
16 | ///
17 | /// This is primarily used for the collection import.
18 | /// a dictionary with the hashes as the key and the beatmap set id as value
19 | public Dictionary GetBeatmapHashes();
20 |
21 | ///
22 | /// Reads the osu! collections from the database.
23 | ///
24 | /// the osu! path
25 | /// a list of s
26 | public Task?> GetCollections(string path);
27 |
28 | ///
29 | /// Reads the full map entry from the existing
30 | ///
31 | /// the osu! path
32 | /// the corresponding
33 | /// the db offset (if applicable)
34 | /// the database id (if applicable)
35 | ///
36 | public IMapEntry? ReadFullEntry(string path, IMapEntryBase mapEntryBase, long? dbOffset = null, Guid? id = null);
37 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/StorageModels/Playlist.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
2 |
3 | namespace OsuPlayer.Data.OsuPlayer.StorageModels;
4 |
5 | ///
6 | /// A playlist object containing an , the , the and a
7 | /// list
8 | ///
9 | public class Playlist
10 | {
11 | public Guid Id { get; set; } = Guid.NewGuid();
12 | public string Name { get; set; }
13 | public DateTime CreationTime { get; set; } = DateTime.UtcNow;
14 |
15 | ///
16 | /// Contains the hashes of the songs in the
17 | ///
18 | public HashSet Songs { get; set; } = new();
19 |
20 | private bool Equals(Playlist other)
21 | {
22 | return Id.Equals(other.Id) && Name == other.Name && CreationTime.Equals(other.CreationTime);
23 | }
24 |
25 | public override bool Equals(object? obj)
26 | {
27 | if (ReferenceEquals(null, obj)) return false;
28 | if (ReferenceEquals(this, obj)) return true;
29 | if (obj.GetType() != GetType()) return false;
30 | return Equals((Playlist) obj);
31 | }
32 |
33 | public override int GetHashCode()
34 | {
35 | return HashCode.Combine(Id, Name, CreationTime, Songs);
36 | }
37 |
38 | public override string ToString()
39 | {
40 | return Name;
41 | }
42 |
43 | public static bool operator ==(Playlist? left, Playlist? right)
44 | {
45 | return left?.Id == right?.Id;
46 | }
47 |
48 | public static bool operator !=(Playlist? left, Playlist? right)
49 | {
50 | return left?.Id != right?.Id;
51 | }
52 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/ShuffleService.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Extensions;
2 | using OsuPlayer.Interfaces.Service;
3 | using OsuPlayer.IO.Storage.Config;
4 |
5 | namespace OsuPlayer.Services;
6 |
7 | ///
8 | /// Provides a service for shuffle implementation registering the services using Splat.
9 | ///
10 | public class ShuffleService : OsuPlayerService, IShuffleServiceProvider
11 | {
12 | public List ShuffleAlgorithms { get; }
13 | public IShuffleImpl? ShuffleImpl { get; private set; }
14 |
15 | public override string ServiceName => "SHUFFLE_SERVICE";
16 |
17 | public ShuffleService()
18 | {
19 | using var config = new Config();
20 |
21 | var shuffleType = typeof(IShuffleImpl);
22 | var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(p => shuffleType.IsAssignableFrom(p) && p != shuffleType);
23 |
24 | ShuffleAlgorithms = types.Select(x => Activator.CreateInstance(x) as IShuffleImpl).ToList();
25 |
26 | ShuffleAlgorithms.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCulture));
27 |
28 | var shuffleAlgo = ShuffleAlgorithms.FirstOrDefault(x =>
29 | string.Equals(x.GetType().Name, config.Container.ShuffleAlgorithm, StringComparison.InvariantCultureIgnoreCase));
30 |
31 | ShuffleImpl = shuffleAlgo ?? ShuffleAlgorithms.FirstOrDefault(x => x.GetType().IsDefined(typeof(DefaultImplAttr), false));
32 | }
33 |
34 | public void SetShuffleImpl(IShuffleImpl? algorithm)
35 | {
36 | using var config = new Config();
37 | config.Container.ShuffleAlgorithm = algorithm?.GetType().Name;
38 |
39 | ShuffleImpl = algorithm;
40 | }
41 | }
--------------------------------------------------------------------------------
/OsuPlayer/UI Extensions/MessageBox.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Avalonia.Controls;
3 |
4 | namespace OsuPlayer.UI_Extensions;
5 |
6 | ///
7 | /// Own implementation of a Messagebox
8 | ///
9 | public static class MessageBox
10 | {
11 | ///
12 | /// Opens a new messagebox to display to the user
13 | ///
14 | /// The text inside of the messagebox
15 | /// The title of the messagebox
16 | public static void Show(string text, string? title = null)
17 | {
18 | var box = new MessageBoxWindow(text, title);
19 |
20 | box.Show();
21 | }
22 |
23 | ///
24 | /// Opens a new messagebox to display to the user
25 | ///
26 | /// The parent window
27 | /// The text inside of the messagebox
28 | /// The title of the messagebox
29 | public static void Show(Window window, string text, string? title = null)
30 | {
31 | var box = new MessageBoxWindow(text, title);
32 |
33 | box.Show(window);
34 | }
35 |
36 | ///
37 | /// Opens a new messagebox dialog to display to the user
38 | ///
39 | /// The parent window
40 | /// The text inside of the messagebox
41 | /// The title of the messagebox
42 | public static async Task ShowDialogAsync(Window window, string text, string? title = null)
43 | {
44 | var box = new MessageBoxWindow(text, title);
45 |
46 | await box.ShowDialog(window);
47 | }
48 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/ObservableSorter.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.DataModels.Interfaces;
2 |
3 | namespace OsuPlayer.Data.DataModels;
4 |
5 | public class ObservableSorter : IObservable>
6 | {
7 | private readonly List>> _observers = new();
8 | private IComparer? _lastComparer;
9 |
10 | public IDisposable Subscribe(IObserver> observer)
11 | {
12 | if (!_observers.Contains(observer))
13 | _observers.Add(observer);
14 |
15 | if (_lastComparer != null)
16 | observer.OnNext(_lastComparer);
17 |
18 | return new Unsubscribe(_observers, observer);
19 | }
20 |
21 | public void UpdateComparer(IComparer? comparer)
22 | {
23 | foreach (var observer in _observers)
24 | if (comparer == null)
25 | observer.OnError(new NullReferenceException());
26 | else
27 | observer.OnNext(comparer);
28 |
29 | _lastComparer = comparer;
30 | }
31 |
32 | private class Unsubscribe : IDisposable
33 | {
34 | private readonly IObserver>? _observer;
35 | private readonly List>> _observers;
36 |
37 | public Unsubscribe(List>> observers, IObserver> observer)
38 | {
39 | _observers = observers;
40 | _observer = observer;
41 | }
42 |
43 | public void Dispose()
44 | {
45 | if (_observer != null && _observers.Contains(_observer))
46 | _observers.Remove(_observer);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/ValueConverterTests/ShuffleConverterTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Material.Icons;
4 | using NUnit.Framework;
5 | using OsuPlayer.Extensions.ValueConverters;
6 |
7 | namespace OsuPlayer.Tests.ValueConverterTests;
8 |
9 | public class ShuffleConverterTests
10 | {
11 | private readonly Type _expectedInput = typeof(bool);
12 | private readonly Type _expectedOutput = typeof(MaterialIconKind);
13 | private ShuffleConverter _repeatConverter = null!;
14 |
15 | [SetUp]
16 | public void Setup()
17 | {
18 | _repeatConverter = new ShuffleConverter();
19 | }
20 |
21 | [TestCase(10)]
22 | [TestCase("test")]
23 | public void TestWrongInputHandled(object input)
24 | {
25 | Assert.That(input, Is.Not.InstanceOf(_expectedInput));
26 | Assert.DoesNotThrow(() => _repeatConverter.Convert(input, _expectedOutput, null, CultureInfo.InvariantCulture));
27 | }
28 |
29 | [Test]
30 | public void TestNullInputHandled()
31 | {
32 | Assert.DoesNotThrow(() => _repeatConverter.Convert(null, _expectedOutput, null, CultureInfo.InvariantCulture));
33 | }
34 |
35 | [Test]
36 | public void TestCorrectUsage()
37 | {
38 | var output = _repeatConverter.Convert(true, _expectedOutput, null, CultureInfo.InvariantCulture);
39 | Assert.That(output, Is.InstanceOf(_expectedOutput));
40 | }
41 |
42 | [Test]
43 | public void TestOutputOnIncorrectInput()
44 | {
45 | var output = _repeatConverter.Convert(10, _expectedOutput, null, CultureInfo.InvariantCulture);
46 | Assert.That(output, Is.InstanceOf(_expectedOutput));
47 | Assert.That(output, Is.EqualTo(MaterialIconKind.QuestionMark));
48 | }
49 | }
--------------------------------------------------------------------------------
/OsuPlayer.IO/Importer/ISongSourceProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using DynamicData;
3 | using OsuPlayer.Data.DataModels.Interfaces;
4 |
5 | namespace OsuPlayer.IO.Importer;
6 |
7 | ///
8 | /// This interface is used as a service provider for accessing imported songs.
9 | ///
10 | public interface ISongSourceProvider
11 | {
12 | SourceList SongSource { get; }
13 |
14 | ///
15 | /// An observable which can be used e.g. to put a custom filter on
16 | ///
17 | public IObservable>? Songs { get; }
18 |
19 | ///
20 | /// An read-only observable collection used to find/access songs
21 | ///
22 | public ReadOnlyObservableCollection? SongSourceList { get; }
23 |
24 | ///
25 | /// Gets the by the md5 hash
26 | ///
27 | /// The md5 hash to find the entry for
28 | /// The found or null if not found
29 | public IMapEntryBase? GetMapEntryFromHash(string? hash);
30 |
31 | ///
32 | /// Gets the s by a md5 hash enumerable
33 | ///
34 | /// The md5 hashes to find the entries for
35 | /// The md5 hashes that could not be mapped to a map entry
36 | ///
37 | /// A of s which contain all found entries. The list will be
38 | /// empty of none found
39 | ///
40 | public List GetMapEntriesFromHash(ICollection hashes, out ICollection invalidHashes);
41 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/ValueConverterTests/PlayPauseConverterTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Material.Icons;
4 | using NUnit.Framework;
5 | using OsuPlayer.Extensions.ValueConverters;
6 |
7 | namespace OsuPlayer.Tests.ValueConverterTests;
8 |
9 | public class PlayPauseConverterTests
10 | {
11 | private readonly Type _expectedInput = typeof(bool);
12 | private readonly Type _expectedOutput = typeof(MaterialIconKind);
13 | private PlayPauseConverter _playPauseConverter = null!;
14 |
15 | [SetUp]
16 | public void Setup()
17 | {
18 | _playPauseConverter = new PlayPauseConverter();
19 | }
20 |
21 | [TestCase(10)]
22 | [TestCase("test")]
23 | public void TestWrongInputHandled(object input)
24 | {
25 | Assert.That(input, Is.Not.InstanceOf(_expectedInput));
26 | Assert.DoesNotThrow(() =>
27 | _playPauseConverter.Convert(input, _expectedOutput, null, CultureInfo.InvariantCulture));
28 | }
29 |
30 | [Test]
31 | public void TestNullInputHandled()
32 | {
33 | Assert.DoesNotThrow(
34 | () => _playPauseConverter.Convert(null, _expectedOutput, null, CultureInfo.InvariantCulture));
35 | }
36 |
37 | [Test]
38 | public void TestCorrectUsage()
39 | {
40 | var output = _playPauseConverter.Convert(true, _expectedOutput, null, CultureInfo.InvariantCulture);
41 | Assert.That(output, Is.InstanceOf(_expectedOutput));
42 | }
43 |
44 | [Test]
45 | public void TestOutputOnIncorrectInput()
46 | {
47 | var output = _playPauseConverter.Convert(10, _expectedOutput, null, CultureInfo.InvariantCulture);
48 | Assert.That(output, Is.InstanceOf(_expectedOutput));
49 | Assert.That(output, Is.EqualTo(MaterialIconKind.QuestionMark));
50 | }
51 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/UnhandledExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace OsuPlayer.Extensions;
4 |
5 | ///
6 | /// A class to handle an unhandled thrown in the Main method.
7 | ///
8 | public static class UnhandledExceptionHandler
9 | {
10 | ///
11 | /// Creates missing log directory if it does not exists
12 | ///
13 | private static void CreatLogsDirectoryIfItsMissing()
14 | {
15 | Directory.CreateDirectory("logs");
16 | }
17 |
18 | ///
19 | /// Create a crashlog from an unhandled exception and save it inside the logs folder.
20 | ///
21 | /// The exception that should be logged
22 | public static void HandleException(Exception ex)
23 | {
24 | CreatLogsDirectoryIfItsMissing();
25 |
26 | var date = DateTime.UtcNow;
27 |
28 | var dateString = date.ToString("yyyyMMdd_HHmmss");
29 |
30 | //Not using concatenation so it is better readable
31 | var crashlog =
32 | "A shit, it looks like you did something that the osu!player did not like. If you think this is a bug, please report this crashlog to Founntain by using the buttons below! (Also please don't forget to state how you achieved the crash e. g. what did you do, click etc.)"
33 | + Environment.NewLine
34 | + Environment.NewLine
35 | + "UTC Time: " + date.ToString("f", new CultureInfo("en-us"))
36 | + Environment.NewLine
37 | + Environment.NewLine
38 | + "Error stacktrace below:"
39 | + Environment.NewLine
40 | + ex.Message + Environment.NewLine + ex.StackTrace;
41 |
42 | File.WriteAllText($"logs/{dateString}.txt", crashlog);
43 | }
44 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/HomeView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Interactivity;
3 | using Nein.Base;
4 | using Nein.Extensions;
5 | using OsuPlayer.Data.DataModels.Interfaces;
6 | using OsuPlayer.IO.Storage.Blacklist;
7 | using OsuPlayer.UI_Extensions;
8 | using OsuPlayer.Windows;
9 | using Splat;
10 | using TappedEventArgs = Avalonia.Input.TappedEventArgs;
11 |
12 | namespace OsuPlayer.Views;
13 |
14 | public partial class HomeView : ReactiveControl
15 | {
16 | private FluentAppWindow? _mainWindow;
17 |
18 | public HomeView()
19 | {
20 | InitializeComponent();
21 |
22 | _mainWindow = Locator.Current.GetRequiredService();
23 |
24 | HomeViewInitialized();
25 | }
26 |
27 | private async void HomeViewInitialized()
28 | {
29 | if (_mainWindow == default) return;
30 |
31 | var config = new Config();
32 | var osuPath = (await config.ReadAsync()).OsuPath;
33 |
34 | if (string.IsNullOrWhiteSpace(osuPath))
35 | await MessageBox.ShowDialogAsync(_mainWindow,
36 | "Before you can start listening to your songs, you have to import them.\nPlease head to the settings to select your osu!.db or client.realm.");
37 |
38 | //ViewModel!.Songs = new ObservableCollection(songs);
39 | }
40 |
41 | private async void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e)
42 | {
43 | var list = sender as ListBox;
44 | var song = list!.SelectedItem as IMapEntryBase;
45 |
46 | await ViewModel.Player.TryPlaySongAsync(song);
47 | }
48 |
49 | private void AddToBlacklist_OnClick(object? sender, RoutedEventArgs e)
50 | {
51 | using var blacklist = new Blacklist();
52 | blacklist.Container.Songs.Add(ViewModel.SelectedSong?.Hash);
53 | }
54 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/DataModels/Interfaces/IMapEntryBase.cs:
--------------------------------------------------------------------------------
1 | using Nein.Extensions;
2 |
3 | namespace OsuPlayer.Data.DataModels.Interfaces;
4 |
5 | public interface IMapEntryBase : IEquatable, IComparable
6 | {
7 | public IDbReaderFactory DbReaderFactory { get; init; }
8 |
9 | public string Artist { get; }
10 | public string ArtistUnicode { get; }
11 | public string Title { get; }
12 | public string TitleUnicode { get; }
13 | public string Hash { get; }
14 | public int BeatmapSetId { get; }
15 | public int TotalTime { get; }
16 | public string TotalTimeString => TimeSpan.FromMilliseconds(TotalTime).FormatTime();
17 | public string SongName => GetSongName();
18 | public string ArtistString => GetArtist();
19 | public string TitleString => GetTitle();
20 |
21 | public bool UseUnicode { get; set; }
22 |
23 | public string GetArtist();
24 |
25 | public string GetTitle();
26 |
27 | ///
28 | /// Gets a formatted version of artist and title
29 | ///
30 | /// the formatted song name
31 | public string GetSongName()
32 | {
33 | return $"{GetArtist()} - {GetTitle()}";
34 | }
35 |
36 | ///
37 | /// Reads the full from this
38 | ///
39 | ///
40 | /// a full for extended usage. Returns null if the path doesn't exist or the map was not
41 | /// found.
42 | ///
43 | public IMapEntry? ReadFullEntry();
44 |
45 | ///
46 | /// Gets the corresponding of the beatmap
47 | ///
48 | /// a instance of the specific database reader implementation
49 | public IDatabaseReader GetReader();
50 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/IBeatmapInfo.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.LazerModels.Interfaces;
2 |
3 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
4 |
5 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
6 | // See the LICENCE file in the repository root for full licence text.
7 | public interface IBeatmapInfo : IHasOnlineID, IEquatable
8 | {
9 | ///
10 | /// The user-specified name given to this beatmap.
11 | ///
12 | string DifficultyName { get; }
13 |
14 | ///
15 | /// The metadata representing this beatmap. May be shared between multiple beatmaps.
16 | ///
17 | IBeatmapMetadataInfo Metadata { get; }
18 |
19 | ///
20 | /// The difficulty settings for this beatmap.
21 | ///
22 | IBeatmapDifficultyInfo Difficulty { get; }
23 |
24 | ///
25 | /// The beatmap set this beatmap is part of.
26 | ///
27 | IBeatmapSetInfo? BeatmapSet { get; }
28 |
29 | ///
30 | /// The playable length in milliseconds of this beatmap.
31 | ///
32 | double Length { get; }
33 |
34 | ///
35 | /// The most common BPM of this beatmap.
36 | ///
37 | double BPM { get; }
38 |
39 | ///
40 | /// The SHA-256 hash representing this beatmap's contents.
41 | ///
42 | string Hash { get; }
43 |
44 | ///
45 | /// MD5 is kept for legacy support (matching against replays etc.).
46 | ///
47 | string MD5Hash { get; }
48 |
49 | ///
50 | /// The ruleset this beatmap was made for.
51 | ///
52 | IRulesetInfo Ruleset { get; }
53 |
54 | ///
55 | /// The basic star rating for this beatmap (with no mods applied).
56 | ///
57 | double StarRating { get; }
58 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Beatmaps/BeatmapMetadata.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using JetBrains.Annotations;
3 | using OsuPlayer.Data.LazerModels.Extensions;
4 | using OsuPlayer.Data.LazerModels.Interfaces;
5 | using Realms;
6 |
7 | namespace OsuPlayer.Data.LazerModels.Beatmaps;
8 |
9 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
10 | // See the LICENCE file in the repository root for full licence text.
11 | [Serializable]
12 | [MapTo("BeatmapMetadata")]
13 | public class BeatmapMetadata : RealmObject, IBeatmapMetadataInfo
14 | {
15 | public RealmUser Author { get; set; } = null!;
16 |
17 | public string Title { get; set; } = string.Empty;
18 |
19 | [JsonPropertyName("title_unicode")]
20 | public string TitleUnicode { get; set; } = string.Empty;
21 |
22 | public string Artist { get; set; } = string.Empty;
23 |
24 | [JsonPropertyName("artist_unicode")]
25 | public string ArtistUnicode { get; set; } = string.Empty;
26 |
27 | public string Source { get; set; } = string.Empty;
28 |
29 | [JsonPropertyName(@"tags")]
30 | public string Tags { get; set; } = string.Empty;
31 |
32 | ///
33 | /// The time in milliseconds to begin playing the track for preview purposes.
34 | /// If -1, the track should begin playing at 40% of its length.
35 | ///
36 | public int PreviewTime { get; set; } = -1;
37 |
38 | public string AudioFile { get; set; } = string.Empty;
39 | public string BackgroundFile { get; set; } = string.Empty;
40 |
41 | IUser IBeatmapMetadataInfo.Author => Author;
42 |
43 | public BeatmapMetadata(RealmUser? user = null)
44 | {
45 | Author = user ?? new RealmUser();
46 | }
47 |
48 | [UsedImplicitly] // Realm
49 | private BeatmapMetadata()
50 | {
51 | }
52 |
53 | public override string ToString()
54 | {
55 | return this.GetDisplayTitle();
56 | }
57 | }
--------------------------------------------------------------------------------
/OsuPlayer/Windows/FullscreenWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media.Imaging;
2 | using Avalonia.Threading;
3 | using Nein.Base;
4 | using OsuPlayer.Data.DataModels.Interfaces;
5 | using OsuPlayer.Modules;
6 | using OsuPlayer.Modules.Audio.Interfaces;
7 | using ReactiveUI;
8 |
9 | namespace OsuPlayer.Windows;
10 |
11 | public class FullscreenWindowViewModel : BaseWindowViewModel
12 | {
13 | public readonly IPlayer Player;
14 | public readonly Bindable CurrentSong = new();
15 |
16 | private Bitmap? _currentSongImage;
17 |
18 | public Bitmap? CurrentSongImage
19 | {
20 | get => _currentSongImage;
21 | set
22 | {
23 | _currentSongImage?.Dispose();
24 | this.RaiseAndSetIfChanged(ref _currentSongImage, value);
25 | }
26 | }
27 |
28 | public string TitleText => CurrentSong.Value?.Title ?? "No song is playing";
29 |
30 | public string ArtistText => CurrentSong.Value?.Artist ?? "please select from song list";
31 |
32 | public FullscreenWindowViewModel(IPlayer player)
33 | {
34 | Player = player;
35 |
36 | CurrentSong.BindTo(Player.CurrentSong);
37 | CurrentSong.BindValueChanged(_ =>
38 | {
39 | this.RaisePropertyChanged(nameof(TitleText));
40 | this.RaisePropertyChanged(nameof(ArtistText));
41 | });
42 |
43 | Player.CurrentSongImage.BindValueChanged(d =>
44 | {
45 | Dispatcher.UIThread.Post(() =>
46 | {
47 | CurrentSongImage?.Dispose();
48 |
49 | if (!string.IsNullOrEmpty(d.NewValue) && File.Exists(d.NewValue))
50 | {
51 | CurrentSongImage = BitmapExtensions.BlurBitmap(d.NewValue, blurRadius: 25, opacity: 0.75f);
52 |
53 | return;
54 | }
55 |
56 | CurrentSongImage = null;
57 | });
58 | }, true, true);
59 | }
60 | }
--------------------------------------------------------------------------------
/OsuPlayer.Network/API/NorthFox/NorthFox.Badge.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Api.Data.API.EntityModels;
2 |
3 | namespace OsuPlayer.Network.API.NorthFox;
4 |
5 | public class NorthFoxBadgeEndpoint
6 | {
7 | private readonly AbstractApiBase _apiBase;
8 |
9 | public NorthFoxBadgeEndpoint(AbstractApiBase apiBase)
10 | {
11 | _apiBase = apiBase;
12 | }
13 |
14 | #region GET Requests
15 |
16 | public async Task?> GetAllBadges()
17 | {
18 | return await _apiBase.Get("Badge");
19 | }
20 |
21 | public async Task GetBadge(Guid uniqueId)
22 | {
23 | return await _apiBase.GetById("Badge", uniqueId);
24 | }
25 |
26 | #endregion
27 |
28 | #region POST Requests
29 |
30 | // public async Task EditUser(UserModel editData)
31 | // {
32 | // return await PostRequestAsync("edit", editData);
33 | // }
34 | //
35 | // public async Task ChangePassword(byte[] newPassword)
36 | // {
37 | // return await PostRequestAsync("changePassword", newPassword);
38 | // }
39 | //
40 | // public async Task UpdateSongsPlayed(string username, int amount, int beatmapSetId = -1)
41 | // {
42 | // if (string.IsNullOrWhiteSpace(username)) return default;
43 | //
44 | // return await PostRequestWithParametersAsync("updateSongsPlayed", $"username={username}&amount={amount}&beatmapSetId={beatmapSetId}");
45 | // }
46 | //
47 | // public async Task UpdateXp(UpdateXpModel updateXpModel)
48 | // {
49 | // return await PostRequestAsync("updateXp", updateXpModel);
50 | // }
51 |
52 | #endregion
53 |
54 | #region DELETE Requests
55 |
56 | // public async Task DeleteUser()
57 | // {
58 | // return await DeleteRequestAsync("delete");
59 | // }
60 |
61 | #endregion
62 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/OsuPlayer/Classes/EqPreset.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.OsuPlayer.Classes;
2 |
3 | ///
4 | /// Object for an equalizer preset. Contained in
5 | ///
6 | public class EqPreset
7 | {
8 | public Guid Id { get; init; } = Guid.NewGuid();
9 | public string Name { get; set; }
10 | public decimal[] Gain { get; set; } = new decimal[10];
11 |
12 | public static EqPreset Flat { get; } = new()
13 | {
14 | Name = "Flat (Default)",
15 | Gain = new decimal[]
16 | {
17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
18 | }
19 | };
20 |
21 | public static EqPreset Custom { get; set; } = new()
22 | {
23 | Name = "Custom",
24 | Gain = new decimal[]
25 | {
26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
27 | }
28 | };
29 |
30 | public static EqPreset Classic { get; } = new()
31 | {
32 | Name = "Classic",
33 | Gain = new decimal[]
34 | {
35 | 0, 0, 0, 0, 0, 0, 0, -2, -3, -4
36 | }
37 | };
38 |
39 | public static EqPreset LaptopSpeaker { get; } = new()
40 | {
41 | Name = "Laptop speaker",
42 | Gain = new decimal[]
43 | {
44 | 2, 6, 2, -2, -1, 0, 2, 3, 5, 8
45 | }
46 | };
47 |
48 | public override bool Equals(object? obj)
49 | {
50 | if (obj is not EqPreset preset) return false;
51 |
52 | return Id.Equals(preset.Id);
53 | }
54 |
55 | public static bool operator ==(EqPreset? left, EqPreset? right)
56 | {
57 | return left?.Id == right?.Id;
58 | }
59 |
60 | public static bool operator !=(EqPreset? left, EqPreset? right)
61 | {
62 | return left?.Id != right?.Id;
63 | }
64 |
65 | public override int GetHashCode()
66 | {
67 | return Id.GetHashCode();
68 | }
69 |
70 | public override string ToString()
71 | {
72 | return Name;
73 | }
74 | }
--------------------------------------------------------------------------------
/OsuPlayer.Extensions/EnumExtensions/FontWeightExtensions.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Media;
2 | using OsuPlayer.Data.OsuPlayer.Enums;
3 | using OsuPlayer.Data.OsuPlayer.StorageModels;
4 |
5 | namespace OsuPlayer.Extensions.EnumExtensions;
6 |
7 | public static class FontWeightExtensions
8 | {
9 | public static FontWeights GetNextBiggerFont(this ConfigContainer container)
10 | {
11 | return container.DefaultFontWeight.GetNextBiggerFont();
12 | }
13 |
14 | public static FontWeights GetNextBiggerFont(this FontWeights font)
15 | {
16 | var fontSizes = (FontWeights[]) Enum.GetValues(typeof(FontWeights));
17 |
18 | var i = Array.IndexOf(fontSizes, font) + 1;
19 | return fontSizes.Length == i ? fontSizes[i - 1] : fontSizes[i];
20 | }
21 |
22 | public static FontWeights GetNextSmallerFont(this ConfigContainer container)
23 | {
24 | return container.DefaultFontWeight.GetNextSmallerFont();
25 | }
26 |
27 | public static FontWeights GetNextSmallerFont(this FontWeights font)
28 | {
29 | var fontSizes = (FontWeights[]) Enum.GetValues(typeof(FontWeights));
30 |
31 | var i = Array.IndexOf(fontSizes, font) - 1;
32 | return i == -1 ? fontSizes[i + 1] : fontSizes[i];
33 | }
34 |
35 | public static FontWeight ToFontWeight(this FontWeights font)
36 | {
37 | return font switch
38 | {
39 | FontWeights.Black => FontWeight.Black,
40 | FontWeights.Thin => FontWeight.Thin,
41 | FontWeights.ExtraLight => FontWeight.ExtraLight,
42 | FontWeights.Light => FontWeight.Light,
43 | FontWeights.Regular => FontWeight.Regular,
44 | FontWeights.Medium => FontWeight.Medium,
45 | FontWeights.SemiBold => FontWeight.SemiBold,
46 | FontWeights.Bold => FontWeight.Bold,
47 | FontWeights.ExtraBold => FontWeight.ExtraBold,
48 | _ => FontWeight.Regular
49 | };
50 | }
51 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/OsuSongSourceService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using DynamicData;
3 | using OsuPlayer.Data.DataModels.Interfaces;
4 | using OsuPlayer.Interfaces.Service;
5 | using OsuPlayer.IO.Importer;
6 |
7 | namespace OsuPlayer.Services;
8 |
9 | public class OsuSongSourceService : OsuPlayerService, ISongSourceProvider
10 | {
11 | private readonly ReadOnlyObservableCollection? _songSourceList;
12 |
13 | public SourceList SongSource { get; } = new();
14 | public IObservable>? Songs { get; }
15 | public ReadOnlyObservableCollection? SongSourceList => _songSourceList;
16 |
17 | public override string ServiceName => "OSU_SONGSOURCE_SERVICE";
18 |
19 | public OsuSongSourceService(ISortProvider? sortProvider = null)
20 | {
21 | if (sortProvider != null)
22 | {
23 | sortProvider.SortedSongs = SongSource.Connect().Sort(sortProvider.SortingModeObservable);
24 |
25 | Songs = sortProvider.SortedSongs;
26 |
27 | Songs.Bind(out _songSourceList).Subscribe();
28 | }
29 | else
30 | {
31 | Songs = SongSource.Connect();
32 |
33 | Songs.Bind(out _songSourceList).Subscribe();
34 | }
35 | }
36 |
37 | public IMapEntryBase? GetMapEntryFromHash(string? hash)
38 | {
39 | return SongSourceList!.FirstOrDefault(x => x.Hash == hash);
40 | }
41 |
42 | public List GetMapEntriesFromHash(ICollection hashes, out ICollection invalidHashes)
43 | {
44 | var maps = hashes.Select(x => SongSourceList!.FirstOrDefault(map => map.Hash == x)).ToArray();
45 |
46 | invalidHashes = new List();
47 |
48 | for (var i = 0; i < maps.Length; i++)
49 | if (maps[i] == null)
50 | invalidHashes.Add(hashes.ElementAt(i));
51 |
52 | return maps.Where(map => map != null).ToList();
53 | }
54 | }
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Collections/BeatmapCollection.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
2 | // See the LICENCE file in the repository root for full licence text.
3 |
4 | using JetBrains.Annotations;
5 | using OsuPlayer.Data.LazerModels.Beatmaps;
6 | using OsuPlayer.Data.LazerModels.Files;
7 | using Realms;
8 |
9 | namespace OsuPlayer.Data.LazerModels.Collections;
10 |
11 | ///
12 | /// A collection of beatmaps grouped by a name.
13 | ///
14 | public class BeatmapCollection : RealmObject, IHasGuidPrimaryKey
15 | {
16 | ///
17 | /// The collection's name.
18 | ///
19 | public string Name { get; set; } = string.Empty;
20 |
21 | ///
22 | /// The es of beatmaps contained by the collection.
23 | ///
24 | ///
25 | /// We store as hashes rather than references to s to allow collections to maintain
26 | /// references to beatmaps even if they are removed. This helps with cases like importing collections before
27 | /// importing the beatmaps they contain, or when sharing collections between users.
28 | /// This can probably change in the future as we build the system up.
29 | ///
30 | public IList BeatmapMD5Hashes { get; } = null!;
31 |
32 | ///
33 | /// The date when this collection was last modified.
34 | ///
35 | public DateTimeOffset LastModified { get; set; }
36 |
37 | [PrimaryKey]
38 | public Guid ID { get; set; }
39 |
40 | public BeatmapCollection(string? name = null, IList? beatmapMD5Hashes = null)
41 | {
42 | ID = Guid.NewGuid();
43 | Name = name ?? string.Empty;
44 | BeatmapMD5Hashes = beatmapMD5Hashes ?? new List();
45 |
46 | LastModified = DateTimeOffset.UtcNow;
47 | }
48 |
49 | [UsedImplicitly]
50 | private BeatmapCollection()
51 | {
52 | }
53 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/CrashHandlerMainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using Avalonia.Controls;
5 | using Avalonia.Interactivity;
6 | using Nein.Base;
7 | using Nein.Extensions;
8 |
9 | namespace OsuPlayer.CrashHandler;
10 |
11 | public partial class CrashHandlerMainWindow : ReactiveWindow
12 | {
13 | public CrashHandlerMainWindow()
14 | {
15 | ViewModel = new CrashHandlerMainWindowViewModel();
16 |
17 | InitializeComponent();
18 |
19 | // this.WhenActivated(_ => { });
20 | }
21 |
22 | private async void Window_OnActivated(object? sender, EventArgs e)
23 | {
24 | if (ViewModel == default) return;
25 |
26 | var files = Directory.GetFiles("logs").Select(x => new FileInfo(x));
27 |
28 | var latestLog = files.MaxBy(x => x.CreationTimeUtc);
29 |
30 | if (latestLog == default) return;
31 |
32 | var crashLog = await File.ReadAllTextAsync(latestLog.FullName);
33 |
34 | ViewModel.CrashLog = crashLog;
35 | }
36 |
37 | private async void Copy_OnClick(object? sender, RoutedEventArgs e)
38 | {
39 | if (ViewModel == null) return;
40 |
41 | var topLevel = TopLevel.GetTopLevel(this);
42 |
43 | if (topLevel == default || topLevel.Clipboard == default) return;
44 |
45 | await topLevel.Clipboard.SetTextAsync(ViewModel.CrashLog);
46 | }
47 |
48 | private void GitHub_OnClick(object? sender, RoutedEventArgs e)
49 | {
50 | GeneralExtensions.OpenUrl(@"https://github.com/osu-player/osuplayer/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBUG%5D+");
51 | }
52 |
53 | private void Discord_OnClick(object? sender, RoutedEventArgs e)
54 | {
55 | GeneralExtensions.OpenUrl(@"https://discord.gg/RJQSc5B");
56 | }
57 |
58 | private void Email_OnClick(object? sender, RoutedEventArgs e)
59 | {
60 | GeneralExtensions.OpenUrl(@"mailto:7@founntain.dev");
61 | }
62 | }
--------------------------------------------------------------------------------
/OsuPlayer.CrashHandler/CrashHandlerMainWindow.axaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
18 |
19 |
22 |
23 |
24 |
27 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/OsuPlayer.Services/SortService.cs:
--------------------------------------------------------------------------------
1 | using DynamicData;
2 | using Nein.Extensions.Bindables;
3 | using OsuPlayer.Data.DataModels;
4 | using OsuPlayer.Data.DataModels.Interfaces;
5 | using OsuPlayer.Data.OsuPlayer.Enums;
6 | using OsuPlayer.Interfaces.Service;
7 |
8 | namespace OsuPlayer.Services;
9 |
10 | public class SortService : OsuPlayerService, ISortProvider
11 | {
12 | public IObservable>? SortedSongs { get; set; }
13 | public Bindable SortingModeBindable { get; } = new();
14 | public ObservableSorter SortingModeObservable { get; } = new();
15 |
16 | public override string ServiceName => "SORT_SERVICE";
17 |
18 | public SortService()
19 | {
20 | SortingModeBindable.BindValueChanged(d => SortingModeObservable.UpdateComparer(new MapSorter(d.NewValue)), true, true);
21 | }
22 |
23 | public IComparable CustomSorter(IMapEntryBase map, SortingMode sortingMode)
24 | {
25 | return sortingMode switch
26 | {
27 | SortingMode.Title => map.Title,
28 | SortingMode.Artist => map.Artist,
29 | SortingMode.SetId => map.BeatmapSetId,
30 | _ => ""
31 | };
32 | }
33 |
34 | private class MapSorter : IComparer
35 | {
36 | private readonly SortingMode _sortingMode;
37 |
38 | public MapSorter(SortingMode sortingMode)
39 | {
40 | _sortingMode = sortingMode;
41 | }
42 |
43 | public int Compare(IMapEntryBase? x, IMapEntryBase? y)
44 | {
45 | if (x == null || y == null)
46 | return 0;
47 |
48 | return _sortingMode switch
49 | {
50 | SortingMode.Artist => string.Compare(x.Artist, y.Artist, StringComparison.InvariantCulture),
51 | SortingMode.Title => string.Compare(x.Title, y.Title, StringComparison.InvariantCulture),
52 | SortingMode.SetId => x.BeatmapSetId.CompareTo(y.BeatmapSetId),
53 | _ => 0
54 | };
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/UpdateView.axaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/OsuPlayer/Views/CustomControls/AudioVisualizerView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.ReactiveUI;
2 | using Avalonia.Threading;
3 | using Nein.Base;
4 | using Nein.Extensions;
5 | using OsuPlayer.Modules.Audio.Interfaces;
6 | using ReactiveUI;
7 | using Splat;
8 |
9 | namespace OsuPlayer.Views.CustomControls;
10 |
11 | public partial class AudioVisualizerView : ReactiveUserControl
12 | {
13 | private object _lockObj = new ();
14 |
15 | public AudioVisualizerView()
16 | {
17 | InitializeComponent();
18 |
19 | this.WhenActivated(_ =>
20 | {
21 | ViewModel.AudioVisualizerUpdateTimer.Interval = TimeSpan.FromMilliseconds(2);
22 | ViewModel.AudioVisualizerUpdateTimer.Tick += AudioVisualizerUpdateTimer_OnTick;
23 |
24 | ViewModel.AudioVisualizerUpdateTimer.Start();
25 | });
26 | }
27 |
28 | private void AudioVisualizerUpdateTimer_OnTick(object? sender, EventArgs e)
29 | {
30 | Dispatcher.UIThread.Invoke(() =>
31 | {
32 | using var config = new Config();
33 |
34 | // Do nothing if audio visualizer is disabled
35 | if (!config.Container.DisplayAudioVisualizer) return;
36 |
37 | var player = Locator.Current.GetRequiredService();
38 |
39 | if (ViewModel == default) return;
40 |
41 | if (!player.IsPlaying.Value)
42 | {
43 | foreach (var t in ViewModel.SeriesValues.Where(x => x.Value != 0))
44 | {
45 | t.Value = 0;
46 | }
47 |
48 | return;
49 | }
50 |
51 | lock (_lockObj)
52 | {
53 | // var audioEngine = Locator.Current.GetRequiredService();
54 |
55 | var vData = ViewModel.AudioEngine.GetVisualizationData();
56 |
57 | for (var i = 0; i < vData.Length; i++)
58 | {
59 | ViewModel.SeriesValues[i].Value = vData[i] * 5;
60 | }
61 | }
62 | });
63 | }
64 | }
--------------------------------------------------------------------------------
/OsuPlayer/Views/TopBarView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Input;
3 | using Avalonia.Interactivity;
4 | using Nein.Base;
5 | using Nein.Extensions;
6 | using OsuPlayer.Windows;
7 | using Splat;
8 |
9 | namespace OsuPlayer.Views;
10 |
11 | internal partial class TopBarView : ReactiveControl
12 | {
13 | private FluentAppWindow? _mainWindow;
14 |
15 | public TopBarView()
16 | {
17 | InitializeComponent();
18 |
19 | _mainWindow = Locator.Current.GetRequiredService();
20 | }
21 | private void Navigation_Clicked(object? sender, RoutedEventArgs e)
22 | {
23 | if (_mainWindow?.ViewModel == default) return;
24 |
25 | switch ((sender as Control)?.Name)
26 | {
27 | case "BeatmapsNavigation":
28 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.BeatmapView;
29 | break;
30 | case "SearchNavigation":
31 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.SearchView;
32 | break;
33 | case "PlaylistNavigation":
34 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.PlaylistView;
35 | break;
36 | case "HomeNavigation":
37 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.HomeView;
38 | break;
39 | case "UserNavigation":
40 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.UserView;
41 | break;
42 | case "PartyNavigation":
43 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.PartyView;
44 | break;
45 | case "StatisticsNavigation":
46 | _mainWindow.ViewModel!.MainView = _mainWindow.ViewModel.StatisticsView;
47 | break;
48 | }
49 | }
50 |
51 | private void TopBarGrid_PointerPressed(object? sender, PointerPressedEventArgs e)
52 | {
53 | if (_mainWindow == default) return;
54 |
55 | _mainWindow.BeginMoveDrag(e);
56 | e.Handled = false;
57 | }
58 | }
--------------------------------------------------------------------------------
/OsuPlayer.Services/ShuffleImpl/BalancedShuffler.cs:
--------------------------------------------------------------------------------
1 | using OsuPlayer.Data.OsuPlayer.Enums;
2 | using OsuPlayer.Interfaces.Service;
3 |
4 | namespace OsuPlayer.Services.ShuffleImpl;
5 |
6 | ///
7 | /// This shuffle algorithm performs a full reshuffle of the song list so there aren't any duplicates and biases.
8 | ///
9 | public class BalancedShuffler : OsuPlayerService, IShuffleImpl
10 | {
11 | private readonly List _shuffledIndexes = new();
12 | private int _currentIndex;
13 |
14 | private int _maxRange;
15 |
16 | public string Name => "Balanced Shuffle";
17 | public string Description => "Shuffles the entire list of songs so there aren't any duplicates and biases.";
18 |
19 | public override string ServiceName => "BALANCED_SHUFFLE_SERVICE";
20 |
21 | public void Init(int maxRange)
22 | {
23 | if (_maxRange == maxRange) return;
24 |
25 | _maxRange = maxRange;
26 | _currentIndex = 0;
27 |
28 | if (_maxRange == 0) return;
29 |
30 | _shuffledIndexes.Clear();
31 | _shuffledIndexes.Capacity = _maxRange;
32 |
33 | GenerateRandomIndexes();
34 | }
35 |
36 | public int DoShuffle(int currentIndex, ShuffleDirection direction)
37 | {
38 | if (_shuffledIndexes[_currentIndex] != currentIndex) _currentIndex = _shuffledIndexes.IndexOf(currentIndex);
39 |
40 | _currentIndex += (int) direction;
41 |
42 | if (_currentIndex >= _maxRange) _currentIndex = 0;
43 | if (_currentIndex < 0) _currentIndex = _maxRange - 1;
44 |
45 | return _shuffledIndexes[_currentIndex];
46 | }
47 |
48 | private void GenerateRandomIndexes()
49 | {
50 | for (var i = 0; i < _maxRange; i++) _shuffledIndexes.Add(i);
51 |
52 | var random = new Random();
53 | var n = _maxRange - 1;
54 |
55 | while (n > 1)
56 | {
57 | var k = random.Next(n--);
58 | (_shuffledIndexes[n], _shuffledIndexes[k]) = (_shuffledIndexes[k], _shuffledIndexes[n]);
59 | }
60 | }
61 |
62 | public override string ToString()
63 | {
64 | return Name;
65 | }
66 | }
--------------------------------------------------------------------------------
/OsuPlayer.Tests/ValueConverterTests/SourceListValueConverterTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using DynamicData;
5 | using NUnit.Framework;
6 | using OsuPlayer.Data.OsuPlayer.StorageModels;
7 | using OsuPlayer.Extensions.ValueConverters;
8 |
9 | namespace OsuPlayer.Tests.ValueConverterTests;
10 |
11 | public class SourceListValueConverterTests
12 | {
13 | private readonly Type _expectedInput = typeof(SourceList);
14 | private readonly Type _expectedOutput = typeof(List);
15 | private SourceListValueConverter _playPauseConverter = null!;
16 |
17 | [SetUp]
18 | public void Setup()
19 | {
20 | _playPauseConverter = new SourceListValueConverter();
21 | }
22 |
23 | [TestCase(10)]
24 | [TestCase("test")]
25 | public void TestWrongInputHandled(object input)
26 | {
27 | Assert.That(input, Is.Not.InstanceOf(_expectedInput));
28 | Assert.DoesNotThrow(() =>
29 | _playPauseConverter.Convert(input, _expectedOutput, null, CultureInfo.InvariantCulture));
30 | }
31 |
32 | [Test]
33 | public void TestNullInputHandled()
34 | {
35 | Assert.DoesNotThrow(
36 | () => _playPauseConverter.Convert(null, _expectedOutput, null, CultureInfo.InvariantCulture));
37 | }
38 |
39 | [Test]
40 | public void TestCorrectUsage()
41 | {
42 | var input = new SourceList();
43 | input.Add(new Playlist());
44 | var initialItemCount = input.Count;
45 | Assert.That(input, Is.InstanceOf(_expectedInput));
46 | var output = _playPauseConverter.Convert(input, _expectedOutput, null, CultureInfo.InvariantCulture);
47 | Assert.That(output, Is.InstanceOf(_expectedOutput));
48 | Assert.That(((List) output)!.Count, Is.EqualTo(initialItemCount));
49 | }
50 |
51 | [Test]
52 | public void TestOutputOnIncorrectInput()
53 | {
54 | var output = _playPauseConverter.Convert(10, _expectedOutput, null, CultureInfo.InvariantCulture);
55 | Assert.That(output, Is.InstanceOf(_expectedOutput));
56 | }
57 | }
--------------------------------------------------------------------------------
/OsuPlayer.NativeLibs/OsuPlayer.NativeLibs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | Library
5 | osu!player Libraries
6 | OsuPlayer.NativeLibs
7 | https://github.com/Founntain/osuplayer
8 | https://github.com/Founntain/osuplayer
9 | Founntain
10 | 1.0.6
11 | en
12 |
13 |
14 |
15 | true
16 | osu!player Libraries
17 | Native libraries for osu!player
18 | Founntain.OsuPlayer.NativeLibs
19 | osuplayer libraries
20 | false
21 | icon.png
22 | MIT
23 | README.md
24 |
25 |
26 |
27 |
28 | true
29 | runtimes
30 |
31 |
32 |
33 |
37 | true
38 | lib\$(TargetFramework)
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/OsuPlayer.Data/LazerModels/Interfaces/IMappingOperationOptions.cs:
--------------------------------------------------------------------------------
1 | namespace OsuPlayer.Data.LazerModels.Interfaces;
2 |
3 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
4 | // See the LICENCE file in the repository root for full licence text.
5 | public interface IMappingOperationOptions
6 | {
7 | Func ServiceCtor { get; }
8 |
9 | ///
10 | /// Add context items to be accessed at map time inside an or
11 | ///
12 | ///
13 | IDictionary Items { get; }
14 |
15 | ///
16 | /// Construct services using this callback. Use this for child/nested containers
17 | ///
18 | ///
19 | void ConstructServicesUsing(Func constructor);
20 |
21 | ///
22 | /// Execute a custom function to the source and/or destination types before member mapping
23 | ///
24 | /// Callback for the source/destination types
25 | void BeforeMap(Action