diff --git a/CHANGELOG.md b/CHANGELOG.md index fb91d9d96..bdb3b8539 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## (unreleased) +## v3.0.3477 (2018-07-18) ### **New Features** diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 15383ed12..f73c6fda1 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -452,6 +452,7 @@ namespace Ombi.Core.Engine } request.Available = true; + request.MarkedAsAvailable = DateTime.Now; NotificationHelper.Notify(request, NotificationType.RequestAvailable); await MovieRepository.Update(request); diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index 76be03aff..4c06fd520 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -467,6 +467,7 @@ namespace Ombi.Core.Engine }; } request.Available = true; + request.MarkedAsAvailable = DateTime.Now; foreach (var season in request.SeasonRequests) { foreach (var e in season.Episodes) diff --git a/src/Ombi.Core/Engine/UserStatsEngine.cs b/src/Ombi.Core/Engine/UserStatsEngine.cs new file mode 100644 index 000000000..f416d56e3 --- /dev/null +++ b/src/Ombi.Core/Engine/UserStatsEngine.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Authentication; +using Ombi.Store.Entities; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Core.Engine +{ + public class UserStatsEngine + { + public UserStatsEngine(OmbiUserManager um, IMovieRequestRepository movieRequest, ITvRequestRepository tvRequest) + { + _userManager = um; + _movieRequest = movieRequest; + _tvRequest = tvRequest; + } + + private readonly OmbiUserManager _userManager; + private readonly IMovieRequestRepository _movieRequest; + private readonly ITvRequestRepository _tvRequest; + + public async Task GetSummary(SummaryRequest request) + { + /* What do we want? + + This is Per week/month/all time (filter by date) + + 1. Total Requests + 2. Total Movie Requests + 3. Total Tv Requests + 4. Total Issues (If enabled) + 5. Total Requests fufilled (now available) + + Then + + 2. Most requested user Movie + 3. Most requested user tv + + Then + + 1. + + */ + + // get all movie requests + var movies = _movieRequest.GetWithUser(); + var filteredMovies = movies.Where(x => x.RequestedDate >= request.From && x.RequestedDate <= request.To); + var tv = _tvRequest.GetLite(); + var children = tv.SelectMany(x => + x.ChildRequests.Where(c => c.RequestedDate >= request.From && c.RequestedDate <= request.To)); + + var moviesCount = filteredMovies.CountAsync(); + var childrenCount = children.CountAsync(); + var availableMovies = + movies.Select(x => x.MarkedAsAvailable >= request.From && x.MarkedAsAvailable <= request.To).CountAsync(); + var availableChildren = tv.SelectMany(x => + x.ChildRequests.Where(c => c.MarkedAsAvailable >= request.From && c.MarkedAsAvailable <= request.To)).CountAsync(); + + var userMovie = filteredMovies.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync(); + var userTv = children.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync(); + + + return new UserStatsSummary + { + TotalMovieRequests = await moviesCount, + TotalTvRequests = await childrenCount, + CompletedRequestsTv = await availableChildren, + CompletedRequestsMovies = await availableMovies, + MostRequestedUserMovie = (await userMovie).FirstOrDefault().RequestedUser, + MostRequestedUserTv = (await userTv).FirstOrDefault().RequestedUser, + }; + } + } + + public class SummaryRequest + { + public DateTime From { get; set; } + public DateTime To { get; set; } + } + + public class UserStatsSummary + { + public int TotalRequests => TotalTvRequests + TotalTvRequests; + public int TotalMovieRequests { get; set; } + public int TotalTvRequests { get; set; } + public int TotalIssues { get; set; } + public int CompletedRequestsMovies { get; set; } + public int CompletedRequestsTv { get; set; } + public int CompletedRequests => CompletedRequestsMovies + CompletedRequestsTv; + public OmbiUser MostRequestedUserMovie { get; set; } + public OmbiUser MostRequestedUserTv { get; set; } + + } +} diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs index ec675ebd8..7007b3743 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs @@ -89,6 +89,7 @@ namespace Ombi.Schedule.Jobs.Emby _log.LogInformation("We have found the request {0} on Emby, sending the notification", movie?.Title ?? string.Empty); movie.Available = true; + movie.MarkedAsAvailable = DateTime.Now; if (movie.Available) { var recipient = movie.RequestedUser.Email.HasValue() ? movie.RequestedUser.Email : string.Empty; @@ -185,6 +186,7 @@ namespace Ombi.Schedule.Jobs.Emby { // We have fulfulled this request! child.Available = true; + child.MarkedAsAvailable = DateTime.Now; BackgroundJob.Enqueue(() => _notificationService.Publish(new NotificationOptions { DateTime = DateTime.Now, diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 9978b7e2b..e0278f854 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -123,6 +123,7 @@ namespace Ombi.Schedule.Jobs.Plex { // We have fulfulled this request! child.Available = true; + child.MarkedAsAvailable = DateTime.Now; _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions { DateTime = DateTime.Now, @@ -163,6 +164,7 @@ namespace Ombi.Schedule.Jobs.Plex } movie.Available = true; + movie.MarkedAsAvailable = DateTime.Now; if (movie.Available) { _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions diff --git a/src/Ombi.Store/Entities/Requests/BaseRequest.cs b/src/Ombi.Store/Entities/Requests/BaseRequest.cs index 95395d0bf..f224032f1 100644 --- a/src/Ombi.Store/Entities/Requests/BaseRequest.cs +++ b/src/Ombi.Store/Entities/Requests/BaseRequest.cs @@ -8,10 +8,13 @@ namespace Ombi.Store.Entities.Requests { public string Title { get; set; } public bool Approved { get; set; } + public DateTime MarkedAsApproved { get; set; } public DateTime RequestedDate { get; set; } public bool Available { get; set; } + public DateTime? MarkedAsAvailable { get; set; } public string RequestedUserId { get; set; } public bool? Denied { get; set; } + public DateTime MarkedAsDenied { get; set; } public string DeniedReason { get; set; } public RequestType RequestType { get; set; } diff --git a/src/Ombi.Store/Migrations/20180730085903_UserStats.Designer.cs b/src/Ombi.Store/Migrations/20180730085903_UserStats.Designer.cs new file mode 100644 index 000000000..1f34d280f --- /dev/null +++ b/src/Ombi.Store/Migrations/20180730085903_UserStats.Designer.cs @@ -0,0 +1,988 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Ombi.Store.Context; + +namespace Ombi.Store.Migrations +{ + [DbContext(typeof(OmbiContext))] + [Migration("20180730085903_UserStats")] + partial class UserStats + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider"); + + b.Property("ProviderKey"); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider"); + + b.Property("Name"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Type"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("ApplicationConfiguration"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditArea"); + + b.Property("AuditType"); + + b.Property("DateTime"); + + b.Property("Description"); + + b.Property("User"); + + b.HasKey("Id"); + + b.ToTable("Audit"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("CouchPotatoCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId") + .IsRequired(); + + b.Property("ImdbId"); + + b.Property("ProviderId"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.Property("Type"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId"); + + b.Property("EpisodeNumber"); + + b.Property("ImdbId"); + + b.Property("ParentId"); + + b.Property("ProviderId"); + + b.Property("SeasonNumber"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Content"); + + b.Property("SettingsName"); + + b.HasKey("Id"); + + b.ToTable("GlobalSettings"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Agent"); + + b.Property("Enabled"); + + b.Property("Message"); + + b.Property("NotificationType"); + + b.Property("Subject"); + + b.HasKey("Id"); + + b.ToTable("NotificationTemplates"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("PlayerId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("Alias"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("EmbyConnectUserId"); + + b.Property("EpisodeRequestLimit"); + + b.Property("LastLoggedIn"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("MovieRequestLimit"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("ProviderUserId"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserAccessToken"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("UserType"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("GrandparentKey"); + + b.Property("Key"); + + b.Property("ParentKey"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ParentKey"); + + b.Property("PlexContentId"); + + b.Property("PlexServerContentId"); + + b.Property("SeasonKey"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("PlexServerContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("ImdbId"); + + b.Property("Key"); + + b.Property("Quality"); + + b.Property("ReleaseYear"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.Property("Type"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.ToTable("PlexServerContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("HasFile"); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("ContentId"); + + b.Property("ContentType"); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("RecentlyAddedLog"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("IssueId"); + + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + + b.Property("ParentRequestId"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("SeriesType"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentRequestId"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("ChildRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("IssueCategory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Comment"); + + b.Property("Date"); + + b.Property("IssuesId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("IssuesId"); + + b.HasIndex("UserId"); + + b.ToTable("IssueComments"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueCategoryId"); + + b.Property("IssueId"); + + b.Property("ProviderId"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("ResovledDate"); + + b.Property("Status"); + + b.Property("Subject"); + + b.Property("Title"); + + b.Property("UserReportedId"); + + b.HasKey("Id"); + + b.HasIndex("IssueCategoryId"); + + b.HasIndex("IssueId"); + + b.HasIndex("UserReportedId"); + + b.ToTable("Issues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Background"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("DigitalReleaseDate"); + + b.Property("ImdbId"); + + b.Property("IssueId"); + + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + b.Property("ReleaseDate"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("RootPathOverride"); + + b.Property("Status"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("MovieRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeCount"); + + b.Property("RequestDate"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RequestLog"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Background"); + + b.Property("ImdbId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + b.Property("ReleaseDate"); + + b.Property("RootFolder"); + + b.Property("Status"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("TvRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RequestSubscription"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("HasFile"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AirDate"); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("EpisodeNumber"); + + b.Property("Requested"); + + b.Property("SeasonId"); + + b.Property("Title"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("EpisodeRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChildRequestId"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("ChildRequestId"); + + b.ToTable("SeasonRequests"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany("NotificationUserIds") + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent") + .WithMany("Seasons") + .HasForeignKey("PlexServerContentId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest") + .WithMany("ChildRequests") + .HasForeignKey("ParentRequestId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues") + .WithMany("Comments") + .HasForeignKey("IssuesId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory") + .WithMany() + .HasForeignKey("IssueCategoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported") + .WithMany() + .HasForeignKey("UserReportedId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest") + .WithMany("SeasonRequests") + .HasForeignKey("ChildRequestId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/20180730085903_UserStats.cs b/src/Ombi.Store/Migrations/20180730085903_UserStats.cs new file mode 100644 index 000000000..576ff28c6 --- /dev/null +++ b/src/Ombi.Store/Migrations/20180730085903_UserStats.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Ombi.Store.Migrations +{ + public partial class UserStats : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "MarkedAsApproved", + table: "MovieRequests", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "MarkedAsAvailable", + table: "MovieRequests", + nullable: true); + + migrationBuilder.AddColumn( + name: "MarkedAsDenied", + table: "MovieRequests", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "MarkedAsApproved", + table: "ChildRequests", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "MarkedAsAvailable", + table: "ChildRequests", + nullable: true); + + migrationBuilder.AddColumn( + name: "MarkedAsDenied", + table: "ChildRequests", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "MarkedAsApproved", + table: "MovieRequests"); + + migrationBuilder.DropColumn( + name: "MarkedAsAvailable", + table: "MovieRequests"); + + migrationBuilder.DropColumn( + name: "MarkedAsDenied", + table: "MovieRequests"); + + migrationBuilder.DropColumn( + name: "MarkedAsApproved", + table: "ChildRequests"); + + migrationBuilder.DropColumn( + name: "MarkedAsAvailable", + table: "ChildRequests"); + + migrationBuilder.DropColumn( + name: "MarkedAsDenied", + table: "ChildRequests"); + } + } +} diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs index ea624fadb..5a7520005 100644 --- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs @@ -1,15 +1,9 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using Ombi.Helpers; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Ombi.Store.Context; -using Ombi.Store.Entities; -using Ombi.Store.Entities.Requests; -using System; namespace Ombi.Store.Migrations { @@ -20,7 +14,7 @@ namespace Ombi.Store.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.3-rtm-10026"); + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { @@ -481,6 +475,12 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + b.Property("ParentRequestId"); b.Property("RequestType"); @@ -595,6 +595,12 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + b.Property("Overview"); b.Property("PosterPath"); diff --git a/src/Ombi/ClientApp/app/app.component.html b/src/Ombi/ClientApp/app/app.component.html index ef6e3d461..af7315596 100644 --- a/src/Ombi/ClientApp/app/app.component.html +++ b/src/Ombi/ClientApp/app/app.component.html @@ -134,6 +134,12 @@
  • +
  • + +
  • +
  • + +
  • diff --git a/src/Ombi/ClientApp/app/app.component.ts b/src/Ombi/ClientApp/app/app.component.ts index 16d8b21d6..07be7d56b 100644 --- a/src/Ombi/ClientApp/app/app.component.ts +++ b/src/Ombi/ClientApp/app/app.component.ts @@ -39,14 +39,14 @@ export class AppComponent implements OnInit { if (base.length > 1) { __webpack_public_path__ = base + "/dist/"; } - - this.translate.addLangs(["en", "de", "fr", "da", "es", "it", "nl", "sv", "no"]); + + this.translate.addLangs(["en", "de", "fr", "da", "es", "it", "nl", "sv", "no", "pl", "pt"]); // this language will be used as a fallback when a translation isn't found in the current language this.translate.setDefaultLang("en"); // See if we can match the supported langs with the current browser lang const browserLang: string = translate.getBrowserLang(); - this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no/) ? browserLang : "en"); + this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no|pl|pt/) ? browserLang : "en"); } public ngOnInit() { diff --git a/src/Ombi/ClientApp/app/interfaces/IUser.ts b/src/Ombi/ClientApp/app/interfaces/IUser.ts index bab851420..0e8141b52 100644 --- a/src/Ombi/ClientApp/app/interfaces/IUser.ts +++ b/src/Ombi/ClientApp/app/interfaces/IUser.ts @@ -23,6 +23,11 @@ export interface ICreateWizardUser { usePlexAdminAccount: boolean; } +export interface IWizardUserResult { + result: boolean; + errors: string[]; +} + export enum UserType { LocalUser = 1, PlexUser = 2, diff --git a/src/Ombi/ClientApp/app/services/identity.service.ts b/src/Ombi/ClientApp/app/services/identity.service.ts index 16ea58fb2..e3dc1d8ad 100644 --- a/src/Ombi/ClientApp/app/services/identity.service.ts +++ b/src/Ombi/ClientApp/app/services/identity.service.ts @@ -4,7 +4,7 @@ import { Injectable } from "@angular/core"; import { HttpClient } from "@angular/common/http"; import { Observable } from "rxjs"; -import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser } from "../interfaces"; +import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser, IWizardUserResult } from "../interfaces"; import { ServiceHelpers } from "./service.helpers"; @Injectable() @@ -12,8 +12,8 @@ export class IdentityService extends ServiceHelpers { constructor(http: HttpClient, public platformLocation: PlatformLocation) { super(http, "/api/v1/Identity/", platformLocation); } - public createWizardUser(user: ICreateWizardUser): Observable { - return this.http.post(`${this.url}Wizard/`, JSON.stringify(user), {headers: this.headers}); + public createWizardUser(user: ICreateWizardUser): Observable { + return this.http.post(`${this.url}Wizard/`, JSON.stringify(user), {headers: this.headers}); } public getUser(): Observable { diff --git a/src/Ombi/ClientApp/app/wizard/createadmin/createadmin.component.ts b/src/Ombi/ClientApp/app/wizard/createadmin/createadmin.component.ts index b997f1d9f..ee5514fcb 100644 --- a/src/Ombi/ClientApp/app/wizard/createadmin/createadmin.component.ts +++ b/src/Ombi/ClientApp/app/wizard/createadmin/createadmin.component.ts @@ -17,10 +17,12 @@ export class CreateAdminComponent { public createUser() { this.identityService.createWizardUser({username: this.username, password: this.password, usePlexAdminAccount: false}).subscribe(x => { - if (x) { + if (x.result) { this.router.navigate(["login"]); } else { - this.notificationService.error("There was an error... You might want to put this on Github..."); + if(x.errors.length > 0) { + this.notificationService.error(x.errors[0]); + } } }); } diff --git a/src/Ombi/ClientApp/app/wizard/plex/plex.component.ts b/src/Ombi/ClientApp/app/wizard/plex/plex.component.ts index b540ba065..d3ee8efa6 100644 --- a/src/Ombi/ClientApp/app/wizard/plex/plex.component.ts +++ b/src/Ombi/ClientApp/app/wizard/plex/plex.component.ts @@ -31,18 +31,21 @@ export class PlexComponent implements OnInit { } this.identityService.createWizardUser({ - username: "", - password: "", - usePlexAdminAccount: true, - }).subscribe(y => { - if (y) { - this.router.navigate(["login"]); - } else { - this.notificationService.error("Could not get the Plex Admin Information"); - return; - } - }); - }, + username: "", + password: "", + usePlexAdminAccount: true, + }).subscribe(y => { + if (y.result) { + this.router.navigate(["login"]); + } else { + this.notificationService.error("Could not get the Plex Admin Information"); + if(y.errors.length > 0) { + this.notificationService.error(y.errors[0]); + } + return; + } + }); + }, ); } diff --git a/src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts b/src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts index f2867dfe7..40584a97d 100644 --- a/src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts +++ b/src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; -import { IdentityService, PlexOAuthService, SettingsService } from "../../services"; +import { IdentityService, PlexOAuthService } from "../../services"; import { AuthService } from "./../../auth/auth.service"; @Component({ @@ -13,7 +13,6 @@ export class PlexOAuthComponent implements OnInit { constructor(private route: ActivatedRoute, private plexOauth: PlexOAuthService, private identityService: IdentityService, - private settings: SettingsService, private router: Router, private auth: AuthService) { @@ -31,34 +30,24 @@ export class PlexOAuthComponent implements OnInit { } this.identityService.createWizardUser({ - username: "", - password: "", - usePlexAdminAccount: true, - }).subscribe(u => { - if (u) { - this.auth.oAuth(this.pinId).subscribe(c => { - localStorage.setItem("id_token", c.access_token); - - // Mark that we have done the settings now - this.settings.getOmbi().subscribe(ombi => { - ombi.wizard = true; - - this.settings.saveOmbi(ombi).subscribe(s => { - this.settings.getUserManagementSettings().subscribe(usr => { - - usr.importPlexAdmin = true; - this.settings.saveUserManagementSettings(usr).subscribe(saved => { - this.router.navigate(["login"]); - }); - }); + username: "", + password: "", + usePlexAdminAccount: true, + }).subscribe(u => { + if (u.result) { + this.auth.oAuth(this.pinId).subscribe(c => { + localStorage.setItem("id_token", c.access_token); + this.router.navigate(["login"]); }); - }); + } else { + + if(u.errors.length > 0) { + console.log(u.errors[0]); + } + return; + } }); - } else { - //this.notificationService.error("Could not get the Plex Admin Information"); - return; - } - }); + }); } } diff --git a/src/Ombi/ClientApp/styles/base.scss b/src/Ombi/ClientApp/styles/base.scss index 380c3ba72..d36986be8 100644 --- a/src/Ombi/ClientApp/styles/base.scss +++ b/src/Ombi/ClientApp/styles/base.scss @@ -455,7 +455,7 @@ $border-radius: 10px; } .checkbox input[type=checkbox] { - display: none; + opacity: 0; } .checkbox input[type=checkbox]:checked + label:before { @@ -965,4 +965,4 @@ a > h4:hover { .subject-category, .subject { display: inline-block; -} \ No newline at end of file +} diff --git a/src/Ombi/Controllers/IdentityController.cs b/src/Ombi/Controllers/IdentityController.cs index 38c2d1e94..742d75b34 100644 --- a/src/Ombi/Controllers/IdentityController.cs +++ b/src/Ombi/Controllers/IdentityController.cs @@ -59,7 +59,8 @@ namespace Ombi.Controllers IRepository issues, IRepository issueComments, IRepository notificationRepository, - IRepository subscriptionRepository) + IRepository subscriptionRepository, + ISettingsService umSettings) { UserManager = user; Mapper = mapper; @@ -79,6 +80,7 @@ namespace Ombi.Controllers OmbiSettings = ombiSettings; _requestSubscriptionRepository = subscriptionRepository; _notificationRepository = notificationRepository; + _userManagementSettings = umSettings; } private OmbiUserManager UserManager { get; } @@ -87,6 +89,7 @@ namespace Ombi.Controllers private IEmailProvider EmailProvider { get; } private ISettingsService EmailSettings { get; } private ISettingsService CustomizationSettings { get; } + private readonly ISettingsService _userManagementSettings; private ISettingsService OmbiSettings { get; } private IWelcomeEmail WelcomeEmail { get; } private IMovieRequestRepository MovieRepo { get; } @@ -113,13 +116,13 @@ namespace Ombi.Controllers [HttpPost("Wizard")] [ApiExplorerSettings(IgnoreApi = true)] [AllowAnonymous] - public async Task CreateWizardUser([FromBody] CreateUserWizardModel user) + public async Task CreateWizardUser([FromBody] CreateUserWizardModel user) { var users = UserManager.Users; - if (users.Any(x => !x.UserName.Equals("api", StringComparison.CurrentCultureIgnoreCase))) + if (users.Any(x => !x.UserName.Equals("api", StringComparison.InvariantCultureIgnoreCase))) { // No one should be calling this. Only the wizard - return false; + return new SaveWizardResult{ Result = false, Errors = new List {"Looks like there is an existing user!"} }; } if (user.UsePlexAdminAccount) @@ -129,7 +132,7 @@ namespace Ombi.Controllers if (authToken.IsNullOrEmpty()) { _log.LogWarning("Could not find an auth token to create the plex user with"); - return false; + return new SaveWizardResult { Result = false }; } var plexUser = await _plexApi.GetAccount(authToken); var adminUser = new OmbiUser @@ -140,6 +143,11 @@ namespace Ombi.Controllers ProviderUserId = plexUser.user.id }; + await _userManagementSettings.SaveSettingsAsync(new UserManagementSettings + { + ImportPlexAdmin = true + }); + return await SaveWizardUser(user, adminUser); } @@ -152,9 +160,10 @@ namespace Ombi.Controllers return await SaveWizardUser(user, userToCreate); } - private async Task SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate) + private async Task SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate) { IdentityResult result; + var retVal = new SaveWizardResult(); // When creating the admin as the plex user, we do not pass in the password. if (user.Password.HasValue()) { @@ -182,6 +191,7 @@ namespace Ombi.Controllers if (!result.Succeeded) { LogErrors(result); + retVal.Errors.AddRange(result.Errors.Select(x => x.Description)); } // Update the wizard flag @@ -189,7 +199,8 @@ namespace Ombi.Controllers settings.Wizard = true; await OmbiSettings.SaveSettingsAsync(settings); - return result.Succeeded; + retVal.Result = result.Succeeded; + return retVal; } private void LogErrors(IdentityResult result) diff --git a/src/Ombi/Models/Identity/SaveWizardResult.cs b/src/Ombi/Models/Identity/SaveWizardResult.cs new file mode 100644 index 000000000..0d9cdd048 --- /dev/null +++ b/src/Ombi/Models/Identity/SaveWizardResult.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Ombi.Models.Identity +{ + public class SaveWizardResult + { + public bool Result { get; set; } + public List Errors { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/da.json b/src/Ombi/wwwroot/translations/da.json index dd3872ac0..92f298767 100644 --- a/src/Ombi/wwwroot/translations/da.json +++ b/src/Ombi/wwwroot/translations/da.json @@ -62,9 +62,12 @@ "Italian": "Italiensk", "Danish": "Dansk", "Dutch": "Hollandsk", - "Norwegian": "Norsk" + "Norwegian": "Norsk", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Åbn mobilapp" + "OpenMobileApp": "Åbn mobilapp", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Søg", @@ -113,6 +116,7 @@ "RequestStatus": "Status for anmodning:", "Denied": " Afvist:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Dato for anmodning:", "QualityOverride": "Tilsidesæt kvalitet:", @@ -129,7 +133,14 @@ "GridStatus": "Status", "ReportIssue": "Rapportér problem", "Filter": "Filter", - "SeasonNumberHeading": "Sæson: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Sæson: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Problemer", @@ -154,6 +165,7 @@ "ClearFilter": "Nulstil filter", "FilterHeaderAvailability": "Tilgængelighed", "FilterHeaderRequestStatus": "Status", - "Approved": "Godkendt" + "Approved": "Godkendt", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/de.json b/src/Ombi/wwwroot/translations/de.json index 2a46e2db3..c74f20140 100644 --- a/src/Ombi/wwwroot/translations/de.json +++ b/src/Ombi/wwwroot/translations/de.json @@ -62,9 +62,12 @@ "Italian": "Italienisch", "Danish": "Dänisch", "Dutch": "Niederländisch", - "Norwegian": "Norwegisch" + "Norwegian": "Norwegisch", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Mobile App" + "OpenMobileApp": "Mobile App", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Suche", @@ -113,6 +116,7 @@ "RequestStatus": "Anfrage Status:", "Denied": " Abgelehnt:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Datum der Anfrage:", "QualityOverride": "Qualitäts Überschreiben:", @@ -129,7 +133,14 @@ "GridStatus": "Status", "ReportIssue": "Problem melden", "Filter": "Filter", - "SeasonNumberHeading": "Staffel: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Staffel: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Probleme", @@ -154,6 +165,7 @@ "ClearFilter": "Filter zurücksetzen", "FilterHeaderAvailability": "Verfügbarkeit", "FilterHeaderRequestStatus": "Status", - "Approved": "Bestätigt" + "Approved": "Bestätigt", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index 289db8be5..b70e065cb 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -65,7 +65,9 @@ "Italian": "Italian", "Danish": "Danish", "Dutch": "Dutch", - "Norwegian":"Norwegian" + "Norwegian":"Norwegian", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish":"Polish" }, "OpenMobileApp":"Open Mobile App", "RecentlyAdded":"Recently Added" diff --git a/src/Ombi/wwwroot/translations/es.json b/src/Ombi/wwwroot/translations/es.json index 17036ade3..0003bc499 100644 --- a/src/Ombi/wwwroot/translations/es.json +++ b/src/Ombi/wwwroot/translations/es.json @@ -62,9 +62,12 @@ "Italian": "Italiano", "Danish": "Danés", "Dutch": "Holandés", - "Norwegian": "Norwegian" + "Norwegian": "Norwegian", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Open Mobile App" + "OpenMobileApp": "Open Mobile App", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Buscar", @@ -113,6 +116,7 @@ "RequestStatus": "Estado de la solicitud:", "Denied": " Denegado:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Fecha de solicitud:", "QualityOverride": "Sobreescribir calidad:", @@ -129,7 +133,14 @@ "GridStatus": "Estado", "ReportIssue": "Report Issue", "Filter": "Filter", - "SeasonNumberHeading": "Season: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Incidencias", @@ -154,6 +165,7 @@ "ClearFilter": "Clear Filter", "FilterHeaderAvailability": "Availability", "FilterHeaderRequestStatus": "Status", - "Approved": "Approved" + "Approved": "Approved", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/fr.json b/src/Ombi/wwwroot/translations/fr.json index bc3f395dd..94fd3ddb3 100644 --- a/src/Ombi/wwwroot/translations/fr.json +++ b/src/Ombi/wwwroot/translations/fr.json @@ -62,9 +62,12 @@ "Italian": "Italien", "Danish": "Danois", "Dutch": "Néerlandais", - "Norwegian": "Norvégien" + "Norwegian": "Norvégien", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Ouvrir l'application mobile" + "OpenMobileApp": "Ouvrir l'application mobile", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Rechercher", @@ -113,6 +116,7 @@ "RequestStatus": "Statut de la demande :", "Denied": " Refusé :", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Date de la demande :", "QualityOverride": "Remplacement de la qualité :", @@ -129,7 +133,14 @@ "GridStatus": "Statut", "ReportIssue": "Report Issue", "Filter": "Filter", - "SeasonNumberHeading": "Season: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Problèmes", @@ -154,6 +165,7 @@ "ClearFilter": "Clear Filter", "FilterHeaderAvailability": "Availability", "FilterHeaderRequestStatus": "Status", - "Approved": "Approved" + "Approved": "Approved", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/it.json b/src/Ombi/wwwroot/translations/it.json index 1e91047ff..832da0940 100644 --- a/src/Ombi/wwwroot/translations/it.json +++ b/src/Ombi/wwwroot/translations/it.json @@ -62,9 +62,12 @@ "Italian": "Italiano", "Danish": "Danese", "Dutch": "Olandese", - "Norwegian": "Norvegese" + "Norwegian": "Norvegese", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Apri l'applicazione mobile" + "OpenMobileApp": "Apri l'applicazione mobile", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Cerca", @@ -113,6 +116,7 @@ "RequestStatus": "Stato della richiesta:", "Denied": " Rifiutato:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Data della richiesta:", "QualityOverride": "Sovrascrivi qualità:", @@ -129,7 +133,14 @@ "GridStatus": "Stato", "ReportIssue": "Report Issue", "Filter": "Filter", - "SeasonNumberHeading": "Season: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Problemi", @@ -154,6 +165,7 @@ "ClearFilter": "Clear Filter", "FilterHeaderAvailability": "Availability", "FilterHeaderRequestStatus": "Status", - "Approved": "Approved" + "Approved": "Approved", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/nl.json b/src/Ombi/wwwroot/translations/nl.json index d5fd62bba..439f06968 100644 --- a/src/Ombi/wwwroot/translations/nl.json +++ b/src/Ombi/wwwroot/translations/nl.json @@ -62,9 +62,12 @@ "Italian": "Italiaans", "Danish": "Deens", "Dutch": "Nederlands", - "Norwegian": "Noors" + "Norwegian": "Noors", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Open Mobiele App" + "OpenMobileApp": "Open Mobiele App", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Zoeken", @@ -113,6 +116,7 @@ "RequestStatus": "Aanvraagstatus:", "Denied": " Geweigerd:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Aanvraag Datum:", "QualityOverride": "Kwaliteit overschrijven:", @@ -129,7 +133,14 @@ "GridStatus": "Status", "ReportIssue": "Probleem Melden", "Filter": "Filter", - "SeasonNumberHeading": "Seizoen: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Seizoen: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Problemen", @@ -154,6 +165,7 @@ "ClearFilter": "Verwijder Filter", "FilterHeaderAvailability": "Beschikbaarheid", "FilterHeaderRequestStatus": "Status", - "Approved": "Goedgekeurd" + "Approved": "Goedgekeurd", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/no.json b/src/Ombi/wwwroot/translations/no.json index d94e977df..479a11b3c 100644 --- a/src/Ombi/wwwroot/translations/no.json +++ b/src/Ombi/wwwroot/translations/no.json @@ -62,9 +62,12 @@ "Italian": "Italiensk", "Danish": "Dansk", "Dutch": "Nederlandsk", - "Norwegian": "Norsk" + "Norwegian": "Norsk", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Åpne mobilapp" + "OpenMobileApp": "Åpne mobilapp", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Søk", @@ -113,6 +116,7 @@ "RequestStatus": "Status for forespørsel:", "Denied": " Avslått:", "TheatricalRelease": "Kinopremiere: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital utgivelse: {{date}}", "RequestDate": "Dato for forespørsel:", "QualityOverride": "Overstyr kvalitet:", @@ -129,7 +133,14 @@ "GridStatus": "Status", "ReportIssue": "Rapportér en feil", "Filter": "Filter", - "SeasonNumberHeading": "Sesong: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Sesong: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Mangler", @@ -154,6 +165,7 @@ "ClearFilter": "Tøm filter", "FilterHeaderAvailability": "Tilgjengelighet", "FilterHeaderRequestStatus": "Status", - "Approved": "Godkjent" + "Approved": "Godkjent", + "PendingApproval": "Pending Approval" } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/pl.json b/src/Ombi/wwwroot/translations/pl.json new file mode 100644 index 000000000..aee642699 --- /dev/null +++ b/src/Ombi/wwwroot/translations/pl.json @@ -0,0 +1,171 @@ +{ + "Login": { + "SignInButton": "Sign in", + "UsernamePlaceholder": "Username", + "PasswordPlaceholder": "Password", + "RememberMe": "Remember Me", + "ForgottenPassword": "Forgot your password?", + "Errors": { + "IncorrectCredentials": "Incorrect username or password" + } + }, + "Common": { + "ContinueButton": "Continue", + "Available": "Available", + "NotAvailable": "Not Available", + "ProcessingRequest": "Processing Request", + "PendingApproval": "Pending Approval", + "RequestDenied": "Request Denied", + "NotRequested": "Not Requested", + "Requested": "Requested", + "Request": "Request", + "Denied": "Denied", + "Approve": "Approve", + "PartlyAvailable": "Partly Available", + "Errors": { + "Validation": "Please check your entered values" + } + }, + "PasswordReset": { + "EmailAddressPlaceholder": "Email Address", + "ResetPasswordButton": "Reset Password" + }, + "LandingPage": { + "OnlineHeading": "Currently Online", + "OnlineParagraph": "The media server is currently online", + "PartiallyOnlineHeading": "Partially Online", + "PartiallyOnlineParagraph": "The media server is partially online.", + "MultipleServersUnavailable": "There are {{serversUnavailable}} servers offline out of {{totalServers}}.", + "SingleServerUnavailable": "There is {{serversUnavailable}} server offline out of {{totalServers}}.", + "OfflineHeading": "Currently Offline", + "OfflineParagraph": "The media server is currently offline.", + "CheckPageForUpdates": "Check this page for continuous site updates." + }, + "NavigationBar": { + "Search": "Search", + "Requests": "Requests", + "UserManagement": "User Management", + "Issues": "Issues", + "Donate": "Donate!", + "DonateLibraryMaintainer": "Donate to Library Maintainer", + "DonateTooltip": "This is how I convince my wife to let me spend my spare time developing Ombi ;)", + "UpdateAvailableTooltip": "Update Available!", + "Settings": "Settings", + "Welcome": "Welcome {{username}}", + "UpdateDetails": "Update Details", + "Logout": "Logout", + "Language": { + "English": "English", + "French": "French", + "Spanish": "Spanish", + "German": "German", + "Italian": "Italian", + "Danish": "Danish", + "Dutch": "Dutch", + "Norwegian": "Norwegian", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" + }, + "OpenMobileApp": "Open Mobile App", + "RecentlyAdded": "Recently Added" + }, + "Search": { + "Title": "Search", + "Paragraph": "Want to watch something that is not currently available? No problem, just search for it below and request it!", + "MoviesTab": "Movies", + "TvTab": "TV Shows", + "Suggestions": "Suggestions", + "NoResults": "Sorry, we didn't find any results!", + "DigitalDate": "Digital Release: {{date}}", + "TheatricalRelease": "Theatrical Release: {{date}}", + "ViewOnPlex": "View On Plex", + "ViewOnEmby": "View On Emby", + "RequestAdded": "Request for {{title}} has been added successfully", + "Similar": "Similar", + "Movies": { + "PopularMovies": "Popular Movies", + "UpcomingMovies": "Upcoming Movies", + "TopRatedMovies": "Top Rated Movies", + "NowPlayingMovies": "Now Playing Movies", + "HomePage": "Home Page", + "Trailer": "Trailer" + }, + "TvShows": { + "Popular": "Popular", + "Trending": "Trending", + "MostWatched": "Most Watched", + "MostAnticipated": "Most Anticipated", + "Results": "Results", + "AirDate": "Air Date:", + "AllSeasons": "All Seasons", + "FirstSeason": "First Season", + "LatestSeason": "Latest Season", + "Select": "Select ...", + "SubmitRequest": "Submit Request", + "Season": "Season: {{seasonNumber}}", + "SelectAllInSeason": "Select All in Season {{seasonNumber}}" + } + }, + "Requests": { + "Title": "Requests", + "Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.", + "MoviesTab": "Movies", + "TvTab": "TV Shows", + "RequestedBy": "Requested By:", + "Status": "Status:", + "RequestStatus": "Request status:", + "Denied": " Denied:", + "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", + "DigitalRelease": "Digital Release: {{date}}", + "RequestDate": "Request Date:", + "QualityOverride": "Quality Override:", + "RootFolderOverride": "Root Folder Override:", + "ChangeRootFolder": "Root Folder", + "ChangeQualityProfile": "Quality Profile", + "MarkUnavailable": "Mark Unavailable", + "MarkAvailable": "Mark Available", + "Remove": "Remove", + "Deny": "Deny", + "Season": "Season:", + "GridTitle": "Title", + "AirDate": "AirDate", + "GridStatus": "Status", + "ReportIssue": "Report Issue", + "Filter": "Filter", + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" + }, + "Issues": { + "Title": "Issues", + "PendingTitle": "Pending Issues", + "InProgressTitle": "In Progress Issues", + "ResolvedTitle": "Resolved Issues", + "ColumnTitle": "Title", + "Category": "Category", + "Status": "Status", + "Details": "Details", + "Description": "Description", + "NoComments": "No Comments!", + "MarkInProgress": "Mark In Progress", + "MarkResolved": "Mark Resolved", + "SendMessageButton": "Send", + "Subject": "Subject", + "Comments": "Comments", + "WriteMessagePlaceholder": "Write your message here...", + "ReportedBy": "Reported By" + }, + "Filter": { + "ClearFilter": "Clear Filter", + "FilterHeaderAvailability": "Availability", + "FilterHeaderRequestStatus": "Status", + "Approved": "Approved", + "PendingApproval": "Pending Approval" + } +} \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/pt.json b/src/Ombi/wwwroot/translations/pt.json new file mode 100644 index 000000000..aee642699 --- /dev/null +++ b/src/Ombi/wwwroot/translations/pt.json @@ -0,0 +1,171 @@ +{ + "Login": { + "SignInButton": "Sign in", + "UsernamePlaceholder": "Username", + "PasswordPlaceholder": "Password", + "RememberMe": "Remember Me", + "ForgottenPassword": "Forgot your password?", + "Errors": { + "IncorrectCredentials": "Incorrect username or password" + } + }, + "Common": { + "ContinueButton": "Continue", + "Available": "Available", + "NotAvailable": "Not Available", + "ProcessingRequest": "Processing Request", + "PendingApproval": "Pending Approval", + "RequestDenied": "Request Denied", + "NotRequested": "Not Requested", + "Requested": "Requested", + "Request": "Request", + "Denied": "Denied", + "Approve": "Approve", + "PartlyAvailable": "Partly Available", + "Errors": { + "Validation": "Please check your entered values" + } + }, + "PasswordReset": { + "EmailAddressPlaceholder": "Email Address", + "ResetPasswordButton": "Reset Password" + }, + "LandingPage": { + "OnlineHeading": "Currently Online", + "OnlineParagraph": "The media server is currently online", + "PartiallyOnlineHeading": "Partially Online", + "PartiallyOnlineParagraph": "The media server is partially online.", + "MultipleServersUnavailable": "There are {{serversUnavailable}} servers offline out of {{totalServers}}.", + "SingleServerUnavailable": "There is {{serversUnavailable}} server offline out of {{totalServers}}.", + "OfflineHeading": "Currently Offline", + "OfflineParagraph": "The media server is currently offline.", + "CheckPageForUpdates": "Check this page for continuous site updates." + }, + "NavigationBar": { + "Search": "Search", + "Requests": "Requests", + "UserManagement": "User Management", + "Issues": "Issues", + "Donate": "Donate!", + "DonateLibraryMaintainer": "Donate to Library Maintainer", + "DonateTooltip": "This is how I convince my wife to let me spend my spare time developing Ombi ;)", + "UpdateAvailableTooltip": "Update Available!", + "Settings": "Settings", + "Welcome": "Welcome {{username}}", + "UpdateDetails": "Update Details", + "Logout": "Logout", + "Language": { + "English": "English", + "French": "French", + "Spanish": "Spanish", + "German": "German", + "Italian": "Italian", + "Danish": "Danish", + "Dutch": "Dutch", + "Norwegian": "Norwegian", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" + }, + "OpenMobileApp": "Open Mobile App", + "RecentlyAdded": "Recently Added" + }, + "Search": { + "Title": "Search", + "Paragraph": "Want to watch something that is not currently available? No problem, just search for it below and request it!", + "MoviesTab": "Movies", + "TvTab": "TV Shows", + "Suggestions": "Suggestions", + "NoResults": "Sorry, we didn't find any results!", + "DigitalDate": "Digital Release: {{date}}", + "TheatricalRelease": "Theatrical Release: {{date}}", + "ViewOnPlex": "View On Plex", + "ViewOnEmby": "View On Emby", + "RequestAdded": "Request for {{title}} has been added successfully", + "Similar": "Similar", + "Movies": { + "PopularMovies": "Popular Movies", + "UpcomingMovies": "Upcoming Movies", + "TopRatedMovies": "Top Rated Movies", + "NowPlayingMovies": "Now Playing Movies", + "HomePage": "Home Page", + "Trailer": "Trailer" + }, + "TvShows": { + "Popular": "Popular", + "Trending": "Trending", + "MostWatched": "Most Watched", + "MostAnticipated": "Most Anticipated", + "Results": "Results", + "AirDate": "Air Date:", + "AllSeasons": "All Seasons", + "FirstSeason": "First Season", + "LatestSeason": "Latest Season", + "Select": "Select ...", + "SubmitRequest": "Submit Request", + "Season": "Season: {{seasonNumber}}", + "SelectAllInSeason": "Select All in Season {{seasonNumber}}" + } + }, + "Requests": { + "Title": "Requests", + "Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.", + "MoviesTab": "Movies", + "TvTab": "TV Shows", + "RequestedBy": "Requested By:", + "Status": "Status:", + "RequestStatus": "Request status:", + "Denied": " Denied:", + "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", + "DigitalRelease": "Digital Release: {{date}}", + "RequestDate": "Request Date:", + "QualityOverride": "Quality Override:", + "RootFolderOverride": "Root Folder Override:", + "ChangeRootFolder": "Root Folder", + "ChangeQualityProfile": "Quality Profile", + "MarkUnavailable": "Mark Unavailable", + "MarkAvailable": "Mark Available", + "Remove": "Remove", + "Deny": "Deny", + "Season": "Season:", + "GridTitle": "Title", + "AirDate": "AirDate", + "GridStatus": "Status", + "ReportIssue": "Report Issue", + "Filter": "Filter", + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" + }, + "Issues": { + "Title": "Issues", + "PendingTitle": "Pending Issues", + "InProgressTitle": "In Progress Issues", + "ResolvedTitle": "Resolved Issues", + "ColumnTitle": "Title", + "Category": "Category", + "Status": "Status", + "Details": "Details", + "Description": "Description", + "NoComments": "No Comments!", + "MarkInProgress": "Mark In Progress", + "MarkResolved": "Mark Resolved", + "SendMessageButton": "Send", + "Subject": "Subject", + "Comments": "Comments", + "WriteMessagePlaceholder": "Write your message here...", + "ReportedBy": "Reported By" + }, + "Filter": { + "ClearFilter": "Clear Filter", + "FilterHeaderAvailability": "Availability", + "FilterHeaderRequestStatus": "Status", + "Approved": "Approved", + "PendingApproval": "Pending Approval" + } +} \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/sv.json b/src/Ombi/wwwroot/translations/sv.json index cbc87c2d4..b74101fd3 100644 --- a/src/Ombi/wwwroot/translations/sv.json +++ b/src/Ombi/wwwroot/translations/sv.json @@ -62,9 +62,12 @@ "Italian": "Italienska", "Danish": "Danska", "Dutch": "Holländska", - "Norwegian": "Norska" + "Norwegian": "Norska", + "BrazillianPortuguese": "Brazillian Portuguese", + "Polish": "Polish" }, - "OpenMobileApp": "Öppna Mobil App" + "OpenMobileApp": "Öppna Mobil App", + "RecentlyAdded": "Recently Added" }, "Search": { "Title": "Sök", @@ -113,6 +116,7 @@ "RequestStatus": "Status för efterfrågan:", "Denied": " Nekad:", "TheatricalRelease": "Theatrical Release: {{date}}", + "TheatricalReleaseSort": "Theatrical Release", "DigitalRelease": "Digital Release: {{date}}", "RequestDate": "Datum för efterfrågan:", "QualityOverride": "Kvalité överskridande:", @@ -129,7 +133,14 @@ "GridStatus": "Status", "ReportIssue": "Report Issue", "Filter": "Filter", - "SeasonNumberHeading": "Season: {seasonNumber}" + "Sort": "Sort", + "SeasonNumberHeading": "Season: {seasonNumber}", + "SortTitleAsc": "Title ▲", + "SortTitleDesc": "Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc": "Status ▲", + "SortStatusDesc": "Status ▼" }, "Issues": { "Title": "Problem", @@ -154,6 +165,7 @@ "ClearFilter": "Clear Filter", "FilterHeaderAvailability": "Availability", "FilterHeaderRequestStatus": "Status", - "Approved": "Approved" + "Approved": "Approved", + "PendingApproval": "Pending Approval" } } \ No newline at end of file