Browse Source

fix searching when queries include non-ascii characters (#271)

pull/272/head
Jason Dove 5 years ago committed by GitHub
parent
commit
b580125e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 58
      ErsatzTV/Extensions/StringExtensions.cs
  3. 17
      ErsatzTV/Pages/Artist.razor
  4. 19
      ErsatzTV/Pages/ArtistList.razor
  5. 19
      ErsatzTV/Pages/EpisodeList.razor
  6. 31
      ErsatzTV/Pages/Movie.razor
  7. 19
      ErsatzTV/Pages/MovieList.razor
  8. 19
      ErsatzTV/Pages/MusicVideoList.razor
  9. 44
      ErsatzTV/Pages/Search.razor
  10. 8
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  11. 23
      ErsatzTV/Pages/TelevisionSeasonList.razor
  12. 19
      ErsatzTV/Pages/TelevisionShowList.razor
  13. 4
      ErsatzTV/Shared/LetterBar.razor
  14. 18
      ErsatzTV/Shared/MainLayout.razor

1
CHANGELOG.md

@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix blazor error font color - Fix blazor error font color
- Fix some audio stream languages missing from UI and search index - Fix some audio stream languages missing from UI and search index
- Fix audio stream selection for languages with multiple codes - Fix audio stream selection for languages with multiple codes
- Fix searching when queries contain non-ascii characters
## [0.0.46-prealpha] - 2021-06-14 ## [0.0.46-prealpha] - 2021-06-14
### Added ### Added

58
ErsatzTV/Extensions/StringExtensions.cs

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;
namespace ErsatzTV.Extensions
{
public static class StringExtensions
{
public static string GetSearchQuery(this string uri)
{
try
{
string query = new Uri(uri).Query;
Dictionary<string, StringValues> parsed = QueryHelpers.ParseQuery(query);
if (parsed.TryGetValue("query", out StringValues value))
{
return value;
}
if (parsed.TryGetValue("b64query", out StringValues base64Value))
{
return base64Value.DecodeBase64();
}
}
catch (Exception)
{
// do nothing
}
return string.Empty;
}
public static string GetRelativeSearchQuery(this string query)
{
(string key, string value) = EncodeQuery(query);
return $"/search?{key}={value}";
}
private static string DecodeBase64(this StringValues input) =>
Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(input));
public static EncodedQueryResult EncodeQuery(this string query)
{
string encoded = Uri.EscapeDataString(query);
// TODO: remove this on dotnet 6
// see https://github.com/dotnet/aspnetcore/pull/26769
var fakeAbsolute = $"https://whatever.com/test?query={encoded}";
return Uri.IsWellFormedUriString(fakeAbsolute, UriKind.Absolute)
? new EncodedQueryResult("query", encoded)
: new EncodedQueryResult("b64query", WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(query)));
}
public record EncodedQueryResult(string Key, string Value);
}
}

17
ErsatzTV/Pages/Artist.razor

@ -8,6 +8,7 @@
@using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands @using ErsatzTV.Application.ProgramSchedules.Commands
@using System.Globalization @using System.Globalization
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inject IMediator _mediator @inject IMediator _mediator
@inject IDialogService _dialog @inject IDialogService _dialog
@ -73,11 +74,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Languages:&nbsp;</MudText> <MudText GutterBottom="true">Languages:&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(_sortedLanguages.Head().EnglishName.ToLowerInvariant())}%22")">@_sortedLanguages.Head().EnglishName</MudLink> <MudLink Href="@(@$"language:""{_sortedLanguages.Head().EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedLanguages.Head().EnglishName</MudLink>
@foreach (CultureInfo language in _sortedLanguages.Skip(1)) @foreach (CultureInfo language in _sortedLanguages.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(language.EnglishName.ToLowerInvariant())}%22")">@language.EnglishName</MudLink> <MudLink Href="@(@$"language:""{language.EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@language.EnglishName</MudLink>
} }
</div> </div>
} }
@ -85,11 +86,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Genres:&nbsp;</MudText> <MudText GutterBottom="true">Genres:&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(_sortedGenres.Head())}%22")">@_sortedGenres.Head()</MudLink> <MudLink Href="@(@$"genre:""{_sortedGenres.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedGenres.Head()</MudLink>
@foreach (string genre in _sortedGenres.Skip(1)) @foreach (string genre in _sortedGenres.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(genre)}%22")">@genre</MudLink> <MudLink Href="@(@$"genre:""{genre.ToLowerInvariant()}""".GetRelativeSearchQuery())">@genre</MudLink>
} }
</div> </div>
} }
@ -97,11 +98,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Styles:&nbsp;</MudText> <MudText GutterBottom="true">Styles:&nbsp;</MudText>
<MudLink Href="@($"/search?query=style%3a%22{Uri.EscapeDataString(_sortedStyles.Head())}%22")">@_sortedStyles.Head()</MudLink> <MudLink Href="@(@$"style:""{_sortedStyles.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedStyles.Head()</MudLink>
@foreach (string style in _sortedStyles.Skip(1)) @foreach (string style in _sortedStyles.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=style%3a%22{Uri.EscapeDataString(style)}%22")">@style</MudLink> <MudLink Href="@(@$"style:""{style.ToLowerInvariant()}""".GetRelativeSearchQuery())">@style</MudLink>
} }
</div> </div>
} }
@ -109,11 +110,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Moods:&nbsp;</MudText> <MudText GutterBottom="true">Moods:&nbsp;</MudText>
<MudLink Href="@($"/search?query=mood%3a%22{Uri.EscapeDataString(_sortedMoods.Head())}%22")">@_sortedMoods.Head()</MudLink> <MudLink Href="@(@$"mood:""{_sortedMoods.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedMoods.Head()</MudLink>
@foreach (string mood in _sortedMoods.Skip(1)) @foreach (string mood in _sortedMoods.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=mood%3a%22{Uri.EscapeDataString(mood)}%22")">@mood</MudLink> <MudLink Href="@(@$"mood:""{mood.ToLowerInvariant()}""".GetRelativeSearchQuery())">@mood</MudLink>
} }
</div> </div>
} }

19
ErsatzTV/Pages/ArtistList.razor

@ -2,11 +2,11 @@
@page "/media/music/artists/page/{PageNumber:int}" @page "/media/music/artists/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess @using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<MusicVideoList> @inherits MultiSelectBase<MusicVideoList>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -90,16 +90,7 @@
PageNumber = 1; PageNumber = 1;
} }
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = null;
}
return RefreshData(); return RefreshData();
} }
@ -114,7 +105,8 @@
var uri = $"/media/music/artists/page/{PageNumber - 1}"; var uri = $"/media/music/artists/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }
@ -124,7 +116,8 @@
var uri = $"/media/music/artists/page/{PageNumber + 1}"; var uri = $"/media/music/artists/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }

19
ErsatzTV/Pages/EpisodeList.razor

@ -2,11 +2,11 @@
@page "/media/tv/episodes/page/{PageNumber:int}" @page "/media/tv/episodes/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess @using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<EpisodeList> @inherits MultiSelectBase<EpisodeList>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -90,16 +90,7 @@
PageNumber = 1; PageNumber = 1;
} }
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = null;
}
return RefreshData(); return RefreshData();
} }
@ -114,7 +105,8 @@
var uri = $"/media/tv/episodes/page/{PageNumber - 1}"; var uri = $"/media/tv/episodes/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }
@ -124,7 +116,8 @@
var uri = $"/media/tv/episodes/page/{PageNumber + 1}"; var uri = $"/media/tv/episodes/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }

31
ErsatzTV/Pages/Movie.razor

@ -5,6 +5,7 @@
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Extensions
@inject IMediator _mediator @inject IMediator _mediator
@inject IDialogService _dialog @inject IDialogService _dialog
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -67,11 +68,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Content Ratings:&nbsp;</MudText> <MudText GutterBottom="true">Content Ratings:&nbsp;</MudText>
<MudLink Href="@($"/search?query=content_rating%3a%22{Uri.EscapeDataString(_sortedContentRatings.Head())}%22")">@_sortedContentRatings.Head()</MudLink> <MudLink Href="@(@$"content_rating:""{_sortedContentRatings.Head()}""".GetRelativeSearchQuery())">@_sortedContentRatings.Head()</MudLink>
@foreach (string contentRating in _sortedContentRatings.Skip(1)) @foreach (string contentRating in _sortedContentRatings.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=content_rating%3a%22{Uri.EscapeDataString(contentRating)}%22")">@contentRating</MudLink> <MudLink Href="@(@$"content_rating:""{contentRating}""".GetRelativeSearchQuery())">@contentRating</MudLink>
} }
</div> </div>
} }
@ -79,11 +80,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Languages:&nbsp;</MudText> <MudText GutterBottom="true">Languages:&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(_sortedLanguages.Head().EnglishName.ToLowerInvariant())}%22")">@_sortedLanguages.Head().EnglishName</MudLink> <MudLink Href="@(@$"language:""{_sortedLanguages.Head().EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedLanguages.Head().EnglishName</MudLink>
@foreach (CultureInfo language in _sortedLanguages.Skip(1)) @foreach (CultureInfo language in _sortedLanguages.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(language.EnglishName.ToLowerInvariant())}%22")">@language.EnglishName</MudLink> <MudLink Href="@(@$"language:""{language.EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@language.EnglishName</MudLink>
} }
</div> </div>
} }
@ -91,11 +92,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Studios:&nbsp;</MudText> <MudText GutterBottom="true">Studios:&nbsp;</MudText>
<MudLink Href="@($"/search?query=studio%3a%22{Uri.EscapeDataString(_sortedStudios.Head())}%22")">@_sortedStudios.Head()</MudLink> <MudLink Href="@(@$"studio:""{_sortedStudios.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedStudios.Head()</MudLink>
@foreach (string studio in _sortedStudios.Skip(1)) @foreach (string studio in _sortedStudios.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=studio%3a%22{Uri.EscapeDataString(studio)}%22")">@studio</MudLink> <MudLink Href="@(@$"studio:""{studio.ToLowerInvariant()}""".GetRelativeSearchQuery())">@studio</MudLink>
} }
</div> </div>
} }
@ -103,11 +104,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Directors:&nbsp;</MudText> <MudText GutterBottom="true">Directors:&nbsp;</MudText>
<MudLink Href="@($"/search?query=director%3a%22{Uri.EscapeDataString(_sortedDirectors.Head())}%22")">@_sortedDirectors.Head()</MudLink> <MudLink Href="@(@$"director:""{_sortedDirectors.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedDirectors.Head()</MudLink>
@foreach (string director in _sortedDirectors.Skip(1)) @foreach (string director in _sortedDirectors.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=director%3a%22{Uri.EscapeDataString(director)}%22")">@director</MudLink> <MudLink Href="@(@$"director:""{director.ToLowerInvariant()}""".GetRelativeSearchQuery())">@director</MudLink>
} }
</div> </div>
} }
@ -115,11 +116,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Writers:&nbsp;</MudText> <MudText GutterBottom="true">Writers:&nbsp;</MudText>
<MudLink Href="@($"/search?query=writer%3a%22{Uri.EscapeDataString(_sortedWriters.Head())}%22")">@_sortedWriters.Head()</MudLink> <MudLink Href="@(@$"writer:""{_sortedWriters.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedWriters.Head()</MudLink>
@foreach (string writer in _sortedWriters.Skip(1)) @foreach (string writer in _sortedWriters.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=writer%3a%22{Uri.EscapeDataString(writer)}%22")">@writer</MudLink> <MudLink Href="@(@$"writer:""{writer.ToLowerInvariant()}""".GetRelativeSearchQuery())">@writer</MudLink>
} }
</div> </div>
} }
@ -127,11 +128,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Genres:&nbsp;</MudText> <MudText GutterBottom="true">Genres:&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(_sortedGenres.Head())}%22")">@_sortedGenres.Head()</MudLink> <MudLink Href="@(@$"genre:""{_sortedGenres.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedGenres.Head()</MudLink>
@foreach (string genre in _sortedGenres.Skip(1)) @foreach (string genre in _sortedGenres.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(genre)}%22")">@genre</MudLink> <MudLink Href="@(@$"genre:""{genre.ToLowerInvariant()}""".GetRelativeSearchQuery())">@genre</MudLink>
} }
</div> </div>
} }
@ -139,11 +140,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Tags:&nbsp;</MudText> <MudText GutterBottom="true">Tags:&nbsp;</MudText>
<MudLink Href="@($"/search?query=tag%3a%22{Uri.EscapeDataString(_sortedTags.Head())}%22")">@_sortedTags.Head()</MudLink> <MudLink Href="@(@$"tag:""{_sortedTags.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedTags.Head()</MudLink>
@foreach (string tag in _sortedTags.Skip(1)) @foreach (string tag in _sortedTags.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=tag%3a%22{Uri.EscapeDataString(tag)}%22")">@tag</MudLink> <MudLink Href="@(@$"tag:""{tag.ToLowerInvariant()}""".GetRelativeSearchQuery())">@tag</MudLink>
} }
</div> </div>
} }
@ -159,7 +160,7 @@
@foreach (ActorCardViewModel actor in _movie.Actors) @foreach (ActorCardViewModel actor in _movie.Actors)
{ {
<MediaCard Data="@actor" <MediaCard Data="@actor"
Link="@($"/search?query=actor%3a%22{Uri.EscapeDataString(actor.Name.ToLowerInvariant())}%22")" Link="@(@$"actor:""{actor.Name.ToLowerInvariant()}""".GetRelativeSearchQuery())"
IsRemoteArtwork="true" IsRemoteArtwork="true"
ArtworkKind="ArtworkKind.Thumbnail"/> ArtworkKind="ArtworkKind.Thumbnail"/>
} }

19
ErsatzTV/Pages/MovieList.razor

@ -2,11 +2,11 @@
@page "/media/movies/page/{PageNumber:int}" @page "/media/movies/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess @using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<MovieList> @inherits MultiSelectBase<MovieList>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -89,16 +89,7 @@
PageNumber = 1; PageNumber = 1;
} }
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = null;
}
return RefreshData(); return RefreshData();
} }
@ -113,7 +104,8 @@
var uri = $"/media/movies/page/{PageNumber - 1}"; var uri = $"/media/movies/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }
@ -123,7 +115,8 @@
var uri = $"/media/movies/page/{PageNumber + 1}"; var uri = $"/media/movies/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }

19
ErsatzTV/Pages/MusicVideoList.razor

@ -2,11 +2,11 @@
@page "/media/music/videos/page/{PageNumber:int}" @page "/media/music/videos/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess @using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<MusicVideoList> @inherits MultiSelectBase<MusicVideoList>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -90,16 +90,7 @@
PageNumber = 1; PageNumber = 1;
} }
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = null;
}
return RefreshData(); return RefreshData();
} }
@ -114,7 +105,8 @@
var uri = $"/media/music/videos/page/{PageNumber - 1}"; var uri = $"/media/music/videos/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }
@ -124,7 +116,8 @@
var uri = $"/media/music/videos/page/{PageNumber + 1}"; var uri = $"/media/music/videos/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }

44
ErsatzTV/Pages/Search.razor

@ -4,8 +4,8 @@
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search @using ErsatzTV.Application.Search
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<Search> @inherits MultiSelectBase<Search>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -35,27 +35,27 @@
else else
{ {
<MudText Style="margin-bottom: auto; margin-top: auto">@_query</MudText> <MudText Style="margin-bottom: auto; margin-top: auto">@_query</MudText>
if (_movies.Count > 0) if (_movies?.Count > 0)
{ {
<MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#movies")" Style="margin-bottom: auto; margin-top: auto">@_movies.Count Movies</MudLink> <MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#movies")" Style="margin-bottom: auto; margin-top: auto">@_movies.Count Movies</MudLink>
} }
if (_shows.Count > 0) if (_shows?.Count > 0)
{ {
<MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#shows")" Style="margin-bottom: auto; margin-top: auto">@_shows.Count Shows</MudLink> <MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#shows")" Style="margin-bottom: auto; margin-top: auto">@_shows.Count Shows</MudLink>
} }
if (_episodes.Count > 0) if (_episodes?.Count > 0)
{ {
<MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#episodes")" Style="margin-bottom: auto; margin-top: auto">@_episodes.Count Episodes</MudLink> <MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#episodes")" Style="margin-bottom: auto; margin-top: auto">@_episodes.Count Episodes</MudLink>
} }
if (_artists.Count > 0) if (_artists?.Count > 0)
{ {
<MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#artists")" Style="margin-bottom: auto; margin-top: auto">@_artists.Count Artists</MudLink> <MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#artists")" Style="margin-bottom: auto; margin-top: auto">@_artists.Count Artists</MudLink>
} }
if (_musicVideos.Count > 0) if (_musicVideos?.Count > 0)
{ {
<MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#music_videos")" Style="margin-bottom: auto; margin-top: auto">@_musicVideos.Count Music Videos</MudLink> <MudLink Class="ml-4" Href="@(_navigationManager.Uri.Split("#").Head() + "#music_videos")" Style="margin-bottom: auto; margin-top: auto">@_musicVideos.Count Music Videos</MudLink>
} }
@ -71,7 +71,7 @@
</div> </div>
</MudPaper> </MudPaper>
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Style="margin-top: 96px"> <MudContainer MaxWidth="MaxWidth.ExtraLarge" Style="margin-top: 96px">
@if (_movies.Count > 0) @if (_movies?.Count > 0)
{ {
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;"> <div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4" <MudText Typo="Typo.h4"
@ -98,7 +98,7 @@
</MudContainer> </MudContainer>
} }
@if (_shows.Count > 0) @if (_shows?.Count > 0)
{ {
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;"> <div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4" <MudText Typo="Typo.h4"
@ -125,7 +125,7 @@
</MudContainer> </MudContainer>
} }
@if (_episodes.Count > 0) @if (_episodes?.Count > 0)
{ {
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;"> <div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4" <MudText Typo="Typo.h4"
@ -153,7 +153,7 @@
</MudContainer> </MudContainer>
} }
@if (_artists.Count > 0) @if (_artists?.Count > 0)
{ {
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;"> <div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4" <MudText Typo="Typo.h4"
@ -181,7 +181,7 @@
</MudContainer> </MudContainer>
} }
@if (_musicVideos.Count > 0) @if (_musicVideos?.Count > 0)
{ {
<div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;"> <div class="mb-4" style="align-items: baseline; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4" <MudText Typo="Typo.h4"
@ -220,12 +220,9 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (!string.IsNullOrWhiteSpace(_query))
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{ {
_query = value;
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50)); _movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50));
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50)); _shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50));
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50)); _episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50));
@ -362,7 +359,8 @@
var uri = "/media/movies/page/1"; var uri = "/media/movies/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri; return uri;
} }
@ -372,7 +370,8 @@
var uri = "/media/tv/shows/page/1"; var uri = "/media/tv/shows/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri; return uri;
} }
@ -382,7 +381,8 @@
var uri = "/media/tv/episodes/page/1"; var uri = "/media/tv/episodes/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri; return uri;
} }
@ -392,7 +392,8 @@
var uri = "/media/music/artists/page/1"; var uri = "/media/music/artists/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri; return uri;
} }
@ -402,7 +403,8 @@
var uri = "/media/music/videos/page/1"; var uri = "/media/music/videos/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri; return uri;
} }

8
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -116,11 +116,11 @@
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Directors:&nbsp;</MudText> <MudText GutterBottom="true">Directors:&nbsp;</MudText>
<MudLink Href="@($"/search?query=director%3a%22{Uri.EscapeDataString(sorted.Head())}%22")">@sorted.Head()</MudLink> <MudLink Href="@(@$"director:""{sorted.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@sorted.Head()</MudLink>
@foreach (string director in sorted.Skip(1)) @foreach (string director in sorted.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=director%3a%22{Uri.EscapeDataString(director)}%22")">@director</MudLink> <MudLink Href="@(@$"director:""{director.ToLowerInvariant()}""".GetRelativeSearchQuery())">@director</MudLink>
} }
</div> </div>
} }
@ -130,11 +130,11 @@
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Writers:&nbsp;</MudText> <MudText GutterBottom="true">Writers:&nbsp;</MudText>
<MudLink Href="@($"/search?query=writer%3a%22{Uri.EscapeDataString(sorted.Head())}%22")">@sorted.Head()</MudLink> <MudLink Href="@(@$"writer:""{sorted.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@sorted.Head()</MudLink>
@foreach (string writer in sorted.Skip(1)) @foreach (string writer in sorted.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=writer%3a%22{Uri.EscapeDataString(writer)}%22")">@writer</MudLink> <MudLink Href="@(@$"writer:""{writer.ToLowerInvariant()}""".GetRelativeSearchQuery())">@writer</MudLink>
} }
</div> </div>
} }

23
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -8,6 +8,7 @@
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands @using ErsatzTV.Application.ProgramSchedules.Commands
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inject IMediator _mediator @inject IMediator _mediator
@inject ILogger<TelevisionSeasonList> _logger @inject ILogger<TelevisionSeasonList> _logger
@ -81,11 +82,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Content Ratings:&nbsp;</MudText> <MudText GutterBottom="true">Content Ratings:&nbsp;</MudText>
<MudLink Href="@($"/search?query=content_rating%3a%22{Uri.EscapeDataString(_sortedContentRatings.Head())}%22")">@_sortedContentRatings.Head()</MudLink> <MudLink Href="@(@$"content_rating:""{_sortedContentRatings.Head()}""".GetRelativeSearchQuery())">@_sortedContentRatings.Head()</MudLink>
@foreach (string contentRating in _sortedContentRatings.Skip(1)) @foreach (string contentRating in _sortedContentRatings.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=content_rating%3a%22{Uri.EscapeDataString(contentRating)}%22")">@contentRating</MudLink> <MudLink Href="@(@$"content_rating:""{contentRating}""".GetRelativeSearchQuery())">@contentRating</MudLink>
} }
</div> </div>
} }
@ -93,11 +94,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Languages:&nbsp;</MudText> <MudText GutterBottom="true">Languages:&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(_sortedLanguages.Head().EnglishName.ToLowerInvariant())}%22")">@_sortedLanguages.Head().EnglishName</MudLink> <MudLink Href="@(@$"language:""{_sortedLanguages.Head().EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedLanguages.Head().EnglishName</MudLink>
@foreach (CultureInfo language in _sortedLanguages.Skip(1)) @foreach (CultureInfo language in _sortedLanguages.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=language%3a%22{Uri.EscapeDataString(language.EnglishName.ToLowerInvariant())}%22")">@language.EnglishName</MudLink> <MudLink Href="@(@$"language:""{language.EnglishName.ToLowerInvariant()}""".GetRelativeSearchQuery())">@language.EnglishName</MudLink>
} }
</div> </div>
} }
@ -105,11 +106,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Studios:&nbsp;</MudText> <MudText GutterBottom="true">Studios:&nbsp;</MudText>
<MudLink Href="@($"/search?query=studio%3a%22{Uri.EscapeDataString(_sortedStudios.Head())}%22")">@_sortedStudios.Head()</MudLink> <MudLink Href="@(@$"studio:""{_sortedStudios.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedStudios.Head()</MudLink>
@foreach (string studio in _sortedStudios.Skip(1)) @foreach (string studio in _sortedStudios.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=studio%3a%22{Uri.EscapeDataString(studio)}%22")">@studio</MudLink> <MudLink Href="@(@$"studio:""{studio.ToLowerInvariant()}""".GetRelativeSearchQuery())">@studio</MudLink>
} }
</div> </div>
} }
@ -117,11 +118,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Genres:&nbsp;</MudText> <MudText GutterBottom="true">Genres:&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(_sortedGenres.Head())}%22")">@_sortedGenres.Head()</MudLink> <MudLink Href="@(@$"genre:""{_sortedGenres.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedGenres.Head()</MudLink>
@foreach (string genre in _sortedGenres.Skip(1)) @foreach (string genre in _sortedGenres.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=genre%3a%22{Uri.EscapeDataString(genre)}%22")">@genre</MudLink> <MudLink Href="@(@$"genre:""{genre.ToLowerInvariant()}""".GetRelativeSearchQuery())">@genre</MudLink>
} }
</div> </div>
} }
@ -129,11 +130,11 @@
{ {
<div style="display: flex; flex-direction: row; flex-wrap: wrap"> <div style="display: flex; flex-direction: row; flex-wrap: wrap">
<MudText GutterBottom="true">Tags:&nbsp;</MudText> <MudText GutterBottom="true">Tags:&nbsp;</MudText>
<MudLink Href="@($"/search?query=tag%3a%22{Uri.EscapeDataString(_sortedTags.Head())}%22")">@_sortedTags.Head()</MudLink> <MudLink Href="@(@$"tag:""{_sortedTags.Head().ToLowerInvariant()}""".GetRelativeSearchQuery())">@_sortedTags.Head()</MudLink>
@foreach (string tag in _sortedTags.Skip(1)) @foreach (string tag in _sortedTags.Skip(1))
{ {
<MudText>,&nbsp;</MudText> <MudText>,&nbsp;</MudText>
<MudLink Href="@($"/search?query=tag%3a%22{Uri.EscapeDataString(tag)}%22")">@tag</MudLink> <MudLink Href="@(@$"tag:""{tag.ToLowerInvariant()}""".GetRelativeSearchQuery())">@tag</MudLink>
} }
</div> </div>
} }
@ -160,7 +161,7 @@
@foreach (ActorCardViewModel actor in _show.Actors) @foreach (ActorCardViewModel actor in _show.Actors)
{ {
<MediaCard Data="@actor" <MediaCard Data="@actor"
Link="@($"/search?query=actor%3a%22{Uri.EscapeDataString(actor.Name.ToLowerInvariant())}%22")" Link="@(@$"actor:""{actor.Name.ToLowerInvariant()}""".GetRelativeSearchQuery())"
IsRemoteArtwork="true" IsRemoteArtwork="true"
ArtworkKind="ArtworkKind.Thumbnail"/> ArtworkKind="ArtworkKind.Thumbnail"/>
} }

19
ErsatzTV/Pages/TelevisionShowList.razor

@ -2,11 +2,11 @@
@page "/media/tv/shows/page/{PageNumber:int}" @page "/media/tv/shows/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess @using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using ErsatzTV.Application.MediaCards @using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Search.Queries @using ErsatzTV.Application.Search.Queries
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit @using Unit = LanguageExt.Unit
@inherits MultiSelectBase<TelevisionShowList> @inherits MultiSelectBase<TelevisionShowList>
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -89,16 +89,7 @@
PageNumber = 1; PageNumber = 1;
} }
string query = new Uri(_navigationManager.Uri).Query; _query = _navigationManager.Uri.GetSearchQuery();
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = null;
}
return RefreshData(); return RefreshData();
} }
@ -113,7 +104,8 @@
var uri = $"/media/tv/shows/page/{PageNumber - 1}"; var uri = $"/media/tv/shows/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }
@ -123,7 +115,8 @@
var uri = $"/media/tv/shows/page/{PageNumber + 1}"; var uri = $"/media/tv/shows/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", _query); (string key, string value) = _query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
_navigationManager.NavigateTo(uri); _navigationManager.NavigateTo(uri);
} }

4
ErsatzTV/Shared/LetterBar.razor

@ -1,4 +1,5 @@
@using ErsatzTV.Core.Search @using ErsatzTV.Core.Search
@using ErsatzTV.Extensions
@using Microsoft.AspNetCore.WebUtilities @using Microsoft.AspNetCore.WebUtilities
<div class="letter-bar-container"> <div class="letter-bar-container">
<div class="letter-bar"> <div class="letter-bar">
@ -48,7 +49,8 @@
var uri = $"{BaseUri}/page/{PageMap.PageMap[letter]}"; var uri = $"{BaseUri}/page/{PageMap.PageMap[letter]}";
if (!string.IsNullOrWhiteSpace(Query)) if (!string.IsNullOrWhiteSpace(Query))
{ {
uri = QueryHelpers.AddQueryString(uri, "query", Query); (string key, string value) = Query.EncodeQuery();
uri = $"{uri}?{key}={value}";
} }
return uri + $"#letter-{letter}"; return uri + $"#letter-{letter}";
} }

18
ErsatzTV/Shared/MainLayout.razor

@ -1,7 +1,5 @@
@using System.Reflection @using System.Reflection
@using Microsoft.AspNetCore.WebUtilities @using ErsatzTV.Extensions
@using Microsoft.Extensions.Primitives
@using System.Web
@inherits LayoutComponentBase @inherits LayoutComponentBase
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
@ -107,22 +105,12 @@
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
await base.OnParametersSetAsync(); await base.OnParametersSetAsync();
_query = _navigationManager.Uri.GetSearchQuery();
string query = new Uri(_navigationManager.Uri).Query;
if (QueryHelpers.ParseQuery(query).TryGetValue("query", out StringValues value))
{
_query = value;
}
else
{
_query = string.Empty;
}
} }
private void PerformSearch() private void PerformSearch()
{ {
string query = HttpUtility.UrlEncode(_query); _navigationManager.NavigateTo(_query.GetRelativeSearchQuery(), true);
_navigationManager.NavigateTo($"/search?query={query}", true);
StateHasChanged(); StateHasChanged();
} }

Loading…
Cancel
Save