Files
ytLlive/Services/SocialValidator.cs
T

83 lines
2.9 KiB
C#

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ytLive.Models;
namespace ytLive.Services;
public sealed class SocialLookupResult
{
public bool Success { get; init; }
public string ProfileUrl { get; init; } = string.Empty;
public string Handle { get; init; } = string.Empty;
public string Error { get; init; } = string.Empty;
}
public interface ISocialValidator
{
Task<SocialLookupResult> LookupAsync(SocialService service, string handleOrUrl);
}
/// <summary>
/// Validates a social handle/URL by constructing the canonical profile URL and
/// issuing an HTTP GET — the "act of validation" the creator trusts before the
/// icon lands on their bar. Best-effort: some platforms return challenges/blocks
/// to HEAD requests, so a 200 OR a 301/302 redirect counts as "exists"; 404 or
/// connection failure = rejected. Never blind trust.
/// </summary>
public sealed class HttpSocialValidator : ISocialValidator
{
private readonly HttpClient _client;
public HttpSocialValidator(HttpClient? client = null)
{
_client = client ?? new HttpClient();
_client.DefaultRequestHeaders.UserAgent.ParseAdd(
"Mozilla/5.0 (compatible; ytLlive social validator)");
}
public async Task<SocialLookupResult> LookupAsync(SocialService service, string handleOrUrl)
{
var input = handleOrUrl.Trim();
if (string.IsNullOrWhiteSpace(input))
return new SocialLookupResult { Error = "Enter a handle or URL." };
var handle = input;
if (input.StartsWith("http://", System.StringComparison.OrdinalIgnoreCase) ||
input.StartsWith("https://", System.StringComparison.OrdinalIgnoreCase))
{
var uri = new System.Uri(input);
handle = uri.AbsolutePath.Trim('/');
}
var url = SocialServiceIcons.CanonicalUrlFor(service, handle);
try
{
using var resp = await _client.GetAsync(url, CancellationToken.None);
if (resp.IsSuccessStatusCode || (int)resp.StatusCode is 301 or 302 or 303 or 307 or 308)
return new SocialLookupResult
{
Success = true,
ProfileUrl = url,
Handle = handle.TrimStart('@'),
};
return new SocialLookupResult
{
Error = $"{service} returned {resp.StatusCode} for '{handle}'. The handle may be wrong or the page doesn't exist.",
};
}
catch (System.Net.Http.HttpRequestException)
{
return new SocialLookupResult
{
Error = $"Couldn't reach {service} to validate '{handle}'. Check your connection and try again.",
};
}
catch (System.Exception ex)
{
return new SocialLookupResult { Error = ex.Message };
}
}
}