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;