From 73766a85afe5487439aa9992ee88191672efa04d Mon Sep 17 00:00:00 2001 From: XeroxDev Date: Sun, 25 Feb 2024 13:52:22 +0100 Subject: [PATCH] feat: add support for more frameworks --- README.md | 2 +- YTMDesktopCompanion.Example/Program.cs | 28 +- .../YTMDesktopCompanion.Example.csproj | 3 +- YTMDesktopCompanion/Clients/RestClient.cs | 518 +++++++++------- YTMDesktopCompanion/Clients/SocketClient.cs | 251 ++++---- YTMDesktopCompanion/CompanionConnector.cs | 116 ++-- YTMDesktopCompanion/Constants/Endpoints.cs | 101 ++-- .../Converter/SemanticVersionJsonConverter.cs | 66 ++- YTMDesktopCompanion/Enums/ECommand.cs | 88 ++- YTMDesktopCompanion/Enums/ELikeStatus.cs | 64 +- YTMDesktopCompanion/Enums/ERepeatMode.cs | 61 +- YTMDesktopCompanion/Enums/ESocketState.cs | 59 +- YTMDesktopCompanion/Enums/ETrackState.cs | 64 +- .../Exceptions/ApiException.cs | 76 ++- .../Interfaces/IGenericClient.cs | 49 +- .../Models/Input/Auth/RequestCodeInput.cs | 150 +++-- .../Models/Input/Auth/RequestInput.cs | 111 ++-- .../Models/Input/CommandInput.cs | 83 ++- .../Models/Output/Auth/RequestCodeOutput.cs | 48 +- .../Models/Output/Auth/RequestOutput.cs | 48 +- .../Models/Output/ErrorOutput.cs | 85 ++- .../Models/Output/MetadataOutput.cs | 47 +- .../Models/Output/PlaylistOutput.cs | 59 +- .../Models/Output/StateOutput.cs | 556 ++++++++++-------- .../Properties/AssemblyInfo.cs | 40 ++ .../Settings/ConnectorSettings.cs | 200 ++++--- .../YTMDesktopCompanion.csproj | 18 +- release-please-config.json | 3 +- 28 files changed, 1869 insertions(+), 1125 deletions(-) create mode 100644 YTMDesktopCompanion/Properties/AssemblyInfo.cs diff --git a/README.md b/README.md index 766a2b6..f7c0f08 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ This is a library for the YTMDesktop Companion Server which lets you easier comm authorization and so on. ## Table of contents + - [Badges](#badges) @@ -25,7 +26,6 @@ authorization and so on. [![Awesome Badges](https://img.shields.io/badge/badges-awesome-green?style=for-the-badge)](https://shields.io) - ## Installation TODO: Add installation instructions diff --git a/YTMDesktopCompanion.Example/Program.cs b/YTMDesktopCompanion.Example/Program.cs index 51fcc12..a30b6c7 100644 --- a/YTMDesktopCompanion.Example/Program.cs +++ b/YTMDesktopCompanion.Example/Program.cs @@ -1,8 +1,34 @@ -using System.Text.Json; +// This file is part of the YTMDesktopCompanion.Example project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Text.Json; using NuGet.Versioning; using XeroxDev.YTMDesktop.Companion; using XeroxDev.YTMDesktop.Companion.Settings; +#endregion + #region Setup // Set YOUR version (or fetch them from anywhere) I will use a static version for this example diff --git a/YTMDesktopCompanion.Example/YTMDesktopCompanion.Example.csproj b/YTMDesktopCompanion.Example/YTMDesktopCompanion.Example.csproj index 8aa494d..b9b677a 100644 --- a/YTMDesktopCompanion.Example/YTMDesktopCompanion.Example.csproj +++ b/YTMDesktopCompanion.Example/YTMDesktopCompanion.Example.csproj @@ -6,10 +6,11 @@ enable enable XeroxDev.YTMDesktop.Companion.Example + latest + en - diff --git a/YTMDesktopCompanion/Clients/RestClient.cs b/YTMDesktopCompanion/Clients/RestClient.cs index 1dad41c..9d20283 100644 --- a/YTMDesktopCompanion/Clients/RestClient.cs +++ b/YTMDesktopCompanion/Clients/RestClient.cs @@ -1,5 +1,32 @@ -using System.Net.Http.Json; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Net.Http; +using System.Net.Http.Json; using System.Text.Json; +using System.Threading.Tasks; using XeroxDev.YTMDesktop.Companion.Constants; using XeroxDev.YTMDesktop.Companion.Enums; using XeroxDev.YTMDesktop.Companion.Exceptions; @@ -10,272 +37,343 @@ using XeroxDev.YTMDesktop.Companion.Models.Output.Auth; using XeroxDev.YTMDesktop.Companion.Settings; -namespace XeroxDev.YTMDesktop.Companion.Clients; +#endregion -/// -/// A REST client to communicate with the companion servers REST API -/// -public class RestClient : IGenericClient +namespace XeroxDev.YTMDesktop.Companion.Clients { - private readonly HttpClient _httpClient = new(); - /// - /// A REST client to communicate with the companion servers REST API + /// A REST client to communicate with the companion servers REST API /// - /// The settings to use for the client - public RestClient(ConnectorSettings settings) + public class RestClient : IGenericClient { - Settings = settings; - } + private readonly HttpClient _httpClient = new HttpClient(); - /// - /// The settings to use for the client - /// - public ConnectorSettings Settings { get; set; } + /// + /// A REST client to communicate with the companion servers REST API + /// + /// The settings to use for the client + public RestClient(ConnectorSettings settings) + { + Settings = settings; + } - /// - public void SetAuthToken(string token) => Settings.Token = token; + #region IGenericClient Members - /// - /// Get the metadata from the API - /// - /// The metadata from the API - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task GetMetadata() => await SendGetRequest(Endpoints.Metadata); + /// + /// The settings to use for the client + /// + public ConnectorSettings Settings { get; set; } - /// - /// Get the state from the API - /// - /// The state from the API - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task GetState() => await SendGetRequest(Endpoints.State, Settings.Token); + /// + public void SetAuthToken(string token) + { + Settings.Token = token; + } - /// - /// Get the playlists from the API - /// - /// The playlists from the API - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task GetPlaylists() => (await SendGetRequest(Endpoints.Playlists, Settings.Token)) ?? Array.Empty(); + #endregion - /// - /// Requests a code to exchange for an auth token - /// - /// The code to exchange for an auth token - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task GetAuthCode() => ( - await SendPostRequest(Endpoints.AuthRequestCode, new RequestCodeInput(Settings.AppId, Settings.AppName, Settings.AppVersion)) - )?.Code; + /// + /// Get the metadata from the API + /// + /// The metadata from the API + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task GetMetadata() + { + return await SendGetRequest(Endpoints.Metadata); + } - /// - /// Get the authentication token that is required to access the API.
- ///
- /// You should save this token safely and set it either:
- /// 1. in the settings
- /// 2. use the method in this class
- /// 3. use the method in the class - ///
- /// The code you got from the method - /// The authentication token that is required to access the API - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task GetAuthToken(string code) => ( - await SendPostRequest(Endpoints.AuthRequest, new RequestInput(Settings.AppId, code)) - )?.Token; + /// + /// Get the state from the API + /// + /// The state from the API + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task GetState() + { + return await SendGetRequest(Endpoints.State, Settings.Token); + } - #region Commands + /// + /// Get the playlists from the API + /// + /// The playlists from the API + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task GetPlaylists() + { + return await SendGetRequest(Endpoints.Playlists, Settings.Token) ?? Array.Empty(); + } - /// - /// Play or pause the current song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task PlayPause() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.PlayPause), Settings.Token); + /// + /// Requests a code to exchange for an auth token + /// + /// The code to exchange for an auth token + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task GetAuthCode() + { + return ( + await SendPostRequest(Endpoints.AuthRequestCode, new RequestCodeInput(Settings.AppId, Settings.AppName, Settings.AppVersion)) + )?.Code; + } - /// - /// Play the current song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Play() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Play), Settings.Token); + /// + /// Get the authentication token that is required to access the API.
+ ///
+ /// You should save this token safely and set it either:
+ /// 1. in the settings
+ /// 2. use the method in this class
+ /// 3. use the method in the class + ///
+ /// The code you got from the method + /// The authentication token that is required to access the API + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task GetAuthToken(string code) + { + return ( + await SendPostRequest(Endpoints.AuthRequest, new RequestInput(Settings.AppId, code)) + )?.Token; + } - /// - /// Pause the current song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Pause() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Pause), Settings.Token); + /// + /// Send a GET request to the server + /// + /// The path to send the request to + /// The token to use for the request + /// The type of the response + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + private async Task SendGetRequest(string path, string token = null) + { + using (var request = new HttpRequestMessage(HttpMethod.Get, $"http://{Settings.Host}:{Settings.Port}{path}")) + { + request.Headers.Add("Accept", "application/json"); + if (token != null) request.Headers.Add("Authorization", token); - /// - /// Increase the volume - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task VolumeUp() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.VolumeUp), Settings.Token); + return await SendRequest(request); + } + } - /// - /// Decrease the volume - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task VolumeDown() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.VolumeDown), Settings.Token); + private async Task SendPostRequest(string path, TBody body, string token = null) + { + using (var request = new HttpRequestMessage(HttpMethod.Post, $"http://{Settings.Host}:{Settings.Port}{path}")) + { + request.Headers.Add("Accept", "application/json"); + if (token != null) request.Headers.Add("Authorization", token); + try + { + request.Content = JsonContent.Create(body); + } + catch (Exception e) + { + throw new ApiException("An error occurred while creating the request", e, new ErrorOutput { StatusCode = e.HResult, Error = "Unknown Exception", Message = e.Message }); + } - /// - /// Set the volume - /// - /// The volume to set - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task SetVolume(int volume) => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.SetVolume, volume), Settings.Token); + return await SendRequest(request); + } + } - /// - /// Mute the volume - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Mute() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Mute), Settings.Token); + private async Task SendRequest(HttpRequestMessage request) + { + HttpResponseMessage response; + try + { + response = await _httpClient.SendAsync(request); + } + catch (Exception e) + { + throw new ApiException("An error occurred while sending the request", e, new ErrorOutput + { + StatusCode = e.HResult, + Error = "Unknown Exception", + Message = e.Message + }); + } - /// - /// Unmute the volume - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Unmute() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Unmute), Settings.Token); + var content = await response.Content.ReadAsStringAsync(); - /// - /// Seek to a specific time in the song - /// - /// The time to seek to - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task SeekTo(int time) => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.SeekTo, time), Settings.Token); + if (!response.IsSuccessStatusCode) + { + var error = JsonSerializer.Deserialize(content); + if (error == null) + { + throw new ApiException(new ErrorOutput + { + StatusCode = (int)response.StatusCode, + Error = response.ReasonPhrase ?? "Unknown Error", + Message = response.Content.ReadAsStringAsync().Result + }); + } - /// - /// Skip to the next song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Next() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Next), Settings.Token); + error.StatusCode = (int)response.StatusCode; - /// - /// Skip to the previous song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Previous() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Previous), Settings.Token); + throw new ApiException(error); + } - /// - /// Set the repeat mode - /// - /// The mode to set - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task SetRepeatMode(ERepeatMode mode) => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.RepeatMode, mode), Settings.Token); + // Server still sends for some endpoints no content, so we have to check if the content is empty and return null if it is + if (string.IsNullOrWhiteSpace(content)) return default; - /// - /// Shuffle the queue - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task Shuffle() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Shuffle), Settings.Token); + // Try parsing the response to ErrorOutput, if it's successful, throw an ApiException + try + { + var errorOutput = JsonSerializer.Deserialize(content); + if (errorOutput?.Error != null && errorOutput.Message != null && errorOutput.StatusCode != null && errorOutput.Code != null) throw new ApiException(errorOutput); + } + catch (Exception e) + { + if (e is ApiException) throw; + } - /// - /// Play a song from the queue - /// - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task PlayQueueIndex(int index) => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.PlayQueueIndex, index), Settings.Token); + return JsonSerializer.Deserialize(content); + } - /// - /// Toggle like the current song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task ToggleLike() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.ToggleLike), Settings.Token); + #region Commands - /// - /// Toggle dislike the current song - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - public async Task ToggleDislike() => await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.ToggleDislike), Settings.Token); + /// + /// Play or pause the current song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task PlayPause() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.PlayPause), Settings.Token); + } - #endregion + /// + /// Play the current song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Play() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Play), Settings.Token); + } - /// - /// Send a GET request to the server - /// - /// The path to send the request to - /// The token to use for the request - /// The type of the response - /// - /// Thrown when an error occurred while sending the request. Error is either from the server or from the client - private async Task SendGetRequest(string path, string? token = null) - { - using var request = new HttpRequestMessage(HttpMethod.Get, $"http://{Settings.Host}:{Settings.Port}{path}"); - request.Headers.Add("Accept", "application/json"); - if (token != null) request.Headers.Add("Authorization", token); + /// + /// Pause the current song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Pause() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Pause), Settings.Token); + } - return await SendRequest(request); - } + /// + /// Increase the volume + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task VolumeUp() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.VolumeUp), Settings.Token); + } - private async Task SendPostRequest(string path, TBody body, string? token = null) - { - using var request = new HttpRequestMessage(HttpMethod.Post, $"http://{Settings.Host}:{Settings.Port}{path}"); - request.Headers.Add("Accept", "application/json"); - if (token != null) request.Headers.Add("Authorization", token); - try + /// + /// Decrease the volume + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task VolumeDown() { - request.Content = JsonContent.Create(body); + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.VolumeDown), Settings.Token); } - catch (Exception e) + + /// + /// Set the volume + /// + /// The volume to set + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task SetVolume(int volume) { - throw new ApiException("An error occurred while creating the request", e, new ErrorOutput { StatusCode = e.HResult, Error = "Unknown Exception", Message = e.Message }); + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.SetVolume, volume), Settings.Token); } - return await SendRequest(request); - } + /// + /// Mute the volume + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Mute() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Mute), Settings.Token); + } - private async Task SendRequest(HttpRequestMessage request) - { - HttpResponseMessage response; - try + /// + /// Unmute the volume + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Unmute() { - response = await _httpClient.SendAsync(request); + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Unmute), Settings.Token); } - catch (Exception e) + + /// + /// Seek to a specific time in the song + /// + /// The time to seek to + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task SeekTo(int time) { - throw new ApiException("An error occurred while sending the request", e, new ErrorOutput - { - StatusCode = e.HResult, - Error = "Unknown Exception", - Message = e.Message - }); + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.SeekTo, time), Settings.Token); } - var content = await response.Content.ReadAsStringAsync(); + /// + /// Skip to the next song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Next() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Next), Settings.Token); + } - if (!response.IsSuccessStatusCode) + /// + /// Skip to the previous song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Previous() { - var error = JsonSerializer.Deserialize(content); - if (error == null) - { - throw new ApiException(new ErrorOutput() - { - StatusCode = (int)response.StatusCode, - Error = response.ReasonPhrase ?? "Unknown Error", - Message = response.Content.ReadAsStringAsync().Result - }); - } + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Previous), Settings.Token); + } - error.StatusCode = (int)response.StatusCode; + /// + /// Set the repeat mode + /// + /// The mode to set + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task SetRepeatMode(ERepeatMode mode) + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.RepeatMode, mode), Settings.Token); + } - throw new ApiException(error); + /// + /// Shuffle the queue + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task Shuffle() + { + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.Shuffle), Settings.Token); } - // Server still sends for some endpoints no content, so we have to check if the content is empty and return null if it is - if (string.IsNullOrWhiteSpace(content)) + /// + /// Play a song from the queue + /// + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task PlayQueueIndex(int index) { - return default; + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.PlayQueueIndex, index), Settings.Token); } - // Try parsing the response to ErrorOutput, if it's successful, throw an ApiException - try + /// + /// Toggle like the current song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task ToggleLike() { - var errorOutput = JsonSerializer.Deserialize(content); - if (errorOutput is not null && errorOutput.Error is not null && errorOutput.Message is not null && errorOutput.StatusCode is not null && errorOutput.Code is not null) - { - throw new ApiException(errorOutput); - } + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.ToggleLike), Settings.Token); } - catch (Exception e) + + /// + /// Toggle dislike the current song + /// + /// Thrown when an error occurred while sending the request. Error is either from the server or from the client + public async Task ToggleDislike() { - if (e is ApiException) throw; + await SendPostRequest(Endpoints.Command, new CommandInput(ECommand.ToggleDislike), Settings.Token); } - return JsonSerializer.Deserialize(content); + #endregion } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Clients/SocketClient.cs b/YTMDesktopCompanion/Clients/SocketClient.cs index fbf76f6..315701b 100644 --- a/YTMDesktopCompanion/Clients/SocketClient.cs +++ b/YTMDesktopCompanion/Clients/SocketClient.cs @@ -1,4 +1,30 @@ -using SocketIOClient; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Threading.Tasks; +using SocketIOClient; using SocketIOClient.Transport; using SocketIOClient.Windows7; using XeroxDev.YTMDesktop.Companion.Constants; @@ -7,132 +33,139 @@ using XeroxDev.YTMDesktop.Companion.Models.Output; using XeroxDev.YTMDesktop.Companion.Settings; -namespace XeroxDev.YTMDesktop.Companion.Clients; +#endregion -public class SocketClient : IGenericClient +namespace XeroxDev.YTMDesktop.Companion.Clients { - /// - /// The settings for the socket client. - /// - public ConnectorSettings Settings + public class SocketClient : IGenericClient { - get => _settings; - set + private ConnectorSettings _settings; + + /// + /// The socket client + /// + private SocketIOClient.SocketIO _socket; + + public SocketClient(ConnectorSettings settings) { - if (value is null) throw new ArgumentNullException(nameof(value), "The settings cannot be null."); - var reconnect = false; - try - { - reconnect = Settings.Host != value.Host || Settings.Port != value.Port || Settings.Token != value.Token; - } - catch - { - // ignored - } + _settings = settings; + } + + #region IGenericClient Members - _settings = value; + /// + /// The settings for the socket client. + /// + public ConnectorSettings Settings + { + get => _settings; + set + { + if (value is null) throw new ArgumentNullException(nameof(value), "The settings cannot be null."); + var reconnect = false; + try + { + reconnect = Settings.Host != value.Host || Settings.Port != value.Port || Settings.Token != value.Token; + } + catch + { + // ignored + } + + _settings = value; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - if (reconnect && _socket is not null) Connect(); + if (reconnect && _socket != null) Connect(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + } } - } - - /// - public void SetAuthToken(string token) - { - var settings = Settings; - settings.Token = token; - Settings = settings; - } - /// - /// The socket client - /// - private SocketIOClient.SocketIO? _socket; - - private ConnectorSettings _settings; - - #region Events - - /// - /// The event that is raised when the client receives errors. - /// - public event EventHandler OnError = delegate { }; + /// + public void SetAuthToken(string token) + { + var settings = Settings; + settings.Token = token; + Settings = settings; + } - /// - /// The event that is raised when the socket connection is changed. - /// - public event EventHandler OnConnectionChange = delegate { }; + #endregion - /// - /// The event that is raised when the YTMDesktop State has changed. - /// - public event EventHandler OnStateChange = delegate { }; + /// + /// Get the whole socket object. Use with caution!
+ /// Useful for custom things that are not implemented in the library yet. + ///
+ /// The socket object + public SocketIOClient.SocketIO GetSocket() + { + return _socket; + } - /// - /// The event that is raised when a playlist was created - /// - public event EventHandler OnPlaylistCreated = delegate { }; + /// + /// Connect to the socket server + /// + public async Task Connect() + { + try + { + if (_socket != null) + { + await _socket.DisconnectAsync(); + _socket.Dispose(); + _socket = null; + OnConnectionChange(this, ESocketState.Disconnected); + } + + OnConnectionChange(this, ESocketState.Connecting); + + _socket = new SocketIOClient.SocketIO($"http://{Settings.Host}:{Settings.Port}{Endpoints.Realtime}", new SocketIOOptions + { + Transport = TransportProtocol.WebSocket, + Auth = Settings.Token + }); + _socket.ClientWebSocketProvider = () => new SystemNetWebSocketsClientWebSocket(); + + _socket.OnConnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connected); + _socket.OnDisconnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Disconnected); + _socket.OnError += (sender, args) => OnError(sender ?? this, new Exception(args)); + _socket.OnReconnectError += (sender, args) => OnError(sender ?? this, args); + _socket.OnReconnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connected); + _socket.OnReconnectAttempt += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connecting); + _socket.On("state-update", data => OnStateChange(this, data.GetValue())); + _socket.On("playlist-created", data => OnPlaylistCreated(this, data.GetValue())); + _socket.On("playlist-delete", data => OnPlaylistDeleted(this, data.GetValue())); + } + catch (Exception ex) + { + OnError(this, ex); + } + } - /// - /// The event that is raised when a playlist was deleted - /// - public event EventHandler OnPlaylistDeleted = delegate { }; + #region Events - #endregion + /// + /// The event that is raised when the client receives errors. + /// + public event EventHandler OnError = delegate { }; - public SocketClient(ConnectorSettings settings) - { - _settings = settings; - } + /// + /// The event that is raised when the socket connection is changed. + /// + public event EventHandler OnConnectionChange = delegate { }; - /// - /// Get the whole socket object. Use with caution!
- /// Useful for custom things that are not implemented in the library yet. - ///
- /// The socket object - public SocketIOClient.SocketIO GetSocket() - { - return _socket!; - } + /// + /// The event that is raised when the YTMDesktop State has changed. + /// + public event EventHandler OnStateChange = delegate { }; - /// - /// Connect to the socket server - /// - public async Task Connect() - { - try - { - if (_socket is not null) - { - await _socket.DisconnectAsync(); - _socket.Dispose(); - _socket = null; - OnConnectionChange(this, ESocketState.Disconnected); - } + /// + /// The event that is raised when a playlist was created + /// + public event EventHandler OnPlaylistCreated = delegate { }; - OnConnectionChange(this, ESocketState.Connecting); + /// + /// The event that is raised when a playlist was deleted + /// + public event EventHandler OnPlaylistDeleted = delegate { }; - _socket = new SocketIOClient.SocketIO($"http://{Settings.Host}:{Settings.Port}{Endpoints.Realtime}", new SocketIOOptions - { - Transport = TransportProtocol.WebSocket, - Auth = Settings.Token, - }); - _socket.ClientWebSocketProvider = () => new SystemNetWebSocketsClientWebSocket(); - - _socket.OnConnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connected); - _socket.OnDisconnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Disconnected); - _socket.OnError += (sender, args) => OnError(sender ?? this, new Exception(args)); - _socket.OnReconnectError += (sender, args) => OnError(sender ?? this, args); - _socket.OnReconnected += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connected); - _socket.OnReconnectAttempt += (sender, _) => OnConnectionChange(sender ?? this, ESocketState.Connecting); - _socket.On("state-update", data => OnStateChange(this, data.GetValue())); - _socket.On("playlist-created", data => OnPlaylistCreated(this, data.GetValue())); - _socket.On("playlist-delete", data => OnPlaylistDeleted(this, data.GetValue())); - } - catch (Exception ex) - { - OnError(this, ex); - } + #endregion } } \ No newline at end of file diff --git a/YTMDesktopCompanion/CompanionConnector.cs b/YTMDesktopCompanion/CompanionConnector.cs index 558a403..4462a59 100644 --- a/YTMDesktopCompanion/CompanionConnector.cs +++ b/YTMDesktopCompanion/CompanionConnector.cs @@ -1,60 +1,88 @@ -using XeroxDev.YTMDesktop.Companion.Clients; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using XeroxDev.YTMDesktop.Companion.Clients; using XeroxDev.YTMDesktop.Companion.Settings; -namespace XeroxDev.YTMDesktop.Companion; +#endregion -/// -/// Companion Connector. This class is the main class of the library. It contains the rest and socket client.
-/// You can also use the and directly if you want to. But you have to manage the settings update for both clients yourself. -///
-public class CompanionConnector +namespace XeroxDev.YTMDesktop.Companion { /// - /// Gets or sets the settings for the rest and socket clients. + /// Companion Connector. This class is the main class of the library. It contains the rest and socket client.
+ /// You can also use the and directly if you want to. But you have to manage the settings update for both clients yourself. ///
- public ConnectorSettings Settings + public class CompanionConnector { - get => RestClient.Settings ?? SocketClient.Settings ?? throw new NullReferenceException("Settings are not set"); - set + public CompanionConnector(ConnectorSettings settings) { - RestClient.Settings = value; - SocketClient.Settings = value; + RestClient = new RestClient(settings); + SocketClient = new SocketClient(settings); } - } - /// - /// The rest client to make requests to the server. - /// - public RestClient RestClient { get; } + /// + /// Gets or sets the settings for the rest and socket clients. + /// + public ConnectorSettings Settings + { + get => RestClient.Settings ?? SocketClient.Settings ?? throw new NullReferenceException("Settings are not set"); + set + { + RestClient.Settings = value; + SocketClient.Settings = value; + } + } - /// - /// The socket client to make requests to the server. - /// - public SocketClient SocketClient { get; } + /// + /// The rest client to make requests to the server. + /// + public RestClient RestClient { get; } - public CompanionConnector(ConnectorSettings settings) - { - RestClient = new RestClient(settings); - SocketClient = new SocketClient(settings); - } + /// + /// The socket client to make requests to the server. + /// + public SocketClient SocketClient { get; } - /// - /// Set the settings for the rest and socket clients. - /// - /// The settings to set - public void SetSettings(ConnectorSettings settings) - { - Settings = settings; - } + /// + /// Set the settings for the rest and socket clients. + /// + /// The settings to set + public void SetSettings(ConnectorSettings settings) + { + Settings = settings; + } - /// - /// Set the authentication token, so it can be used for further requests.
- /// This automatically sets the token for both clients and reconnects the socket client if the token changed. - ///
- /// The token to set - public void SetAuthToken(string token) - { - RestClient.SetAuthToken(token); - SocketClient.SetAuthToken(token); + /// + /// Set the authentication token, so it can be used for further requests.
+ /// This automatically sets the token for both clients and reconnects the socket client if the token changed. + ///
+ /// The token to set + public void SetAuthToken(string token) + { + RestClient.SetAuthToken(token); + SocketClient.SetAuthToken(token); + } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Constants/Endpoints.cs b/YTMDesktopCompanion/Constants/Endpoints.cs index 9c3dcd6..d720694 100644 --- a/YTMDesktopCompanion/Constants/Endpoints.cs +++ b/YTMDesktopCompanion/Constants/Endpoints.cs @@ -1,52 +1,75 @@ -namespace XeroxDev.YTMDesktop.Companion.Constants; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -/// -/// This class contains the endpoints for the API. -/// -public static class Endpoints +namespace XeroxDev.YTMDesktop.Companion.Constants { /// - /// The supported version. Will be used to build the API path. + /// This class contains the endpoints for the API. /// - public const string SupportedVersion = "v1"; + public static class Endpoints + { + /// + /// The supported version. Will be used to build the API path. + /// + public const string SupportedVersion = "v1"; - /// - /// The API path. - /// - public const string Api = "/api/" + Endpoints.SupportedVersion; + /// + /// The API path. + /// + public const string Api = "/api/" + SupportedVersion; - /// - /// The API path for the realtime endpoint. - /// - public const string Realtime = Endpoints.Api + "/realtime"; + /// + /// The API path for the realtime endpoint. + /// + public const string Realtime = Api + "/realtime"; - /// - /// The API path for the metadata endpoint. - /// - public const string Metadata = "/metadata"; + /// + /// The API path for the metadata endpoint. + /// + public const string Metadata = "/metadata"; - /// - /// The API path for the auth request endpoint. - /// - public const string AuthRequest = Endpoints.Api + "/auth/request"; + /// + /// The API path for the auth request endpoint. + /// + public const string AuthRequest = Api + "/auth/request"; - /// - /// The API path for the auth request code endpoint. - /// - public const string AuthRequestCode = Endpoints.Api + "/auth/requestcode"; + /// + /// The API path for the auth request code endpoint. + /// + public const string AuthRequestCode = Api + "/auth/requestcode"; - /// - /// The API path for the state endpoint. - /// - public const string State = Endpoints.Api + "/state"; + /// + /// The API path for the state endpoint. + /// + public const string State = Api + "/state"; - /// - /// The API path for the playlists" endpoint. - /// - public const string Playlists = Endpoints.Api + "/playlists"; + /// + /// The API path for the playlists" endpoint. + /// + public const string Playlists = Api + "/playlists"; - /// - /// The API path for the command endpoint. - /// - public const string Command = Endpoints.Api + "/command"; + /// + /// The API path for the command endpoint. + /// + public const string Command = Api + "/command"; + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Converter/SemanticVersionJsonConverter.cs b/YTMDesktopCompanion/Converter/SemanticVersionJsonConverter.cs index e0c955a..74fb23b 100644 --- a/YTMDesktopCompanion/Converter/SemanticVersionJsonConverter.cs +++ b/YTMDesktopCompanion/Converter/SemanticVersionJsonConverter.cs @@ -1,32 +1,58 @@ -using System.Text.Json; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Text.Json; using System.Text.Json.Serialization; using NuGet.Versioning; -namespace XeroxDev.YTMDesktop.Companion.Converter; +#endregion -/// -/// This class is used to convert a to and from a JSON string. -/// -public class SemanticVersionJsonConverter : JsonConverter +namespace XeroxDev.YTMDesktop.Companion.Converter { - public override SemanticVersion? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + /// + /// This class is used to convert a to and from a JSON string. + /// + public class SemanticVersionJsonConverter : JsonConverter { - try + public override SemanticVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType != JsonTokenType.String) return null; - if (reader.GetString() is null) return null; - if (!SemanticVersion.TryParse(reader.GetString()!, out var version)) return null; + try + { + if (reader.TokenType != JsonTokenType.String) return null; + if (reader.GetString() is null) return null; + return !SemanticVersion.TryParse(reader.GetString(), out var version) ? null : version; + } + catch (Exception) + { + return null; + } } - catch (Exception) + + public override void Write(Utf8JsonWriter writer, SemanticVersion value, JsonSerializerOptions options) { - return null; + writer.WriteStringValue(value.ToString()); } - - return null; - } - - public override void Write(Utf8JsonWriter writer, SemanticVersion value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToString()); } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Enums/ECommand.cs b/YTMDesktopCompanion/Enums/ECommand.cs index 4569312..56f208c 100644 --- a/YTMDesktopCompanion/Enums/ECommand.cs +++ b/YTMDesktopCompanion/Enums/ECommand.cs @@ -1,37 +1,63 @@ -namespace XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -/// -/// All the known commands that can be sent to the command endpoint. -/// -public enum ECommand +namespace XeroxDev.YTMDesktop.Companion.Enums { - PlayPause, - Play, - Pause, - VolumeUp, - VolumeDown, - SetVolume, - Mute, - Unmute, - SeekTo, - Next, - Previous, - RepeatMode, - Shuffle, - PlayQueueIndex, - ToggleLike, - ToggleDislike, -} + /// + /// All the known commands that can be sent to the command endpoint. + /// + public enum ECommand + { + PlayPause, + Play, + Pause, + VolumeUp, + VolumeDown, + SetVolume, + Mute, + Unmute, + SeekTo, + Next, + Previous, + RepeatMode, + Shuffle, + PlayQueueIndex, + ToggleLike, + ToggleDislike + } -/// -/// Command extensions for the enum to convert it to a string. -/// -public static class CommandExtensions -{ /// - /// This method converts the enum to a string that can be used as a command. + /// Command extensions for the enum to convert it to a string. /// - /// - /// - public static string ToCommandString(this ECommand command) => char.ToLowerInvariant(command.ToString()[0]) + command.ToString()[1..]; + public static class CommandExtensions + { + /// + /// This method converts the enum to a string that can be used as a command. + /// + /// + /// + public static string ToCommandString(this ECommand command) + { + return char.ToLowerInvariant(command.ToString()[0]) + command.ToString().Substring(1); + } + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Enums/ELikeStatus.cs b/YTMDesktopCompanion/Enums/ELikeStatus.cs index 9f7d383..803cb1a 100644 --- a/YTMDesktopCompanion/Enums/ELikeStatus.cs +++ b/YTMDesktopCompanion/Enums/ELikeStatus.cs @@ -1,24 +1,50 @@ -namespace XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -/// -/// The like status -/// -public enum ELikeStatus +namespace XeroxDev.YTMDesktop.Companion.Enums { /// - /// Unknown like status + /// The like status /// - Unknown = -1, - /// - /// Dislike status - /// - Dislike = 0, - /// - /// Indifferent status. (neither like nor dislike) - /// - Indifferent = 1, - /// - /// Like status - /// - Like = 2 + public enum ELikeStatus + { + /// + /// Unknown like status + /// + Unknown = -1, + + /// + /// Dislike status + /// + Dislike = 0, + + /// + /// Indifferent status. (neither like nor dislike) + /// + Indifferent = 1, + + /// + /// Like status + /// + Like = 2 + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Enums/ERepeatMode.cs b/YTMDesktopCompanion/Enums/ERepeatMode.cs index 8192e37..e47f6d9 100644 --- a/YTMDesktopCompanion/Enums/ERepeatMode.cs +++ b/YTMDesktopCompanion/Enums/ERepeatMode.cs @@ -1,27 +1,50 @@ -namespace XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -/// -/// Repeat mode -/// -public enum ERepeatMode +namespace XeroxDev.YTMDesktop.Companion.Enums { /// - /// Unknown repeat mode. + /// Repeat mode /// - Unknown = -1, + public enum ERepeatMode + { + /// + /// Unknown repeat mode. + /// + Unknown = -1, - /// - /// No repeat. - /// - None = 0, + /// + /// No repeat. + /// + None = 0, - /// - /// Repeat whole playlist. - /// - All = 1, + /// + /// Repeat whole playlist. + /// + All = 1, - /// - /// Repeat current track. - /// - One = 2, + /// + /// Repeat current track. + /// + One = 2 + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Enums/ESocketState.cs b/YTMDesktopCompanion/Enums/ESocketState.cs index 2431146..f139d29 100644 --- a/YTMDesktopCompanion/Enums/ESocketState.cs +++ b/YTMDesktopCompanion/Enums/ESocketState.cs @@ -1,24 +1,47 @@ -namespace XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -public enum ESocketState +namespace XeroxDev.YTMDesktop.Companion.Enums { - /// - /// If the socket is connecting - /// - Connecting, + public enum ESocketState + { + /// + /// If the socket is connecting + /// + Connecting, - /// - /// If the socket is connected - /// - Connected, + /// + /// If the socket is connected + /// + Connected, - /// - /// If the socket is disconnected - /// - Disconnected, + /// + /// If the socket is disconnected + /// + Disconnected, - /// - /// The socket seems to be disconnected due to an error - /// - Error + /// + /// The socket seems to be disconnected due to an error + /// + Error + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Enums/ETrackState.cs b/YTMDesktopCompanion/Enums/ETrackState.cs index a3645bc..e5d6e9f 100644 --- a/YTMDesktopCompanion/Enums/ETrackState.cs +++ b/YTMDesktopCompanion/Enums/ETrackState.cs @@ -1,24 +1,50 @@ -namespace XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -/// -/// The track state -/// -public enum ETrackState +namespace XeroxDev.YTMDesktop.Companion.Enums { /// - /// The track state is unknown + /// The track state /// - Unknown = -1, - /// - /// The track is paused - /// - Paused = 0, - /// - /// The track is playing - /// - Playing = 1, - /// - /// The track is buffering - /// - Buffering = 2 + public enum ETrackState + { + /// + /// The track state is unknown + /// + Unknown = -1, + + /// + /// The track is paused + /// + Paused = 0, + + /// + /// The track is playing + /// + Playing = 1, + + /// + /// The track is buffering + /// + Buffering = 2 + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Exceptions/ApiException.cs b/YTMDesktopCompanion/Exceptions/ApiException.cs index 63b4516..2b2fdc2 100644 --- a/YTMDesktopCompanion/Exceptions/ApiException.cs +++ b/YTMDesktopCompanion/Exceptions/ApiException.cs @@ -1,36 +1,58 @@ -using XeroxDev.YTMDesktop.Companion.Models.Output; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -namespace XeroxDev.YTMDesktop.Companion.Exceptions; +#region -/// -/// Represents an exception that is thrown when an API error occurs. -/// -[Serializable] -public class ApiException : Exception -{ - public ErrorOutput Error { get; } +using System; +using XeroxDev.YTMDesktop.Companion.Models.Output; - public ApiException(ErrorOutput error) : this(null, null, error) - { - } +#endregion - public ApiException(string? message, ErrorOutput error) : this(message, null, error) +namespace XeroxDev.YTMDesktop.Companion.Exceptions +{ + /// + /// Represents an exception that is thrown when an API error occurs. + /// + [Serializable] + public class ApiException : Exception { - } + public ApiException(ErrorOutput error) : this(null, null, error) + { + } - public ApiException(string? message, Exception? innerException, ErrorOutput error) : base(message, innerException) - { - Error = error; - } + public ApiException(string message, ErrorOutput error) : this(message, null, error) + { + } - public override string ToString() - { - return $""" - {base.ToString()} - ========= - API Error - ========= - {Error} - """; + public ApiException(string message, Exception innerException, ErrorOutput error) : base(message, innerException) + { + Error = error; + } + + public ErrorOutput Error { get; } + + public override string ToString() + { + return $"{base.ToString()}\n=========\nAPI Error\n=========\n{Error}"; + } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Interfaces/IGenericClient.cs b/YTMDesktopCompanion/Interfaces/IGenericClient.cs index 6558cbc..98874c7 100644 --- a/YTMDesktopCompanion/Interfaces/IGenericClient.cs +++ b/YTMDesktopCompanion/Interfaces/IGenericClient.cs @@ -1,16 +1,43 @@ -using XeroxDev.YTMDesktop.Companion.Settings; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -namespace XeroxDev.YTMDesktop.Companion.Interfaces; +#region -public interface IGenericClient +using XeroxDev.YTMDesktop.Companion.Settings; + +#endregion + +namespace XeroxDev.YTMDesktop.Companion.Interfaces { - public ConnectorSettings Settings { get; set; } + public interface IGenericClient + { + ConnectorSettings Settings { get; set; } - /// - /// Set the authentication token, so it can be used for further requests.
- /// We recommend to use the method in the - /// class instead of this method because it also reconnects the socket client if the token changed. - ///
- /// The token to set - public void SetAuthToken(string token); + /// + /// Set the authentication token, so it can be used for further requests.
+ /// We recommend to use the method in the + /// class instead of this method because it also reconnects the socket client if the token changed. + ///
+ /// The token to set + void SetAuthToken(string token); + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Input/Auth/RequestCodeInput.cs b/YTMDesktopCompanion/Models/Input/Auth/RequestCodeInput.cs index b171768..705ca72 100644 --- a/YTMDesktopCompanion/Models/Input/Auth/RequestCodeInput.cs +++ b/YTMDesktopCompanion/Models/Input/Auth/RequestCodeInput.cs @@ -1,80 +1,108 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using NuGet.Versioning; using XeroxDev.YTMDesktop.Companion.Converter; -namespace XeroxDev.YTMDesktop.Companion.Models.Input.Auth; +#endregion -/// -/// The input for the request code endpoint. -/// -[JsonSerializable(typeof(RequestCodeInput))] -public partial class RequestCodeInput +namespace XeroxDev.YTMDesktop.Companion.Models.Input.Auth { - private string _appId = null!; - private string _appName = null!; - - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ + /// The input for the request code endpoint. ///
- [JsonPropertyName("appId"), JsonRequired] - public string AppId + [JsonSerializable(typeof(RequestCodeInput))] + public class RequestCodeInput { - get => _appId; - set + private string _appId; + private string _appName; + + /// + /// The Request Code Input. + /// + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + /// + /// The name of your app. Must be between 2 and 48 characters. + /// The version of your app. Must be semantic versioning compatible. + /// Thrown when the app id or app name is null or empty. + /// Thrown when the app id is not valid or the app name is too short or too long. + public RequestCodeInput(string appId, string appName, SemanticVersion appVersion) { - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); - if (!AppIdRegex().IsMatch(value)) - throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); - _appId = value; + AppId = appId; + AppName = appName; + AppVersion = appVersion; } - } - /// - /// The name of your app. Must be between 2 and 48 characters. - /// - [JsonPropertyName("appName"), JsonRequired] - public string AppName - { - get => _appName; - set + + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + ///
+ [JsonPropertyName("appId")] + [JsonRequired] + public string AppId { - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app name can't be null or empty"); - _appName = value.Length switch + get => _appId; + set { - < 2 => throw new ArgumentException("The app name must be at least 2 characters long", nameof(value)), - > 48 => throw new ArgumentException("The app name can't be longer than 48 characters", nameof(value)), - _ => value - }; + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); + if (!Regex.IsMatch(value, "^[a-z0-9_\\-]{2,32}$")) + throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); + _appId = value; + } } - } - /// - /// The version of your app. Must be semantic versioning compatible. - /// - [JsonPropertyName("appVersion"), JsonRequired, JsonConverter(typeof(SemanticVersionJsonConverter))] - public SemanticVersion AppVersion { get; set; } - - [GeneratedRegex("^[a-z0-9_\\-]{2,32}$")] - private static partial Regex AppIdRegex(); + /// + /// The name of your app. Must be between 2 and 48 characters. + /// + [JsonPropertyName("appName")] + [JsonRequired] + public string AppName + { + get => _appName; + set + { + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app name can't be null or empty"); + if (value.Length < 2) + throw new ArgumentException("The app name must be at least 2 characters long", nameof(value)); + if (value.Length > 48) + throw new ArgumentException("The app name can't be longer than 48 characters", nameof(value)); + _appName = value; + } + } - /// - /// The Request Code Input. - /// - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ - /// - /// The name of your app. Must be between 2 and 48 characters. - /// The version of your app. Must be semantic versioning compatible. - /// Thrown when the app id or app name is null or empty. - /// Thrown when the app id is not valid or the app name is too short or too long. - public RequestCodeInput(string appId, string appName, SemanticVersion appVersion) - { - AppId = appId; - AppName = appName; - AppVersion = appVersion; + /// + /// The version of your app. Must be semantic versioning compatible. + /// + [JsonPropertyName("appVersion")] + [JsonRequired] + [JsonConverter(typeof(SemanticVersionJsonConverter))] + public SemanticVersion AppVersion { get; set; } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Input/Auth/RequestInput.cs b/YTMDesktopCompanion/Models/Input/Auth/RequestInput.cs index a014be8..5c93b89 100644 --- a/YTMDesktopCompanion/Models/Input/Auth/RequestInput.cs +++ b/YTMDesktopCompanion/Models/Input/Auth/RequestInput.cs @@ -1,56 +1,83 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using XeroxDev.YTMDesktop.Companion.Models.Output.Auth; -namespace XeroxDev.YTMDesktop.Companion.Models.Input.Auth; +#endregion -/// -/// The input for the request code endpoint. -/// -[JsonSerializable(typeof(RequestInput))] -public partial class RequestInput +namespace XeroxDev.YTMDesktop.Companion.Models.Input.Auth { - private string _appId = null!; - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ + /// The input for the request code endpoint. ///
- [JsonPropertyName("appId"), JsonRequired] - public string AppId + [JsonSerializable(typeof(RequestInput))] + public class RequestInput { - get => _appId; - set + private string _appId; + + /// + /// The Request Input. + /// + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + /// + /// The you've received from the server via + /// Thrown when the app id or app name is null or empty. + /// Thrown when the app id is not valid. + public RequestInput(string appId, string code) { - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); - if (!AppIdRegex().IsMatch(value)) - throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); - _appId = value; + AppId = appId; + Code = code; } - } - - [GeneratedRegex("^[a-z0-9_\\-]{2,32}$")] - private static partial Regex AppIdRegex(); - /// - /// The you've received from the server via - /// - [JsonPropertyName("code"), JsonRequired] - public string Code { get; set; } + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + ///
+ [JsonPropertyName("appId")] + [JsonRequired] + public string AppId + { + get => _appId; + set + { + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); + if (!Regex.IsMatch(value, "^[a-z0-9_\\-]{2,32}$")) + throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); + _appId = value; + } + } - /// - /// The Request Input. - /// - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ - /// - /// The you've received from the server via - /// Thrown when the app id or app name is null or empty. - /// Thrown when the app id is not valid. - public RequestInput(string appId, string code) - { - AppId = appId; - Code = code; + /// + /// The you've received from the server via + /// + [JsonPropertyName("code")] + [JsonRequired] + public string Code { get; set; } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Input/CommandInput.cs b/YTMDesktopCompanion/Models/Input/CommandInput.cs index 2003060..9ddc5f7 100644 --- a/YTMDesktopCompanion/Models/Input/CommandInput.cs +++ b/YTMDesktopCompanion/Models/Input/CommandInput.cs @@ -1,37 +1,66 @@ -using System.Text.Json.Serialization; -using XeroxDev.YTMDesktop.Companion.Enums; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -namespace XeroxDev.YTMDesktop.Companion.Models.Input; +#region -/// -/// The input for the command endpoint. -/// -[JsonSerializable(typeof(CommandInput))] -public class CommandInput -{ - [JsonPropertyName("command"), JsonRequired] - public string Command { get; set; } +using System.Text.Json.Serialization; +using XeroxDev.YTMDesktop.Companion.Enums; - [JsonPropertyName("data"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public object? Data { get; set; } +#endregion +namespace XeroxDev.YTMDesktop.Companion.Models.Input +{ /// - /// The input for the command endpoint. + /// The input for the command endpoint. /// - /// The command to execute - /// The data to send with - public CommandInput(string command, object? data = null) + [JsonSerializable(typeof(CommandInput))] + public class CommandInput { - Command = command; - Data = data; - } + /// + /// The input for the command endpoint. + /// + /// The command to execute + /// The data to send with + public CommandInput(string command, object data = null) + { + Command = command; + Data = data; + } - /// - /// The input for the command endpoint. - /// - /// The command to execute - /// The data to send with - public CommandInput(ECommand command, object? data = null) : this(command.ToCommandString(), data) - { + /// + /// The input for the command endpoint. + /// + /// The command to execute + /// The data to send with + public CommandInput(ECommand command, object data = null) : this(command.ToCommandString(), data) + { + } + + [JsonPropertyName("command")] + [JsonRequired] + public string Command { get; set; } + + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object Data { get; set; } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/Auth/RequestCodeOutput.cs b/YTMDesktopCompanion/Models/Output/Auth/RequestCodeOutput.cs index c663c9f..47bfd59 100644 --- a/YTMDesktopCompanion/Models/Output/Auth/RequestCodeOutput.cs +++ b/YTMDesktopCompanion/Models/Output/Auth/RequestCodeOutput.cs @@ -1,17 +1,45 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Text.Json.Serialization; using XeroxDev.YTMDesktop.Companion.Constants; -namespace XeroxDev.YTMDesktop.Companion.Models.Output.Auth; +#endregion -/// -/// This class is the output from the endpoint. -/// -[JsonSerializable(typeof(RequestCodeOutput))] -public class RequestCodeOutput +namespace XeroxDev.YTMDesktop.Companion.Models.Output.Auth { /// - /// The code to use to authenticate the app. + /// This class is the output from the endpoint. /// - [JsonPropertyName("code"), JsonRequired] - public string Code { get; set; } = null!; + [JsonSerializable(typeof(RequestCodeOutput))] + public class RequestCodeOutput + { + /// + /// The code to use to authenticate the app. + /// + [JsonPropertyName("code")] + [JsonRequired] + public string Code { get; set; } = null; + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/Auth/RequestOutput.cs b/YTMDesktopCompanion/Models/Output/Auth/RequestOutput.cs index e01f8fe..5b78160 100644 --- a/YTMDesktopCompanion/Models/Output/Auth/RequestOutput.cs +++ b/YTMDesktopCompanion/Models/Output/Auth/RequestOutput.cs @@ -1,17 +1,45 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Text.Json.Serialization; using XeroxDev.YTMDesktop.Companion.Constants; -namespace XeroxDev.YTMDesktop.Companion.Models.Output.Auth; +#endregion -/// -/// This class is the output from the endpoint. -/// -[JsonSerializable(typeof(RequestOutput))] -public class RequestOutput +namespace XeroxDev.YTMDesktop.Companion.Models.Output.Auth { /// - /// The authorization token that has to be used for all the privileged endpoints. + /// This class is the output from the endpoint. /// - [JsonPropertyName("token"), JsonRequired] - public string Token { get; set; } = null!; + [JsonSerializable(typeof(RequestOutput))] + public class RequestOutput + { + /// + /// The authorization token that has to be used for all the privileged endpoints. + /// + [JsonPropertyName("token")] + [JsonRequired] + public string Token { get; set; } = null; + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/ErrorOutput.cs b/YTMDesktopCompanion/Models/Output/ErrorOutput.cs index c929f30..1481cc9 100644 --- a/YTMDesktopCompanion/Models/Output/ErrorOutput.cs +++ b/YTMDesktopCompanion/Models/Output/ErrorOutput.cs @@ -1,40 +1,67 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -namespace XeroxDev.YTMDesktop.Companion.Models.Output; +#region -/// -/// This class is used to represent the error output of the API. -/// -[JsonSerializable(typeof(ErrorOutput))] -public class ErrorOutput +using System.Text.Json.Serialization; + +#endregion + +namespace XeroxDev.YTMDesktop.Companion.Models.Output { /// - /// The status code of the error. (e.g. 403) + /// This class is used to represent the error output of the API. /// - [JsonPropertyName("statusCode")] - public int? StatusCode { get; set; } + [JsonSerializable(typeof(ErrorOutput))] + public class ErrorOutput + { + /// + /// The status code of the error. (e.g. 403) + /// + [JsonPropertyName("statusCode")] + public int? StatusCode { get; set; } - /// - /// An error code with specific information about the error (e.g. AUTHORIZATION_DISABLED)
- /// It is not always available. - ///
- [JsonPropertyName("code")] - public string? Code { get; set; } + /// + /// An error code with specific information about the error (e.g. AUTHORIZATION_DISABLED)
+ /// It is not always available. + ///
+ [JsonPropertyName("code")] + public string Code { get; set; } - /// - /// The error message title. (e.g. Forbidden) - /// - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + /// The error message title. (e.g. Forbidden) + /// + [JsonPropertyName("error")] + public string Error { get; set; } - /// - /// The error message. (e.g. Authorization requests are disabled) - /// - [JsonPropertyName("message")] - public string? Message { get; set; } + /// + /// The error message. (e.g. Authorization requests are disabled) + /// + [JsonPropertyName("message")] + public string Message { get; set; } - public override string ToString() - { - return $"Status Code: {StatusCode}\nCode: {Code}\nError: {Error}\nMessage: {Message}"; + public override string ToString() + { + return $"Status Code: {StatusCode}\nCode: {Code}\nError: {Error}\nMessage: {Message}"; + } } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/MetadataOutput.cs b/YTMDesktopCompanion/Models/Output/MetadataOutput.cs index f972c38..5549588 100644 --- a/YTMDesktopCompanion/Models/Output/MetadataOutput.cs +++ b/YTMDesktopCompanion/Models/Output/MetadataOutput.cs @@ -1,16 +1,45 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Collections.Generic; +using System.Text.Json.Serialization; using XeroxDev.YTMDesktop.Companion.Constants; -namespace XeroxDev.YTMDesktop.Companion.Models.Output; +#endregion -/// -/// This class is the output from the endpoint. -/// -public class MetadataOutput +namespace XeroxDev.YTMDesktop.Companion.Models.Output { /// - /// All available API version. + /// This class is the output from the endpoint. /// - [JsonPropertyName("apiVersions"), JsonRequired] - public List ApiVersions { get; set; } = null!; + public class MetadataOutput + { + /// + /// All available API version. + /// + [JsonPropertyName("apiVersions")] + [JsonRequired] + public List ApiVersions { get; set; } = null; + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/PlaylistOutput.cs b/YTMDesktopCompanion/Models/Output/PlaylistOutput.cs index 2d65d1a..1ecba3d 100644 --- a/YTMDesktopCompanion/Models/Output/PlaylistOutput.cs +++ b/YTMDesktopCompanion/Models/Output/PlaylistOutput.cs @@ -1,23 +1,52 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Text.Json.Serialization; using XeroxDev.YTMDesktop.Companion.Constants; -namespace XeroxDev.YTMDesktop.Companion.Models.Output; +#endregion -/// -/// This class is the output from the endpoint. (as a single item, the endpoint will return an array of this) -/// -[JsonSerializable(typeof(PlaylistOutput))] -public class PlaylistOutput +namespace XeroxDev.YTMDesktop.Companion.Models.Output { /// - /// The playlist id + /// This class is the output from the endpoint. (as a single item, the endpoint will return an array of this) /// - [JsonPropertyName("id"), JsonRequired] - public string Id { get; set; } = null!; + [JsonSerializable(typeof(PlaylistOutput))] + public class PlaylistOutput + { + /// + /// The playlist id + /// + [JsonPropertyName("id")] + [JsonRequired] + public string Id { get; set; } = null; - /// - /// The playlist title - /// - [JsonPropertyName("title"), JsonRequired] - public string Title { get; set; } = null!; + /// + /// The playlist title + /// + [JsonPropertyName("title")] + [JsonRequired] + public string Title { get; set; } = null; + } } \ No newline at end of file diff --git a/YTMDesktopCompanion/Models/Output/StateOutput.cs b/YTMDesktopCompanion/Models/Output/StateOutput.cs index 91ba675..4f411c4 100644 --- a/YTMDesktopCompanion/Models/Output/StateOutput.cs +++ b/YTMDesktopCompanion/Models/Output/StateOutput.cs @@ -1,263 +1,307 @@ -using System.Text.Json.Serialization; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Text.Json.Serialization; using XeroxDev.YTMDesktop.Companion.Constants; using XeroxDev.YTMDesktop.Companion.Enums; -namespace XeroxDev.YTMDesktop.Companion.Models.Output; - -/// -/// This class is the output from the endpoint. (as a single item, the endpoint will return an array of this) -/// -[JsonSerializable(typeof(StateOutput))] -public class StateOutput -{ - /// - /// The player state - /// - [JsonPropertyName("player"), JsonRequired] - public Player Player { get; set; } = null!; - - /// - /// The video state - /// - [JsonPropertyName("video")] - public Video? Video { get; set; } - - /// - /// The playlist id - /// - [JsonPropertyName("playlistId"), JsonRequired] - public string PlaylistId { get; set; } = null!; -} - -#region Shared - -/// -/// The thumbnail -/// -[JsonSerializable(typeof(Thumbnail))] -public class Thumbnail -{ - /// - /// The url - /// - [JsonPropertyName("url"), JsonRequired] - public string Url { get; set; } = null!; - - /// - /// The width - /// - [JsonPropertyName("width"), JsonRequired] - public int Width { get; set; } - - /// - /// The height - /// - [JsonPropertyName("height"), JsonRequired] - public int Height { get; set; } -} - -#endregion - -#region Player classes - -/// -/// The player state -/// -[JsonSerializable(typeof(Player))] -public class Player -{ - /// - /// The track state - /// - [JsonPropertyName("trackState")] - public ETrackState TrackState { get; set; } = ETrackState.Unknown; - - /// - /// The video progress - /// - [JsonPropertyName("videoProgress")] - public double VideoProgress { get; set; } - - /// - /// The volume - /// - [JsonPropertyName("volume")] - public double Volume { get; set; } - - /// - /// If an ad is playing - /// - [JsonPropertyName("adPlaying")] - public bool AdPlaying { get; set; } - - /// - /// The queue - /// - [JsonPropertyName("queue")] - public Queue? Queue { get; set; } -} - -/// -/// The queue -/// -[JsonSerializable(typeof(Queue))] -public class Queue -{ - /// - /// If autoplay is enabled - /// - [JsonPropertyName("autoplay")] - public bool Autoplay { get; set; } - - /// - /// The queue items - /// - [JsonPropertyName("items"), JsonRequired] - public QueueItem[] Items { get; set; } = null!; - - /// - /// The automix items - /// - [JsonPropertyName("automixItems")] - public QueueItem[]? AutomixItems { get; set; } - - /// - /// If the queue is generating - /// - [JsonPropertyName("isGenerating")] - public bool IsGenerating { get; set; } - - /// - /// If the queue is infinite - /// - [JsonPropertyName("isInfinite")] - public bool IsInfinite { get; set; } - - /// - /// The repeat mode - /// - [JsonPropertyName("repeatMode")] - public ERepeatMode RepeatMode { get; set; } - - /// - /// The selected item index - /// - [JsonPropertyName("selectedItemIndex")] - public int SelectedItemIndex { get; set; } -} - -/// -/// The queue item -/// -[JsonSerializable(typeof(QueueItem))] -public class QueueItem -{ - /// - /// The thumbnails - /// - [JsonPropertyName("thumbnails"), JsonRequired] - public Thumbnail[] Thumbnails { get; set; } = null!; - - /// - /// The title - /// - [JsonPropertyName("title"), JsonRequired] - public string Title { get; set; } = null!; - - /// - /// The author - /// - [JsonPropertyName("author"), JsonRequired] - public string Author { get; set; } = null!; - - /// - /// The duration - /// - [JsonPropertyName("duration"), JsonRequired] - public string Duration { get; set; } = null!; - - /// - /// If the item is selected - /// - [JsonPropertyName("selected")] - public bool Selected { get; set; } - - /// - /// The video id - /// - [JsonPropertyName("videoId"), JsonRequired] - public string VideoId { get; set; } = null!; - - /// - /// The counterparts - /// - [JsonPropertyName("counterparts")] - public QueueItem[]? Counterparts { get; set; } -} - #endregion -#region Video classes - -/// -/// The video state -/// -[JsonSerializable(typeof(Video))] -public class Video +namespace XeroxDev.YTMDesktop.Companion.Models.Output { /// - /// The author - /// - [JsonPropertyName("author"), JsonRequired] - public string Author { get; set; } = null!; - - /// - /// The channel id - /// - [JsonPropertyName("channelId"), JsonRequired] - public string ChannelId { get; set; } = null!; - - /// - /// The title - /// - [JsonPropertyName("title"), JsonRequired] - public string Title { get; set; } = null!; - - /// - /// The album - /// - [JsonPropertyName("album")] - public string? Album { get; set; } - - /// - /// The album id - /// - [JsonPropertyName("albumId")] - public string? AlbumId { get; set; } - - /// - /// The like status - /// - [JsonPropertyName("likeStatus")] - public ELikeStatus? LikeStatus { get; set; } - - /// - /// The thumbnails - /// - [JsonPropertyName("thumbnails"), JsonRequired] - public Thumbnail[] Thumbnails { get; set; } = null!; - - /// - /// The duration in seconds - /// - [JsonPropertyName("durationSeconds"), JsonRequired] - public int DurationSeconds { get; set; } - - /// - /// The id - /// - [JsonPropertyName("id"), JsonRequired] - public string Id { get; set; } = null!; -} - -#endregion \ No newline at end of file + /// This class is the output from the endpoint. (as a single item, the endpoint will return an array of this) + /// + [JsonSerializable(typeof(StateOutput))] + public class StateOutput + { + /// + /// The player state + /// + [JsonPropertyName("player")] + [JsonRequired] + public Player Player { get; set; } = null; + + /// + /// The video state + /// + [JsonPropertyName("video")] + public Video Video { get; set; } + + /// + /// The playlist id + /// + [JsonPropertyName("playlistId")] + [JsonRequired] + public string PlaylistId { get; set; } = null; + } + + #region Shared + + /// + /// The thumbnail + /// + [JsonSerializable(typeof(Thumbnail))] + public class Thumbnail + { + /// + /// The url + /// + [JsonPropertyName("url")] + [JsonRequired] + public string Url { get; set; } = null; + + /// + /// The width + /// + [JsonPropertyName("width")] + [JsonRequired] + public int Width { get; set; } + + /// + /// The height + /// + [JsonPropertyName("height")] + [JsonRequired] + public int Height { get; set; } + } + + #endregion + + #region Player classes + + /// + /// The player state + /// + [JsonSerializable(typeof(Player))] + public class Player + { + /// + /// The track state + /// + [JsonPropertyName("trackState")] + public ETrackState TrackState { get; set; } = ETrackState.Unknown; + + /// + /// The video progress + /// + [JsonPropertyName("videoProgress")] + public double VideoProgress { get; set; } + + /// + /// The volume + /// + [JsonPropertyName("volume")] + public double Volume { get; set; } + + /// + /// If an ad is playing + /// + [JsonPropertyName("adPlaying")] + public bool AdPlaying { get; set; } + + /// + /// The queue + /// + [JsonPropertyName("queue")] + public Queue Queue { get; set; } + } + + /// + /// The queue + /// + [JsonSerializable(typeof(Queue))] + public class Queue + { + /// + /// If autoplay is enabled + /// + [JsonPropertyName("autoplay")] + public bool Autoplay { get; set; } + + /// + /// The queue items + /// + [JsonPropertyName("items")] + [JsonRequired] + public QueueItem[] Items { get; set; } = null; + + /// + /// The automix items + /// + [JsonPropertyName("automixItems")] + public QueueItem[] AutomixItems { get; set; } + + /// + /// If the queue is generating + /// + [JsonPropertyName("isGenerating")] + public bool IsGenerating { get; set; } + + /// + /// If the queue is infinite + /// + [JsonPropertyName("isInfinite")] + public bool IsInfinite { get; set; } + + /// + /// The repeat mode + /// + [JsonPropertyName("repeatMode")] + public ERepeatMode RepeatMode { get; set; } + + /// + /// The selected item index + /// + [JsonPropertyName("selectedItemIndex")] + public int SelectedItemIndex { get; set; } + } + + /// + /// The queue item + /// + [JsonSerializable(typeof(QueueItem))] + public class QueueItem + { + /// + /// The thumbnails + /// + [JsonPropertyName("thumbnails")] + [JsonRequired] + public Thumbnail[] Thumbnails { get; set; } = null; + + /// + /// The title + /// + [JsonPropertyName("title")] + [JsonRequired] + public string Title { get; set; } = null; + + /// + /// The author + /// + [JsonPropertyName("author")] + [JsonRequired] + public string Author { get; set; } = null; + + /// + /// The duration + /// + [JsonPropertyName("duration")] + [JsonRequired] + public string Duration { get; set; } = null; + + /// + /// If the item is selected + /// + [JsonPropertyName("selected")] + public bool Selected { get; set; } + + /// + /// The video id + /// + [JsonPropertyName("videoId")] + [JsonRequired] + public string VideoId { get; set; } = null; + + /// + /// The counterparts + /// + [JsonPropertyName("counterparts")] + public QueueItem[] Counterparts { get; set; } + } + + #endregion + + #region Video classes + + /// + /// The video state + /// + [JsonSerializable(typeof(Video))] + public class Video + { + /// + /// The author + /// + [JsonPropertyName("author")] + [JsonRequired] + public string Author { get; set; } = null; + + /// + /// The channel id + /// + [JsonPropertyName("channelId")] + [JsonRequired] + public string ChannelId { get; set; } = null; + + /// + /// The title + /// + [JsonPropertyName("title")] + [JsonRequired] + public string Title { get; set; } = null; + + /// + /// The album + /// + [JsonPropertyName("album")] + public string Album { get; set; } + + /// + /// The album id + /// + [JsonPropertyName("albumId")] + public string AlbumId { get; set; } + + /// + /// The like status + /// + [JsonPropertyName("likeStatus")] + public ELikeStatus? LikeStatus { get; set; } + + /// + /// The thumbnails + /// + [JsonPropertyName("thumbnails")] + [JsonRequired] + public Thumbnail[] Thumbnails { get; set; } = null; + + /// + /// The duration in seconds + /// + [JsonPropertyName("durationSeconds")] + [JsonRequired] + public int DurationSeconds { get; set; } + + /// + /// The id + /// + [JsonPropertyName("id")] + [JsonRequired] + public string Id { get; set; } = null; + } + + #endregion +} \ No newline at end of file diff --git a/YTMDesktopCompanion/Properties/AssemblyInfo.cs b/YTMDesktopCompanion/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2734b8a --- /dev/null +++ b/YTMDesktopCompanion/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System.Reflection; +using System.Runtime.InteropServices; + +#endregion + +[assembly: AssemblyTitle("XeroxDev.YTMDesktop.Companion")] +[assembly: AssemblyDescription("A library to control the YTMDesktop App")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("XeroxDev")] +[assembly: AssemblyProduct("XeroxDev.YTMDesktop.Companion")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("en")] +[assembly: ComVisible(false)] +[assembly: Guid("749F5EBA-0CFB-4F3A-84A7-9D0E288620D2")] +[assembly: AssemblyVersion("1.0.0")] // x-release-please-version \ No newline at end of file diff --git a/YTMDesktopCompanion/Settings/ConnectorSettings.cs b/YTMDesktopCompanion/Settings/ConnectorSettings.cs index 4663a52..92964f0 100644 --- a/YTMDesktopCompanion/Settings/ConnectorSettings.cs +++ b/YTMDesktopCompanion/Settings/ConnectorSettings.cs @@ -1,107 +1,131 @@ -using System.Text.RegularExpressions; +// This file is part of the YTMDesktopCompanion project. +// +// Copyright (c) 2024 Dominic Ris +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#region + +using System; +using System.Text.RegularExpressions; using NuGet.Versioning; -namespace XeroxDev.YTMDesktop.Companion.Settings; +#endregion -public partial class ConnectorSettings +namespace XeroxDev.YTMDesktop.Companion.Settings { - private string _host = null!; - private string _appId = null!; - private string _appName = null!; - - /// - /// The host name of the server (has to be without a protocol like http:// or https:// and can't have a trailing slash nor a port)
- /// Hint: Some operating systems, such as Windows, may use an IPv6 address for localhost. This would result in a connection failure as the server is not listening on the IPv6 address. - ///
- public string Host + public class ConnectorSettings { - get => _host; - set + private string _appId; + private string _appName; + private string _host; + + /// + /// The settings for the connector. + /// + /// + /// The host name of the server (has to be without a protocol like http:// or https:// and can't have a trailing slash nor a port)
+ /// Hint: Some operating systems, such as Windows, may use an IPv6 address for localhost. This would result in a connection failure as the server is not listening on the IPv6 address. + /// + /// The port of the server. + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + /// + /// The name of your app. Must be between 2 and 48 characters. + /// The version of your app. Must be semantic versioning compatible. + /// The token to connect to the server (if available). + /// Thrown when the host, app id or app name is null or empty. + /// Thrown when the host contains a protocol, a port, the app id is not valid or the app name is too short or too long. + public ConnectorSettings(string host, int port, string appId, string appName, SemanticVersion appVersion, string token = null) { - // check if the value is null or empty - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The host can't be null or empty"); - if (value.Contains("://")) throw new ArgumentException("The host can't contain a protocol like http:// or https://", nameof(value)); - if (value.Contains(':')) throw new ArgumentException("The host can't contain a port", nameof(value)); - _host = value.EndsWith('/') ? value[..^1] : value; + Host = host; + AppId = appId; + AppName = appName; + Port = port; + AppVersion = appVersion; + Token = token; } - } - /// - /// The port of the server. - /// - public int Port { get; set; } + /// + /// The host name of the server (has to be without a protocol like http:// or https:// and can't have a trailing slash nor a port)
+ /// Hint: Some operating systems, such as Windows, may use an IPv6 address for localhost. This would result in a connection failure as the server is not listening on the IPv6 address. + ///
+ public string Host + { + get => _host; + set + { + // check if the value is null or empty + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The host can't be null or empty"); + if (value.Contains("://")) throw new ArgumentException("The host can't contain a protocol like http:// or https://", nameof(value)); + if (value.Contains(":")) throw new ArgumentException("The host can't contain a port", nameof(value)); + _host = value.EndsWith("/") ? value.Substring(0, value.Length - 1) : value; + } + } - /// - /// The token to connect to the server (if available). - /// - public string? Token { get; set; } + /// + /// The port of the server. + /// + public int Port { get; set; } - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ - ///
- public string AppId - { - get => _appId; - set + /// + /// The token to connect to the server (if available). + /// + public string Token { get; set; } + + /// + /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
+ /// Regex: ^[a-z0-9_\\-]{2,32}$ + ///
+ public string AppId { - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); - if (!AppIdRegex().IsMatch(value)) - throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); - _appId = value; + get => _appId; + set + { + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app id can't be null or empty"); + if (!Regex.IsMatch(value, "^[a-z0-9_\\-]{2,32}$")) + throw new ArgumentException("The app id must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters", nameof(value)); + _appId = value; + } } - } - /// - /// The name of your app. Must be between 2 and 48 characters. - /// - public string AppName - { - get => _appName; - set + /// + /// The name of your app. Must be between 2 and 48 characters. + /// + public string AppName { - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app name can't be null or empty"); - _appName = value.Length switch + get => _appName; + set { - < 2 => throw new ArgumentException("The app name must be at least 2 characters long", nameof(value)), - > 48 => throw new ArgumentException("The app name can't be longer than 48 characters", nameof(value)), - _ => value - }; + if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value), "The app name can't be null or empty"); + if (value.Length < 2) + throw new ArgumentException("The app name must be at least 2 characters long", nameof(value)); + if (value.Length > 48) + throw new ArgumentException("The app name can't be longer than 48 characters", nameof(value)); + _appName = value; + } } - } - - /// - /// The version of your app. Must be semantic versioning compatible. - /// - public SemanticVersion AppVersion { get; set; } - /// - /// The settings for the connector. - /// - /// - /// The host name of the server (has to be without a protocol like http:// or https:// and can't have a trailing slash nor a port)
- /// Hint: Some operating systems, such as Windows, may use an IPv6 address for localhost. This would result in a connection failure as the server is not listening on the IPv6 address. - /// - /// The port of the server. - /// - /// The id of your app. Must be all lowercase with only alphanumeric characters, no spaces and between 2 and 32 characters.
- /// Regex: ^[a-z0-9_\\-]{2,32}$ - /// - /// The name of your app. Must be between 2 and 48 characters. - /// The version of your app. Must be semantic versioning compatible. - /// The token to connect to the server (if available). - /// Thrown when the host, app id or app name is null or empty. - /// Thrown when the host contains a protocol, a port, the app id is not valid or the app name is too short or too long. - public ConnectorSettings(string host, int port, string appId, string appName, SemanticVersion appVersion, string? token = null) - { - Host = host; - AppId = appId; - AppName = appName; - Port = port; - AppVersion = appVersion; - Token = token; + /// + /// The version of your app. Must be semantic versioning compatible. + /// + public SemanticVersion AppVersion { get; set; } } - - [GeneratedRegex("^[a-z0-9_\\-]{2,32}$")] - private static partial Regex AppIdRegex(); } \ No newline at end of file diff --git a/YTMDesktopCompanion/YTMDesktopCompanion.csproj b/YTMDesktopCompanion/YTMDesktopCompanion.csproj index 330c8c0..520c453 100644 --- a/YTMDesktopCompanion/YTMDesktopCompanion.csproj +++ b/YTMDesktopCompanion/YTMDesktopCompanion.csproj @@ -1,8 +1,7 @@  - enable - enable + disable XeroxDev.YTMDesktop.Companion XeroxDev.YTMDesktop.Companion XeroxDev.YTMDesktop.Companion @@ -21,10 +20,7 @@ https://github.com/XeroxDev/ytmdesktop-cs-companion git library dotnet csharp ytmdesktop companion-server - - Please see the CHANGELOG.md file for release notes. You can find the CHANGELOG.md file at https://github.com/XeroxDev/ytmdesktop-cs-companion/blob/main/CHANGELOG.md - For more information and documentation, please visit the project page at https://github.com/XeroxDev/ytmdesktop-cs-companion - + https://github.com/XeroxDev/ytmdesktop-cs-companion/blob/main/CHANGELOG.md true snupkg true @@ -33,15 +29,21 @@ true en XeroxDev.YTMDesktop.Companion.snk - net7.0;net7.0-windows;net8.0;net8.0-windows + net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows;netstandard2.0;netstandard2.1;net472;net48;net481 + 7.3 + false + false + 749F5EBA-0CFB-4F3A-84A7-9D0E288620D2 + + - + true diff --git a/release-please-config.json b/release-please-config.json index 12c43b4..f8a1c56 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -9,7 +9,8 @@ "prerelease": false, "include-component-in-tag": false, "extra-files": [ - "YTMDesktopCompanion/YTMDesktopCompanion.csproj" + "YTMDesktopCompanion/YTMDesktopCompanion.csproj", + "YTMDesktopCompanion/Properties/AssemblyInfo.cs" ] } },