pull/3895/head
tidusjar 6 years ago
commit e77d54c6d1

@ -1,48 +0,0 @@
<!---
!! Please use the Support / bug report template, otherwise we will close the Github issue !!
Version 2.X is not supported anymore. Please don't open a issue for the 2.x version.
See https://github.com/tidusjar/Ombi/issues/1455 for more information.
(Pleas submit a feature request over here: http://feathub.com/tidusjar/Ombi)
--->
#### Ombi build Version:
V 3.0.XX
#### Update Branch:
Open Beta
#### Media Sever:
Plex/Emby
#### Media Server Version:
<!-- If appropriate --->
#### Operating System:
(Place text here)
#### Ombi Applicable Logs (from `/logs/` directory or the Admin page):
```
(Logs go here. Don't remove the ' tags for showing your logs correctly. Please make sure you remove any personal information from the logs)
```
#### Problem Description:
(Place text here)
#### Reproduction Steps:
Please include any steps to reproduce the issue, this the request that is causing the problem etc.

@ -0,0 +1,37 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs (Logs directory where Ombi is located)**
If applicable, a snippet of the logs that seems relevant to the bug if present.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
**Ombi Version (please complete the following information):**
- Version [e.g. 3.0.1158]
- Media Server [e.g. Plex]
**Additional context**
Add any other context about the problem here.

@ -1,14 +1,9 @@
# Changelog
## (unreleased)
### **New Features**
- Added new classes to the posters #2732. [TidusJar]
## v3.0.4119 (2019-1-09)
## v3.0.4119 (2019-01-09)
### **New Features**
- Update CHANGELOG.md. [Jamie]
@ -29,33 +24,27 @@
- Added the ability to specify a year when searching for movies. [tidusjar]
- Update NewsletterTemplate.html. [d1slact0r]
- Update NewsletterTemplate.html. [d1slact0r]
- Update NewsletterTemplate.html. [d1slact0r]
- Update HtmlTemplateGenerator.cs. [d1slact0r]
- Update NewsletterTemplate.html. [d1slact0r]
- Made the newsletter use the default lanuage code set in the Ombi settings for movie information. [TidusJar]
- Update HtmlTemplateGenerator.cs. [d1slact0r]
- Added a global language flag that now applies to the search by default. [tidusjar]
- Update NewsletterTemplate.html. [d1slact0r]
- Updated the frontend packages (Using Angular 7 now) [TidusJar]
- Update NewsletterTemplate.html. [d1slact0r]
- Added capture of anonymous analytical data. [tidusjar]
- Update NewsletterTemplate.html. [d1slact0r]
- Added {AvailableDate} as a Notification Variable, this is the date the request was marked as available. See here: https://github.com/tidusjar/Ombi/wiki/Notification-Template-Variables. [tidusjar]
- Update HtmlTemplateGenerator.cs. [d1slact0r]
- Updated the Newsletter template! Better mail client support [d1slact0r]
- Updated boostrap #2694. [Jamie]
- Updated boostrap #2694. [TidusJar]
- Added the ability to deny a request with a reason. [TidusJar]
- Updated to .net core 2.2 and included a linux-arm64 build. [aptalca]
- Make the newsletter BCC the users rather than creating a million newsletters (Hopefully will stop SMTP providers from marking as spam). This does mean that the custom user customization in the newsletter will no longer work. [TidusJar]
- Update EmbyEpisodeSync.cs. [Jamie]
- Updated to .net core 2.2 and included a linux-arm64 build. [TidusJar]
- New translations [TidusJar]
### **Fixes**
@ -77,62 +66,12 @@
- Fixed #2716. [tidusjar]
- Make the newsletter BCC the users rather than creating a million newsletters (Hopefully will stop SMTP providers from marking as spam). This does mean that the custom user customization in the newsletter will no longer work. [TidusJar]
- If we don't know the Plex agent, then see if it's a ImdbId, if it's not check the string for any episode and season hints #2695. [tidusjar]
- New translations en.json (Swedish) [Jamie]
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Norwegian) [Jamie]
- New translations en.json (Italian) [Jamie]
- New translations en.json (German) [Jamie]
- New translations en.json (French) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Danish) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- Made the search results the language specified in the search refinement. [tidusjar]
- Fixed #2704. [tidusjar]
- Now it is fixed :) [d1slact0r]
- Android please be nice now. [d1slact0r]
- Fixed title bit better. [d1slact0r]
- Fixed titles. [d1slact0r]
- This should fix the build for sure (stupid quotes) [d1slact0r]
- Fixes build. [d1slact0r]
- Rewritten the whole newsletter template. [d1slact0r]
- Fixed #2697. [tidusjar]
- Add linux-arm runtime identifier. [aptalca]
- Add back arm packages. [aptalca]
- Add arm32 package. [aptalca]
- Fixed #2691. [tidusjar]
- Fixed linting. [TidusJar]
@ -141,13 +80,10 @@
- Fixed #2678. [TidusJar]
- Deny reason for movie requests. [TidusJar]
- Set the landing and login pages background refresh to 15 seconds rather than 10 and 7. [TidusJar]
- Fixed a bug with us thinking future dated emby episodes are not available, Consoldated the emby and plex search rules (since they have the same logic) [TidusJar]
- Fixed build. [TidusJar]
## v3.0.4036 (2018-12-11)

@ -117,13 +117,12 @@ Please feel free to submit a pull request!
# Donation
If you feel like donating you can donate with the below buttons!
[![Patreon](https://www.ombi.io/img/patreondonate.svg)](https://patreon.com/tidusjar/Ombi)
[![Paypal](https://www.ombi.io/img/paypaldonate.svg)](https://paypal.me/PlexRequestsNet)
[![Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://patreon.com/tidusjar/Ombi)
[![Paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://paypal.me/PlexRequestsNet)
### A massive thanks to everyone for all their help!
## Stats
[![Throughput Graph](https://graphs.waffle.io/tidusjar/PlexRequests.Net/throughput.svg)](https://waffle.io/tidusjar/PlexRequests.Net/metrics/throughput)
### Sponsors ###
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools

@ -385,6 +385,7 @@ namespace Ombi.Core.Engine
foreach (var ep in s.Episodes)
{
ep.Approved = true;
ep.Requested = true;
}
}

@ -99,7 +99,7 @@ namespace Ombi.Core.Engine
{
Url = e.url,
Title = e.name,
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
EpisodeNumber = e.number,
});
@ -112,7 +112,7 @@ namespace Ombi.Core.Engine
{
Url = e.url,
Title = e.name,
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
EpisodeNumber = e.number,
});
}

@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Models.Search;
@ -87,11 +88,11 @@ namespace Ombi.Core.Rule.Rules.Search
}
}
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available && e.AirDate > DateTime.MinValue)))
{
request.FullyAvailable = true;
}
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available)))
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available && e.AirDate > DateTime.MinValue)))
{
request.PartlyAvailable = true;
}

@ -49,7 +49,6 @@ namespace Ombi.Core.Senders
{
try
{
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
//var watcherSettings = await WatcherSettings.GetSettingsAsync();
var radarrSettings = await RadarrSettings.GetSettingsAsync();
@ -76,7 +75,7 @@ namespace Ombi.Core.Senders
}
catch (Exception e)
{
Log.LogError(e, "Error when seing movie to DVR app, added to the request queue");
Log.LogError(e, "Error when sending movie to DVR app, added to the request queue");
// Check if already in request quee
var existingQueue = await _requestQueuRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);

@ -16,6 +16,7 @@ using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Remotion.Linq.Parsing.Structure.IntermediateModel;
namespace Ombi.Core.Senders
{
@ -57,7 +58,7 @@ namespace Ombi.Core.Senders
var sonarr = await SonarrSettings.GetSettingsAsync();
if (sonarr.Enabled)
{
var result = await SendToSonarr(model);
var result = await SendToSonarr(model, sonarr);
if (result != null)
{
return new SenderResult
@ -109,7 +110,7 @@ namespace Ombi.Core.Senders
catch (Exception e)
{
Logger.LogError(e, "Exception thrown when sending a movie to DVR app, added to the request queue");
// Check if already in request quee
// Check if already in request queue
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
if (existingQueue != null)
{
@ -134,7 +135,7 @@ namespace Ombi.Core.Senders
return new SenderResult
{
Success = false,
Message = "Something wen't wrong!"
Message = "Something went wrong!"
};
}
@ -150,13 +151,8 @@ namespace Ombi.Core.Senders
/// <param name="s"></param>
/// <param name="model"></param>
/// <returns></returns>
public async Task<NewSeries> SendToSonarr(ChildRequests model)
public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
{
var s = await SonarrSettings.GetSettingsAsync();
if (!s.Enabled)
{
return null;
}
if (string.IsNullOrEmpty(s.ApiKey))
{
return null;
@ -319,10 +315,19 @@ namespace Ombi.Core.Senders
foreach (var season in model.SeasonRequests)
{
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber);
var sonarrEpCount = sonarrSeason.Count();
var sonarrEpisodeList = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber).ToList();
var sonarrEpCount = sonarrEpisodeList.Count;
var ourRequestCount = season.Episodes.Count;
var ourEpisodes = season.Episodes.Select(x => x.EpisodeNumber).ToList();
var unairedEpisodes = sonarrEpisodeList.Where(x => x.airDateUtc > DateTime.UtcNow).Select(x => x.episodeNumber).ToList();
//// Check if we have requested all the latest episodes, if we have then monitor
//// NOTE, not sure if needed since ombi ui displays future episodes anyway...
//ourEpisodes.AddRange(unairedEpisodes);
//var distinctEpisodes = ourEpisodes.Distinct().ToList();
//var missingEpisodes = Enumerable.Range(distinctEpisodes.Min(), distinctEpisodes.Count).Except(distinctEpisodes);
var existingSeason =
result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
if (existingSeason == null)
@ -332,7 +337,7 @@ namespace Ombi.Core.Senders
}
if (sonarrEpCount == ourRequestCount)
if (sonarrEpCount == ourRequestCount /*|| !missingEpisodes.Any()*/)
{
// We have the same amount of requests as all of the episodes in the season.

@ -26,8 +26,6 @@ namespace Ombi.Notifications
MovieRepository = movie;
TvRepository = tv;
CustomizationSettings = customization;
Settings.ClearCache();
CustomizationSettings.ClearCache();
RequestSubscription = sub;
_log = log;
AlbumRepository = album;
@ -55,14 +53,12 @@ namespace Ombi.Notifications
public async Task NotifyAsync(NotificationOptions model)
{
Settings.ClearCache();
var configuration = await GetConfiguration();
await NotifyAsync(model, configuration);
}
public async Task NotifyAsync(NotificationOptions model, Settings.Settings.Models.Settings settings)
{
Settings.ClearCache();
if (settings == null) await NotifyAsync(model);
var notificationSettings = (T)settings;

@ -5,6 +5,7 @@ using MailKit.Net.Smtp;
using Microsoft.Extensions.Logging;
using MimeKit;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Notifications.Models;
using Ombi.Notifications.Templates;
using Ombi.Settings.Settings.Models;
@ -56,6 +57,11 @@ namespace Ombi.Notifications
using (var client = new SmtpClient())
{
if (customization.ApplicationUrl.HasValue())
{
client.LocalDomain = customization.ApplicationUrl;
}
if (settings.DisableCertificateChecking)
{
// Disable validation of the certificate associated with the SMTP service

@ -28,7 +28,6 @@ namespace Ombi.Schedule.Jobs.Emby
_repo = repo;
_episodeSync = epSync;
_metadata = metadata;
_settings.ClearCache();
}
private readonly ILogger<EmbyContentSync> _logger;

@ -49,7 +49,6 @@ namespace Ombi.Schedule.Jobs.Emby
_settings = s;
_repo = repo;
_avaliabilityChecker = checker;
_settings.ClearCache();
}
private readonly ISettingsService<EmbySettings> _settings;

@ -50,8 +50,6 @@ namespace Ombi.Schedule.Jobs.Emby
_log = log;
_embySettings = embySettings;
_userManagementSettings = ums;
_userManagementSettings.ClearCache();
_embySettings.ClearCache();
}
private readonly IEmbyApi _api;

@ -1,19 +1,16 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr;
using Ombi.Api.Radarr;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Context;
using Ombi.Store.Entities;
using Serilog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Ombi.Schedule.Jobs.Lidarr
@ -29,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Lidarr
_ctx = ctx;
_job = job;
_availability = availability;
_lidarrSettings.ClearCache();
}
private readonly ISettingsService<LidarrSettings> _lidarrSettings;

@ -1,19 +1,16 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr;
using Ombi.Api.Radarr;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Context;
using Ombi.Store.Entities;
using Serilog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Ombi.Schedule.Jobs.Lidarr
@ -29,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Lidarr
_ctx = ctx;
_job = background;
_albumSync = album;
_lidarrSettings.ClearCache();
}
private readonly ISettingsService<LidarrSettings> _lidarrSettings;

@ -28,9 +28,9 @@ namespace Ombi.Schedule.Jobs.Ombi
return;
}
var now = DateTime.Now.AddDays(-settings.DaysAfterResolvedToDelete).Date;
var deletionDate = DateTime.Now.AddDays(settings.DaysAfterResolvedToDelete).Date;
var resolved = _issuesRepository.GetAll().Where(x => x.Status == IssueStatus.Resolved);
var toDelete = resolved.Where(x => x.ResovledDate.HasValue && x.ResovledDate.Value.Date <= now);
var toDelete = resolved.Where(x => x.ResovledDate.HasValue && x.ResovledDate.Value.Date >= deletionDate);
foreach (var d in toDelete)
{

@ -10,28 +10,23 @@ using Ombi.Schedule.Jobs.Emby;
using Ombi.Schedule.Jobs.Plex.Interfaces;
using Ombi.Store.Repository;
namespace Ombi.Schedule.Jobs.Plex
namespace Ombi.Schedule.Jobs.Ombi
{
public class MediaDatabaseRefresh : IMediaDatabaseRefresh
{
public MediaDatabaseRefresh(ISettingsService<PlexSettings> s, ILogger<MediaDatabaseRefresh> log, IPlexApi plexApi,
IPlexContentRepository plexRepo, IPlexContentSync c, IEmbyContentRepository embyRepo, IEmbyContentSync embySync)
public MediaDatabaseRefresh(ISettingsService<PlexSettings> s, ILogger<MediaDatabaseRefresh> log,
IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo, IEmbyContentSync embySync)
{
_settings = s;
_log = log;
_api = plexApi;
_plexRepo = plexRepo;
_plexContentSync = c;
_embyRepo = embyRepo;
_embyContentSync = embySync;
_settings.ClearCache();
}
private readonly ISettingsService<PlexSettings> _settings;
private readonly ILogger _log;
private readonly IPlexApi _api;
private readonly IPlexContentRepository _plexRepo;
private readonly IPlexContentSync _plexContentSync;
private readonly IEmbyContentRepository _embyRepo;
private readonly IEmbyContentSync _embyContentSync;

@ -16,6 +16,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Api.TvMaze;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Notifications;
using Ombi.Notifications.Models;
@ -36,7 +37,7 @@ namespace Ombi.Schedule.Jobs.Ombi
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log,
ILidarrApi lidarrApi, IRepository<LidarrAlbumCache> albumCache, ISettingsService<LidarrSettings> lidarrSettings,
ISettingsService<OmbiSettings> ombiSettings)
ISettingsService<OmbiSettings> ombiSettings, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings)
{
_plex = plex;
_emby = emby;
@ -49,16 +50,13 @@ namespace Ombi.Schedule.Jobs.Ombi
_emailSettings = emailSettings;
_newsletterSettings = newsletter;
_userManager = um;
_emailSettings.ClearCache();
_customizationSettings.ClearCache();
_newsletterSettings.ClearCache();
_log = log;
_lidarrApi = lidarrApi;
_lidarrAlbumRepository = albumCache;
_lidarrSettings = lidarrSettings;
_ombiSettings = ombiSettings;
_ombiSettings.ClearCache();
_lidarrSettings.ClearCache();
_plexSettings = plexSettings;
_embySettings = embySettings;
}
private readonly IPlexContentRepository _plex;
@ -77,6 +75,8 @@ namespace Ombi.Schedule.Jobs.Ombi
private readonly ILidarrApi _lidarrApi;
private readonly IRepository<LidarrAlbumCache> _lidarrAlbumRepository;
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ISettingsService<PlexSettings> _plexSettings;
private readonly ISettingsService<EmbySettings> _embySettings;
public async Task Start(NewsletterSettings settings, bool test)
{
@ -132,6 +132,8 @@ namespace Ombi.Schedule.Jobs.Ombi
_log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count());
_log.LogInformation("Emby Episodes to send: {0}", embyEpisodesToSend.Count());
var plexSettings = await _plexSettings.GetSettingsAsync();
var embySettings = await _embySettings.GetSettingsAsync();
var body = string.Empty;
if (test)
{
@ -140,11 +142,11 @@ namespace Ombi.Schedule.Jobs.Ombi
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings);
body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings, embySettings, plexSettings);
}
else
{
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings);
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings, embySettings, plexSettings);
if (body.IsNullOrEmpty())
{
return;
@ -333,7 +335,8 @@ namespace Ombi.Schedule.Jobs.Ombi
}
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend,
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings)
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings, EmbySettings embySettings,
PlexSettings plexSettings)
{
var ombiSettings = await _ombiSettings.GetSettingsAsync();
var sb = new StringBuilder();
@ -349,8 +352,16 @@ namespace Ombi.Schedule.Jobs.Ombi
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
sb.Append("<tr>");
await ProcessPlexMovies(plexMovies, sb, ombiSettings.DefaultLanguageCode);
await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode);
if (plexSettings.Enable)
{
await ProcessPlexMovies(plexMovies, sb, ombiSettings.DefaultLanguageCode);
}
if (embySettings.Enable)
{
await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode);
}
sb.Append("</tr>");
sb.Append("</table>");
sb.Append("</td>");
@ -367,8 +378,16 @@ namespace Ombi.Schedule.Jobs.Ombi
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
sb.Append("<tr>");
await ProcessPlexTv(plexEpisodes, sb);
await ProcessEmbyTv(embyEp, sb);
if (plexSettings.Enable)
{
await ProcessPlexTv(plexEpisodes, sb);
}
if (embySettings.Enable)
{
await ProcessEmbyTv(embyEp, sb);
}
sb.Append("</tr>");
sb.Append("</table>");
sb.Append("</td>");

@ -5,18 +5,13 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Hangfire;
using Hangfire.Console;
using Hangfire.Server;
using Microsoft.Extensions.Logging;
using Ombi.Api.Service;
using Ombi.Api.Service.Models;
using Ombi.Core.Processor;
using Ombi.Core.Settings;
using Ombi.Helpers;
@ -40,7 +35,6 @@ namespace Ombi.Schedule.Jobs.Ombi
Settings = s;
_processProvider = proc;
_appConfig = appConfig;
Settings.ClearCache();
}
private ILogger<OmbiAutomaticUpdater> Logger { get; }

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.Extensions.Logging;
using Ombi.Api.Emby;
using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Api.TvMaze;
@ -21,7 +22,8 @@ namespace Ombi.Schedule.Jobs.Ombi
{
public RefreshMetadata(IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo,
ILogger<RefreshMetadata> log, ITvMazeApi tvApi, ISettingsService<PlexSettings> plexSettings,
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IPlexAvailabilityChecker plexAvailability, IEmbyAvaliabilityChecker embyAvaliability)
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IPlexAvailabilityChecker plexAvailability, IEmbyAvaliabilityChecker embyAvaliability,
IEmbyApi embyApi)
{
_plexRepo = plexRepo;
_embyRepo = embyRepo;
@ -32,6 +34,7 @@ namespace Ombi.Schedule.Jobs.Ombi
_embySettings = embySettings;
_plexAvailabilityChecker = plexAvailability;
_embyAvaliabilityChecker = embyAvaliability;
_embyApi = embyApi;
}
private readonly IPlexContentRepository _plexRepo;
@ -43,6 +46,7 @@ namespace Ombi.Schedule.Jobs.Ombi
private readonly ITvMazeApi _tvApi;
private readonly ISettingsService<PlexSettings> _plexSettings;
private readonly ISettingsService<EmbySettings> _embySettings;
private readonly IEmbyApi _embyApi;
public async Task Start()
{
@ -54,11 +58,11 @@ namespace Ombi.Schedule.Jobs.Ombi
{
await StartPlex();
}
var embySettings = await _embySettings.GetSettingsAsync();
if (embySettings.Enable)
{
await StartEmby();
await StartEmby(embySettings);
}
}
catch (Exception e)
@ -123,9 +127,9 @@ namespace Ombi.Schedule.Jobs.Ombi
await StartPlexTv(allTv);
}
private async Task StartEmby()
private async Task StartEmby(EmbySettings s)
{
await StartEmbyMovies();
await StartEmbyMovies(s);
await StartEmbyTv();
}
@ -158,7 +162,7 @@ namespace Ombi.Schedule.Jobs.Ombi
_plexRepo.UpdateWithoutSave(show);
}
tvCount++;
if (tvCount >= 20)
if (tvCount >= 75)
{
await _plexRepo.SaveChangesAsync();
tvCount = 0;
@ -198,7 +202,7 @@ namespace Ombi.Schedule.Jobs.Ombi
_embyRepo.UpdateWithoutSave(show);
}
tvCount++;
if (tvCount >= 20)
if (tvCount >= 75)
{
await _embyRepo.SaveChangesAsync();
tvCount = 0;
@ -229,7 +233,7 @@ namespace Ombi.Schedule.Jobs.Ombi
_plexRepo.UpdateWithoutSave(movie);
}
movieCount++;
if (movieCount >= 20)
if (movieCount >= 75)
{
await _plexRepo.SaveChangesAsync();
movieCount = 0;
@ -239,31 +243,56 @@ namespace Ombi.Schedule.Jobs.Ombi
await _plexRepo.SaveChangesAsync();
}
private async Task StartEmbyMovies()
private async Task StartEmbyMovies(EmbySettings settings)
{
var allMovies = _embyRepo.GetAll().Where(x =>
x.Type == EmbyMediaType.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
int movieCount = 0;
foreach (var movie in allMovies)
{
var hasImdb = movie.ImdbId.HasValue();
var hasTheMovieDb = movie.TheMovieDbId.HasValue();
movie.ImdbId.HasValue();
movie.TheMovieDbId.HasValue();
// Movies don't really use TheTvDb
if (!hasImdb)
// Check if it even has 1 ID
if (!movie.HasImdb && !movie.HasTheMovieDb)
{
var imdbId = await GetImdbId(hasTheMovieDb, false, movie.Title, movie.TheMovieDbId, string.Empty);
// Ok this sucks,
// The only think I can think that has happened is that we scanned Emby before Emby has got the metadata
// So let's recheck emby to see if they have got the metadata now
_log.LogInformation($"Movie {movie.Title} does not have a ImdbId or TheMovieDbId, so rechecking emby");
foreach (var server in settings.Servers)
{
_log.LogInformation($"Checking server {server.Name} for upto date metadata");
var movieInfo = await _embyApi.GetMovieInformation(movie.EmbyId, server.ApiKey, server.AdministratorId,
server.FullUri);
if (movieInfo.ProviderIds?.Imdb.HasValue() ?? false)
{
movie.ImdbId = movieInfo.ProviderIds.Imdb;
}
if (movieInfo.ProviderIds?.Tmdb.HasValue() ?? false)
{
movie.TheMovieDbId = movieInfo.ProviderIds.Tmdb;
}
}
}
if (!movie.HasImdb)
{
var imdbId = await GetImdbId(movie.HasTheMovieDb, false, movie.Title, movie.TheMovieDbId, string.Empty);
movie.ImdbId = imdbId;
_embyRepo.UpdateWithoutSave(movie);
}
if (!hasTheMovieDb)
if (!movie.HasTheMovieDb)
{
var id = await GetTheMovieDbId(false, hasImdb, string.Empty, movie.ImdbId, movie.Title, true);
var id = await GetTheMovieDbId(false, movie.HasImdb, string.Empty, movie.ImdbId, movie.Title, true);
movie.TheMovieDbId = id;
_embyRepo.UpdateWithoutSave(movie);
}
movieCount++;
if (movieCount >= 20)
if (movieCount >= 75)
{
await _embyRepo.SaveChangesAsync();
movieCount = 0;

@ -20,8 +20,6 @@ namespace Ombi.Schedule.Jobs.Ombi
_email = provider;
_templates = template;
_customizationSettings = c;
email.ClearCache();
_customizationSettings.ClearCache();
}
private readonly ISettingsService<EmailNotificationSettings> _emailSettings;

@ -57,7 +57,6 @@ namespace Ombi.Schedule.Jobs.Plex
EpisodeSync = epsiodeSync;
Metadata = metadataRefresh;
Checker = checker;
plex.ClearCache();
}
private ISettingsService<PlexSettings> Plex { get; }

@ -26,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Plex
_api = plexApi;
_repo = repo;
_availabilityChecker = a;
_settings.ClearCache();
}
private readonly ISettingsService<PlexSettings> _settings;

@ -24,8 +24,6 @@ namespace Ombi.Schedule.Jobs.Plex
_log = log;
_plexSettings = plexSettings;
_userManagementSettings = ums;
_userManagementSettings.ClearCache();
_plexSettings.ClearCache();
}
private readonly IPlexApi _api;

@ -22,7 +22,6 @@ namespace Ombi.Schedule.Jobs.Radarr
RadarrApi = radarrApi;
Logger = log;
_ctx = ctx;
RadarrSettings.ClearCache();
}
private ISettingsService<RadarrSettings> RadarrSettings { get; }

@ -22,7 +22,6 @@ namespace Ombi.Schedule.Jobs.SickRage
_api = api;
_log = l;
_ctx = ctx;
_settings.ClearCache();
}
private readonly ISettingsService<SickRageSettings> _settings;

@ -25,7 +25,6 @@ namespace Ombi.Schedule.Jobs.Sonarr
_api = api;
_log = l;
_ctx = ctx;
_settings.ClearCache();
}
private readonly ISettingsService<SonarrSettings> _settings;

@ -61,7 +61,7 @@ namespace Ombi.Settings.Settings
var model = obj;
return model;
}, DateTime.Now.AddHours(2));
}, DateTime.Now.AddHours(5));
}
public bool SaveSettings(T model)

@ -87,53 +87,6 @@ namespace Ombi.Store.Context
public void Seed()
{
// VACUUM;
Database.ExecuteSqlCommand("VACUUM;");
// Make sure we have the roles
var newsletterRole = Roles.Where(x => x.Name == OmbiRoles.ReceivesNewsletter);
if (!newsletterRole.Any())
{
Roles.Add(new IdentityRole(OmbiRoles.ReceivesNewsletter)
{
NormalizedName = OmbiRoles.ReceivesNewsletter.ToUpper()
});
SaveChanges();
}
var requestMusicRole = Roles.Where(x => x.Name == OmbiRoles.RequestMusic);
if (!requestMusicRole.Any())
{
Roles.Add(new IdentityRole(OmbiRoles.RequestMusic)
{
NormalizedName = OmbiRoles.RequestMusic.ToUpper()
});
Roles.Add(new IdentityRole(OmbiRoles.AutoApproveMusic)
{
NormalizedName = OmbiRoles.AutoApproveMusic.ToUpper()
});
SaveChanges();
}
var manageOwnRequestsRole = Roles.Where(x => x.Name == OmbiRoles.ManageOwnRequests);
if (!manageOwnRequestsRole.Any())
{
Roles.Add(new IdentityRole(OmbiRoles.ManageOwnRequests)
{
NormalizedName = OmbiRoles.ManageOwnRequests.ToUpper()
});
SaveChanges();
}
var editCustomPage = Roles.Where(x => x.Name == OmbiRoles.EditCustomPage);
if (!editCustomPage.Any())
{
Roles.Add(new IdentityRole(OmbiRoles.EditCustomPage)
{
NormalizedName = OmbiRoles.EditCustomPage.ToUpper()
});
SaveChanges();
}
// Make sure we have the API User
var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase));
if (!apiUserExists)

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Globalization;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
@ -27,9 +28,10 @@ namespace Ombi.Store.Repository.Requests
public bool Approved { get; set; }
public bool Requested { get; set; }
public int SeasonId { get; set; }
[ForeignKey(nameof(SeasonId))]
public SeasonRequests Season { get; set; }
[NotMapped] public string AirDateDisplay => AirDate == DateTime.MinValue ? "Unknown" : AirDate.ToString(CultureInfo.InvariantCulture);
}
}

@ -17,10 +17,6 @@ namespace Ombi.Store.Entities.Requests
public DateTime ReleaseDate { get; set; }
public string Status { get; set; }
/// <summary>
/// This is so we can correctly send the right amount of seasons to Sonarr
/// </summary>
[NotMapped]
public int TotalSeasons { get; set; }
public List<ChildRequests> ChildRequests { get; set; }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Ombi.Helpers;
namespace Ombi.Store.Migrations
{
public partial class Roles : Migration
{
protected override void Up(MigrationBuilder mb)
{
// Make sure we have the roles
InsertRole(mb, OmbiRoles.ReceivesNewsletter);
InsertRole(mb, OmbiRoles.RequestMusic);
InsertRole(mb, OmbiRoles.AutoApproveMusic);
InsertRole(mb, OmbiRoles.ManageOwnRequests);
InsertRole(mb, OmbiRoles.EditCustomPage);
}
private void InsertRole(MigrationBuilder mb, string role)
{
mb.Sql($@"
INSERT INTO AspnetRoles(Id, ConcurrencyStamp, Name, NormalizedName)
SELECT '{Guid.NewGuid().ToString()}','{Guid.NewGuid().ToString()}','{role}', '{role.ToUpper()}'
WHERE NOT EXISTS(SELECT 1 FROM AspnetRoles WHERE Name = '{role}');");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Ombi.Store.Migrations
{
public partial class TvRequestsTotalSeasons : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "TotalSeasons",
table: "TvRequests",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TotalSeasons",
table: "TvRequests");
}
}
}

@ -819,6 +819,8 @@ namespace Ombi.Store.Migrations
b.Property<string>("Title");
b.Property<int>("TotalSeasons");
b.Property<int>("TvDbId");
b.HasKey("Id");

@ -146,6 +146,7 @@ export interface IEpisodesRequests {
episodeNumber: number;
title: string;
airDate: Date;
airDateDisplay: string;
url: string;
available: boolean;
requested: boolean;

@ -42,8 +42,11 @@
<td>
{{ep.title}}
</td>
<td>
<td *ngIf="ep.airDateDisplay != 'Unknown'">
{{ep.airDate | amLocal | amDateFormat: 'L' }}
</td>
<td *ngIf="ep.airDateDisplay == 'Unknown'">
{{ep.airDateDisplay }}
</td>
<td>
<ng-template [ngIf]="ep.available"><span class="label label-success" id="availableLabel">Available</span></ng-template>

@ -15,4 +15,8 @@ export class MobileService extends ServiceHelpers {
public getUserDeviceList(): Observable<IMobileUsersViewModel[]> {
return this.http.get<IMobileUsersViewModel[]>(`${this.url}notification/`, {headers: this.headers});
}
public deleteUser(userId: string): Observable<boolean> {
return this.http.post<boolean>(`${this.url}remove/`, userId, {headers: this.headers});
}
}

@ -38,7 +38,7 @@
<span>Discord</span>
</td>
<td>
<a href="https://discord.gg/Sa7wNWb" target="_blank">https://discord.gg/</a>
<a href="https://discord.gg/Sa7wNWb" target="_blank">https://discord.gg/Sa7wNWb</a>
</td>
</tr>

@ -35,7 +35,7 @@
<div class="row">
<div class="form-group">
<label for="select" class="control-label">User to send test notification to</label>
<label for="select" class="control-label">Users</label>
<div>
<select class="form-control form-control-custom" id="select" [(ngModel)]="testUserId" [ngModelOptions]="{standalone: true}">
<option value="">Please select</option>
@ -46,7 +46,12 @@
<div class="form-group">
<div>
<button [disabled]="form.invalid" type="button" (click)="test(form)" class="btn btn-danger-outline">Test</button>
<button [disabled]="form.invalid" type="button" (click)="test(form)" class="btn btn-danger-outline">Send Test Notification</button>
</div>
</div>
<div class="form-group">
<div>
<button [disabled]="form.invalid" type="button" (click)="remove(form)" class="btn btn-danger-outline">Remove User</button>
</div>
</div>

@ -79,4 +79,24 @@ export class MobileComponent implements OnInit {
});
}
public remove() {
if (!this.testUserId) {
this.notificationService.warning("Warning", "Please select a user to remove");
return;
}
this.mobileService.deleteUser(this.testUserId).subscribe(x => {
if (x) {
this.notificationService.success("Removed users notification");
const userToRemove = this.userList.filter(u => {
return u.userId === this.testUserId;
})[1];
this.userList.splice(this.userList.indexOf(userToRemove),1);
} else {
this.notificationService.error("There was an error when removing the notification. Please check your logs");
}
});
}
}

@ -22,7 +22,6 @@ namespace Ombi.Controllers.V1.External
RadarrApi = radarr;
RadarrSettings = settings;
Cache = mem;
RadarrSettings.ClearCache();
}
private IRadarrApi RadarrApi { get; }

@ -21,7 +21,6 @@ namespace Ombi.Controllers.V1.External
SonarrApi = sonarr;
SonarrV3Api = sonarrv3;
SonarrSettings = settings;
SonarrSettings.ClearCache();
}
private ISonarrApi SonarrApi { get; }

@ -130,7 +130,7 @@ namespace Ombi.Controllers.V1
public async Task<int> CreateIssue([FromBody]Issues i)
{
i.IssueCategory = null;
i.UserReportedId = (await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name)).Id;
i.UserReportedId = (await _userManager.Users.FirstOrDefaultAsync(x => x.UserName.Equals(User.Identity.Name, StringComparison.InvariantCultureIgnoreCase))).Id;
await _issues.Add(i);
var category = await _categories.GetAll().FirstOrDefaultAsync(x => i.IssueCategoryId == x.Id);
if (category != null)
@ -197,7 +197,7 @@ namespace Ombi.Controllers.V1
[HttpPost("comments")]
public async Task<IssueComments> AddComment([FromBody] NewIssueCommentViewModel comment)
{
var user = await _userManager.Users.Where(x => User.Identity.Name == x.UserName)
var user = await _userManager.Users.Where(x => User.Identity.Name.Equals(x.UserName, StringComparison.InvariantCultureIgnoreCase))
.FirstOrDefaultAsync();
var issue = await _issues.GetAll().Include(x => x.UserReported).Include(x => x.IssueCategory).FirstOrDefaultAsync(x => x.Id == comment.IssueId);
if (issue == null)
@ -256,7 +256,7 @@ namespace Ombi.Controllers.V1
[HttpPost("status")]
public async Task<bool> UpdateStatus([FromBody] IssueStateViewModel model)
{
var user = await _userManager.Users.Where(x => User.Identity.Name == x.UserName)
var user = await _userManager.Users.Where(x => User.Identity.Name.Equals(x.UserName, StringComparison.InvariantCultureIgnoreCase))
.FirstOrDefaultAsync();
var issue = await _issues.GetAll().Include(x => x.UserReported).Include(x => x.IssueCategory).FirstOrDefaultAsync(x => x.Id == model.IssueId);
if (issue == null)
@ -265,6 +265,11 @@ namespace Ombi.Controllers.V1
}
issue.Status = model.Status;
if (model.Status == IssueStatus.Resolved)
{
issue.ResovledDate = DateTime.UtcNow;
}
await _issues.SaveChangesAsync();
if (issue.Status == IssueStatus.Resolved)

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Attributes;
using Ombi.Core.Authentication;
using Ombi.Helpers;
@ -20,14 +21,16 @@ namespace Ombi.Controllers.V1
[ApiController]
public class MobileController : ControllerBase
{
public MobileController(IRepository<NotificationUserId> notification, OmbiUserManager user)
public MobileController(IRepository<NotificationUserId> notification, OmbiUserManager user, ILogger<MobileController> log)
{
_notification = notification;
_userManager = user;
_log = log;
}
private readonly IRepository<NotificationUserId> _notification;
private readonly OmbiUserManager _userManager;
private readonly ILogger _log;
[HttpPost("Notification")]
[ApiExplorerSettings(IgnoreApi = true)]
@ -78,5 +81,24 @@ namespace Ombi.Controllers.V1
}
return vm;
}
[HttpPost]
[ApiExplorerSettings(IgnoreApi = true)]
[Admin]
public async Task<bool> RemoveUser([FromBody] string userId)
{
var user = await _userManager.Users.Include(x => x.NotificationUserIds).FirstOrDefaultAsync(x => x.Id.Equals(userId, StringComparison.InvariantCultureIgnoreCase));
try
{
await _notification.DeleteRange(user.NotificationUserIds);
return true;
}
catch (Exception e)
{
_log.LogError(e, "Could not delete user notification");
}
return false;
}
}
}

@ -4190,7 +4190,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -4208,11 +4209,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4225,15 +4228,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -4336,7 +4342,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -4346,6 +4353,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4358,17 +4366,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -4385,6 +4396,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4457,7 +4469,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -4467,6 +4480,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4542,7 +4556,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -4572,6 +4587,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -4589,6 +4605,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4627,11 +4644,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true
"bundled": true,
"optional": true
}
}
},

@ -126,7 +126,7 @@
"GridTitle": "Título",
"AirDate": "Fecha de estreno",
"GridStatus": "Estado",
"ReportIssue": "Informar de un problema/error",
"ReportIssue": "Informar de Problema",
"Filter": "Filtrar",
"Sort": "Ordenar",
"SeasonNumberHeading": "Temporada: {seasonNumber}",

@ -13,7 +13,7 @@
"ContinueButton": "Doorgaan",
"Available": "Beschikbaar",
"PartiallyAvailable": "Deels Beschikbaar",
"Monitored": "Gecontroleerd",
"Monitored": "Onder toezicht",
"NotAvailable": "Niet Beschikbaar",
"ProcessingRequest": "Verzoek wordt verwerkt",
"PendingApproval": "Wacht op goedkeuring",

@ -48,7 +48,7 @@
"Requests": "Solicitações",
"UserManagement": "Gerenciador de Usuário",
"Issues": "Problemas",
"Vote": "Vote",
"Vote": "Votar",
"Donate": "Fazer uma doação!",
"DonateLibraryMaintainer": "Doar para o Dono da Biblioteca",
"DonateTooltip": "É assim que eu convenço a minha mulher a deixar-me passar o meu tempo livre desenvolvendo Ombi;)",
@ -74,7 +74,7 @@
"ViewOnEmby": "Assistir no Emby",
"RequestAdded": "Pedido de {{title}} foi adicionado com sucesso",
"Similar": "Semelhante",
"Refine": "Refine",
"Refine": "Filtro",
"Movies": {
"PopularMovies": "Filmes populares",
"UpcomingMovies": "Próximos filmes",
@ -137,11 +137,11 @@
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼",
"Remaining": {
"Quota": "{{remaining}}/{{total}} requests remaining",
"NextDays": "Another request will be added in {{time}} days",
"NextHours": "Another request will be added in {{time}} hours",
"NextMinutes": "Another request will be added in {{time}} minutes",
"NextMinute": "Another request will be added in {{time}} minute"
"Quota": "{{remaining}}/{{total}} solicitações restantes",
"NextDays": "Outro pedido será adicionado em {{time}} dias",
"NextHours": "Outro pedido será adicionado em {{time}} horas",
"NextMinutes": "Outro pedido será adicionado em {{time}} minutos",
"NextMinute": "Outro pedido será adicionado em {{time}} minuto"
}
},
"Issues": {
@ -171,15 +171,15 @@
"PendingApproval": "Aprovação Pendente"
},
"UserManagment": {
"TvRemaining": "TV: {{remaining}}/{{total}} remaining",
"MovieRemaining": "Movies: {{remaining}}/{{total}} remaining",
"MusicRemaining": "Music: {{remaining}}/{{total}} remaining",
"TvRemaining": "Tv: {{remaining}}/{{total}} restantes",
"MovieRemaining": "Filmes: {{remaining}}/{{total}} restantes",
"MusicRemaining": "Música: {{remaining}}/{{total}} restantes",
"TvDue": "TV: {{date}}",
"MovieDue": "Movie: {{date}}",
"MusicDue": "Music: {{date}}"
"MovieDue": "Filme: {{date}}",
"MusicDue": "Música: {{date}}"
},
"Votes": {
"CompletedVotesTab": "Voted",
"VotesTab": "Votes Needed"
"CompletedVotesTab": "Votado",
"VotesTab": "Votos necessários"
}
}

Loading…
Cancel
Save