mirror of
https://github.com/claunia/marechai.git
synced 2026-07-08 17:57:08 +00:00
404 lines
12 KiB
C#
404 lines
12 KiB
C#
/******************************************************************************
|
|
// MARECHAI: Master repository of computing history artifacts information
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// --[ License ] --------------------------------------------------------------
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright © 2003-2026 Natalia Portillo
|
|
*******************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Marechai.ApiClient.Models;
|
|
using Microsoft.Kiota.Abstractions;
|
|
|
|
namespace Marechai.Services;
|
|
|
|
public class SoundSynthsService(Marechai.ApiClient.Client client, IndexNowService indexNow)
|
|
{
|
|
static string ExtractErrorMessage(ApiException ex)
|
|
{
|
|
if(ex is ProblemDetails pd) return pd.Detail ?? pd.Title ?? ex.Message;
|
|
|
|
return ex.Message;
|
|
}
|
|
|
|
public async Task<List<SoundSynthDto>> GetAllAsync(int? skip = null, int? take = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
List<SoundSynthDto> synths = await client.SoundSynths.GetAsync(config =>
|
|
{
|
|
if(skip.HasValue) config.QueryParameters.Skip = skip.Value;
|
|
if(take.HasValue) config.QueryParameters.Take = take.Value;
|
|
}, cancellationToken);
|
|
|
|
return synths ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Server-side paged fetch used by the admin <c>MudDataGrid</c>. Pushes the
|
|
/// sort + filter spec all the way down to the SQL query so paging,
|
|
/// filtering and ordering happen in the database. Filters are
|
|
/// <c>"{Column}||{Operator}||{Value}"</c> triples mirroring MudBlazor's
|
|
/// <c>FilterDefinition</c> shape; <see cref="Marechai.Server.Controllers.SoundSynthsController.ApplyFilters"/>
|
|
/// translates them into LINQ predicates.
|
|
/// </summary>
|
|
public async Task<List<SoundSynthDto>> GetPagedAsync(int skip, int take, string sortBy, bool sortDescending,
|
|
IReadOnlyList<string> filters,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
List<SoundSynthDto> synths = await client.SoundSynths.GetAsync(config =>
|
|
{
|
|
config.QueryParameters.Skip = skip;
|
|
config.QueryParameters.Take = take;
|
|
if(!string.IsNullOrWhiteSpace(sortBy)) config.QueryParameters.SortBy = sortBy;
|
|
if(sortDescending) config.QueryParameters.SortDescending = true;
|
|
if(filters is { Count: > 0 }) config.QueryParameters.Filters = filters.ToArray();
|
|
}, cancellationToken);
|
|
|
|
return synths ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public async Task<int> GetCountAsync(IReadOnlyList<string> filters = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
int? count = await client.SoundSynths.Count.GetAsync(config =>
|
|
{
|
|
if(filters is { Count: > 0 }) config.QueryParameters.Filters = filters.ToArray();
|
|
}, cancellationToken);
|
|
|
|
return count ?? 0;
|
|
}
|
|
catch
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public async Task<SoundSynthDto> GetByIdAsync(int id)
|
|
{
|
|
try
|
|
{
|
|
return await client.SoundSynths[id].GetAsync();
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the consolidated /soundsynth/{Id} payload (head + company logo + description
|
|
/// + machines + photos + videos) in a single HTTP round-trip. Replaces the original
|
|
/// 5-call sequence (GetByIdAsync + GetMachinesBySoundSynthAsync + GetDescriptionTextAsync
|
|
/// + SoundSynthPhotosService.GetGuidsBySoundSynthAsync + GetVideosBySoundSynthAsync).
|
|
/// Returns <c>null</c> on any transport-level failure or 404; the caller should treat
|
|
/// null the same way it treated <c>GetByIdAsync</c> returning null.
|
|
/// </summary>
|
|
public async Task<SoundSynthFullDto> GetFullAsync(int id, string lang = "eng")
|
|
{
|
|
try
|
|
{
|
|
return await client.SoundSynths[id].Full.GetAsync(rc =>
|
|
{
|
|
if(!string.IsNullOrEmpty(lang)) rc.QueryParameters.Lang = lang;
|
|
});
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<(long? id, string error)> CreateAsync(SoundSynthDto dto)
|
|
{
|
|
try
|
|
{
|
|
long? id = await client.SoundSynths.PostAsync(dto);
|
|
|
|
if(id.HasValue) indexNow.EnqueueUrl($"/soundsynth/{id}");
|
|
|
|
return (id, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (null, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (null, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> UpdateAsync(int id, SoundSynthDto dto)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths[id].PutAsync(dto);
|
|
|
|
indexNow.EnqueueUrl($"/soundsynth/{id}");
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> DeleteAsync(int id)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths[id].DeleteAsync();
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<List<CompanyDto>> GetCompaniesAsync()
|
|
{
|
|
try
|
|
{
|
|
List<CompanyDto> companies = await client.Companies.GetAsync();
|
|
|
|
return companies ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public async Task<List<MachineDto>> GetMachinesBySoundSynthAsync(int soundSynthId)
|
|
{
|
|
try
|
|
{
|
|
List<MachineDto> machines = await client.SoundSynths[soundSynthId].Machines.GetAsync();
|
|
|
|
return machines ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Description management
|
|
public async Task<string> GetDescriptionTextAsync(int id, string lang = "eng")
|
|
{
|
|
try
|
|
{
|
|
SoundSynthDescriptionDto desc = await client.SoundSynths[id].Description.GetAsync(rc =>
|
|
{
|
|
if(!string.IsNullOrWhiteSpace(lang)) rc.QueryParameters.Lang = lang;
|
|
});
|
|
|
|
return desc?.Html ?? desc?.Markdown;
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetch the full description DTO so the caller can detect language fallback (the
|
|
/// <c>LanguageCode</c> on the returned object is the language actually served, not the
|
|
/// language requested). Returns <c>null</c> when no description exists in any language.
|
|
/// </summary>
|
|
public async Task<SoundSynthDescriptionDto> GetDescriptionAsync(int id, string lang = "eng")
|
|
{
|
|
try
|
|
{
|
|
return await client.SoundSynths[id].Description.GetAsync(rc =>
|
|
{
|
|
if(!string.IsNullOrWhiteSpace(lang)) rc.QueryParameters.Lang = lang;
|
|
});
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<List<SoundSynthDescriptionDto>> GetDescriptionsAsync(int soundSynthId)
|
|
{
|
|
try
|
|
{
|
|
List<SoundSynthDescriptionDto> descriptions = await client.SoundSynths[soundSynthId].Descriptions.GetAsync();
|
|
|
|
return descriptions ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> CreateOrUpdateDescriptionAsync(int soundSynthId,
|
|
SoundSynthDescriptionDto dto)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths[soundSynthId].Description.PostAsync(dto);
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> DeleteDescriptionAsync(int soundSynthId, string languageCode)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths[soundSynthId].Description[languageCode].DeleteAsync();
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
|
|
// ── Videos ──
|
|
|
|
public async Task<List<SoundSynthVideoDto>> GetVideosBySoundSynthAsync(int soundSynthId)
|
|
{
|
|
try
|
|
{
|
|
var result = await client.SoundSynths[soundSynthId].Videos.GetAsync();
|
|
|
|
return result ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public async Task<(SoundSynthVideoDto dto, string error)> CreateVideoAsync(int soundSynthId, string provider,
|
|
string videoId,
|
|
string title)
|
|
{
|
|
try
|
|
{
|
|
var dto = await client.SoundSynths[soundSynthId]
|
|
.Videos.PostAsync(new CreateSoundSynthVideoRequest
|
|
{
|
|
Provider = provider,
|
|
VideoId = videoId,
|
|
Title = title
|
|
});
|
|
|
|
return (dto, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (null, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (null, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> UpdateVideoTitleAsync(long id, string title)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths.Videos[id].PutAsync(new UpdateSoundSynthVideoRequest
|
|
{
|
|
Title = title
|
|
});
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<(bool succeeded, string error)> DeleteVideoAsync(long id)
|
|
{
|
|
try
|
|
{
|
|
await client.SoundSynths.Videos[id].DeleteAsync();
|
|
|
|
return (true, null);
|
|
}
|
|
catch(ApiException ex)
|
|
{
|
|
return (false, ExtractErrorMessage(ex));
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
return (false, ex.Message);
|
|
}
|
|
}
|
|
}
|