diff --git a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj index 1f34981..470002c 100644 --- a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj +++ b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj @@ -14,8 +14,11 @@ RageAgainstThePixel 2023 ElevenLabs, AI, ML, Voice, TTS - 1.3.0 - Version 1.3.0 + 1.3.2 + Version 1.3.2 +- Added voice equality operators +- Added better parameter validation checks in Endpoints +Version 1.3.0 - Added ModelsEndpoint - Updated TextToSpeech.TextToSpeechAsync with optional Model parameter. Defaults to eleven_monolingual_v1 Version 1.2.1 diff --git a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechEndpoint.cs b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechEndpoint.cs index ca6f1c5..d6013c5 100644 --- a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechEndpoint.cs +++ b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechEndpoint.cs @@ -37,6 +37,12 @@ public async Task TextToSpeechAsync(string text, Voice voice, VoiceSetti { throw new ArgumentOutOfRangeException(nameof(text), $"{nameof(text)} cannot exceed 5000 characters"); } + + if (voice == null) + { + throw new ArgumentNullException(nameof(voice)); + } + var rootDirectory = (saveDirectory ?? Directory.GetCurrentDirectory()).CreateNewDirectory(nameof(ElevenLabs)); var downloadDirectory = rootDirectory.CreateNewDirectory("TextToSpeech"); var fileName = $"{text.GenerateGuid()}.mp3"; diff --git a/ElevenLabs-DotNet/Voices/Voice.cs b/ElevenLabs-DotNet/Voices/Voice.cs index 2927628..3d9fe3c 100644 --- a/ElevenLabs-DotNet/Voices/Voice.cs +++ b/ElevenLabs-DotNet/Voices/Voice.cs @@ -1,5 +1,6 @@ // Licensed under the MIT License. See LICENSE in the project root for license information. +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -78,5 +79,55 @@ public Voice(string id) public static Voice Sam { get; } = new Voice("yoZ06aMxZJJ28mfd3POQ"); #endregion Premade Voices + + public bool Equals(Voice other) + { + if (ReferenceEquals(null, other)) + { + return string.IsNullOrWhiteSpace(Id); + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return Name == other.Name && + Id == other.Id && + Equals(Samples, other.Samples) && + Category == other.Category && + Equals(Labels, other.Labels) && + PreviewUrl == other.PreviewUrl && + Equals(AvailableForTiers, other.AvailableForTiers) && + Equals(Settings, other.Settings); + } + + public override bool Equals(object voice) + => ReferenceEquals(this, voice) || voice is Voice other && Equals(other); + + public override int GetHashCode() + => HashCode.Combine(Name, Id, Samples, Category, Labels, PreviewUrl, AvailableForTiers, Settings); + + public static bool operator !=(Voice left, Voice right) => !(left == right); + + public static bool operator ==(Voice left, Voice right) + { + if (left is null && right is null) + { + return true; + } + + if (left is null) + { + return string.IsNullOrWhiteSpace(right.Id); + } + + if (right is null) + { + return string.IsNullOrWhiteSpace(left.Id); + } + + return left.Equals(right); + } } } diff --git a/ElevenLabs-DotNet/Voices/VoicesEndpoint.cs b/ElevenLabs-DotNet/Voices/VoicesEndpoint.cs index 9ac0078..e88db8e 100644 --- a/ElevenLabs-DotNet/Voices/VoicesEndpoint.cs +++ b/ElevenLabs-DotNet/Voices/VoicesEndpoint.cs @@ -82,6 +82,11 @@ public async Task GetDefaultVoiceSettingsAsync(CancellationToken /// . public async Task GetVoiceSettingsAsync(string voiceId, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + var response = await Api.Client.GetAsync(GetUrl($"/{voiceId}/settings"), cancellationToken); var responseAsString = await response.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseAsString, Api.JsonSerializationOptions); @@ -96,6 +101,11 @@ public async Task GetVoiceSettingsAsync(string voiceId, Cancellat /// . public async Task GetVoiceAsync(string voiceId, bool withSettings = true, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + var response = await Api.Client.GetAsync(GetUrl($"/{voiceId}?with_settings={withSettings}"), cancellationToken); var responseAsString = await response.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseAsString, Api.JsonSerializationOptions); @@ -110,6 +120,11 @@ public async Task GetVoiceAsync(string voiceId, bool withSettings = true, /// True, if voice settings was successfully edited. public async Task EditVoiceSettingsAsync(string voiceId, VoiceSettings voiceSettings, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + var payload = JsonSerializer.Serialize(voiceSettings).ToJsonStringContent(); var response = await Api.Client.PostAsync(GetUrl($"/{voiceId}/settings/edit"), payload, cancellationToken); await response.ReadAsStringAsync(); @@ -229,6 +244,11 @@ public async Task EditVoiceAsync(Voice voice, IEnumerable samplePa /// True, if voice was successfully deleted. public async Task DeleteVoiceAsync(string voiceId, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + var response = await Api.Client.DeleteAsync(GetUrl($"/{voiceId}"), cancellationToken); await response.CheckResponseAsync(cancellationToken); return response.IsSuccessStatusCode; @@ -245,6 +265,16 @@ public async Task DeleteVoiceAsync(string voiceId, CancellationToken cance /// Optional, . public async Task GetVoiceSampleAsync(string voiceId, string sampleId, string saveDirectory = null, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + + if (string.IsNullOrWhiteSpace(sampleId)) + { + throw new ArgumentNullException(nameof(sampleId)); + } + var response = await Api.Client.GetAsync(GetUrl($"/{voiceId}/samples/{sampleId}/audio"), cancellationToken); await response.CheckResponseAsync(cancellationToken); @@ -291,6 +321,16 @@ public async Task GetVoiceSampleAsync(string voiceId, string sampleId, s /// True, if was successfully deleted. public async Task DeleteVoiceSampleAsync(string voiceId, string sampleId, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(voiceId)) + { + throw new ArgumentNullException(nameof(voiceId)); + } + + if (string.IsNullOrWhiteSpace(sampleId)) + { + throw new ArgumentNullException(nameof(sampleId)); + } + var response = await Api.Client.DeleteAsync(GetUrl($"/{voiceId}/samples/{sampleId}"), cancellationToken); await response.CheckResponseAsync(cancellationToken); return response.IsSuccessStatusCode;