Browse Source

proxy server improvements (#996)

pull/997/head
Jason Dove 4 years ago committed by GitHub
parent
commit
2ce0fcb264
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 2
      ErsatzTV.Infrastructure/Health/Checks/FileNotFoundHealthCheck.cs
  3. 2
      ErsatzTV.Infrastructure/Health/Checks/UnavailableHealthCheck.cs
  4. 8
      ErsatzTV/Controllers/IptvController.cs
  5. 2
      ErsatzTV/Extensions/StringExtensions.cs
  6. 10
      ErsatzTV/Pages/Artist.razor
  7. 8
      ErsatzTV/Pages/ArtistList.razor
  8. 4
      ErsatzTV/Pages/Channels.razor
  9. 2
      ErsatzTV/Pages/CollectionEditor.razor
  10. 12
      ErsatzTV/Pages/CollectionItems.razor
  11. 8
      ErsatzTV/Pages/Collections.razor
  12. 8
      ErsatzTV/Pages/EpisodeList.razor
  13. 8
      ErsatzTV/Pages/FFmpeg.razor
  14. 2
      ErsatzTV/Pages/FillerPresetEditor.razor
  15. 4
      ErsatzTV/Pages/FillerPresets.razor
  16. 2
      ErsatzTV/Pages/Libraries.razor
  17. 4
      ErsatzTV/Pages/LocalLibraries.razor
  18. 4
      ErsatzTV/Pages/LocalLibraryEditor.razor
  19. 2
      ErsatzTV/Pages/LocalLibraryPathEditor.razor
  20. 6
      ErsatzTV/Pages/Movie.razor
  21. 8
      ErsatzTV/Pages/MovieList.razor
  22. 2
      ErsatzTV/Pages/MultiCollectionEditor.razor
  23. 6
      ErsatzTV/Pages/MusicVideoList.razor
  24. 6
      ErsatzTV/Pages/OtherVideoList.razor
  25. 2
      ErsatzTV/Pages/Playouts.razor
  26. 4
      ErsatzTV/Pages/PlexMediaSources.razor
  27. 6
      ErsatzTV/Pages/Schedules.razor
  28. 26
      ErsatzTV/Pages/Search.razor
  29. 6
      ErsatzTV/Pages/SongList.razor
  30. 12
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  31. 10
      ErsatzTV/Pages/TelevisionSeasonList.razor
  32. 8
      ErsatzTV/Pages/TelevisionSeasonSearchResults.razor
  33. 8
      ErsatzTV/Pages/TelevisionShowList.razor
  34. 2
      ErsatzTV/Pages/TraktLists.razor
  35. 26
      ErsatzTV/Pages/Trash.razor
  36. 4
      ErsatzTV/Pages/Watermarks.razor
  37. 2
      ErsatzTV/Pages/_Host.cshtml
  38. 50
      ErsatzTV/Shared/MainLayout.razor
  39. 2
      ErsatzTV/Shared/MediaCard.razor
  40. 2
      ErsatzTV/Shared/RemoteMediaSourceEditor.razor
  41. 2
      ErsatzTV/Shared/RemoteMediaSourceLibrariesEditor.razor
  42. 2
      ErsatzTV/Shared/RemoteMediaSourcePathReplacementsEditor.razor
  43. 8
      ErsatzTV/Shared/RemoteMediaSources.razor
  44. 10
      ErsatzTV/Startup.cs

2
CHANGELOG.md

@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix bug where tail or fallback filler would sometimes schedule much longer than expected - Fix bug where tail or fallback filler would sometimes schedule much longer than expected
- This only happened with fixed start schedule items following a schedule item with tail or fallback filler - This only happened with fixed start schedule items following a schedule item with tail or fallback filler
- Fix NFO reader bug that caused inaccurate warning messages about invalid XML and incomplete metadata - Fix NFO reader bug that caused inaccurate warning messages about invalid XML and incomplete metadata
- Fix reverse proxy SSL termination support by supporting `X-Forwarded-Proto` header
### Added ### Added
- Add music video credits template system - Add music video credits template system
@ -37,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- All groups of part numbers (i.e. all part 1s, all part 2s) will be shuffled - All groups of part numbers (i.e. all part 1s, all part 2s) will be shuffled
- The playout order will then schedule a random part 1 followed by a random part 2, etc - The playout order will then schedule a random part 1 followed by a random part 2, etc
- Un-split (`nil`) episodes will be randomly placed between re-combined parts (e.g. part1, part2, part3, un-split, part1, part2, part3) - Un-split (`nil`) episodes will be randomly placed between re-combined parts (e.g. part1, part2, part3, un-split, part1, part2, part3)
- Add `ETV_BASE_URL` environment variable to support reverse proxies that use paths (e.g. `/ersatztv`)
### Changed ### Changed
- No longer place watermarks within content by default (e.g. within 4:3 content padded to a 16:9 resolution) - No longer place watermarks within content by default (e.g. within 4:3 content padded to a 16:9 resolution)

2
ErsatzTV.Infrastructure/Health/Checks/FileNotFoundHealthCheck.cs

@ -58,7 +58,7 @@ public class FileNotFoundHealthCheck : BaseHealthCheck, IFileNotFoundHealthCheck
return WarningResult( return WarningResult(
$"There are {count} items that do not exist on disk, including the following: {files}", $"There are {count} items that do not exist on disk, including the following: {files}",
"/media/trash"); "media/trash");
} }
return OkResult(); return OkResult();

2
ErsatzTV.Infrastructure/Health/Checks/UnavailableHealthCheck.cs

@ -83,7 +83,7 @@ public class UnavailableHealthCheck : BaseHealthCheck, IUnavailableHealthCheck
return WarningResult( return WarningResult(
$"There are {count} items that are unavailable because ErsatzTV cannot find them on disk, including the following: {files}", $"There are {count} items that are unavailable because ErsatzTV cannot find them on disk, including the following: {files}",
"/search?query=state%3aUnavailable"); "search?query=state%3aUnavailable");
} }
return OkResult(); return OkResult();

8
ErsatzTV/Controllers/IptvController.cs

@ -77,7 +77,7 @@ public class IptvController : ControllerBase
mode = "ts"; mode = "ts";
break; break;
default: default:
return Redirect($"/iptv/channel/{channelNumber}.m3u8"); return Redirect($"~/iptv/channel/{channelNumber}.m3u8");
} }
} }
} }
@ -167,7 +167,7 @@ public class IptvController : ControllerBase
mode = "segmenter"; mode = "segmenter";
break; break;
default: default:
return Redirect($"/iptv/channel/{channelNumber}.ts"); return Redirect($"~/iptv/channel/{channelNumber}.ts");
} }
} }
} }
@ -184,7 +184,7 @@ public class IptvController : ControllerBase
"Session started; returning multi-variant playlist for channel {Channel}", "Session started; returning multi-variant playlist for channel {Channel}",
channelNumber); channelNumber);
return Content(GetMultiVariantPlaylist(channelNumber), "application/x-mpegurl"); return Content(GetMultiVariantPlaylist(channelNumber), "application/x-mpegurl");
// return Redirect($"/iptv/session/{channelNumber}/hls.m3u8"); // return Redirect($"~/iptv/session/{channelNumber}/hls.m3u8");
}, },
error => error =>
{ {
@ -195,7 +195,7 @@ public class IptvController : ControllerBase
"Session is already active; returning multi-variant playlist for channel {Channel}", "Session is already active; returning multi-variant playlist for channel {Channel}",
channelNumber); channelNumber);
return Content(GetMultiVariantPlaylist(channelNumber), "application/x-mpegurl"); return Content(GetMultiVariantPlaylist(channelNumber), "application/x-mpegurl");
// return RedirectPreserveMethod($"/iptv/session/{channelNumber}/hls.m3u8"); // return RedirectPreserveMethod($"iptv/session/{channelNumber}/hls.m3u8");
default: default:
_logger.LogWarning( _logger.LogWarning(
"Failed to start segmenter for channel {ChannelNumber}: {Error}", "Failed to start segmenter for channel {ChannelNumber}: {Error}",

2
ErsatzTV/Extensions/StringExtensions.cs

@ -33,7 +33,7 @@ public static class StringExtensions
public static string GetRelativeSearchQuery(this string query) public static string GetRelativeSearchQuery(this string query)
{ {
(string key, string value) = EncodeQuery(query); (string key, string value) = EncodeQuery(query);
return $"/search?{key}={value}"; return $"search?{key}={value}";
} }
private static string DecodeBase64(this StringValues input) => private static string DecodeBase64(this StringValues input) =>

10
ErsatzTV/Pages/Artist.razor

@ -16,7 +16,7 @@
<div class="fanart-tint"></div> <div class="fanart-tint"></div>
@if (!string.IsNullOrWhiteSpace(_artist.FanArt)) @if (!string.IsNullOrWhiteSpace(_artist.FanArt))
{ {
<img src="@($"/artwork/fanart/{_artist.FanArt}")" alt="fan art"/> <img src="@($"artwork/fanart/{_artist.FanArt}")" alt="fan art"/>
} }
</MudContainer> </MudContainer>
<MudContainer MaxWidth="MaxWidth.Large" Style="margin-top: 200px"> <MudContainer MaxWidth="MaxWidth.Large" Style="margin-top: 200px">
@ -25,7 +25,7 @@
{ {
<img class="mud-elevation-2 mr-6" <img class="mud-elevation-2 mr-6"
style="border-radius: 4px; flex-shrink: 0; height: 220px; width: 220px" style="border-radius: 4px; flex-shrink: 0; height: 220px; width: 220px"
src="@($"/artwork/thumbnails/{_artist.Thumbnail}")" alt="artist thumbnail"/> src="@($"artwork/thumbnails/{_artist.Thumbnail}")" alt="artist thumbnail"/>
} }
<div style="display: flex; flex-direction: column; height: 100%"> <div style="display: flex; flex-direction: column; height: 100%">
<MudText Typo="Typo.h2" Class="media-item-title">@_artist.Name</MudText> <MudText Typo="Typo.h2" Class="media-item-title">@_artist.Name</MudText>
@ -125,7 +125,7 @@
@if (!string.IsNullOrWhiteSpace(musicVideo.Poster)) @if (!string.IsNullOrWhiteSpace(musicVideo.Poster))
{ {
<MudPaper style="display: flex; flex-direction: column; position: relative"> <MudPaper style="display: flex; flex-direction: column; position: relative">
<MudCardMedia Image="@($"/artwork/thumbnails/{musicVideo.Poster}")" Style="flex-grow: 1; height: 220px; width: 293px;"/> <MudCardMedia Image="@($"artwork/thumbnails/{musicVideo.Poster}")" Style="flex-grow: 1; height: 220px; width: 293px;"/>
@if (musicVideo.State == MediaItemState.FileNotFound) @if (musicVideo.State == MediaItemState.FileNotFound)
{ {
<div style="position: absolute; right: 10px; top: 8px;"> <div style="position: absolute; right: 10px; top: 8px;">
@ -245,7 +245,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{ {
await _mediator.Send(new AddArtistToCollection(collection.Id, ArtistId), _cts.Token); await _mediator.Send(new AddArtistToCollection(collection.Id, ArtistId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}"); _navigationManager.NavigateTo($"media/collections/{collection.Id}");
} }
} }
@ -259,7 +259,7 @@
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{ {
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token); await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"schedules/{schedule.Id}/items");
} }
} }

8
ErsatzTV/Pages/ArtistList.razor

@ -55,7 +55,7 @@
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> <MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
<FragmentLetterAnchor TCard="ArtistCardViewModel" Cards="@_data.Cards"> <FragmentLetterAnchor TCard="ArtistCardViewModel" Cards="@_data.Cards">
<MediaCard Data="@context" <MediaCard Data="@context"
Link="@($"/media/music/artists/{context.ArtistId}")" Link="@($"media/music/artists/{context.ArtistId}")"
ArtworkKind="ArtworkKind.Thumbnail" ArtworkKind="ArtworkKind.Thumbnail"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(context, e))" SelectClicked="@(e => SelectClicked(context, e))"
@ -67,7 +67,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/music/artists" BaseUri="media/music/artists"
Query="@_query"/> Query="@_query"/>
} }
@ -99,7 +99,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/music/artists/page/{PageNumber - 1}"; string uri = $"media/music/artists/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -110,7 +110,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/music/artists/page/{PageNumber + 1}"; string uri = $"media/music/artists/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

4
ErsatzTV/Pages/Channels.razor

@ -58,7 +58,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Channel"> <MudTooltip Text="Edit Channel">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/channels/{context.Id}")"> Link="@($"channels/{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Channel"> <MudTooltip Text="Delete Channel">
@ -73,7 +73,7 @@
<MudTablePager/> <MudTablePager/>
</PagerContent> </PagerContent>
</MudTable> </MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/channels/add" Class="mt-4"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="channels/add" Class="mt-4">
Add Channel Add Channel
</MudButton> </MudButton>
</MudContainer> </MudContainer>

2
ErsatzTV/Pages/CollectionEditor.razor

@ -83,7 +83,7 @@
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);
_logger.LogError("Error saving collection: {Error}", error.Value); _logger.LogError("Error saving collection: {Error}", error.Value);
}, },
() => _navigationManager.NavigateTo(_model.Id > 0 ? $"/media/collections/{_model.Id}" : "/media/collections")); () => _navigationManager.NavigateTo(_model.Id > 0 ? $"media/collections/{_model.Id}" : "media/collections"));
} }
} }

12
ErsatzTV/Pages/CollectionItems.razor

@ -32,7 +32,7 @@
<div style="align-items: center; display: flex; flex-direction: row;"> <div style="align-items: center; display: flex; flex-direction: row;">
<MudText Typo="Typo.h4">@_data.Name</MudText> <MudText Typo="Typo.h4">@_data.Name</MudText>
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/media/collections/{Id}/edit")"/> Link="@($"media/collections/{Id}/edit")"/>
</div> </div>
@if (_data.MovieCards.Any()) @if (_data.MovieCards.Any())
{ {
@ -95,7 +95,7 @@
@foreach (MovieCardViewModel card in OrderMovies(_data.MovieCards)) @foreach (MovieCardViewModel card in OrderMovies(_data.MovieCards))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/movies/{card.MovieId}")" Link="@($"media/movies/{card.MovieId}")"
DeleteClicked="@RemoveMovieFromCollection" DeleteClicked="@RemoveMovieFromCollection"
SelectColor="@Color.Error" SelectColor="@Color.Error"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -118,7 +118,7 @@
@foreach (TelevisionShowCardViewModel card in _data.ShowCards.OrderBy(m => m.SortTitle)) @foreach (TelevisionShowCardViewModel card in _data.ShowCards.OrderBy(m => m.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/shows/{card.TelevisionShowId}")" Link="@($"media/tv/shows/{card.TelevisionShowId}")"
DeleteClicked="@RemoveShowFromCollection" DeleteClicked="@RemoveShowFromCollection"
SelectColor="@Color.Error" SelectColor="@Color.Error"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -141,7 +141,7 @@
@foreach (TelevisionSeasonCardViewModel card in _data.SeasonCards.OrderBy(m => m.SortTitle)) @foreach (TelevisionSeasonCardViewModel card in _data.SeasonCards.OrderBy(m => m.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/seasons/{card.TelevisionSeasonId}")" Link="@($"media/tv/seasons/{card.TelevisionSeasonId}")"
Title="@card.ShowTitle" Title="@card.ShowTitle"
Subtitle="@card.Title" Subtitle="@card.Title"
DeleteClicked="@RemoveSeasonFromCollection" DeleteClicked="@RemoveSeasonFromCollection"
@ -166,7 +166,7 @@
@foreach (TelevisionEpisodeCardViewModel card in _data.EpisodeCards.OrderBy(e => e.Aired)) @foreach (TelevisionEpisodeCardViewModel card in _data.EpisodeCards.OrderBy(e => e.Aired))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")" Link="@($"media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")"
Title="@card.ShowTitle" Title="@card.ShowTitle"
Subtitle="@card.Title" Subtitle="@card.Title"
ContainerClass="media-card-episode-container mx-2" ContainerClass="media-card-episode-container mx-2"
@ -194,7 +194,7 @@
@foreach (ArtistCardViewModel card in _data.ArtistCards.OrderBy(e => e.SortTitle)) @foreach (ArtistCardViewModel card in _data.ArtistCards.OrderBy(e => e.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/music/artists/{card.ArtistId}")" Link="@($"media/music/artists/{card.ArtistId}")"
ArtworkKind="ArtworkKind.Thumbnail" ArtworkKind="ArtworkKind.Thumbnail"
DeleteClicked="@RemoveArtistFromCollection" DeleteClicked="@RemoveArtistFromCollection"
SelectColor="@Color.Error" SelectColor="@Color.Error"

8
ErsatzTV/Pages/Collections.razor

@ -8,10 +8,10 @@
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8"> <MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<div> <div>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/media/collections/add"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="media/collections/add">
Add Collection Add Collection
</MudButton> </MudButton>
<MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Primary" Link="/media/multi-collections/add"> <MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Primary" Link="media/multi-collections/add">
Add Multi Collection Add Multi Collection
</MudButton> </MudButton>
</div> </div>
@ -38,7 +38,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Collection"> <MudTooltip Text="Edit Collection">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/media/collections/{context.Id}")"> Link="@($"media/collections/{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Collection"> <MudTooltip Text="Delete Collection">
@ -76,7 +76,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Collection"> <MudTooltip Text="Edit Collection">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/media/multi-collections/{context.Id}/edit")"> Link="@($"media/multi-collections/{context.Id}/edit")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Collection"> <MudTooltip Text="Delete Collection">

8
ErsatzTV/Pages/EpisodeList.razor

@ -55,7 +55,7 @@
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> <MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
<FragmentLetterAnchor TCard="TelevisionEpisodeCardViewModel" Cards="@_data.Cards"> <FragmentLetterAnchor TCard="TelevisionEpisodeCardViewModel" Cards="@_data.Cards">
<MediaCard Data="@context" <MediaCard Data="@context"
Link="@($"/media/tv/seasons/{context.SeasonId}#episode-{context.EpisodeId}")" Link="@($"media/tv/seasons/{context.SeasonId}#episode-{context.EpisodeId}")"
Subtitle="@($"{context.ShowTitle} - S{context.Season} E{context.Episode}")" Subtitle="@($"{context.ShowTitle} - S{context.Season} E{context.Episode}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(context, e))" SelectClicked="@(e => SelectClicked(context, e))"
@ -67,7 +67,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/tv/episodes" BaseUri="media/tv/episodes"
Query="@_query"/> Query="@_query"/>
} }
@ -99,7 +99,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/tv/episodes/page/{PageNumber - 1}"; string uri = $"media/tv/episodes/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -110,7 +110,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/tv/episodes/page/{PageNumber + 1}"; string uri = $"media/tv/episodes/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

8
ErsatzTV/Pages/FFmpeg.razor

@ -3,8 +3,6 @@
@implements IDisposable @implements IDisposable
@inject IDialogService _dialog @inject IDialogService _dialog
@inject IMediator _mediator @inject IMediator _mediator
@inject ILogger<FFmpeg> _logger
@inject ISnackbar _snackbar
@inject NavigationManager _navigationManager @inject NavigationManager _navigationManager
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8"> <MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
@ -44,7 +42,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Profile"> <MudTooltip Text="Edit Profile">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/ffmpeg/{context.Id}")"> Link="@($"ffmpeg/{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Copy Profile"> <MudTooltip Text="Copy Profile">
@ -61,7 +59,7 @@
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/ffmpeg/add" Class="mt-4"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="ffmpeg/add" Class="mt-4">
Add Profile Add Profile
</MudButton> </MudButton>
</MudContainer> </MudContainer>
@ -105,7 +103,7 @@
DialogResult dialogResult = await dialog.Result; DialogResult dialogResult = await dialog.Result;
if (!dialogResult.Cancelled && dialogResult.Data is FFmpegProfileViewModel data) if (!dialogResult.Cancelled && dialogResult.Data is FFmpegProfileViewModel data)
{ {
_navigationManager.NavigateTo($"/ffmpeg/{data.Id}"); _navigationManager.NavigateTo($"ffmpeg/{data.Id}");
} }
} }

2
ErsatzTV/Pages/FillerPresetEditor.razor

@ -230,7 +230,7 @@
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);
_logger.LogError("Error saving filler preset: {Error}", error.Value); _logger.LogError("Error saving filler preset: {Error}", error.Value);
}, },
() => _navigationManager.NavigateTo("/media/filler/presets")); () => _navigationManager.NavigateTo("media/filler/presets"));
} }
} }

4
ErsatzTV/Pages/FillerPresets.razor

@ -8,7 +8,7 @@
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8"> <MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<div> <div>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/media/filler/presets/add"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="media/filler/presets/add">
Add Filler Preset Add Filler Preset
</MudButton> </MudButton>
</div> </div>
@ -49,7 +49,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Filler Preset"> <MudTooltip Text="Edit Filler Preset">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/media/filler/presets/{context.Id}/edit")"> Link="@($"media/filler/presets/{context.Id}/edit")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Filler Preset"> <MudTooltip Text="Delete Filler Preset">

2
ErsatzTV/Pages/Libraries.razor

@ -77,7 +77,7 @@
} }
<MudTooltip Text="Search Library"> <MudTooltip Text="Search Library">
<MudIconButton Icon="@Icons.Material.Filled.Search" <MudIconButton Icon="@Icons.Material.Filled.Search"
Link="@($"/search?query=library_id%3a{context.Id}")"> Link="@($"search?query=library_id%3a{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
</div> </div>

4
ErsatzTV/Pages/LocalLibraries.razor

@ -32,7 +32,7 @@
<MudTooltip Text="Edit Library"> <MudTooltip Text="Edit Library">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Disabled="@_locker.IsLibraryLocked(context.Id)" Disabled="@_locker.IsLibraryLocked(context.Id)"
Link="@($"/media/sources/local/{context.Id}/edit")"> Link="@($"media/sources/local/{context.Id}/edit")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Library"> <MudTooltip Text="Delete Library">
@ -45,7 +45,7 @@
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/media/sources/local/add" Class="mt-4"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="media/sources/local/add" Class="mt-4">
Add Local Library Add Local Library
</MudButton> </MudButton>
</MudContainer> </MudContainer>

4
ErsatzTV/Pages/LocalLibraryEditor.razor

@ -148,7 +148,7 @@
var request = new MoveLocalLibraryPath(libraryPath.Id, library.Id); var request = new MoveLocalLibraryPath(libraryPath.Id, library.Id);
Either<BaseError, Unit> moveResult = await _mediator.Send(request, _cts.Token); Either<BaseError, Unit> moveResult = await _mediator.Send(request, _cts.Token);
moveResult.Match( moveResult.Match(
_ => _navigationManager.NavigateTo($"/media/sources/local/{library.Id}/edit"), _ => _navigationManager.NavigateTo($"media/sources/local/{library.Id}/edit"),
error => error =>
{ {
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);
@ -214,7 +214,7 @@
_model.Paths.Map(p => p.Path).ToList()), _cts.Token); _model.Paths.Map(p => p.Path).ToList()), _cts.Token);
result.Match( result.Match(
_ => _navigationManager.NavigateTo("/media/sources/local"), _ => _navigationManager.NavigateTo("media/sources/local"),
error => error =>
{ {
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);

2
ErsatzTV/Pages/LocalLibraryPathEditor.razor

@ -81,7 +81,7 @@
if (_locker.LockLibrary(_library.Id)) if (_locker.LockLibrary(_library.Id))
{ {
await _channel.WriteAsync(new ScanLocalLibraryIfNeeded(_library.Id), _cts.Token); await _channel.WriteAsync(new ScanLocalLibraryIfNeeded(_library.Id), _cts.Token);
_navigationManager.NavigateTo("/media/libraries"); _navigationManager.NavigateTo("media/libraries");
} }
}); });
} }

6
ErsatzTV/Pages/Movie.razor

@ -19,7 +19,7 @@
} }
else else
{ {
<img src="@($"/artwork/fanart/{_movie.FanArt}")" alt="fan art"/> <img src="@($"artwork/fanart/{_movie.FanArt}")" alt="fan art"/>
} }
} }
</MudContainer> </MudContainer>
@ -38,7 +38,7 @@
{ {
<img class="mud-elevation-2" <img class="mud-elevation-2"
style="border-radius: 4px; flex-shrink: 0; max-height: 440px;" style="border-radius: 4px; flex-shrink: 0; max-height: 440px;"
src="@($"/artwork/posters/{_movie.Poster}")" alt="movie poster"/> src="@($"artwork/posters/{_movie.Poster}")" alt="movie poster"/>
} }
@if (_movie.MediaItemState == MediaItemState.FileNotFound) @if (_movie.MediaItemState == MediaItemState.FileNotFound)
{ {
@ -249,7 +249,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{ {
await _mediator.Send(new AddMovieToCollection(collection.Id, MovieId), _cts.Token); await _mediator.Send(new AddMovieToCollection(collection.Id, MovieId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}"); _navigationManager.NavigateTo($"media/collections/{collection.Id}");
} }
} }

8
ErsatzTV/Pages/MovieList.razor

@ -55,7 +55,7 @@
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> <MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
<FragmentLetterAnchor TCard="MovieCardViewModel" Cards="@_data.Cards"> <FragmentLetterAnchor TCard="MovieCardViewModel" Cards="@_data.Cards">
<MediaCard Data="@context" <MediaCard Data="@context"
Link="@($"/media/movies/{context.MovieId}")" Link="@($"media/movies/{context.MovieId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(context, e))" SelectClicked="@(e => SelectClicked(context, e))"
IsSelected="@IsSelected(context)" IsSelected="@IsSelected(context)"
@ -66,7 +66,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/movies" BaseUri="media/movies"
Query="@_query"/> Query="@_query"/>
} }
@ -98,7 +98,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/movies/page/{PageNumber - 1}"; string uri = $"media/movies/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -109,7 +109,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/movies/page/{PageNumber + 1}"; string uri = $"media/movies/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

2
ErsatzTV/Pages/MultiCollectionEditor.razor

@ -186,7 +186,7 @@
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);
_logger.LogError("Error saving collection: {Error}", error.Value); _logger.LogError("Error saving collection: {Error}", error.Value);
}, },
() => _navigationManager.NavigateTo("/media/collections")); () => _navigationManager.NavigateTo("media/collections"));
} }
} }

6
ErsatzTV/Pages/MusicVideoList.razor

@ -67,7 +67,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/music/videos" BaseUri="media/music/videos"
Query="@_query"/> Query="@_query"/>
} }
@ -99,7 +99,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/music/videos/page/{PageNumber - 1}"; string uri = $"media/music/videos/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -110,7 +110,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/music/videos/page/{PageNumber + 1}"; string uri = $"media/music/videos/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

6
ErsatzTV/Pages/OtherVideoList.razor

@ -67,7 +67,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/other/videos" BaseUri="media/other/videos"
Query="@_query"/> Query="@_query"/>
} }
@ -99,7 +99,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/other/videos/page/{PageNumber - 1}"; string uri = $"media/other/videos/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -110,7 +110,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/other/videos/page/{PageNumber + 1}"; string uri = $"media/other/videos/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

2
ErsatzTV/Pages/Playouts.razor

@ -7,7 +7,7 @@
@inject IMediator _mediator @inject IMediator _mediator
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8"> <MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/playouts/add"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="playouts/add">
Add Playout Add Playout
</MudButton> </MudButton>
<MudTable Hover="true" <MudTable Hover="true"

4
ErsatzTV/Pages/PlexMediaSources.razor

@ -39,12 +39,12 @@
</MudTooltip> </MudTooltip>
<MudTooltip Text="Edit Libraries"> <MudTooltip Text="Edit Libraries">
<MudIconButton Icon="@Icons.Material.Filled.VideoLibrary" <MudIconButton Icon="@Icons.Material.Filled.VideoLibrary"
Link="@($"/media/sources/plex/{context.Id}/libraries")"> Link="@($"media/sources/plex/{context.Id}/libraries")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Edit Path Replacements"> <MudTooltip Text="Edit Path Replacements">
<MudIconButton Icon="@Icons.Material.Filled.Folder" <MudIconButton Icon="@Icons.Material.Filled.Folder"
Link="@($"/media/sources/plex/{context.Id}/paths")"> Link="@($"media/sources/plex/{context.Id}/paths")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
</div> </div>

6
ErsatzTV/Pages/Schedules.razor

@ -34,12 +34,12 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Properties"> <MudTooltip Text="Edit Properties">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/schedules/{context.Id}")"> Link="@($"schedules/{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Edit Schedule Items"> <MudTooltip Text="Edit Schedule Items">
<MudIconButton Icon="@Icons.Material.Filled.FormatListNumbered" <MudIconButton Icon="@Icons.Material.Filled.FormatListNumbered"
Link="@($"/schedules/{context.Id}/items")"> Link="@($"schedules/{context.Id}/items")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Delete Schedule"> <MudTooltip Text="Delete Schedule">
@ -54,7 +54,7 @@
<MudTablePager/> <MudTablePager/>
</PagerContent> </PagerContent>
</MudTable> </MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/schedules/add" Class="mt-4"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="schedules/add" Class="mt-4">
Add Schedule Add Schedule
</MudButton> </MudButton>

26
ErsatzTV/Pages/Search.razor

@ -110,7 +110,7 @@
@foreach (MovieCardViewModel card in _movies.Cards.OrderBy(m => m.SortTitle)) @foreach (MovieCardViewModel card in _movies.Cards.OrderBy(m => m.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/movies/{card.MovieId}")" Link="@($"media/movies/{card.MovieId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
IsSelected="@IsSelected(card)" IsSelected="@IsSelected(card)"
@ -137,7 +137,7 @@
@foreach (TelevisionShowCardViewModel card in _shows.Cards.OrderBy(s => s.SortTitle)) @foreach (TelevisionShowCardViewModel card in _shows.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/shows/{card.TelevisionShowId}")" Link="@($"media/tv/shows/{card.TelevisionShowId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
IsSelected="@IsSelected(card)" IsSelected="@IsSelected(card)"
@ -164,7 +164,7 @@
@foreach (TelevisionSeasonCardViewModel card in _seasons.Cards.OrderBy(s => s.SortTitle)) @foreach (TelevisionSeasonCardViewModel card in _seasons.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/seasons/{card.TelevisionSeasonId}")" Link="@($"media/tv/seasons/{card.TelevisionSeasonId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
IsSelected="@IsSelected(card)" IsSelected="@IsSelected(card)"
@ -192,7 +192,7 @@
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
Link="@($"/media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")" Link="@($"media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")"
Subtitle="@($"{card.ShowTitle} - S{card.Season} E{card.Episode}")" Subtitle="@($"{card.ShowTitle} - S{card.Season} E{card.Episode}")"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
IsSelected="@IsSelected(card)" IsSelected="@IsSelected(card)"
@ -219,7 +219,7 @@
@foreach (ArtistCardViewModel card in _artists.Cards.OrderBy(s => s.SortTitle)) @foreach (ArtistCardViewModel card in _artists.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/music/artists/{card.ArtistId}")" Link="@($"media/music/artists/{card.ArtistId}")"
ArtworkKind="ArtworkKind.Thumbnail" ArtworkKind="ArtworkKind.Thumbnail"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -511,7 +511,7 @@
private string GetMoviesLink() private string GetMoviesLink()
{ {
var uri = "/media/movies/page/1"; var uri = "media/movies/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -522,7 +522,7 @@
private string GetShowsLink() private string GetShowsLink()
{ {
var uri = "/media/tv/shows/page/1"; var uri = "media/tv/shows/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -533,7 +533,7 @@
private string GetSeasonsLink() private string GetSeasonsLink()
{ {
var uri = "/media/tv/seasons/page/1"; var uri = "media/tv/seasons/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -544,7 +544,7 @@
private string GetEpisodesLink() private string GetEpisodesLink()
{ {
var uri = "/media/tv/episodes/page/1"; var uri = "media/tv/episodes/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -555,7 +555,7 @@
private string GetArtistsLink() private string GetArtistsLink()
{ {
var uri = "/media/music/artists/page/1"; var uri = "media/music/artists/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -566,7 +566,7 @@
private string GetMusicVideosLink() private string GetMusicVideosLink()
{ {
var uri = "/media/music/videos/page/1"; var uri = "media/music/videos/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -577,7 +577,7 @@
private string GetOtherVideosLink() private string GetOtherVideosLink()
{ {
var uri = "/media/other/videos/page/1"; var uri = "media/other/videos/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -588,7 +588,7 @@
private string GetSongsLink() private string GetSongsLink()
{ {
var uri = "/media/music/songs/page/1"; var uri = "media/music/songs/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

6
ErsatzTV/Pages/SongList.razor

@ -67,7 +67,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/music/songs" BaseUri="media/music/songs"
Query="@_query"/> Query="@_query"/>
} }
@ -99,7 +99,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/music/songs/page/{PageNumber - 1}"; string uri = $"media/music/songs/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -110,7 +110,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/music/songs/page/{PageNumber + 1}"; string uri = $"media/music/songs/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

12
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -23,7 +23,7 @@
} }
else else
{ {
<img src="@($"/artwork/fanart/{_season.FanArt}")" alt="fan art"/> <img src="@($"artwork/fanart/{_season.FanArt}")" alt="fan art"/>
} }
} }
</MudContainer> </MudContainer>
@ -41,11 +41,11 @@
{ {
<img class="mud-elevation-2 mr-6" <img class="mud-elevation-2 mr-6"
style="border-radius: 4px; flex-shrink: 0; max-height: 440px;" style="border-radius: 4px; flex-shrink: 0; max-height: 440px;"
src="@($"/artwork/posters/{_season.Poster}")" alt="season poster"/> src="@($"artwork/posters/{_season.Poster}")" alt="season poster"/>
} }
} }
<div style="display: flex; flex-direction: column; height: 100%"> <div style="display: flex; flex-direction: column; height: 100%">
<MudLink Href="@($"/media/tv/shows/{_season.ShowId}")"> <MudLink Href="@($"media/tv/shows/{_season.ShowId}")">
<MudText Typo="Typo.h2" Class="media-item-title">@_season.Title</MudText> <MudText Typo="Typo.h2" Class="media-item-title">@_season.Title</MudText>
</MudLink> </MudLink>
<MudText Typo="Typo.subtitle1" Class="media-item-subtitle mb-6 mud-text-secondary">@_season.Name</MudText> <MudText Typo="Typo.subtitle1" Class="media-item-subtitle mb-6 mud-text-secondary">@_season.Name</MudText>
@ -81,7 +81,7 @@
} }
else else
{ {
<MudCardMedia Image="@($"/artwork/thumbnails/{episode.Poster}")" Style="flex-grow: 1; height: 220px; width: 392px;"/> <MudCardMedia Image="@($"artwork/thumbnails/{episode.Poster}")" Style="flex-grow: 1; height: 220px; width: 392px;"/>
} }
@if (episode.State == MediaItemState.FileNotFound) @if (episode.State == MediaItemState.FileNotFound)
{ {
@ -219,7 +219,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{ {
await _mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId), _cts.Token); await _mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}"); _navigationManager.NavigateTo($"media/collections/{collection.Id}");
} }
} }
@ -234,7 +234,7 @@
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{ {
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token); await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"schedules/{schedule.Id}/items");
} }
} }

10
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -23,7 +23,7 @@
} }
else else
{ {
<img src="@($"/artwork/fanart/{_show.FanArt}")" alt="fan art"/> <img src="@($"artwork/fanart/{_show.FanArt}")" alt="fan art"/>
} }
} }
</MudContainer> </MudContainer>
@ -41,7 +41,7 @@
{ {
<img class="mud-elevation-2 mr-6" <img class="mud-elevation-2 mr-6"
style="border-radius: 4px; flex-shrink: 0; max-height: 440px;" style="border-radius: 4px; flex-shrink: 0; max-height: 440px;"
src="@($"/artwork/posters/{_show.Poster}")" alt="movie poster"/> src="@($"artwork/posters/{_show.Poster}")" alt="movie poster"/>
} }
} }
<div style="display: flex; flex-direction: column; height: 100%"> <div style="display: flex; flex-direction: column; height: 100%">
@ -144,7 +144,7 @@
@foreach (TelevisionSeasonCardViewModel card in _data.Cards) @foreach (TelevisionSeasonCardViewModel card in _data.Cards)
{ {
<MediaCard Data="@card" Placeholder="@card.Placeholder" <MediaCard Data="@card" Placeholder="@card.Placeholder"
Link="@($"/media/tv/seasons/{card.TelevisionSeasonId}")" Link="@($"media/tv/seasons/{card.TelevisionSeasonId}")"
AddToCollectionClicked="@AddSeasonToCollection"/> AddToCollectionClicked="@AddSeasonToCollection"/>
} }
</MudContainer> </MudContainer>
@ -215,7 +215,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection) if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{ {
await _mediator.Send(new AddShowToCollection(collection.Id, ShowId), _cts.Token); await _mediator.Send(new AddShowToCollection(collection.Id, ShowId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}"); _navigationManager.NavigateTo($"media/collections/{collection.Id}");
} }
} }
@ -229,7 +229,7 @@
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{ {
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token); await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"schedules/{schedule.Id}/items");
} }
} }

8
ErsatzTV/Pages/TelevisionSeasonSearchResults.razor

@ -55,7 +55,7 @@
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> <MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
<FragmentLetterAnchor TCard="TelevisionSeasonCardViewModel" Cards="@_data.Cards"> <FragmentLetterAnchor TCard="TelevisionSeasonCardViewModel" Cards="@_data.Cards">
<MediaCard Data="@context" <MediaCard Data="@context"
Link="@($"/media/tv/seasons/{context.TelevisionSeasonId}")" Link="@($"media/tv/seasons/{context.TelevisionSeasonId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(context, e))" SelectClicked="@(e => SelectClicked(context, e))"
IsSelected="@IsSelected(context)" IsSelected="@IsSelected(context)"
@ -66,7 +66,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/tv/seasons" BaseUri="media/tv/seasons"
Query="@_query"/> Query="@_query"/>
} }
@ -98,7 +98,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/tv/seasons/page/{PageNumber - 1}"; string uri = $"media/tv/seasons/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -109,7 +109,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/tv/seasons/page/{PageNumber + 1}"; string uri = $"media/tv/seasons/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

8
ErsatzTV/Pages/TelevisionShowList.razor

@ -55,7 +55,7 @@
<MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid"> <MudContainer MaxWidth="MaxWidth.False" Class="media-card-grid">
<FragmentLetterAnchor TCard="TelevisionShowCardViewModel" Cards="@_data.Cards"> <FragmentLetterAnchor TCard="TelevisionShowCardViewModel" Cards="@_data.Cards">
<MediaCard Data="@context" <MediaCard Data="@context"
Link="@($"/media/tv/shows/{context.TelevisionShowId}")" Link="@($"media/tv/shows/{context.TelevisionShowId}")"
AddToCollectionClicked="@AddToCollection" AddToCollectionClicked="@AddToCollection"
SelectClicked="@(e => SelectClicked(context, e))" SelectClicked="@(e => SelectClicked(context, e))"
IsSelected="@IsSelected(context)" IsSelected="@IsSelected(context)"
@ -66,7 +66,7 @@
@if (_data.PageMap.IsSome) @if (_data.PageMap.IsSome)
{ {
<LetterBar PageMap="@_data.PageMap.ValueUnsafe()" <LetterBar PageMap="@_data.PageMap.ValueUnsafe()"
BaseUri="/media/tv/shows" BaseUri="media/tv/shows"
Query="@_query"/> Query="@_query"/>
} }
@ -98,7 +98,7 @@
private void PrevPage() private void PrevPage()
{ {
string uri = $"/media/tv/shows/page/{PageNumber - 1}"; string uri = $"media/tv/shows/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -109,7 +109,7 @@
private void NextPage() private void NextPage()
{ {
string uri = $"/media/tv/shows/page/{PageNumber + 1}"; string uri = $"media/tv/shows/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

2
ErsatzTV/Pages/TraktLists.razor

@ -48,7 +48,7 @@
<MudTooltip Text="Search Trakt List"> <MudTooltip Text="Search Trakt List">
<MudIconButton Icon="@Icons.Material.Filled.Search" <MudIconButton Icon="@Icons.Material.Filled.Search"
Disabled="@_locker.IsTraktLocked()" Disabled="@_locker.IsTraktLocked()"
Link="@($"/search?query=trakt_list%3a{context.TraktId}")"> Link="@($"search?query=trakt_list%3a{context.TraktId}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Match Trakt List Items"> <MudTooltip Text="Match Trakt List Items">

26
ErsatzTV/Pages/Trash.razor

@ -107,7 +107,7 @@
@foreach (MovieCardViewModel card in _movies.Cards.OrderBy(m => m.SortTitle)) @foreach (MovieCardViewModel card in _movies.Cards.OrderBy(m => m.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/movies/{card.MovieId}")" Link="@($"media/movies/{card.MovieId}")"
DeleteClicked="@DeleteItemFromDatabase" DeleteClicked="@DeleteItemFromDatabase"
SelectColor="@Color.Error" SelectColor="@Color.Error"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -135,7 +135,7 @@
@foreach (TelevisionShowCardViewModel card in _shows.Cards.OrderBy(s => s.SortTitle)) @foreach (TelevisionShowCardViewModel card in _shows.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/shows/{card.TelevisionShowId}")" Link="@($"media/tv/shows/{card.TelevisionShowId}")"
DeleteClicked="@DeleteItemFromDatabase" DeleteClicked="@DeleteItemFromDatabase"
SelectColor="@Color.Error" SelectColor="@Color.Error"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -163,7 +163,7 @@
@foreach (TelevisionSeasonCardViewModel card in _seasons.Cards.OrderBy(s => s.SortTitle)) @foreach (TelevisionSeasonCardViewModel card in _seasons.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/tv/seasons/{card.TelevisionSeasonId}")" Link="@($"media/tv/seasons/{card.TelevisionSeasonId}")"
DeleteClicked="@DeleteItemFromDatabase" DeleteClicked="@DeleteItemFromDatabase"
SelectColor="@Color.Error" SelectColor="@Color.Error"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
@ -193,7 +193,7 @@
<MediaCard Data="@card" <MediaCard Data="@card"
DeleteClicked="@DeleteItemFromDatabase" DeleteClicked="@DeleteItemFromDatabase"
SelectColor="@Color.Error" SelectColor="@Color.Error"
Link="@($"/media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")" Link="@($"media/tv/seasons/{card.SeasonId}#episode-{card.EpisodeId}")"
Subtitle="@($"{card.ShowTitle} - S{card.Season} E{card.Episode}")" Subtitle="@($"{card.ShowTitle} - S{card.Season} E{card.Episode}")"
SelectClicked="@(e => SelectClicked(card, e))" SelectClicked="@(e => SelectClicked(card, e))"
IsSelected="@IsSelected(card)" IsSelected="@IsSelected(card)"
@ -220,7 +220,7 @@
@foreach (ArtistCardViewModel card in _artists.Cards.OrderBy(s => s.SortTitle)) @foreach (ArtistCardViewModel card in _artists.Cards.OrderBy(s => s.SortTitle))
{ {
<MediaCard Data="@card" <MediaCard Data="@card"
Link="@($"/media/music/artists/{card.ArtistId}")" Link="@($"media/music/artists/{card.ArtistId}")"
ArtworkKind="ArtworkKind.Thumbnail" ArtworkKind="ArtworkKind.Thumbnail"
DeleteClicked="@DeleteItemFromDatabase" DeleteClicked="@DeleteItemFromDatabase"
SelectColor="@Color.Error" SelectColor="@Color.Error"
@ -368,7 +368,7 @@
private string GetMoviesLink() private string GetMoviesLink()
{ {
var uri = "/media/movies/page/1"; var uri = "media/movies/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -379,7 +379,7 @@
private string GetShowsLink() private string GetShowsLink()
{ {
var uri = "/media/tv/shows/page/1"; var uri = "media/tv/shows/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -390,7 +390,7 @@
private string GetSeasonsLink() private string GetSeasonsLink()
{ {
var uri = "/media/tv/seasons/page/1"; var uri = "media/tv/seasons/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -401,7 +401,7 @@
private string GetEpisodesLink() private string GetEpisodesLink()
{ {
var uri = "/media/tv/episodes/page/1"; var uri = "media/tv/episodes/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -412,7 +412,7 @@
private string GetArtistsLink() private string GetArtistsLink()
{ {
var uri = "/media/music/artists/page/1"; var uri = "media/music/artists/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -423,7 +423,7 @@
private string GetMusicVideosLink() private string GetMusicVideosLink()
{ {
var uri = "/media/music/videos/page/1"; var uri = "media/music/videos/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -434,7 +434,7 @@
private string GetOtherVideosLink() private string GetOtherVideosLink()
{ {
var uri = "/media/other/videos/page/1"; var uri = "media/other/videos/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();
@ -445,7 +445,7 @@
private string GetSongsLink() private string GetSongsLink()
{ {
var uri = "/media/music/songs/page/1"; var uri = "media/music/songs/page/1";
if (!string.IsNullOrWhiteSpace(_query)) if (!string.IsNullOrWhiteSpace(_query))
{ {
(string key, string value) = _query.EncodeQuery(); (string key, string value) = _query.EncodeQuery();

4
ErsatzTV/Pages/Watermarks.razor

@ -48,7 +48,7 @@
<div style="align-items: center; display: flex;"> <div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Watermark"> <MudTooltip Text="Edit Watermark">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/watermarks/{context.Id}")"> Link="@($"watermarks/{context.Id}")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Copy Watermark"> <MudTooltip Text="Copy Watermark">
@ -65,7 +65,7 @@
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="/watermarks/add" Class="mt-4"> <MudButton Variant="Variant.Filled" Color="Color.Primary" Link="watermarks/add" Class="mt-4">
Add Watermark Add Watermark
</MudButton> </MudButton>
</MudContainer> </MudContainer>

2
ErsatzTV/Pages/_Host.cshtml

@ -29,7 +29,7 @@
$.ajax({ $.ajax({
data: data, data: data,
type: 'POST', type: 'POST',
url: `/media/collections/${collectionId}/items` url: `media/collections/${collectionId}/items`
}); });
} }
}); });

50
ErsatzTV/Shared/MainLayout.razor

@ -13,8 +13,8 @@
<MudLayout @onclick="@(() => _isOpen = false)"> <MudLayout @onclick="@(() => _isOpen = false)">
<MudAppBar Elevation="1" Class="app-bar"> <MudAppBar Elevation="1" Class="app-bar">
<div style="min-width: 240px"> <div style="min-width: 240px">
<a href="/"> <a href="">
<img src="/images/ersatztv.png" alt="ErsatzTV"/> <img src="images/ersatztv.png" alt="ErsatzTV"/>
</a> </a>
</div> </div>
<EditForm Model="@_dummyModel" OnSubmit="@(_ => PerformSearch())"> <EditForm Model="@_dummyModel" OnSubmit="@(_ => PerformSearch())">
@ -61,8 +61,8 @@
</MudPopover> </MudPopover>
</EditForm> </EditForm>
<MudSpacer/> <MudSpacer/>
<MudLink Color="Color.Info" Href="/iptv/channels.m3u" Target="_blank" Underline="Underline.None">M3U</MudLink> <MudLink Color="Color.Info" Href="iptv/channels.m3u" Target="_blank" Underline="Underline.None">M3U</MudLink>
<MudLink Color="Color.Info" Href="/iptv/xmltv.xml" Target="_blank" Class="mx-4" Underline="Underline.None">XMLTV</MudLink> <MudLink Color="Color.Info" Href="iptv/xmltv.xml" Target="_blank" Class="mx-4" Underline="Underline.None">XMLTV</MudLink>
@* <MudLink Color="Color.Info" Href="/swagger" Target="_blank" Class="mr-4" Underline="Underline.None">API</MudLink> *@ @* <MudLink Color="Color.Info" Href="/swagger" Target="_blank" Class="mr-4" Underline="Underline.None">API</MudLink> *@
<MudTooltip Text="Documentation"> <MudTooltip Text="Documentation">
<MudIconButton Icon="@Icons.Material.Filled.Help" Color="Color.Primary" Link="https://ersatztv.org" Target="_blank"/> <MudIconButton Icon="@Icons.Material.Filled.Help" Color="Color.Primary" Link="https://ersatztv.org" Target="_blank"/>
@ -76,33 +76,33 @@
</MudAppBar> </MudAppBar>
<MudDrawer Open="true" Elevation="2" ClipMode="DrawerClipMode.Always"> <MudDrawer Open="true" Elevation="2" ClipMode="DrawerClipMode.Always">
<MudNavMenu> <MudNavMenu>
<MudNavLink Href="/channels">Channels</MudNavLink> <MudNavLink Href="channels">Channels</MudNavLink>
<MudNavLink Href="/ffmpeg">FFmpeg Profiles</MudNavLink> <MudNavLink Href="ffmpeg">FFmpeg Profiles</MudNavLink>
<MudNavLink Href="/watermarks">Watermarks</MudNavLink> <MudNavLink Href="watermarks">Watermarks</MudNavLink>
<MudNavGroup Title="Media Sources" Expanded="true"> <MudNavGroup Title="Media Sources" Expanded="true">
<MudNavLink Href="/media/sources/local">Local</MudNavLink> <MudNavLink Href="media/sources/local">Local</MudNavLink>
<MudNavLink Href="/media/sources/emby">Emby</MudNavLink> <MudNavLink Href="media/sources/emby">Emby</MudNavLink>
<MudNavLink Href="/media/sources/jellyfin">Jellyfin</MudNavLink> <MudNavLink Href="media/sources/jellyfin">Jellyfin</MudNavLink>
<MudNavLink Href="/media/sources/plex">Plex</MudNavLink> <MudNavLink Href="media/sources/plex">Plex</MudNavLink>
</MudNavGroup> </MudNavGroup>
<MudNavGroup Title="Media" Expanded="true"> <MudNavGroup Title="Media" Expanded="true">
<MudNavLink Href="/media/libraries">Libraries</MudNavLink> <MudNavLink Href="media/libraries">Libraries</MudNavLink>
<MudNavLink Href="/media/trash">Trash</MudNavLink> <MudNavLink Href="media/trash">Trash</MudNavLink>
<MudNavLink Href="/media/tv/shows">TV Shows</MudNavLink> <MudNavLink Href="media/tv/shows">TV Shows</MudNavLink>
<MudNavLink Href="/media/movies">Movies</MudNavLink> <MudNavLink Href="media/movies">Movies</MudNavLink>
<MudNavLink Href="/media/music/artists">Music</MudNavLink> <MudNavLink Href="media/music/artists">Music</MudNavLink>
<MudNavLink Href="/media/other/videos">Other Videos</MudNavLink> <MudNavLink Href="media/other/videos">Other Videos</MudNavLink>
<MudNavLink Href="/media/music/songs">Songs</MudNavLink> <MudNavLink Href="media/music/songs">Songs</MudNavLink>
</MudNavGroup> </MudNavGroup>
<MudNavGroup Title="Lists" Expanded="true"> <MudNavGroup Title="Lists" Expanded="true">
<MudNavLink Href="/media/collections">Collections</MudNavLink> <MudNavLink Href="media/collections">Collections</MudNavLink>
<MudNavLink Href="/media/trakt/lists">Trakt Lists</MudNavLink> <MudNavLink Href="media/trakt/lists">Trakt Lists</MudNavLink>
<MudNavLink Href="/media/filler/presets">Filler Presets</MudNavLink> <MudNavLink Href="media/filler/presets">Filler Presets</MudNavLink>
</MudNavGroup> </MudNavGroup>
<MudNavLink Href="/schedules">Schedules</MudNavLink> <MudNavLink Href="schedules">Schedules</MudNavLink>
<MudNavLink Href="/playouts">Playouts</MudNavLink> <MudNavLink Href="playouts">Playouts</MudNavLink>
<MudNavLink Href="/settings">Settings</MudNavLink> <MudNavLink Href="settings">Settings</MudNavLink>
<MudNavLink Href="/system/logs">Logs</MudNavLink> <MudNavLink Href="system/logs">Logs</MudNavLink>
<MudDivider Class="my-6" DividerType="DividerType.Middle"/> <MudDivider Class="my-6" DividerType="DividerType.Middle"/>
<MudContainer Style="text-align: right" Class="mr-6"> <MudContainer Style="text-align: right" Class="mr-6">
<MudText Typo="Typo.body2">ErsatzTV Version</MudText> <MudText Typo="Typo.body2">ErsatzTV Version</MudText>

2
ErsatzTV/Shared/MediaCard.razor

@ -153,7 +153,7 @@
return string.IsNullOrWhiteSpace(Data.Poster) return string.IsNullOrWhiteSpace(Data.Poster)
? "position: relative" ? "position: relative"
: $"position: relative; background-image: url(/artwork/{PathForArtwork()}/{Data.Poster}); background-size: cover; background-position: center"; : $"position: relative; background-image: url(artwork/{PathForArtwork()}/{Data.Poster}); background-size: cover; background-position: center";
} }
private string PathForArtwork() => ArtworkKind switch private string PathForArtwork() => ArtworkKind switch

2
ErsatzTV/Shared/RemoteMediaSourceEditor.razor

@ -53,7 +53,7 @@
{ {
Either<BaseError, Unit> result = await SaveSecrets(_model); Either<BaseError, Unit> result = await SaveSecrets(_model);
result.Match( result.Match(
_ => _navigationManager.NavigateTo($"/media/sources/{Name.ToLowerInvariant()}"), _ => _navigationManager.NavigateTo($"media/sources/{Name.ToLowerInvariant()}"),
error => error =>
{ {
_snackbar.Add(error.Value, Severity.Error); _snackbar.Add(error.Value, Severity.Error);

2
ErsatzTV/Shared/RemoteMediaSourceLibrariesEditor.razor

@ -114,7 +114,7 @@
} }
} }
_navigationManager.NavigateTo($"/media/sources/{Name.ToLowerInvariant()}"); _navigationManager.NavigateTo($"media/sources/{Name.ToLowerInvariant()}");
}); });
} }

2
ErsatzTV/Shared/RemoteMediaSourcePathReplacementsEditor.razor

@ -139,7 +139,7 @@
_snackbar.Add($"Unexpected error saving path replacements: {error.Value}", Severity.Error); _snackbar.Add($"Unexpected error saving path replacements: {error.Value}", Severity.Error);
_logger.LogError("Unexpected error saving path replacements: {Error}", error.Value); _logger.LogError("Unexpected error saving path replacements: {Error}", error.Value);
}, },
() => _navigationManager.NavigateTo($"/media/sources/{Name.ToLowerInvariant()}")); () => _navigationManager.NavigateTo($"media/sources/{Name.ToLowerInvariant()}"));
} }
} }

8
ErsatzTV/Shared/RemoteMediaSources.razor

@ -35,12 +35,12 @@
</MudTooltip> </MudTooltip>
<MudTooltip Text="Edit Libraries"> <MudTooltip Text="Edit Libraries">
<MudIconButton Icon="@Icons.Material.Filled.VideoLibrary" <MudIconButton Icon="@Icons.Material.Filled.VideoLibrary"
Link="@($"/media/sources/{Name.ToLowerInvariant()}/{context.Id}/libraries")"> Link="@($"media/sources/{Name.ToLowerInvariant()}/{context.Id}/libraries")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Edit Path Replacements"> <MudTooltip Text="Edit Path Replacements">
<MudIconButton Icon="@Icons.Material.Filled.Folder" <MudIconButton Icon="@Icons.Material.Filled.Folder"
Link="@($"/media/sources/{Name.ToLowerInvariant()}/{context.Id}/paths")"> Link="@($"media/sources/{Name.ToLowerInvariant()}/{context.Id}/paths")">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
</div> </div>
@ -60,7 +60,7 @@
{ {
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled"
Color="Color.Primary" Color="Color.Primary"
Link="@($"/media/sources/{Name.ToLowerInvariant()}/edit")" Link="@($"media/sources/{Name.ToLowerInvariant()}/edit")"
Class="mt-4"> Class="mt-4">
Connect @Name Connect @Name
</MudButton> </MudButton>
@ -70,7 +70,7 @@
{ {
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled"
Color="Color.Secondary" Color="Color.Secondary"
Link="@($"/media/sources/{Name.ToLowerInvariant()}/edit")" Link="@($"media/sources/{Name.ToLowerInvariant()}/edit")"
Class="ml-4 mt-4"> Class="ml-4 mt-4">
Fix @Name Connection Fix @Name Connection
</MudButton> </MudButton>

10
ErsatzTV/Startup.cs

@ -59,6 +59,7 @@ using FluentValidation.AspNetCore;
using Ganss.Xss; using Ganss.Xss;
using MediatR; using MediatR;
using MediatR.Courier.DependencyInjection; using MediatR.Courier.DependencyInjection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
@ -87,6 +88,7 @@ public class Startup
{ {
BugsnagConfiguration bugsnagConfig = Configuration.GetSection("Bugsnag").Get<BugsnagConfiguration>(); BugsnagConfiguration bugsnagConfig = Configuration.GetSection("Bugsnag").Get<BugsnagConfiguration>();
services.Configure<BugsnagConfiguration>(Configuration.GetSection("Bugsnag")); services.Configure<BugsnagConfiguration>(Configuration.GetSection("Bugsnag"));
services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.All; });
services.AddBugsnag( services.AddBugsnag(
configuration => configuration =>
@ -269,8 +271,16 @@ public class Startup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
string baseUrl = Environment.GetEnvironmentVariable("ETV_BASE_URL");
if (!string.IsNullOrWhiteSpace(baseUrl))
{
app.UsePathBase(baseUrl);
}
app.UseCors("AllowAll"); app.UseCors("AllowAll");
app.UseForwardedHeaders();
// app.UseHttpLogging();
// app.UseSerilogRequestLogging(); // app.UseSerilogRequestLogging();
app.UseStaticFiles(); app.UseStaticFiles();

Loading…
Cancel
Save