Add project files.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
using JSMR.Application.Circles.Ports;
|
||||
|
||||
namespace JSMR.Application.Circles.Commands.UpdateCircleStatus;
|
||||
|
||||
public class UpdateCircleStatusHandler(ICircleWriter writer)
|
||||
{
|
||||
public Task<UpdateCircleStatusResponse> HandleAsync(UpdateCircleStatusRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return writer.UpdateStatusAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Circles.Contracts;
|
||||
|
||||
namespace JSMR.Application.Circles.Commands.UpdateCircleStatus;
|
||||
|
||||
public sealed record UpdateCircleStatusRequest(int CircleId, CircleStatus CircleStatus);
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Circles.Contracts;
|
||||
|
||||
namespace JSMR.Application.Circles.Commands.UpdateCircleStatus;
|
||||
|
||||
public sealed record UpdateCircleStatusResponse(int CircleId, CircleStatus CircleStatus);
|
||||
9
JSMR.Application/Circles/Contracts/CircleStatus.cs
Normal file
9
JSMR.Application/Circles/Contracts/CircleStatus.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Application.Circles.Contracts;
|
||||
|
||||
public enum CircleStatus
|
||||
{
|
||||
Neutral,
|
||||
Favorite,
|
||||
Blacklisted,
|
||||
Spam
|
||||
}
|
||||
6
JSMR.Application/Circles/Ports/ICircleReader.cs
Normal file
6
JSMR.Application/Circles/Ports/ICircleReader.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Circles.Ports;
|
||||
|
||||
public interface ICircleReader
|
||||
{
|
||||
|
||||
}
|
||||
8
JSMR.Application/Circles/Ports/ICircleWriter.cs
Normal file
8
JSMR.Application/Circles/Ports/ICircleWriter.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Circles.Commands.UpdateCircleStatus;
|
||||
|
||||
namespace JSMR.Application.Circles.Ports;
|
||||
|
||||
public interface ICircleWriter
|
||||
{
|
||||
Task<UpdateCircleStatusResponse> UpdateStatusAsync(UpdateCircleStatusRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetCreators;
|
||||
|
||||
public sealed record CircleCreatorItem(
|
||||
string CreatorName,
|
||||
DateTime? FirstCollaborationDate,
|
||||
DateTime? LastCollaborationDate,
|
||||
int Downloads,
|
||||
int Count)
|
||||
{
|
||||
public readonly int AverageDownloads = Downloads / Count;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetCreators;
|
||||
|
||||
public sealed class GetCircleCreatorsHandler(ICircleCreatorsProvider provider)
|
||||
{
|
||||
public Task<GetCircleCreatorsResponse> HandleAsync(GetCircleCreatorsRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return provider.HandleAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetCreators;
|
||||
|
||||
public sealed record GetCircleCreatorsRequest(int? CircleId, string? NameOrMakerId);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetCreators;
|
||||
|
||||
public sealed record GetCircleCreatorsResponse(IReadOnlyList<CircleCreatorItem> Items);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetCreators;
|
||||
|
||||
public interface ICircleCreatorsProvider
|
||||
{
|
||||
Task<GetCircleCreatorsResponse> HandleAsync(GetCircleCreatorsRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetTags;
|
||||
|
||||
public sealed record CircleTagItem(string TagName, string? EnglishTagName, int Count);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetTags;
|
||||
|
||||
public sealed class GetCircleTagsHandler(ICircleTagsProvider provider)
|
||||
{
|
||||
public Task<GetCircleTagsResponse> HandleAsync(GetCircleTagsRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return provider.HandleAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetTags;
|
||||
|
||||
public sealed record GetCircleTagsRequest(int? CircleId, string? NameOrMakerId);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetTags;
|
||||
|
||||
public sealed record GetCircleTagsResponse(IReadOnlyList<CircleTagItem> Items);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Circles.Queries.GetTags;
|
||||
|
||||
public interface ICircleTagsProvider
|
||||
{
|
||||
Task<GetCircleTagsResponse> HandleAsync(GetCircleTagsRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public class CircleSearchCriteria
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
}
|
||||
19
JSMR.Application/Circles/Queries/Search/CircleSearchItem.cs
Normal file
19
JSMR.Application/Circles/Queries/Search/CircleSearchItem.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public record CircleSearchItem
|
||||
{
|
||||
public int CircleId { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string MakerId { get; init; } = string.Empty;
|
||||
public bool Blacklisted { get; init; }
|
||||
public bool Favorite { get; init; }
|
||||
public bool Spam { get; init; }
|
||||
public int Downloads { get; init; }
|
||||
public int Releases { get; init; }
|
||||
public int Pending { get; init; }
|
||||
public DateTime? FirstReleaseDate { get; init; }
|
||||
public DateTime? LatestReleaseDate { get; init; }
|
||||
public string? LatestProductId { get; init; }
|
||||
public bool? LatestVoiceWorkHasImage { get; init; }
|
||||
public DateTime? LatestVoiceWorkSalesDate { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
//public record TagSearchOptions : SearchOptions<TagSearchCriteria, TagSortField>
|
||||
//{
|
||||
|
||||
//}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public record CircleSearchResults : SearchResult<CircleSearchItem>
|
||||
{
|
||||
|
||||
}
|
||||
10
JSMR.Application/Circles/Queries/Search/CircleSortField.cs
Normal file
10
JSMR.Application/Circles/Queries/Search/CircleSortField.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public enum CircleSortField
|
||||
{
|
||||
Name,
|
||||
Blacklisted,
|
||||
Favorite,
|
||||
Spam,
|
||||
VoiceWorkCount
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public interface ICircleSearchProvider : ISearchProvider<CircleSearchItem, CircleSearchCriteria, CircleSortField>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public sealed class SearchCirclesHandler(ICircleSearchProvider searchProvider)
|
||||
{
|
||||
public async Task<SearchCirclesResponse> HandleAsync(SearchCirclesRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
SearchOptions<CircleSearchCriteria, CircleSortField> searchOptions = request.Options;
|
||||
|
||||
SearchResult<CircleSearchItem> results = await searchProvider.SearchAsync(searchOptions, cancellationToken);
|
||||
|
||||
return new SearchCirclesResponse(results);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public sealed record SearchCirclesRequest(SearchOptions<CircleSearchCriteria, CircleSortField> Options);
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Circles.Queries.Search;
|
||||
|
||||
public sealed record SearchCirclesResponse(SearchResult<CircleSearchItem> Results);
|
||||
69
JSMR.Application/Common/Caching/CacheEntryOptions.cs
Normal file
69
JSMR.Application/Common/Caching/CacheEntryOptions.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
namespace JSMR.Application.Common.Caching;
|
||||
|
||||
public class CacheEntryOptions
|
||||
{
|
||||
private DateTimeOffset? _absoluteExpiration;
|
||||
private TimeSpan? _absoluteExpirationRelativeToNow;
|
||||
private TimeSpan? _slidingExpiration;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an absolute expiration date for the cache entry.
|
||||
/// </summary>
|
||||
public DateTimeOffset? AbsoluteExpiration
|
||||
{
|
||||
get
|
||||
{
|
||||
return _absoluteExpiration;
|
||||
}
|
||||
set
|
||||
{
|
||||
_absoluteExpiration = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an absolute expiration time, relative to now.
|
||||
/// </summary>
|
||||
public TimeSpan? AbsoluteExpirationRelativeToNow
|
||||
{
|
||||
get
|
||||
{
|
||||
return _absoluteExpirationRelativeToNow;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value <= TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(AbsoluteExpirationRelativeToNow),
|
||||
value,
|
||||
"The relative expiration value must be positive.");
|
||||
}
|
||||
|
||||
_absoluteExpirationRelativeToNow = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed.
|
||||
/// This will not extend the entry lifetime beyond the absolute expiration (if set).
|
||||
/// </summary>
|
||||
public TimeSpan? SlidingExpiration
|
||||
{
|
||||
get
|
||||
{
|
||||
return _slidingExpiration;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value <= TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(SlidingExpiration),
|
||||
value,
|
||||
"The sliding expiration value must be positive.");
|
||||
}
|
||||
_slidingExpiration = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
JSMR.Application/Common/Caching/ICache.cs
Normal file
7
JSMR.Application/Common/Caching/ICache.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace JSMR.Application.Common.Caching;
|
||||
|
||||
public interface ICache
|
||||
{
|
||||
ValueTask<T?> GetAsync<T>(string key, CancellationToken cancellationToken = default);
|
||||
ValueTask SetAsync<T>(string key, T value, CacheEntryOptions options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
11
JSMR.Application/Common/Language.cs
Normal file
11
JSMR.Application/Common/Language.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Application.Common;
|
||||
|
||||
public enum Language
|
||||
{
|
||||
Unknown,
|
||||
Japanese,
|
||||
English,
|
||||
ChineseSimplified,
|
||||
ChineseTraditional,
|
||||
Korean
|
||||
}
|
||||
8
JSMR.Application/Common/Search/ISearchProvider.cs
Normal file
8
JSMR.Application/Common/Search/ISearchProvider.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public interface ISearchProvider<TItem, TCriteria, TSortField>
|
||||
where TCriteria : new()
|
||||
where TSortField : struct, Enum
|
||||
{
|
||||
Task<SearchResult<TItem>> SearchAsync(SearchOptions<TCriteria, TSortField> options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
8
JSMR.Application/Common/Search/ISearchQueryHandler.cs
Normal file
8
JSMR.Application/Common/Search/ISearchQueryHandler.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public interface ISearchQueryHandler<TItem, TCriteria, TSortField>
|
||||
where TCriteria : new()
|
||||
where TSortField : struct, Enum
|
||||
{
|
||||
Task<SearchResult<TItem>> HandleAsync(SearchOptions<TCriteria, TSortField> options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
11
JSMR.Application/Common/Search/SearchOptions.cs
Normal file
11
JSMR.Application/Common/Search/SearchOptions.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public sealed record SearchOptions<TCriteria, TSortField>
|
||||
where TCriteria : new()
|
||||
where TSortField : struct, Enum
|
||||
{
|
||||
public int PageNumber { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 100;
|
||||
public TCriteria Criteria { get; set; } = new();
|
||||
public SortOption<TSortField>[] SortOptions { get; set; } = [];
|
||||
}
|
||||
71
JSMR.Application/Common/Search/SearchReader.cs
Normal file
71
JSMR.Application/Common/Search/SearchReader.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
|
||||
|
||||
|
||||
//public abstract class SearchReader2<TItem, TCriteria, TSortField> : ISearchReader<TItem, TCriteria, TSortField>
|
||||
// where TSortField : struct, Enum
|
||||
//{
|
||||
// public Task<SearchResult<TItem>> SearchAsync(SearchOptions<TCriteria, TSortField> options, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
//}
|
||||
|
||||
//public abstract class SearchReader<TSearchResultItem, TCriteria, TSortField> where TSortField : struct, Enum
|
||||
//{
|
||||
// public async Task<SearchResult<TSearchResultItem>> SearchAsync(SearchOptions<TCriteria, TSortField> options, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// IQueryable<TSearchResultItem> baseQuery = GetBaseQuery();
|
||||
// IQueryable<TSearchResultItem> filteredQuery = ApplyFilters(baseQuery, options);
|
||||
|
||||
// int total = await filteredQuery.CountAsync(cancellationToken);
|
||||
|
||||
// IOrderedQueryable<TSearchResultItem> orderedQuery = ApplySorting(filteredQuery, options);
|
||||
|
||||
// TSearchResultItem[] items = await orderedQuery
|
||||
// .Skip((options.PageNumber - 1) * options.PageSize)
|
||||
// .Take(options.PageSize)
|
||||
// .ToArrayAsync(cancellationToken);
|
||||
|
||||
// return new SearchResult<TSearchResultItem>()
|
||||
// {
|
||||
// Items = items,
|
||||
// TotalItems = total
|
||||
// };
|
||||
// }
|
||||
|
||||
// protected abstract IQueryable<TSearchResultItem> GetBaseQuery();
|
||||
// protected abstract IQueryable<TSearchResultItem> ApplyFilters(IQueryable<TSearchResultItem> query, SearchOptions<TCriteria, TSortField> options);
|
||||
|
||||
// private IOrderedQueryable<TSearchResultItem> ApplySorting(IQueryable<TSearchResultItem> query, SearchOptions<TCriteria, TSortField> options)
|
||||
// {
|
||||
// IOrderedQueryable<TSearchResultItem>? ordered = null;
|
||||
|
||||
// for (int i = 0; i < options.SortOptions.Length; i++)
|
||||
// {
|
||||
// var (field, direction) = (options.SortOptions[i].Field, options.SortOptions[i].Direction);
|
||||
// bool isDescending = direction == SortDirection.Descending;
|
||||
|
||||
// IOrderedQueryable<TSearchResultItem> applyFirst(Expression<Func<TSearchResultItem, object>> selector) => isDescending ? query.OrderByDescending(selector) : query.OrderBy(selector);
|
||||
// IOrderedQueryable<TSearchResultItem> applyNext(Expression<Func<TSearchResultItem, object>> selector) => isDescending ? ordered!.ThenByDescending(selector) : ordered!.ThenBy(selector);
|
||||
|
||||
// Expression<Func<TSearchResultItem, object>> selector = GetSortExpression(field);
|
||||
|
||||
// ordered = (i == 0) ? applyFirst(selector) : applyNext(selector);
|
||||
// }
|
||||
|
||||
// return ordered ?? GetDefaultSortExpression(query);
|
||||
// }
|
||||
|
||||
// protected abstract Expression<Func<TSearchResultItem, object>> GetSortExpression(TSortField field);
|
||||
// protected abstract IOrderedQueryable<TSearchResultItem> GetDefaultSortExpression(IQueryable<TSearchResultItem> query);
|
||||
//}
|
||||
7
JSMR.Application/Common/Search/SearchResult.cs
Normal file
7
JSMR.Application/Common/Search/SearchResult.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public record SearchResult<T>
|
||||
{
|
||||
public T[] Items { get; set; } = [];
|
||||
public int TotalItems { get; set; }
|
||||
}
|
||||
7
JSMR.Application/Common/Search/SortDirection.cs
Normal file
7
JSMR.Application/Common/Search/SortDirection.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public enum SortDirection
|
||||
{
|
||||
Ascending = 0,
|
||||
Descending = 1
|
||||
}
|
||||
3
JSMR.Application/Common/Search/SortOption.cs
Normal file
3
JSMR.Application/Common/Search/SortOption.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Common.Search;
|
||||
|
||||
public record SortOption<TSortField>(TSortField Field, SortDirection Direction) where TSortField : struct, Enum;
|
||||
@@ -0,0 +1,11 @@
|
||||
using JSMR.Application.Creators.Ports;
|
||||
|
||||
namespace JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
|
||||
public class UpdateCreatorStatusHandler(ICreatorWriter writer)
|
||||
{
|
||||
public Task<UpdateCreatorStatusResponse> HandleAsync(UpdateCreatorStatusRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return writer.UpdateStatusAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Creators.Contracts;
|
||||
|
||||
namespace JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
|
||||
public sealed record UpdateCreatorStatusRequest(int CreatorId, CreatorStatus CreatorStatus);
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Creators.Contracts;
|
||||
|
||||
namespace JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
|
||||
public sealed record UpdateCreatorStatusResponse(int CreatorId, CreatorStatus CreatorStatus);
|
||||
8
JSMR.Application/Creators/Contracts/CreatorStatus.cs
Normal file
8
JSMR.Application/Creators/Contracts/CreatorStatus.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace JSMR.Application.Creators.Contracts;
|
||||
|
||||
public enum CreatorStatus
|
||||
{
|
||||
Neutral,
|
||||
Favorite,
|
||||
Blacklisted
|
||||
}
|
||||
6
JSMR.Application/Creators/Ports/ICreatorReader.cs
Normal file
6
JSMR.Application/Creators/Ports/ICreatorReader.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Creators.Ports;
|
||||
|
||||
public interface ICircleReader
|
||||
{
|
||||
|
||||
}
|
||||
8
JSMR.Application/Creators/Ports/ICreatorWriter.cs
Normal file
8
JSMR.Application/Creators/Ports/ICreatorWriter.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
|
||||
namespace JSMR.Application.Creators.Ports;
|
||||
|
||||
public interface ICreatorWriter
|
||||
{
|
||||
Task<UpdateCreatorStatusResponse> UpdateStatusAsync(UpdateCreatorStatusRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
public class CreatorSearchCriteria
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
public record CreatorSearchItem
|
||||
{
|
||||
public int CreatorId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public bool Favorite { get; init; }
|
||||
public bool Blacklisted { get; init; }
|
||||
public int VoiceWorkCount { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
//public record TagSearchOptions : SearchOptions<TagSearchCriteria, TagSortField>
|
||||
//{
|
||||
|
||||
//}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
public record CreatorSearchResults : SearchResult<CreatorSearchItem>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
public enum CreatorSortField
|
||||
{
|
||||
Name,
|
||||
Blacklisted,
|
||||
Favorite,
|
||||
VoiceWorkCount
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search.Ports;
|
||||
|
||||
public interface ICreatorSearchProvider : ISearchProvider<CreatorSearchItem, CreatorSearchCriteria, CreatorSortField>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using JSMR.Application.Common.Caching;
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
using JSMR.Application.Creators.Queries.Search.Ports;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search;
|
||||
|
||||
public sealed class SearchCreatorsHandler(ICreatorSearchProvider searchProvider, ICache cache)
|
||||
{
|
||||
public async Task<SearchCreatorsResponse> HandleAsync(SearchCreatorsRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
SearchOptions<CreatorSearchCriteria, CreatorSortField> searchOptions = request.Options;
|
||||
|
||||
string cacheKey = $"creator:{searchOptions.GetHashCode()}";
|
||||
|
||||
CreatorSearchResults? cachedResults = await cache.GetAsync<CreatorSearchResults>(cacheKey, cancellationToken);
|
||||
|
||||
if (cachedResults != null)
|
||||
return new SearchCreatorsResponse(cachedResults);
|
||||
|
||||
SearchResult<CreatorSearchItem> results = await searchProvider.SearchAsync(searchOptions, cancellationToken);
|
||||
|
||||
CacheEntryOptions cacheEntryOptions = new()
|
||||
{
|
||||
SlidingExpiration = TimeSpan.FromMinutes(10)
|
||||
};
|
||||
|
||||
await cache.SetAsync(cacheKey, results, cacheEntryOptions, cancellationToken);
|
||||
|
||||
return new SearchCreatorsResponse(results);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search;
|
||||
|
||||
public sealed record SearchCreatorsRequest(SearchOptions<CreatorSearchCriteria, CreatorSortField> Options);
|
||||
@@ -0,0 +1,6 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Creators.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Creators.Queries.Search;
|
||||
|
||||
public sealed record SearchCreatorsResponse(SearchResult<CreatorSearchItem> Results);
|
||||
@@ -0,0 +1,21 @@
|
||||
using JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
using JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
using JSMR.Application.VoiceWorks.Search;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace JSMR.Application.DI;
|
||||
|
||||
public static class ApplicationServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddApplication(this IServiceCollection services)
|
||||
{
|
||||
// Handlers / Use-cases
|
||||
//services.AddScoped<SearchVoiceWorksHandler>();
|
||||
//services.AddScoped<ScanVoiceWorksHandler>();
|
||||
|
||||
services.AddScoped<SetTagEnglishNameHandler>();
|
||||
services.AddScoped<UpdateTagStatusHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace JSMR.Application.Integrations.Chobit.Models;
|
||||
|
||||
public class ChobitResult
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public ChobitWork[] Works { get; set; } = [];
|
||||
}
|
||||
16
JSMR.Application/Integrations/Chobit/Models/ChobitWork.cs
Normal file
16
JSMR.Application/Integrations/Chobit/Models/ChobitWork.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace JSMR.Application.Integrations.Chobit.Models;
|
||||
|
||||
public class ChobitWork
|
||||
{
|
||||
public string? WorkId { get; set; }
|
||||
public string? DLSiteWorkId { get; set; }
|
||||
public string? WorkName { get; set; }
|
||||
public string? WorkNameKana { get; set; }
|
||||
public string? URL { get; set; }
|
||||
public string? EmbedURL { get; set; }
|
||||
public string? Thumb { get; set; }
|
||||
public string? MiniThumb { get; set; }
|
||||
public string? FileType { get; set; }
|
||||
public decimal EmbedWidth { get; set; }
|
||||
public decimal EmbedHeight { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Integrations.Chobit.Models;
|
||||
|
||||
public class ChobitWorkResult : Dictionary<string, ChobitResult> { }
|
||||
8
JSMR.Application/Integrations/Cien/Models/CienArticle.cs
Normal file
8
JSMR.Application/Integrations/Cien/Models/CienArticle.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace JSMR.Application.Integrations.Cien.Models;
|
||||
|
||||
public class CienArticle
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public required string Title { get; set; }
|
||||
public required DateTime ReleasedAt { get; set; }
|
||||
}
|
||||
10
JSMR.Application/Integrations/Cien/Models/CienCreator.cs
Normal file
10
JSMR.Application/Integrations/Cien/Models/CienCreator.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace JSMR.Application.Integrations.Cien.Models;
|
||||
|
||||
public class CienCreator
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Rating { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public CienArticle[] Articles { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Integrations.DLSite.Models;
|
||||
|
||||
public class VoiceWorkDetailCollection : Dictionary<string, VoiceWorkDetails>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using JSMR.Application.Common;
|
||||
|
||||
namespace JSMR.Application.Integrations.DLSite.Models;
|
||||
|
||||
public class VoiceWorkDetails
|
||||
{
|
||||
public VoiceWorkSeries? Series { get; init; }
|
||||
public VoiceWorkTranslation? Translation { get; init; }
|
||||
public int WishlistCount { get; init; }
|
||||
public int DownloadCount { get; init; }
|
||||
public DateTime? RegistrationDate { get; init; }
|
||||
public Language[] SupportedLanguages { get; init; } = [];
|
||||
//public AIGeneration AI { get; init; }
|
||||
public bool HasTrial { get; init; }
|
||||
public bool HasReviews { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace JSMR.Application.Integrations.DLSite.Models;
|
||||
|
||||
public class VoiceWorkSeries
|
||||
{
|
||||
public required string Identifier { get; init; }
|
||||
public required string Name { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using JSMR.Application.Common;
|
||||
|
||||
namespace JSMR.Application.Integrations.DLSite.Models;
|
||||
|
||||
public class VoiceWorkTranslation
|
||||
{
|
||||
public required string OriginalProductId { get; init; }
|
||||
public bool IsOfficialTranslation { get; init; }
|
||||
public required Language Language { get; init; }
|
||||
}
|
||||
8
JSMR.Application/Integrations/Ports/IChobitClient.cs
Normal file
8
JSMR.Application/Integrations/Ports/IChobitClient.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Integrations.Chobit.Models;
|
||||
|
||||
namespace JSMR.Application.Integrations.Ports;
|
||||
|
||||
public interface IChobitClient
|
||||
{
|
||||
Task<ChobitWorkResult> GetSampleInfoAsync(string[] productIds, CancellationToken cancellationToken = default);
|
||||
}
|
||||
8
JSMR.Application/Integrations/Ports/ICienClient.cs
Normal file
8
JSMR.Application/Integrations/Ports/ICienClient.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Integrations.Cien.Models;
|
||||
|
||||
namespace JSMR.Application.Integrations.Ports;
|
||||
|
||||
public interface ICienClient
|
||||
{
|
||||
Task<CienCreator[]> GetCienCreatorAsync(string makerId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
8
JSMR.Application/Integrations/Ports/IDLSiteClient.cs
Normal file
8
JSMR.Application/Integrations/Ports/IDLSiteClient.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Integrations.DLSite.Models;
|
||||
|
||||
namespace JSMR.Application.Integrations.Ports;
|
||||
|
||||
public interface IDLSiteClient
|
||||
{
|
||||
Task<VoiceWorkDetailCollection> GetVoiceWorkDetailsAsync(string[] productIds, CancellationToken cancellationToken = default);
|
||||
}
|
||||
17
JSMR.Application/JSMR.Application.csproj
Normal file
17
JSMR.Application/JSMR.Application.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Tags\Queries\Ports\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,20 @@
|
||||
using JSMR.Application.Tags.Ports;
|
||||
|
||||
namespace JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
|
||||
public sealed class SetTagEnglishNameHandler(ITagWriter tagWriter)
|
||||
{
|
||||
public async Task<SetTagEnglishNameResponse> HandleAsync(SetTagEnglishNameRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.EnglishName))
|
||||
throw new ArgumentException("English name is required.", nameof(request));
|
||||
|
||||
string trimmed = request.EnglishName.Trim();
|
||||
SetTagEnglishNameResponse result = await tagWriter.SetEnglishNameAsync(request with { EnglishName = trimmed }, cancellationToken);
|
||||
|
||||
// Optional: refresh search materialization for all voice works that use this tag
|
||||
//await _searchUpdater.UpdateForTagAsync(request.TagId, cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
|
||||
public sealed record SetTagEnglishNameRequest(int TagId, string EnglishName);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
|
||||
public sealed record SetTagEnglishNameResponse(int TagId, string EnglishName);
|
||||
@@ -0,0 +1,11 @@
|
||||
using JSMR.Application.Tags.Ports;
|
||||
|
||||
namespace JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
|
||||
public sealed class UpdateTagStatusHandler(ITagWriter writer)
|
||||
{
|
||||
public Task<UpdateTagStatusResponse> HandleAsync(UpdateTagStatusRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return writer.UpdateStatusAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Tags.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
|
||||
public sealed record UpdateTagStatusRequest(int TagId, TagStatus TagStatus);
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.Tags.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
|
||||
public sealed record UpdateTagStatusResponse(int TagId, TagStatus TagStatus);
|
||||
8
JSMR.Application/Tags/Contracts/TagStatus.cs
Normal file
8
JSMR.Application/Tags/Contracts/TagStatus.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace JSMR.Application.Tags.Contracts;
|
||||
|
||||
public enum TagStatus
|
||||
{
|
||||
Neutral,
|
||||
Favorite,
|
||||
Blacklisted
|
||||
}
|
||||
8
JSMR.Application/Tags/Ports/ITagReader.cs
Normal file
8
JSMR.Application/Tags/Ports/ITagReader.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Ports;
|
||||
|
||||
public interface ITagReader
|
||||
{
|
||||
//Task<TagSearchResults> SearchAsync(TagSearchOptions options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
10
JSMR.Application/Tags/Ports/ITagWriter.cs
Normal file
10
JSMR.Application/Tags/Ports/ITagWriter.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
using JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
|
||||
namespace JSMR.Application.Tags.Ports;
|
||||
|
||||
public interface ITagWriter
|
||||
{
|
||||
Task<SetTagEnglishNameResponse> SetEnglishNameAsync(SetTagEnglishNameRequest request, CancellationToken cancellationToken = default);
|
||||
Task<UpdateTagStatusResponse> UpdateStatusAsync(UpdateTagStatusRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
public class TagSearchCriteria
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
public record TagSearchItem
|
||||
{
|
||||
public int TagId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public bool Favorite { get; init; }
|
||||
public bool Blacklisted { get; init; }
|
||||
public string? EnglishName { get; init; }
|
||||
public int VoiceWorkCount { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
//public record TagSearchOptions : SearchOptions<TagSearchCriteria, TagSortField>
|
||||
//{
|
||||
|
||||
//}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
public record TagSearchResults : SearchResult<TagSearchItem>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
public enum TagSortField
|
||||
{
|
||||
Name,
|
||||
EnglishName,
|
||||
Blacklisted,
|
||||
Favorite,
|
||||
VoiceWorkCount
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search.Ports;
|
||||
|
||||
public interface ITagSearchProvider : ISearchProvider<TagSearchItem, TagSearchCriteria, TagSortField>
|
||||
{
|
||||
|
||||
}
|
||||
32
JSMR.Application/Tags/Queries/Search/SearchTagsHandler.cs
Normal file
32
JSMR.Application/Tags/Queries/Search/SearchTagsHandler.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using JSMR.Application.Common.Caching;
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
using JSMR.Application.Tags.Queries.Search.Ports;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search;
|
||||
|
||||
public sealed class SearchTagsHandler(ITagSearchProvider searchProvider, ICache cache)
|
||||
{
|
||||
public async Task<SearchTagsResponse> HandleAsync(SearchTagsRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
SearchOptions<TagSearchCriteria, TagSortField> searchOptions = request.Options;
|
||||
|
||||
string cacheKey = $"tag:{searchOptions.GetHashCode()}";
|
||||
|
||||
TagSearchResults? cachedResults = await cache.GetAsync<TagSearchResults>(cacheKey, cancellationToken);
|
||||
|
||||
if (cachedResults != null)
|
||||
return new SearchTagsResponse(cachedResults);
|
||||
|
||||
SearchResult<TagSearchItem> results = await searchProvider.SearchAsync(searchOptions, cancellationToken);
|
||||
|
||||
CacheEntryOptions cacheEntryOptions = new()
|
||||
{
|
||||
SlidingExpiration = TimeSpan.FromMinutes(10)
|
||||
};
|
||||
|
||||
await cache.SetAsync(cacheKey, results, cacheEntryOptions, cancellationToken);
|
||||
|
||||
return new SearchTagsResponse(results);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search;
|
||||
|
||||
public sealed record SearchTagsRequest(SearchOptions<TagSearchCriteria, TagSortField> Options);
|
||||
@@ -0,0 +1,6 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.Tags.Queries.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.Tags.Queries.Search;
|
||||
|
||||
public sealed record SearchTagsResponse(SearchResult<TagSearchItem> Results);
|
||||
9
JSMR.Application/VoiceWorks/Ports/IVoiceWorkReader.cs
Normal file
9
JSMR.Application/VoiceWorks/Ports/IVoiceWorkReader.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Ports;
|
||||
|
||||
public interface IVoiceWorkReader
|
||||
{
|
||||
//Task<VoiceWorkSearchResults> SearchAsync(VoiceWorkSearchOptions options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using JSMR.Application.Common;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
public class VoiceWorkSearchCriteria
|
||||
{
|
||||
public string? Keywords { get; init; }
|
||||
public string? Title { get; init; }
|
||||
public string? Circle { get; init; }
|
||||
//public SaleStatus SaleStatus { get; init; }
|
||||
//public CircleStatus CircleStatus { get; init; }
|
||||
//public TagStatus TagStatus { get; init; }
|
||||
//public CreatorStatus CreatorStatus { get; init; }
|
||||
public int[] TagIds { get; init; } = [];
|
||||
public bool IncludeAllTags { get; init; }
|
||||
public int[] CreatorIds { get; init; } = [];
|
||||
public bool IncludeAllCreators { get; init; }
|
||||
//public VoiceWorkSort Sort { get; init; }
|
||||
//public VoiceWorkLanguage Language { get; init; }
|
||||
public DateTime? ReleaseDateStart { get; init; }
|
||||
public DateTime? ReleaseDateEnd { get; init; }
|
||||
//public List<AgeRating> AgeRatings { get; init; }
|
||||
public Language[] SupportedLanguages { get; init; } = [];
|
||||
//public List<AIGeneration> AIGenerationOptions { get; init; }
|
||||
public bool ShowFavoriteVoiceWorks { get; init; }
|
||||
public bool ShowInvalidVoiceWorks { get; init; }
|
||||
public int? MinDownloads { get; init; }
|
||||
public int? MaxDownloads { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
//public record VoiceWorkSearchOptions : SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>
|
||||
//{
|
||||
|
||||
//}
|
||||
@@ -0,0 +1,8 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
public record VoiceWorkSearchResults : SearchResult<object>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
public enum VoiceWorkSortField
|
||||
{
|
||||
ReleaseDateNewToOld,
|
||||
ReleaseDateOldToNew,
|
||||
BestSelling,
|
||||
MostWishedFor,
|
||||
SalesToWishlistRatio,
|
||||
StarRating
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using JSMR.Application.Common.Caching;
|
||||
using JSMR.Application.VoiceWorks.Ports;
|
||||
using JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search;
|
||||
|
||||
//public sealed class SearchVoiceWorksHandler(IVoiceWorkReader reader, ICache cache)
|
||||
//{
|
||||
// //public async Task<SearchVoiceWorksResponse> HandleAsync(SearchVoiceWorksRequest request, CancellationToken cancellationToken)
|
||||
// //{
|
||||
// // VoiceWorkSearchOptions searchOptions = request.Options;
|
||||
|
||||
// // string cacheKey = $"vw:{searchOptions.GetHashCode()}";
|
||||
|
||||
// // VoiceWorkSearchResults? cachedResults = await cache.GetAsync<VoiceWorkSearchResults>(cacheKey, cancellationToken);
|
||||
|
||||
// // if (cachedResults != null)
|
||||
// // return new SearchVoiceWorksResponse(cachedResults);
|
||||
|
||||
// // VoiceWorkSearchResults results = await reader.SearchAsync(searchOptions, cancellationToken);
|
||||
|
||||
// // CacheEntryOptions cacheEntryOptions = new()
|
||||
// // {
|
||||
// // SlidingExpiration = TimeSpan.FromMinutes(10)
|
||||
// // };
|
||||
|
||||
// // await cache.SetAsync(cacheKey, results, cacheEntryOptions, cancellationToken);
|
||||
|
||||
// // return new SearchVoiceWorksResponse(results);
|
||||
// //}
|
||||
//}
|
||||
@@ -0,0 +1,6 @@
|
||||
using JSMR.Application.Common.Search;
|
||||
using JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search;
|
||||
|
||||
public sealed record SearchVoiceWorksRequest(SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField> Options);
|
||||
@@ -0,0 +1,5 @@
|
||||
using JSMR.Application.VoiceWorks.Search.Contracts;
|
||||
|
||||
namespace JSMR.Application.VoiceWorks.Search;
|
||||
|
||||
public sealed record SearchVoiceWorksResponse(VoiceWorkSearchResults Results);
|
||||
11
JSMR.Domain/Entities/Circle.cs
Normal file
11
JSMR.Domain/Entities/Circle.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class Circle
|
||||
{
|
||||
public int CircleId { get; set; }
|
||||
public required string MakerId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public bool Blacklisted { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Spam { get; set; }
|
||||
}
|
||||
9
JSMR.Domain/Entities/Creator.cs
Normal file
9
JSMR.Domain/Entities/Creator.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class Creator
|
||||
{
|
||||
public int CreatorId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Blacklisted { get; set; }
|
||||
}
|
||||
11
JSMR.Domain/Entities/EnglishTag.cs
Normal file
11
JSMR.Domain/Entities/EnglishTag.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class EnglishTag
|
||||
{
|
||||
public int EnglishTagId { get; set; }
|
||||
|
||||
public int TagId { get; set; }
|
||||
public Tag? Tag { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
}
|
||||
12
JSMR.Domain/Entities/EnglishVoiceWork.cs
Normal file
12
JSMR.Domain/Entities/EnglishVoiceWork.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class EnglishVoiceWork
|
||||
{
|
||||
public int EnglishVoiceWorkId { get; set; }
|
||||
public required string ProductName { get; set; }
|
||||
public required string Description { get; set; }
|
||||
public bool? IsValid { get; set; }
|
||||
|
||||
public int VoiceWorkId { get; set; }
|
||||
public VoiceWork? VoiceWork { get; set; }
|
||||
}
|
||||
12
JSMR.Domain/Entities/Series.cs
Normal file
12
JSMR.Domain/Entities/Series.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class Series
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
|
||||
public int CircleId { get; set; }
|
||||
public Circle? Circle { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
public required string Identifier { get; set; }
|
||||
}
|
||||
9
JSMR.Domain/Entities/Tag.cs
Normal file
9
JSMR.Domain/Entities/Tag.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class Tag
|
||||
{
|
||||
public int TagId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Blacklisted { get; set; }
|
||||
}
|
||||
42
JSMR.Domain/Entities/VoiceWork.cs
Normal file
42
JSMR.Domain/Entities/VoiceWork.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class VoiceWork
|
||||
{
|
||||
public int VoiceWorkId { get; set; }
|
||||
public required string ProductId { get; set; }
|
||||
public string? OriginalProductId { get; set; }
|
||||
public required string ProductName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int Rating { get; set; }
|
||||
public bool HasImage { get; set; }
|
||||
public bool HasTrial { get; set; }
|
||||
public bool Purchased { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public DateTime? ExpectedDate { get; set; }
|
||||
public DateTime? SalesDate { get; set; }
|
||||
public int? Downloads { get; set; }
|
||||
public byte? StarRating { get; set; }
|
||||
public int? Votes { get; set; }
|
||||
public bool? IsValid { get; set; }
|
||||
public DateTime? LastScannedDate { get; set; }
|
||||
public byte Status { get; set; }
|
||||
public byte SubtitleLanguage { get; set; }
|
||||
public bool HasChobit { get; set; }
|
||||
public bool IsPurchased { get; set; }
|
||||
public int? WishlistCount { get; set; }
|
||||
public DateTime? PlannedReleaseDate { get; set; }
|
||||
public byte AIGeneration { get; set; }
|
||||
|
||||
public int CircleId { get; set; }
|
||||
public Circle? Circle { get; set; }
|
||||
|
||||
public int? SeriesId { get; set; }
|
||||
public Series? Series { get; set; }
|
||||
|
||||
//public int? VoiceWorkSearchId { get; set; }
|
||||
//public VoiceWorkSearch? VoiceWorkSearch { get; set; }
|
||||
|
||||
public virtual ICollection<VoiceWorkTag> VoiceWorkTags { get; set; } = [];
|
||||
public virtual ICollection<VoiceWorkCreator> VoiceWorkCreators { get; set; } = [];
|
||||
public virtual ICollection<EnglishVoiceWork> EnglishVoiceWorks { get; set; } = [];
|
||||
}
|
||||
14
JSMR.Domain/Entities/VoiceWorkCreator.cs
Normal file
14
JSMR.Domain/Entities/VoiceWorkCreator.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class VoiceWorkCreator
|
||||
{
|
||||
public int VoiceWorkCreatorId { get; set; }
|
||||
public int? Position { get; set; }
|
||||
public bool? IsValid { get; set; }
|
||||
|
||||
public int CreatorId { get; set; }
|
||||
public Creator? Creator { get; set; }
|
||||
|
||||
public int VoiceWorkId { get; set; }
|
||||
public VoiceWork? VoiceWork { get; set; }
|
||||
}
|
||||
9
JSMR.Domain/Entities/VoiceWorkSearch.cs
Normal file
9
JSMR.Domain/Entities/VoiceWorkSearch.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class VoiceWorkSearch
|
||||
{
|
||||
public int VoiceWorkId { get; set; }
|
||||
public VoiceWork? VoiceWork { get; set; }
|
||||
|
||||
public required string SearchText { get; set; }
|
||||
}
|
||||
14
JSMR.Domain/Entities/VoiceWorkTag.cs
Normal file
14
JSMR.Domain/Entities/VoiceWorkTag.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace JSMR.Domain.Entities;
|
||||
|
||||
public class VoiceWorkTag
|
||||
{
|
||||
public int VoiceWorkTagId { get; set; }
|
||||
public int? Position { get; set; }
|
||||
public bool? IsValid { get; set; }
|
||||
|
||||
public int TagId { get; set; }
|
||||
public Tag? Tag { get; set; }
|
||||
|
||||
public int VoiceWorkId { get; set; }
|
||||
public VoiceWork? VoiceWork { get; set; }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user