Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f04c18c810 | ||
|
|
eca58dbe7f | ||
|
|
cf9479d2a9 | ||
|
|
b6331331b0 | ||
|
|
ed365cfa43 | ||
|
|
b3a1e71570 |
@@ -78,10 +78,10 @@ namespace ErsatzTV.Application.Plex.Commands
|
||||
var existing = connectionParameters.PlexMediaSource.Libraries.OfType<PlexLibrary>().ToList();
|
||||
var toAdd = libraries.Filter(library => existing.All(l => l.Key != library.Key)).ToList();
|
||||
var toRemove = existing.Filter(library => libraries.All(l => l.Key != library.Key)).ToList();
|
||||
connectionParameters.PlexMediaSource.Libraries.AddRange(toAdd);
|
||||
toRemove.ForEach(c => connectionParameters.PlexMediaSource.Libraries.Remove(c));
|
||||
|
||||
return _mediaSourceRepository.Update(connectionParameters.PlexMediaSource);
|
||||
return _mediaSourceRepository.UpdateLibraries(
|
||||
connectionParameters.PlexMediaSource.Id,
|
||||
toAdd,
|
||||
toRemove);
|
||||
},
|
||||
error =>
|
||||
{
|
||||
|
||||
@@ -66,23 +66,20 @@ namespace ErsatzTV.Application.Plex.Commands
|
||||
{
|
||||
existing.ProductVersion = server.ProductVersion;
|
||||
existing.ServerName = server.ServerName;
|
||||
MergeConnections(existing.Connections, server.Connections);
|
||||
if (existing.Connections.Any() && existing.Connections.All(c => !c.IsActive))
|
||||
{
|
||||
existing.Connections.Head().IsActive = true;
|
||||
}
|
||||
|
||||
return _mediaSourceRepository.Update(existing);
|
||||
var toAdd = server.Connections
|
||||
.Filter(connection => existing.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
||||
var toRemove = existing.Connections
|
||||
.Filter(connection => server.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
||||
return _mediaSourceRepository.Update(existing, toAdd, toRemove);
|
||||
},
|
||||
async () =>
|
||||
{
|
||||
await _mediaSourceRepository.Add(server);
|
||||
if (server.Connections.Any())
|
||||
{
|
||||
server.Connections.Head().IsActive = true;
|
||||
}
|
||||
|
||||
await _mediaSourceRepository.Update(server);
|
||||
await _mediaSourceRepository.Add(server);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using static LanguageExt.Prelude;
|
||||
|
||||
namespace ErsatzTV.Application.Plex.Commands
|
||||
{
|
||||
@@ -35,20 +34,7 @@ namespace ErsatzTV.Application.Plex.Commands
|
||||
var toRemove = plexMediaSource.PathReplacements.Filter(r => incoming.All(pr => pr.Id != r.Id)).ToList();
|
||||
var toUpdate = incoming.Except(toAdd).ToList();
|
||||
|
||||
plexMediaSource.PathReplacements.AddRange(toAdd);
|
||||
toRemove.ForEach(pr => plexMediaSource.PathReplacements.Remove(pr));
|
||||
foreach (PlexPathReplacement pathReplacement in toUpdate)
|
||||
{
|
||||
Optional(plexMediaSource.PathReplacements.SingleOrDefault(pr => pr.Id == pathReplacement.Id))
|
||||
.IfSome(
|
||||
pr =>
|
||||
{
|
||||
pr.PlexPath = pathReplacement.PlexPath;
|
||||
pr.LocalPath = pathReplacement.LocalPath;
|
||||
});
|
||||
}
|
||||
|
||||
return _mediaSourceRepository.Update(plexMediaSource).ToUnit();
|
||||
return _mediaSourceRepository.UpdatePathReplacements(plexMediaSource.Id, toAdd, toUpdate, toRemove);
|
||||
}
|
||||
|
||||
private static PlexPathReplacement Project(PlexPathReplacementItem vm) =>
|
||||
|
||||
@@ -20,7 +20,19 @@ namespace ErsatzTV.Core.Interfaces.Repositories
|
||||
Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId);
|
||||
Task<int> CountMediaItems(int id);
|
||||
Task Update(LocalMediaSource localMediaSource);
|
||||
Task Update(PlexMediaSource plexMediaSource);
|
||||
Task Update(PlexMediaSource plexMediaSource, List<PlexConnection> toAdd, List<PlexConnection> toDelete);
|
||||
|
||||
Task<Unit> UpdateLibraries(
|
||||
int plexMediaSourceId,
|
||||
List<PlexLibrary> toAdd,
|
||||
List<PlexLibrary> toDelete);
|
||||
|
||||
Task<Unit> UpdatePathReplacements(
|
||||
int plexMediaSourceId,
|
||||
List<PlexPathReplacement> toAdd,
|
||||
List<PlexPathReplacement> toUpdate,
|
||||
List<PlexPathReplacement> toDelete);
|
||||
|
||||
Task Update(PlexLibrary plexMediaSourceLibrary);
|
||||
Task Delete(int mediaSourceId);
|
||||
Task<Unit> DeleteAllPlex();
|
||||
|
||||
@@ -152,11 +152,94 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task Update(PlexMediaSource plexMediaSource)
|
||||
public async Task Update(
|
||||
PlexMediaSource plexMediaSource,
|
||||
List<PlexConnection> toAdd,
|
||||
List<PlexConnection> toDelete)
|
||||
{
|
||||
await using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
context.PlexMediaSources.Update(plexMediaSource);
|
||||
await context.SaveChangesAsync();
|
||||
await _dbConnection.ExecuteAsync(
|
||||
@"UPDATE PlexMediaSource SET ProductVersion = @ProductVersion, ServerName = @ServerName WHERE Id = @Id",
|
||||
new { plexMediaSource.ProductVersion, plexMediaSource.ServerName, plexMediaSource.Id });
|
||||
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
foreach (PlexConnection add in toAdd)
|
||||
{
|
||||
add.PlexMediaSourceId = plexMediaSource.Id;
|
||||
dbContext.Entry(add).State = EntityState.Added;
|
||||
}
|
||||
|
||||
foreach (PlexConnection delete in toDelete)
|
||||
{
|
||||
dbContext.Entry(delete).State = EntityState.Deleted;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
PlexMediaSource pms = await dbContext.PlexMediaSources.FindAsync(plexMediaSource.Id);
|
||||
await dbContext.Entry(pms).Collection(x => x.Connections).LoadAsync();
|
||||
if (plexMediaSource.Connections.Any() && plexMediaSource.Connections.All(c => !c.IsActive))
|
||||
{
|
||||
plexMediaSource.Connections.Head().IsActive = true;
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Unit> UpdateLibraries(
|
||||
int plexMediaSourceId,
|
||||
List<PlexLibrary> toAdd,
|
||||
List<PlexLibrary> toDelete)
|
||||
{
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
foreach (PlexLibrary add in toAdd)
|
||||
{
|
||||
add.MediaSourceId = plexMediaSourceId;
|
||||
dbContext.Entry(add).State = EntityState.Added;
|
||||
}
|
||||
|
||||
foreach (PlexLibrary delete in toDelete)
|
||||
{
|
||||
dbContext.Entry(delete).State = EntityState.Deleted;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Unit.Default;
|
||||
}
|
||||
|
||||
public async Task<Unit> UpdatePathReplacements(
|
||||
int plexMediaSourceId,
|
||||
List<PlexPathReplacement> toAdd,
|
||||
List<PlexPathReplacement> toUpdate,
|
||||
List<PlexPathReplacement> toDelete)
|
||||
{
|
||||
foreach (PlexPathReplacement add in toAdd)
|
||||
{
|
||||
await _dbConnection.ExecuteAsync(
|
||||
@"INSERT INTO PlexPathReplacement
|
||||
(PlexPath, LocalPath, PlexMediaSourceId)
|
||||
VALUES (@PlexPath, @LocalPath, @PlexMediaSourceId)",
|
||||
new { add.PlexPath, add.LocalPath, PlexMediaSourceId = plexMediaSourceId });
|
||||
}
|
||||
|
||||
foreach (PlexPathReplacement update in toUpdate)
|
||||
{
|
||||
await _dbConnection.ExecuteAsync(
|
||||
@"UPDATE PlexPathReplacement
|
||||
SET PlexPath = @PlexPath, LocalPath = @LocalPath
|
||||
WHERE Id = @Id",
|
||||
new { update.PlexPath, update.LocalPath, update.Id });
|
||||
}
|
||||
|
||||
foreach (PlexPathReplacement delete in toDelete)
|
||||
{
|
||||
await _dbConnection.ExecuteAsync(
|
||||
@"DELETE FROM PlexPathReplacement WHERE Id = @Id",
|
||||
new { delete.Id });
|
||||
}
|
||||
|
||||
return Unit.Default;
|
||||
}
|
||||
|
||||
public async Task Update(PlexLibrary plexMediaSourceLibrary)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||
<PackageReference Include="Refit" Version="6.0.24" />
|
||||
<PackageReference Include="Refit" Version="6.0.38" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -51,17 +51,17 @@ namespace ErsatzTV.Infrastructure.Plex
|
||||
.Append(httpsResources.Filter(resource => resource.HttpsRequired))
|
||||
.ToList();
|
||||
|
||||
IEnumerable<PlexMediaSource> sources = allResources
|
||||
IEnumerable<PlexMediaSource> sources = await allResources
|
||||
.Filter(r => r.Provides.Split(",").Any(p => p == "server"))
|
||||
.Filter(r => r.Owned) // TODO: maybe support non-owned servers in the future
|
||||
.Map(
|
||||
resource =>
|
||||
async resource =>
|
||||
{
|
||||
var serverAuthToken = new PlexServerAuthToken(
|
||||
resource.ClientIdentifier,
|
||||
resource.AccessToken);
|
||||
|
||||
_plexSecretStore.UpsertServerAuthToken(serverAuthToken);
|
||||
await _plexSecretStore.UpsertServerAuthToken(serverAuthToken);
|
||||
List<PlexResourceConnection> sortedConnections = resource.HttpsRequired
|
||||
? resource.Connections
|
||||
: resource.Connections.OrderBy(c => c.Local ? 0 : 1).ToList();
|
||||
@@ -76,7 +76,9 @@ namespace ErsatzTV.Infrastructure.Plex
|
||||
};
|
||||
|
||||
return source;
|
||||
});
|
||||
})
|
||||
.Sequence();
|
||||
|
||||
result.AddRange(sources);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ using Lucene.Net.Sandbox.Queries;
|
||||
using Lucene.Net.Search;
|
||||
using Lucene.Net.Store;
|
||||
using Lucene.Net.Util;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Query = Lucene.Net.Search.Query;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Search
|
||||
@@ -36,6 +37,7 @@ namespace ErsatzTV.Infrastructure.Search
|
||||
private const string LibraryNameField = "library_name";
|
||||
private const string TitleAndYearField = "title_and_year";
|
||||
private const string JumpLetterField = "jump_letter";
|
||||
private const string ReleaseDateField = "release_date";
|
||||
|
||||
private const string MovieType = "movie";
|
||||
private const string ShowType = "show";
|
||||
@@ -43,17 +45,21 @@ namespace ErsatzTV.Infrastructure.Search
|
||||
private static bool _isRebuilding;
|
||||
|
||||
private readonly ILocalFileSystem _localFileSystem;
|
||||
private readonly ILogger<SearchIndex> _logger;
|
||||
|
||||
private readonly string[] _searchFields = { TitleField, GenreField, TagField };
|
||||
private readonly ISearchRepository _searchRepository;
|
||||
|
||||
public SearchIndex(ILocalFileSystem localFileSystem, ISearchRepository searchRepository)
|
||||
public SearchIndex(
|
||||
ILocalFileSystem localFileSystem,
|
||||
ISearchRepository searchRepository,
|
||||
ILogger<SearchIndex> logger)
|
||||
{
|
||||
_localFileSystem = localFileSystem;
|
||||
_searchRepository = searchRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public int Version => 1;
|
||||
public int Version => 2;
|
||||
|
||||
public Task<bool> Initialize()
|
||||
{
|
||||
@@ -150,7 +156,8 @@ namespace ErsatzTV.Infrastructure.Search
|
||||
using var analyzer = new StandardAnalyzer(AppLuceneVersion);
|
||||
QueryParser parser = !string.IsNullOrWhiteSpace(searchField)
|
||||
? new QueryParser(AppLuceneVersion, searchField, analyzer)
|
||||
: new MultiFieldQueryParser(AppLuceneVersion, _searchFields, analyzer);
|
||||
: new MultiFieldQueryParser(AppLuceneVersion, new[] { TitleField }, analyzer);
|
||||
parser.AllowLeadingWildcard = true;
|
||||
Query query = ParseQuery(searchQuery, parser);
|
||||
var filter = new DuplicateFilter(TitleAndYearField);
|
||||
var sort = new Sort(new SortField(SortTitleField, SortFieldType.STRING));
|
||||
@@ -212,77 +219,109 @@ namespace ErsatzTV.Infrastructure.Search
|
||||
return new SearchPageMap(map);
|
||||
}
|
||||
|
||||
private static void UpdateMovie(Movie movie, IndexWriter writer)
|
||||
private void UpdateMovie(Movie movie, IndexWriter writer)
|
||||
{
|
||||
Option<MovieMetadata> maybeMetadata = movie.MovieMetadata.HeadOrNone();
|
||||
if (maybeMetadata.IsSome)
|
||||
{
|
||||
MovieMetadata metadata = maybeMetadata.ValueUnsafe();
|
||||
|
||||
var doc = new Document
|
||||
try
|
||||
{
|
||||
new StringField(IdField, movie.Id.ToString(), Field.Store.YES),
|
||||
new StringField(TypeField, MovieType, Field.Store.NO),
|
||||
new TextField(TitleField, metadata.Title, Field.Store.NO),
|
||||
new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
|
||||
new TextField(LibraryNameField, movie.LibraryPath.Library.Name, Field.Store.NO),
|
||||
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
|
||||
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
|
||||
};
|
||||
var doc = new Document
|
||||
{
|
||||
new StringField(IdField, movie.Id.ToString(), Field.Store.YES),
|
||||
new StringField(TypeField, MovieType, Field.Store.NO),
|
||||
new TextField(TitleField, metadata.Title, Field.Store.NO),
|
||||
new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
|
||||
new TextField(LibraryNameField, movie.LibraryPath.Library.Name, Field.Store.NO),
|
||||
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
|
||||
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(metadata.Plot))
|
||||
{
|
||||
doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
|
||||
if (metadata.ReleaseDate.HasValue)
|
||||
{
|
||||
doc.Add(
|
||||
new StringField(
|
||||
ReleaseDateField,
|
||||
metadata.ReleaseDate.Value.ToString("yyyyMMdd"),
|
||||
Field.Store.NO));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(metadata.Plot))
|
||||
{
|
||||
doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
|
||||
}
|
||||
|
||||
foreach (Genre genre in metadata.Genres)
|
||||
{
|
||||
doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
foreach (Tag tag in metadata.Tags)
|
||||
{
|
||||
doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
writer.UpdateDocument(new Term(IdField, movie.Id.ToString()), doc);
|
||||
}
|
||||
|
||||
foreach (Genre genre in metadata.Genres)
|
||||
catch (Exception ex)
|
||||
{
|
||||
doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
|
||||
_logger.LogWarning(ex, "Error indexing movie with metadata {@Metadata}", metadata);
|
||||
}
|
||||
|
||||
foreach (Tag tag in metadata.Tags)
|
||||
{
|
||||
doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
writer.UpdateDocument(new Term(IdField, movie.Id.ToString()), doc);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateShow(Show show, IndexWriter writer)
|
||||
private void UpdateShow(Show show, IndexWriter writer)
|
||||
{
|
||||
Option<ShowMetadata> maybeMetadata = show.ShowMetadata.HeadOrNone();
|
||||
if (maybeMetadata.IsSome)
|
||||
{
|
||||
ShowMetadata metadata = maybeMetadata.ValueUnsafe();
|
||||
|
||||
var doc = new Document
|
||||
try
|
||||
{
|
||||
new StringField(IdField, show.Id.ToString(), Field.Store.YES),
|
||||
new StringField(TypeField, ShowType, Field.Store.NO),
|
||||
new TextField(TitleField, metadata.Title, Field.Store.NO),
|
||||
new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
|
||||
new TextField(LibraryNameField, show.LibraryPath.Library.Name, Field.Store.NO),
|
||||
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
|
||||
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
|
||||
};
|
||||
var doc = new Document
|
||||
{
|
||||
new StringField(IdField, show.Id.ToString(), Field.Store.YES),
|
||||
new StringField(TypeField, ShowType, Field.Store.NO),
|
||||
new TextField(TitleField, metadata.Title, Field.Store.NO),
|
||||
new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
|
||||
new TextField(LibraryNameField, show.LibraryPath.Library.Name, Field.Store.NO),
|
||||
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
|
||||
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(metadata.Plot))
|
||||
{
|
||||
doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
|
||||
if (metadata.ReleaseDate.HasValue)
|
||||
{
|
||||
doc.Add(
|
||||
new StringField(
|
||||
ReleaseDateField,
|
||||
metadata.ReleaseDate.Value.ToString("yyyyMMdd"),
|
||||
Field.Store.NO));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(metadata.Plot))
|
||||
{
|
||||
doc.Add(new TextField(PlotField, metadata.Plot ?? string.Empty, Field.Store.NO));
|
||||
}
|
||||
|
||||
foreach (Genre genre in metadata.Genres)
|
||||
{
|
||||
doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
foreach (Tag tag in metadata.Tags)
|
||||
{
|
||||
doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
writer.UpdateDocument(new Term(IdField, show.Id.ToString()), doc);
|
||||
}
|
||||
|
||||
foreach (Genre genre in metadata.Genres)
|
||||
catch (Exception ex)
|
||||
{
|
||||
doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
|
||||
_logger.LogWarning(ex, "Error indexing show with metadata {@Metadata}", metadata);
|
||||
}
|
||||
|
||||
foreach (Tag tag in metadata.Tags)
|
||||
{
|
||||
doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));
|
||||
}
|
||||
|
||||
writer.UpdateDocument(new Term(IdField, show.Id.ToString()), doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Accelist.FluentValidation.Blazor" Version="4.0.0" />
|
||||
<PackageReference Include="FluentValidation" Version="9.5.2" />
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="9.5.2" />
|
||||
<PackageReference Include="FluentValidation" Version="9.5.3" />
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="9.5.3" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="3.4.15" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4" />
|
||||
@@ -20,14 +20,14 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MudBlazor" Version="5.0.5" />
|
||||
<PackageReference Include="MudBlazor" Version="5.0.6" />
|
||||
<PackageReference Include="Refit.HttpClientFactory" Version="6.0.24" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.SQLite" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.1.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -95,13 +95,15 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
FFmpegSettingsViewModel ffmpegSettings = await Mediator.Send(new GetFFmpegSettings());
|
||||
|
||||
// TODO: command for new channel
|
||||
IEnumerable<int> channelNumbers = await Mediator.Send(new GetAllChannels())
|
||||
.Map(list => list.Map(c => int.TryParse(c.Number.Split(".").Head(), out int result) ? result : 0));
|
||||
int maxNumber = Optional(channelNumbers).Flatten().DefaultIfEmpty(0).Max();
|
||||
_model.Number = (maxNumber + 1).ToString();
|
||||
_model.Name = "New Channel";
|
||||
_model.FFmpegProfileId = _ffmpegProfiles.Head().Id;
|
||||
_model.FFmpegProfileId = ffmpegSettings.DefaultFFmpegProfileId;
|
||||
_model.StreamingMode = StreamingMode.TransportStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
@using System.Reflection
|
||||
@using Microsoft.AspNetCore.WebUtilities
|
||||
@using Microsoft.Extensions.Primitives
|
||||
@using System.Web
|
||||
@inherits LayoutComponentBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@@ -15,7 +17,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<MudTextField T="string"
|
||||
@ref="_textField"
|
||||
@bind-Value="@_query"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Adornment="Adornment.Start"
|
||||
Variant="Variant.Outlined"
|
||||
@@ -65,7 +67,7 @@
|
||||
@code {
|
||||
private static readonly string InfoVersion = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "unknown";
|
||||
|
||||
private MudTextField<string> _textField;
|
||||
private string _query;
|
||||
|
||||
private MudTheme _ersatzTvTheme => new()
|
||||
{
|
||||
@@ -89,12 +91,26 @@
|
||||
}
|
||||
};
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await base.OnParametersSetAsync();
|
||||
|
||||
string query = new Uri(NavigationManager.Uri).Query;
|
||||
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
|
||||
{
|
||||
_query = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_query = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
if (args.Code == "Enter")
|
||||
{
|
||||
string query = HttpUtility.UrlEncode(_textField.Value);
|
||||
_textField.Reset();
|
||||
string query = HttpUtility.UrlEncode(_query);
|
||||
NavigationManager.NavigateTo($"/search?query={query}", true);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user