mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-14 01:02:57 -07:00
fix(translations): 🌐 Localization - Ensuring all of the app including backend are localized #4366
* Localize TV and movies titles in requests * Add missing release statuses * Localize collection request * Localize TV shows in newsletter Uses TMDB instead of TVMaze for title, genres and synopsis * Localize error messages * Localize albums requests * Use current language for TV and movies requests * Remove unecessary console log
This commit is contained in:
parent
d8d1091564
commit
5e140ab618
28 changed files with 205 additions and 137 deletions
|
@ -120,11 +120,13 @@ namespace Ombi.Core.Engine
|
|||
?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate;
|
||||
|
||||
var ruleResults = (await RunRequestRules(requestModel)).ToList();
|
||||
if (ruleResults.Any(x => !x.Success))
|
||||
var ruleResultInError = ruleResults.Find(x => !x.Success);
|
||||
if (ruleResultInError != null)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message
|
||||
ErrorMessage = ruleResultInError.Message,
|
||||
ErrorCode = ruleResultInError.ErrorCode
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -573,7 +575,8 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
results.Add(await RequestMovie(new MovieRequestViewModel
|
||||
{
|
||||
TheMovieDbId = collection.id
|
||||
TheMovieDbId = collection.id,
|
||||
LanguageCode = langCode
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
namespace Ombi.Core.Engine
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class RequestEngineResult
|
||||
{
|
||||
|
@ -6,6 +9,23 @@
|
|||
public string Message { get; set; }
|
||||
public bool IsError => !string.IsNullOrEmpty(ErrorMessage);
|
||||
public string ErrorMessage { get; set; }
|
||||
public ErrorCode? ErrorCode { get; set; }
|
||||
public int RequestId { get; set; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ErrorCode {
|
||||
AlreadyRequested,
|
||||
EpisodesAlreadyRequested,
|
||||
NoPermissionsOnBehalf,
|
||||
NoPermissions,
|
||||
RequestDoesNotExist,
|
||||
ChildRequestDoesNotExist,
|
||||
NoPermissionsRequestMovie,
|
||||
NoPermissionsRequestTV,
|
||||
NoPermissionsRequestAlbum,
|
||||
MovieRequestQuotaExceeded,
|
||||
TvRequestQuotaExceeded,
|
||||
AlbumRequestQuotaExceeded,
|
||||
}
|
||||
}
|
|
@ -144,6 +144,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.AlreadyRequested,
|
||||
ErrorMessage = "This has already been requested"
|
||||
};
|
||||
}
|
||||
|
@ -166,6 +167,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.NoPermissionsOnBehalf,
|
||||
Message = "You do not have the correct permissions to request on behalf of users!",
|
||||
ErrorMessage = $"You do not have the correct permissions to request on behalf of users!"
|
||||
};
|
||||
|
@ -176,6 +178,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.NoPermissions,
|
||||
Message = "You do not have the correct permissions!",
|
||||
ErrorMessage = $"You do not have the correct permissions!"
|
||||
};
|
||||
|
@ -183,7 +186,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
var tvBuilder = new TvShowRequestBuilderV2(MovieDbApi);
|
||||
(await tvBuilder
|
||||
.GetShowInfo(tv.TheMovieDbId))
|
||||
.GetShowInfo(tv.TheMovieDbId, tv.languageCode))
|
||||
.CreateTvList(tv)
|
||||
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id);
|
||||
|
||||
|
@ -250,6 +253,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.AlreadyRequested,
|
||||
ErrorMessage = "This has already been requested"
|
||||
};
|
||||
}
|
||||
|
@ -685,6 +689,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorCode = ErrorCode.ChildRequestDoesNotExist,
|
||||
ErrorMessage = "Child Request does not exist"
|
||||
};
|
||||
}
|
||||
|
@ -722,6 +727,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorCode = ErrorCode.ChildRequestDoesNotExist,
|
||||
ErrorMessage = "Child Request does not exist"
|
||||
};
|
||||
}
|
||||
|
@ -781,6 +787,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorCode = ErrorCode.ChildRequestDoesNotExist,
|
||||
ErrorMessage = "Child Request does not exist"
|
||||
};
|
||||
}
|
||||
|
@ -808,6 +815,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorCode = ErrorCode.ChildRequestDoesNotExist,
|
||||
ErrorMessage = "Child Request does not exist"
|
||||
};
|
||||
}
|
||||
|
@ -905,6 +913,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.RequestDoesNotExist,
|
||||
ErrorMessage = "Request does not exist"
|
||||
};
|
||||
}
|
||||
|
@ -965,6 +974,7 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorCode = ErrorCode.RequestDoesNotExist,
|
||||
ErrorMessage = "Request does not exist"
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ namespace Ombi.Core.Helpers
|
|||
public TvRequests NewRequest { get; protected set; }
|
||||
protected TvInfo TheMovieDbRecord { get; set; }
|
||||
|
||||
public async Task<TvShowRequestBuilderV2> GetShowInfo(int id)
|
||||
public async Task<TvShowRequestBuilderV2> GetShowInfo(int id, string langCode = "en")
|
||||
{
|
||||
TheMovieDbRecord = await MovieDbApi.GetTVInfo(id.ToString());
|
||||
TheMovieDbRecord = await MovieDbApi.GetTVInfo(id.ToString(), langCode);
|
||||
|
||||
// Remove 'Specials Season'
|
||||
var firstSeason = TheMovieDbRecord.seasons.OrderBy(x => x.season_number).FirstOrDefault();
|
||||
|
|
|
@ -6,5 +6,6 @@ namespace Ombi.Core.Models.Requests
|
|||
public class TvRequestViewModelV2 : TvRequestViewModelBase
|
||||
{
|
||||
public int TheMovieDbId { get; set; }
|
||||
public string languageCode { get; set; } = "en";
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
namespace Ombi.Core.Rule
|
||||
using Ombi.Core.Engine;
|
||||
namespace Ombi.Core.Rule
|
||||
{
|
||||
public abstract class BaseRequestRule
|
||||
{
|
||||
|
@ -7,9 +8,9 @@
|
|||
return new RuleResult {Success = true};
|
||||
}
|
||||
|
||||
public RuleResult Fail(string message)
|
||||
public RuleResult Fail(ErrorCode errorCode, string message = "")
|
||||
{
|
||||
return new RuleResult { Message = message };
|
||||
return new RuleResult { ErrorCode = errorCode, Message = message };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
namespace Ombi.Core.Rule
|
||||
using Ombi.Core.Engine;
|
||||
namespace Ombi.Core.Rule
|
||||
{
|
||||
public class RuleResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; }
|
||||
public ErrorCode ErrorCode { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System.Security.Principal;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
@ -34,7 +35,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
{
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
|
||||
return Success();
|
||||
return Fail("You do not have permissions to Request a Movie");
|
||||
return Fail(ErrorCode.NoPermissionsRequestMovie, "You do not have permissions to Request a Movie");
|
||||
}
|
||||
|
||||
if (obj.RequestType == RequestType.TvShow)
|
||||
|
@ -44,7 +45,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
return Success();
|
||||
}
|
||||
|
||||
return Fail("You do not have permissions to Request a TV Show");
|
||||
return Fail(ErrorCode.NoPermissionsRequestTV, "You do not have permissions to Request a TV Show");
|
||||
}
|
||||
|
||||
if (obj.RequestType == RequestType.Album)
|
||||
|
@ -54,7 +55,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
return Success();
|
||||
}
|
||||
|
||||
return Fail("You do not have permissions to Request an Album");
|
||||
return Fail(ErrorCode.NoPermissionsRequestAlbum, "You do not have permissions to Request an Album");
|
||||
}
|
||||
|
||||
throw new InvalidDataException("Permission check failed: unknown RequestType");
|
||||
|
|
|
@ -6,6 +6,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Rule.Rules.Request
|
||||
|
@ -49,7 +50,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
}
|
||||
if(found)
|
||||
{
|
||||
return Fail($"\"{obj.Title}\" has already been requested");
|
||||
return Fail(ErrorCode.AlreadyRequested, $"\"{obj.Title}\" has already been requested");
|
||||
}
|
||||
}
|
||||
return Success();
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
@ -87,7 +88,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {child.Title}");
|
||||
return Fail(ErrorCode.EpisodesAlreadyRequested, $"We already have episodes requested from series {child.Title}");
|
||||
}
|
||||
|
||||
return Success();
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
@ -63,7 +64,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {tv.Title}");
|
||||
return Fail(ErrorCode.EpisodesAlreadyRequested, $"We already have episodes requested from series {tv.Title}");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
if (remainingLimitsModel.Remaining < 1)
|
||||
{
|
||||
return Fail("You have exceeded your Movie request quota!");
|
||||
return Fail(Engine.ErrorCode.MovieRequestQuotaExceeded, "You have exceeded your Movie request quota!");
|
||||
}
|
||||
}
|
||||
if (obj.RequestType == RequestType.TvShow)
|
||||
|
@ -75,7 +75,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
if ((remainingLimitsModel.Remaining - requestCount) < 0)
|
||||
{
|
||||
return Fail("You have exceeded your Episode request quota!");
|
||||
return Fail(Engine.ErrorCode.TvRequestQuotaExceeded, "You have exceeded your Episode request quota!");
|
||||
}
|
||||
}
|
||||
if (obj.RequestType == RequestType.Album)
|
||||
|
@ -88,7 +88,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
if (remainingLimitsModel.Remaining < 1)
|
||||
{
|
||||
return Fail("You have exceeded your Album request quota!");
|
||||
return Fail(Engine.ErrorCode.AlbumRequestQuotaExceeded, "You have exceeded your Album request quota!");
|
||||
}
|
||||
}
|
||||
return Success();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
|
@ -56,7 +57,7 @@ namespace Ombi.Core.Rule.Rules
|
|||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return new RuleResult { Message = $"We already have episodes requested from series {vm.Title}" };
|
||||
return new RuleResult { ErrorCode = ErrorCode.EpisodesAlreadyRequested, Message = $"We already have episodes requested from series {vm.Title}" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
|
||||
namespace Ombi.Core.Rule
|
||||
{
|
||||
|
@ -9,9 +10,9 @@ namespace Ombi.Core.Rule
|
|||
return new RuleResult { Success = true };
|
||||
}
|
||||
|
||||
public RuleResult Fail(string message)
|
||||
public RuleResult Fail(ErrorCode errorCode, string message = "")
|
||||
{
|
||||
return new RuleResult { Message = message };
|
||||
return new RuleResult { ErrorCode = errorCode, Message = message };
|
||||
}
|
||||
|
||||
public abstract SpecificRules Rule { get; }
|
||||
|
|
|
@ -615,17 +615,17 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
sb.Append("<tr>");
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
await ProcessPlexTv(plexEpisodes, sb, plexSettings.Servers.FirstOrDefault().ServerHostname ?? string.Empty);
|
||||
await ProcessPlexTv(plexEpisodes, sb, ombiSettings.DefaultLanguageCode, plexSettings.Servers.FirstOrDefault().ServerHostname ?? string.Empty);
|
||||
}
|
||||
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
await ProcessEmbyTv(embyEp, sb, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
|
||||
await ProcessEmbyTv(embyEp, sb, ombiSettings.DefaultLanguageCode, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
|
||||
}
|
||||
|
||||
if (jellyfinSettings.Enable)
|
||||
{
|
||||
await ProcessJellyfinTv(jellyfinEp, sb, jellyfinSettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
|
||||
await ProcessJellyfinTv(jellyfinEp, sb, ombiSettings.DefaultLanguageCode, jellyfinSettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
|
||||
}
|
||||
|
||||
sb.Append("</tr>");
|
||||
|
@ -908,7 +908,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
AddGenres(sb, $"Type: {info.albumType}");
|
||||
}
|
||||
|
||||
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb, string serverHostname)
|
||||
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb, string languageCode, string serverHostname)
|
||||
{
|
||||
var series = new List<PlexServerContent>();
|
||||
foreach (var plexEpisode in plexContent)
|
||||
|
@ -975,7 +975,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
banner = banner.ToHttpsUrl(); // Always use the Https banners
|
||||
}
|
||||
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId);
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId, languageCode);
|
||||
if (tvInfo != null && tvInfo.backdrop_path.HasValue())
|
||||
{
|
||||
|
||||
|
@ -989,16 +989,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
AddMediaServerUrl(sb, PlexHelper.BuildPlexMediaUrl(t.Url, serverHostname), banner);
|
||||
AddInfoTable(sb);
|
||||
|
||||
var title = "";
|
||||
if (!string.IsNullOrEmpty(info.premiered) && info.premiered.Length > 4)
|
||||
{
|
||||
title = $"{t.Title} ({info.premiered.Remove(4)})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = $"{t.Title}";
|
||||
}
|
||||
AddTitle(sb, $"https://www.imdb.com/title/{info.externals.imdb}/", title);
|
||||
AddTvTitle(sb, info, tvInfo);
|
||||
|
||||
// Group by the season number
|
||||
var results = t.Episodes.GroupBy(p => p.SeasonNumber,
|
||||
|
@ -1021,18 +1012,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
finalsb.Append("<br />");
|
||||
}
|
||||
|
||||
var summary = info.summary;
|
||||
if (summary.Length > 280)
|
||||
{
|
||||
summary = summary.Remove(280);
|
||||
summary = summary + "...</p>";
|
||||
}
|
||||
AddTvParagraph(sb, finalsb.ToString(), summary);
|
||||
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -1056,7 +1036,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
|
||||
|
||||
private async Task ProcessEmbyTv(HashSet<EmbyEpisode> embyContent, StringBuilder sb, string serverUrl)
|
||||
private async Task ProcessEmbyTv(HashSet<EmbyEpisode> embyContent, StringBuilder sb, string languageCode, string serverUrl)
|
||||
{
|
||||
var series = new List<EmbyContent>();
|
||||
foreach (var episode in embyContent)
|
||||
|
@ -1100,7 +1080,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
banner = banner.ToHttpsUrl(); // Always use the Https banners
|
||||
}
|
||||
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId);
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId, languageCode);
|
||||
if (tvInfo != null && tvInfo.backdrop_path.HasValue())
|
||||
{
|
||||
|
||||
|
@ -1114,16 +1094,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner);
|
||||
AddInfoTable(sb);
|
||||
|
||||
var title = "";
|
||||
if (!String.IsNullOrEmpty(info.premiered) && info.premiered.Length > 4)
|
||||
{
|
||||
title = $"{t.Title} ({info.premiered.Remove(4)})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = $"{t.Title}";
|
||||
}
|
||||
AddTitle(sb, $"https://www.imdb.com/title/{info.externals.imdb}/", title);
|
||||
AddTvTitle(sb, info, tvInfo);
|
||||
|
||||
// Group by the season number
|
||||
var results = t.Episodes?.GroupBy(p => p.SeasonNumber,
|
||||
|
@ -1146,18 +1117,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
finalsb.Append("<br />");
|
||||
}
|
||||
|
||||
var summary = info.summary;
|
||||
if (summary.Length > 280)
|
||||
{
|
||||
summary = summary.Remove(280);
|
||||
summary = summary + "...</p>";
|
||||
}
|
||||
AddTvParagraph(sb, finalsb.ToString(), summary);
|
||||
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -1179,10 +1139,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ProcessJellyfinTv(HashSet<JellyfinEpisode> embyContent, StringBuilder sb, string serverUrl)
|
||||
private async Task ProcessJellyfinTv(HashSet<JellyfinEpisode> jellyfinContent, StringBuilder sb, string languageCode, string serverUrl)
|
||||
{
|
||||
var series = new List<JellyfinContent>();
|
||||
foreach (var episode in embyContent)
|
||||
foreach (var episode in jellyfinContent)
|
||||
{
|
||||
var alreadyAdded = series.FirstOrDefault(x => x.JellyfinId == episode.Series.JellyfinId);
|
||||
if (alreadyAdded != null)
|
||||
|
@ -1223,7 +1183,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
banner = banner.ToHttpsUrl(); // Always use the Https banners
|
||||
}
|
||||
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId);
|
||||
var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId, languageCode);
|
||||
if (tvInfo != null && tvInfo.backdrop_path.HasValue())
|
||||
{
|
||||
|
||||
|
@ -1237,16 +1197,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner);
|
||||
AddInfoTable(sb);
|
||||
|
||||
var title = "";
|
||||
if (!String.IsNullOrEmpty(info.premiered) && info.premiered.Length > 4)
|
||||
{
|
||||
title = $"{t.Title} ({info.premiered.Remove(4)})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = $"{t.Title}";
|
||||
}
|
||||
AddTitle(sb, $"https://www.imdb.com/title/{info.externals.imdb}/", title);
|
||||
AddTvTitle(sb, info, tvInfo);
|
||||
|
||||
// Group by the season number
|
||||
var results = t.Episodes?.GroupBy(p => p.SeasonNumber,
|
||||
|
@ -1269,18 +1220,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
finalsb.Append("<br />");
|
||||
}
|
||||
|
||||
var summary = info.summary;
|
||||
if (summary.Length > 280)
|
||||
{
|
||||
summary = summary.Remove(280);
|
||||
summary = summary + "...</p>";
|
||||
}
|
||||
AddTvParagraph(sb, finalsb.ToString(), summary);
|
||||
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -1302,6 +1242,36 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
}
|
||||
|
||||
private void AddTvTitle(StringBuilder sb, Api.TvMaze.Models.TvMazeShow info, TvInfo tvInfo)
|
||||
{
|
||||
var title = "";
|
||||
if (!String.IsNullOrEmpty(info.premiered) && info.premiered.Length > 4)
|
||||
{
|
||||
title = $"{tvInfo.name} ({info.premiered.Remove(4)})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = $"{tvInfo.name}";
|
||||
}
|
||||
AddTitle(sb, $"https://www.imdb.com/title/{info.externals.imdb}/", title);
|
||||
}
|
||||
|
||||
private void AddTvEpisodesSummaryGenres(StringBuilder sb, string episodes, TvInfo tvInfo)
|
||||
{
|
||||
var summary = tvInfo.overview;
|
||||
if (summary.Length > 280)
|
||||
{
|
||||
summary = summary.Remove(280);
|
||||
summary = summary + "...</p>";
|
||||
}
|
||||
AddTvParagraph(sb, episodes, summary);
|
||||
|
||||
if (tvInfo.genres.Any())
|
||||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", tvInfo.genres.Select(x => x.name.ToString()).ToArray())}");
|
||||
}
|
||||
}
|
||||
|
||||
private void EndLoopHtml(StringBuilder sb)
|
||||
{
|
||||
//NOTE: BR have to be in TD's as per html spec or it will be put outside of the table...
|
||||
|
|
|
@ -124,7 +124,7 @@ export class DiscoverCardComponent implements OnInit {
|
|||
dialog.afterClosed().subscribe((result) => {
|
||||
if (result) {
|
||||
this.requestService.requestMovie({ theMovieDbId: +this.result.id,
|
||||
languageCode: null,
|
||||
languageCode: this.translate.currentLang,
|
||||
qualityPathOverride: result.radarrPathId,
|
||||
requestOnBehalf: result.username?.id,
|
||||
rootFolderOverride: result.radarrFolderId, }).subscribe(x => {
|
||||
|
@ -132,18 +132,18 @@ export class DiscoverCardComponent implements OnInit {
|
|||
this.result.requested = true;
|
||||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", { title: this.result.title }), "Ok");
|
||||
} else {
|
||||
this.messageService.send(x.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.requestService.requestMovie({ theMovieDbId: +this.result.id, languageCode: null, requestOnBehalf: null, qualityPathOverride: null, rootFolderOverride: null }).subscribe(x => {
|
||||
this.requestService.requestMovie({ theMovieDbId: +this.result.id, languageCode: this.translate.currentLang, requestOnBehalf: null, qualityPathOverride: null, rootFolderOverride: null }).subscribe(x => {
|
||||
if (x.result) {
|
||||
this.result.requested = true;
|
||||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", { title: this.result.title }), "Ok");
|
||||
} else {
|
||||
this.messageService.send(x.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(x);
|
||||
}
|
||||
this.loading = false;
|
||||
});
|
||||
|
|
|
@ -46,7 +46,7 @@ export class DiscoverCollectionsComponent implements OnInit {
|
|||
if (result.result) {
|
||||
this.messageService.send(this.translate.instant("Requests.CollectionSuccesfullyAdded", { name: this.collection.name }));
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage);
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
this.finishLoading();
|
||||
});
|
||||
|
|
|
@ -2,5 +2,21 @@
|
|||
result: boolean;
|
||||
message: string;
|
||||
errorMessage: string;
|
||||
errorCode: ErrorCode;
|
||||
requestId: number | undefined;
|
||||
}
|
||||
|
||||
export enum ErrorCode {
|
||||
AlreadyRequested,
|
||||
EpisodesAlreadyRequested,
|
||||
NoPermissionsOnBehalf,
|
||||
NoPermissions,
|
||||
RequestDoesNotExist,
|
||||
ChildRequestDoesNotExist,
|
||||
NoPermissionsRequestMovie,
|
||||
NoPermissionsRequestTV,
|
||||
NoPermissionsRequestAlbum,
|
||||
MovieRequestQuotaExceeded,
|
||||
TvRequestQuotaExceeded,
|
||||
AlbumRequestQuotaExceeded,
|
||||
}
|
|
@ -44,6 +44,7 @@ export interface ISearchTvResult {
|
|||
|
||||
export interface ITvRequestViewModelV2 extends ITvRequestViewModelBase {
|
||||
theMovieDbId: number;
|
||||
languageCode: string;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import { AuthService } from "../../../auth/auth.service";
|
|||
import { DenyDialogComponent } from "../shared/deny-dialog/deny-dialog.component";
|
||||
import { NewIssueComponent } from "../shared/new-issue/new-issue.component";
|
||||
import { IArtistSearchResult, IReleaseGroups } from "../../../interfaces/IMusicSearchResultV2";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./artist-details.component.html",
|
||||
|
@ -26,7 +27,8 @@ export class ArtistDetailsComponent {
|
|||
constructor(private searchService: SearchV2Service, private route: ActivatedRoute,
|
||||
private sanitizer: DomSanitizer, private imageService: ImageService,
|
||||
public dialog: MatDialog, private requestService: RequestService,
|
||||
public messageService: MessageService, private auth: AuthService) {
|
||||
public messageService: MessageService, private auth: AuthService,
|
||||
private translate: TranslateService) {
|
||||
this.route.params.subscribe((params: any) => {
|
||||
this.artistId = params.artistId;
|
||||
this.load();
|
||||
|
@ -92,16 +94,16 @@ export class ArtistDetailsComponent {
|
|||
.then(r => {
|
||||
if (r.result) {
|
||||
a.monitored = true;
|
||||
this.messageService.send(r.message);
|
||||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", {title: a.title}));
|
||||
} else {
|
||||
this.messageService.send(r.errorMessage);
|
||||
this.messageService.sendRequestEngineResultError(r);
|
||||
}
|
||||
|
||||
a.selected = false;
|
||||
})
|
||||
.catch(r => {
|
||||
console.log(r);
|
||||
this.messageService.send("Error when requesting album");
|
||||
this.messageService.sendRequestEngineResultError(r);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
@ -115,16 +117,16 @@ export class ArtistDetailsComponent {
|
|||
.then(r => {
|
||||
if (r.result) {
|
||||
a.monitored = true;
|
||||
this.messageService.send(r.message);
|
||||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", {title: a.title}));
|
||||
} else {
|
||||
this.messageService.send(r.errorMessage);
|
||||
this.messageService.sendRequestEngineResultError(r);
|
||||
}
|
||||
|
||||
a.selected = false;
|
||||
})
|
||||
.catch(r => {
|
||||
console.log(r);
|
||||
this.messageService.send("Error when requesting album");
|
||||
this.messageService.sendRequestEngineResultError(r);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<div *ngIf="artist">
|
||||
<div>
|
||||
<strong>Type:</strong>
|
||||
<strong>{{ 'MediaDetails.Music.Type' | translate }}</strong>
|
||||
<div>{{artist.type}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Country</strong>
|
||||
<strong>{{ 'MediaDetails.Music.Country' | translate }}</strong>
|
||||
<div>{{artist.country}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Start Date</strong>
|
||||
<strong>{{ 'MediaDetails.Music.StartDate' | translate }}</strong>
|
||||
<div>{{artist.startYear}}</div>
|
||||
</div>
|
||||
<div *ngIf="artist.endYear">
|
||||
<strong>End Date</strong>
|
||||
<strong>{{ 'MediaDetails.Music.EndDate' | translate }}</strong>
|
||||
<div>{{artist.endYear}}</div>
|
||||
</div>
|
||||
</div>
|
|
@ -92,7 +92,7 @@ export class MovieDetailsComponent {
|
|||
dialog.afterClosed().subscribe(async (result) => {
|
||||
if (result) {
|
||||
const requestResult = await this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId,
|
||||
languageCode: null,
|
||||
languageCode: this.translate.currentLang,
|
||||
qualityPathOverride: result.radarrPathId,
|
||||
requestOnBehalf: result.username?.id,
|
||||
rootFolderOverride: result.radarrFolderId, }).toPromise();
|
||||
|
@ -102,19 +102,19 @@ export class MovieDetailsComponent {
|
|||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", { title: this.movie.title }), "Ok");
|
||||
this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId);
|
||||
} else {
|
||||
this.messageService.send(requestResult.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(requestResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const result = await this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId, languageCode: null, requestOnBehalf: userId, qualityPathOverride: undefined, rootFolderOverride: undefined }).toPromise();
|
||||
const result = await this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId, languageCode: this.translate.currentLang, requestOnBehalf: userId, qualityPathOverride: undefined, rootFolderOverride: undefined }).toPromise();
|
||||
if (result.result) {
|
||||
this.movie.requested = true;
|
||||
this.movie.requestId = result.requestId;
|
||||
this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId);
|
||||
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", { title: this.movie.title }), "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ export class MovieDetailsComponent {
|
|||
this.messageService.send(this.translate.instant("Requests.SuccessfullyApproved"), "Ok");
|
||||
} else {
|
||||
this.movie.approved = false;
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ export class MovieDetailsComponent {
|
|||
this.movie.available = true;
|
||||
this.messageService.send(this.translate.instant("Requests.NowAvailable"), "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ export class MovieDetailsComponent {
|
|||
this.movie.available = false;
|
||||
this.messageService.send(this.translate.instant("Requests.NowUnavailable"), "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ export class MovieDetailsComponent {
|
|||
if (result.result) {
|
||||
this.messageService.send(result.message ? result.message : this.translate.instant("Requests.SuccessfullyReprocessed"), "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export class DenyDialogComponent {
|
|||
this.messageService.send(this.translate.instant("Requests.DeniedRequest"), "Ok");
|
||||
this.data.denied = true;
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
this.data.denied = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { RequestService } from "../../../../../services/request.service";
|
|||
import { MessageService } from "../../../../../services";
|
||||
import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component";
|
||||
import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { SelectionModel } from "@angular/cdk/collections";
|
||||
import { RequestServiceV2 } from "../../../../../services/requestV2.service";
|
||||
|
@ -27,7 +28,7 @@ export class TvRequestGridComponent {
|
|||
public displayedColumns: string[] = ['select', 'number', 'title', 'airDate', 'status'];
|
||||
|
||||
constructor(private requestService: RequestService, private requestServiceV2: RequestServiceV2, private notificationService: MessageService,
|
||||
private dialog: MatDialog) {
|
||||
private dialog: MatDialog, private translate: TranslateService) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ export class TvRequestGridComponent {
|
|||
|
||||
const viewModel = <ITvRequestViewModelV2>{
|
||||
firstSeason: this.tv.firstSeason, latestSeason: this.tv.latestSeason, requestAll: this.tv.requestAll, theMovieDbId: this.tv.id,
|
||||
requestOnBehalf: null
|
||||
requestOnBehalf: null, languageCode: this.translate.currentLang
|
||||
};
|
||||
viewModel.seasons = [];
|
||||
this.tv.seasonRequests.forEach((season) => {
|
||||
|
@ -236,7 +237,7 @@ export class TvRequestGridComponent {
|
|||
private postRequest(requestResult: IRequestEngineResult) {
|
||||
if (requestResult.result) {
|
||||
this.notificationService.send(
|
||||
`Request for ${this.tv.title} has been added successfully`);
|
||||
this.translate.instant("Requests.RequestAddedSuccessfully", { title:this.tv.title }));
|
||||
|
||||
this.selection.clear();
|
||||
|
||||
|
@ -262,7 +263,7 @@ export class TvRequestGridComponent {
|
|||
}
|
||||
|
||||
} else {
|
||||
this.notificationService.send(requestResult.errorMessage ? requestResult.errorMessage : requestResult.message);
|
||||
this.notificationService.sendRequestEngineResultError(requestResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export class TvRequestsPanelComponent {
|
|||
});
|
||||
this.messageService.send("Request has been approved", "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ export class TvRequestsPanelComponent {
|
|||
if (result.result) {
|
||||
this.messageService.send(result.message ? result.message : "Successfully Re-processed the request", "Ok");
|
||||
} else {
|
||||
this.messageService.send(result.errorMessage, "Ok");
|
||||
this.messageService.sendRequestEngineResultError(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Injectable } from "@angular/core";
|
||||
import { MatSnackBar, MatSnackBarConfig } from "@angular/material/snack-bar";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { IRequestEngineResult } from "../interfaces/IRequestEngineResult";
|
||||
|
||||
@Injectable()
|
||||
export class MessageService {
|
||||
constructor(private snackBar: MatSnackBar) {
|
||||
constructor(private snackBar: MatSnackBar, private translate: TranslateService) {
|
||||
this.config = {
|
||||
duration: 4000,
|
||||
}
|
||||
|
@ -18,4 +20,13 @@ export class MessageService {
|
|||
this.snackBar.open(message, "OK", this.config)
|
||||
}
|
||||
}
|
||||
public sendRequestEngineResultError(result: IRequestEngineResult, action: string = "Ok") {
|
||||
const textKey = 'Requests.ErrorCodes.' + result.errorCode;
|
||||
const text = this.translate.instant(textKey);
|
||||
if (text !== textKey) {
|
||||
this.send(text, action);
|
||||
} else {
|
||||
this.send(result.errorMessage ? result.errorMessage : result.message, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ export class EpisodeRequestComponent {
|
|||
|
||||
const viewModel = <ITvRequestViewModelV2>{
|
||||
firstSeason: this.data.series.firstSeason, latestSeason: this.data.series.latestSeason, requestAll: this.data.series.requestAll, theMovieDbId: this.data.series.id,
|
||||
requestOnBehalf: this.data.requestOnBehalf
|
||||
requestOnBehalf: this.data.requestOnBehalf, languageCode: this.translate.currentLang
|
||||
};
|
||||
viewModel.seasons = [];
|
||||
this.data.series.seasonRequests.forEach((season) => {
|
||||
|
@ -134,7 +134,7 @@ export class EpisodeRequestComponent {
|
|||
});
|
||||
|
||||
} else {
|
||||
this.notificationService.send(requestResult.errorMessage ? requestResult.errorMessage : requestResult.message);
|
||||
this.notificationService.sendRequestEngineResultError(requestResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
"Submit": "Submit",
|
||||
"Update": "Update",
|
||||
"tvShow": "TV Show",
|
||||
"movie": "Movie"
|
||||
"movie": "Movie",
|
||||
"album": "Album"
|
||||
},
|
||||
"PasswordReset": {
|
||||
"EmailAddressPlaceholder": "Email Address",
|
||||
|
@ -204,7 +205,21 @@
|
|||
"RequestCollection": "Request Collection",
|
||||
"CollectionSuccesfullyAdded": "The collection {{name}} has been successfully added!",
|
||||
"NeedToSelectEpisodes": "You need to select some episodes!",
|
||||
"RequestAddedSuccessfully": "Request for {{title}} has been added successfully"
|
||||
"RequestAddedSuccessfully": "Request for {{title}} has been added successfully",
|
||||
"ErrorCodes": {
|
||||
"AlreadyRequested": "This has already been requested",
|
||||
"EpisodesAlreadyRequested": "We already have episodes requested from this series",
|
||||
"NoPermissionsOnBehalf":"You do not have the correct permissions to request on behalf of users!",
|
||||
"NoPermissions":"You do not have the correct permissions!",
|
||||
"RequestDoesNotExist":"Request does not exist",
|
||||
"ChildRequestDoesNotExist":"Child Request does not exist",
|
||||
"NoPermissionsRequestMovie":"You do not have permissions to Request a Movie",
|
||||
"NoPermissionsRequestTV":"You do not have permissions to Request a TV Show",
|
||||
"NoPermissionsRequestAlbum":"You do not have permissions to Request an Album",
|
||||
"MovieRequestQuotaExceeded":"You have exceeded your Movie request quota!",
|
||||
"TvRequestQuotaExceeded":"You have exceeded your Episode request quota!",
|
||||
"AlbumRequestQuotaExceeded":"You have exceeded your Album request quota!"
|
||||
}
|
||||
},
|
||||
"Issues": {
|
||||
"Title": "Issues",
|
||||
|
@ -284,9 +299,12 @@
|
|||
"LanguageProfileSelect":"Select A Language Profile",
|
||||
"Status":"Status:",
|
||||
"StatusValues" : {
|
||||
"Rumored" : "Rumored",
|
||||
"Planned": "Planned",
|
||||
"In Production": "In Production",
|
||||
"Post Production": "Post Production",
|
||||
"Released": "Released",
|
||||
"Running": "Running",
|
||||
"Returning Series": "Returning Series",
|
||||
"Ended": "Ended",
|
||||
"Canceled": "Canceled"
|
||||
|
@ -327,7 +345,13 @@
|
|||
"RequestedBy": "Requested By:",
|
||||
"RequestDate": "Request Date:",
|
||||
"DeniedReason": "Denied Reason:",
|
||||
"ReProcessRequest": "Re-Process Request"
|
||||
"ReProcessRequest": "Re-Process Request",
|
||||
"Music": {
|
||||
"Type": "Type:",
|
||||
"Country": "Country:",
|
||||
"StartDate": "Start Date:",
|
||||
"EndDate": "EndDate:"
|
||||
}
|
||||
},
|
||||
"Discovery": {
|
||||
"PopularTab": "Popular",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue