Browse Source

fix missing audio and subtitle language codes (#1822)

pull/1823/head
Jason Dove 1 year ago committed by GitHub
parent
commit
56a58d7a84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 11
      ErsatzTV.Application/Channels/Commands/CreateChannelHandler.cs
  3. 12
      ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs
  4. 14
      ErsatzTV.Application/MediaItems/Queries/GetAllLanguageCodesHandler.cs
  5. 3
      ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs
  6. 3
      ErsatzTV.Core/Metadata/LanguageCodeAndName.cs
  7. 18
      ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs
  8. 11
      ErsatzTV/Validators/ChannelEditViewModelValidator.cs

2
CHANGELOG.md

@ -44,6 +44,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -44,6 +44,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix adding pad filler to content that is less than one minute in duration
- Generate unique identifier for virtual HDHomeRun tuner by @raknam
- This allows a single Plex server to connect to multiple ETV instances
- Include *all* language codes from media library in preferred audio and subtitle language options
- Language codes where an English name cannot be found will be at the bottom of the list
### Changed
- Remove some unnecessary API calls related to media server scanning and paging

11
ErsatzTV.Application/Channels/Commands/CreateChannelHandler.cs

@ -39,7 +39,6 @@ public class CreateChannelHandler( @@ -39,7 +39,6 @@ public class CreateChannelHandler(
private static async Task<Validation<BaseError, Channel>> Validate(TvContext dbContext, CreateChannel request) =>
(ValidateName(request), await ValidateNumber(dbContext, request),
await FFmpegProfileMustExist(dbContext, request),
ValidatePreferredAudioLanguage(request),
ValidatePreferredSubtitleLanguage(request),
await WatermarkMustExist(dbContext, request),
await FillerPresetMustExist(dbContext, request))
@ -48,7 +47,6 @@ public class CreateChannelHandler( @@ -48,7 +47,6 @@ public class CreateChannelHandler(
name,
number,
ffmpegProfileId,
preferredAudioLanguageCode,
preferredSubtitleLanguageCode,
watermarkId,
fillerPresetId) =>
@ -76,7 +74,7 @@ public class CreateChannelHandler( @@ -76,7 +74,7 @@ public class CreateChannelHandler(
ProgressMode = request.ProgressMode,
StreamingMode = request.StreamingMode,
Artwork = artwork,
PreferredAudioLanguageCode = preferredAudioLanguageCode,
PreferredAudioLanguageCode = request.PreferredAudioLanguageCode,
PreferredAudioTitle = request.PreferredAudioTitle,
PreferredSubtitleLanguageCode = preferredSubtitleLanguageCode,
SubtitleMode = request.SubtitleMode,
@ -101,13 +99,6 @@ public class CreateChannelHandler( @@ -101,13 +99,6 @@ public class CreateChannelHandler(
createChannel.NotEmpty(c => c.Name)
.Bind(_ => createChannel.NotLongerThan(50)(c => c.Name));
private static Validation<BaseError, string> ValidatePreferredAudioLanguage(CreateChannel createChannel) =>
Optional(createChannel.PreferredAudioLanguageCode ?? string.Empty)
.Filter(
lc => string.IsNullOrWhiteSpace(lc) || CultureInfo.GetCultures(CultureTypes.NeutralCultures).Any(
ci => string.Equals(ci.ThreeLetterISOLanguageName, lc, StringComparison.OrdinalIgnoreCase)))
.ToValidation<BaseError>("Preferred audio language code is invalid");
private static Validation<BaseError, string> ValidatePreferredSubtitleLanguage(CreateChannel createChannel) =>
Optional(createChannel.PreferredSubtitleLanguageCode ?? string.Empty)
.Filter(

12
ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs

@ -93,9 +93,8 @@ public class UpdateChannelHandler( @@ -93,9 +93,8 @@ public class UpdateChannelHandler(
private static async Task<Validation<BaseError, Channel>> Validate(TvContext dbContext, UpdateChannel request) =>
(await ChannelMustExist(dbContext, request), ValidateName(request),
await ValidateNumber(dbContext, request),
ValidatePreferredAudioLanguage(request))
.Apply((channelToUpdate, _, _, _) => channelToUpdate);
await ValidateNumber(dbContext, request))
.Apply((channelToUpdate, _, _) => channelToUpdate);
private static Task<Validation<BaseError, Channel>> ChannelMustExist(
TvContext dbContext,
@ -130,11 +129,4 @@ public class UpdateChannelHandler( @@ -130,11 +129,4 @@ public class UpdateChannelHandler(
return BaseError.New("Channel number must be unique");
}
private static Validation<BaseError, string> ValidatePreferredAudioLanguage(UpdateChannel updateChannel) =>
Optional(updateChannel.PreferredAudioLanguageCode ?? string.Empty)
.Filter(
lc => string.IsNullOrWhiteSpace(lc) || CultureInfo.GetCultures(CultureTypes.NeutralCultures).Any(
ci => string.Equals(ci.ThreeLetterISOLanguageName, lc, StringComparison.OrdinalIgnoreCase)))
.ToValidation<BaseError>("Preferred audio language code is invalid");
}

14
ErsatzTV.Application/MediaItems/Queries/GetAllLanguageCodesHandler.cs

@ -1,20 +1,18 @@ @@ -1,20 +1,18 @@
using System.Globalization;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
namespace ErsatzTV.Application.MediaItems;
public class GetAllLanguageCodesHandler : IRequestHandler<GetAllLanguageCodes, List<LanguageCodeViewModel>>
public class GetAllLanguageCodesHandler(IMediaItemRepository mediaItemRepository)
: IRequestHandler<GetAllLanguageCodes, List<LanguageCodeViewModel>>
{
private readonly IMediaItemRepository _mediaItemRepository;
public GetAllLanguageCodesHandler(IMediaItemRepository mediaItemRepository) =>
_mediaItemRepository = mediaItemRepository;
public async Task<List<LanguageCodeViewModel>> Handle(
GetAllLanguageCodes request,
CancellationToken cancellationToken)
{
List<CultureInfo> cultures = await _mediaItemRepository.GetAllLanguageCodeCultures();
return cultures.Map(c => new LanguageCodeViewModel(c.ThreeLetterISOLanguageName, c.EnglishName)).ToList();
List<LanguageCodeAndName> languageCodes = await mediaItemRepository.GetAllLanguageCodesAndNames();
return languageCodes.Map(c => new LanguageCodeViewModel(c.Code, c.Name)).ToList();
}
}

3
ErsatzTV.Core/Interfaces/Repositories/IMediaItemRepository.cs

@ -1,13 +1,14 @@ @@ -1,13 +1,14 @@
using System.Collections.Immutable;
using System.Globalization;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Metadata;
namespace ErsatzTV.Core.Interfaces.Repositories;
public interface IMediaItemRepository
{
Task<List<CultureInfo>> GetAllKnownCultures();
Task<List<CultureInfo>> GetAllLanguageCodeCultures();
Task<List<LanguageCodeAndName>> GetAllLanguageCodesAndNames();
Task<List<int>> FlagFileNotFound(LibraryPath libraryPath, string path);
Task<Unit> FlagNormal(MediaItem mediaItem);
Task<Either<BaseError, Unit>> DeleteItems(List<int> mediaItemIds);

3
ErsatzTV.Core/Metadata/LanguageCodeAndName.cs

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
namespace ErsatzTV.Core.Metadata;
public record LanguageCodeAndName(string Code, string Name);

18
ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core; @@ -5,6 +5,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@ -41,27 +42,38 @@ public class MediaItemRepository : IMediaItemRepository @@ -41,27 +42,38 @@ public class MediaItemRepository : IMediaItemRepository
return result.ToList();
}
public async Task<List<CultureInfo>> GetAllLanguageCodeCultures()
public async Task<List<LanguageCodeAndName>> GetAllLanguageCodesAndNames()
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
var result = new System.Collections.Generic.HashSet<CultureInfo>();
var result = new System.Collections.Generic.HashSet<LanguageCodeAndName>();
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
List<string> mediaCodes = await GetAllLanguageCodes();
var unseenCodes = new System.Collections.Generic.HashSet<string>(mediaCodes);
foreach (string mediaCode in mediaCodes)
{
foreach (string code in await dbContext.LanguageCodes.GetAllLanguageCodes(mediaCode))
{
Option<CultureInfo> maybeCulture = allCultures.Find(
c => string.Equals(code, c.ThreeLetterISOLanguageName, StringComparison.OrdinalIgnoreCase));
foreach (CultureInfo culture in maybeCulture)
{
result.Add(culture);
unseenCodes.Remove(mediaCode);
unseenCodes.Remove(code);
result.Add(new LanguageCodeAndName(culture.ThreeLetterISOLanguageName, culture.EnglishName));
}
}
}
// every language code from the db must appear in the results
// entries that have no culture info (and thus english name) will just use the code twice
foreach (string mediaCode in unseenCodes.Where(c => !string.IsNullOrWhiteSpace(c)))
{
result.Add(new LanguageCodeAndName(mediaCode, mediaCode));
}
return result.ToList();
}

11
ErsatzTV/Validators/ChannelEditViewModelValidator.cs

@ -15,16 +15,5 @@ public class ChannelEditViewModelValidator : AbstractValidator<ChannelEditViewMo @@ -15,16 +15,5 @@ public class ChannelEditViewModelValidator : AbstractValidator<ChannelEditViewMo
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Group).NotEmpty();
RuleFor(x => x.FFmpegProfileId).GreaterThan(0);
RuleFor(x => x.PreferredAudioLanguageCode)
.Must(
languageCode => CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.Any(
ci => string.Equals(
ci.ThreeLetterISOLanguageName,
languageCode,
StringComparison.OrdinalIgnoreCase)))
.When(vm => !string.IsNullOrWhiteSpace(vm.PreferredAudioLanguageCode))
.WithMessage("Preferred audio language code is invalid");
}
}

Loading…
Cancel
Save