merge develop into v4

This commit is contained in:
tidusjar 2019-07-02 13:28:03 +01:00
commit 6a3addae5c
52 changed files with 1529 additions and 344 deletions

23
.github/stale.yml vendored Normal file
View file

@ -0,0 +1,23 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- bug / issue
- help wanted
- possible feature
- planned
- in progress
- enhancement
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View file

@ -1,6 +1,332 @@
# Changelog # Changelog
## v3.0.4256 (2019-02-18) ## (unreleased)
### **New Features**
- Added further logging into the API's (debug logging) [tidusjar]
- Added transactions around all of the CUD operations. [Jamie Rees]
- Update stale.yml. [Jamie]
- Update README.md. [Dyson Parkes]
- Added stalebot. [tidusjar]
- Added some validation around the new crons. [Jamie Rees]
- Added some defensive coding around when we create an artist for #2915. [tidusjar]
- Update README.md. [Jamie]
- Update README.md. [Jamie]
- Update JobSetup.cs. [Jamie]
- Update JobSetup.cs. [Jamie]
- Added a global mutex (not used yet) and moved around the code for loggin in since I suspect the Get Roles call is using deffered execution on the database causing the lock when attempting to access straight away #2750. [Jamie Rees]
- Added a lock on the database commit level to see if I can improve locked db's. [Jamie Rees]
- Update dependancies. [TidusJar]
- Update CHANGELOG.md. [Jamie]
### **Fixes**
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Swedish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Swedish) [Jamie]
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Russian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Norwegian) [Jamie]
- New translations en.json (Italian) [Jamie]
- New translations en.json (Hungarian) [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 (Bulgarian) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Spanish) [Jamie]
- New translations en.json (French) [Jamie]
- New translations en.json (French) [Jamie]
- New translations en.json (Russian) [Jamie]
- New translations en.json (Russian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (Portuguese, Brazilian) [Jamie]
- New translations en.json (German) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Russian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Bulgarian) [Jamie]
- 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 (Russian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Bulgarian) [Jamie]
- 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 (Polish) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Russian) [Jamie]
- New translations en.json (Hungarian) [Jamie]
- New translations en.json (Bulgarian) [Jamie]
- New translations en.json (Dutch) [Jamie]
- New translations en.json (Polish) [Jamie]
- Fixed the issue where the recently added scan was actually calling the RefreshMedia which ends up wiping out the Plex cache instead of refreshing the metadata... i'm a dumbass #3023. [tidusjar]
- Fix #3027. [Jamie]
- Log the request. [tidusjar]
- Really fixed #3010 this time. That's embarrassing. [Jamie]
- Renamed "Extensions" for Spelling Mistake. [bdrumm1234]
- #3010 - Make sure we only sync the Monitored Radarr movies... [tidusjar]
- Fixed build. [Jamie Rees]
- Fixed #2995. [Jamie Rees]
- Fixed. [tidusjar]
- Import System.IO. [Patrick Collins]
- Add exception to handle unknown RequestType. [Patrick Collins]
- Add braces to all if statements. [Patrick Collins]
- Fix album-request-permission error message. [Patrick Collins]
- Use string interpolation. [Austin Jackson]
- Swagger index prepends configured baseurl. [Austin Jackson]
- Add a internal retry when we have a locked db. [Jamie Rees]
- Fixed #2374. [tidusjar]
- Fixed #2950. [Jamie Rees]
- Fixed #2967. [Jamie Rees]
- Re-re fix the remove button. [goldenpipes]
- Fixed the other error for #2955. [tidusjar]
- Stuff. [tidusjar]
- Logging. [tidusjar]
- More to debug logging. [tidusjar]
- Start the scheduler after the jobs have been assigned. [tidusjar]
- Fixed some of the issues with the new scheduler not firing correctly. [Jamie Rees]
- Placeholder Text for Search Boxes (#2939) [Kris Klosterman]
- Reset all of the schedules due to Quartz using a different CRON system. Updated the UI code to reflect this. [tidusjar]
- Fixed the scheduler! [tidusjar]
- Attempting to get the new triggers working. [Jamie Rees]
- Swap out the scheduler #2750. [Jamie Rees]
- Moved the jobs to use quartz. [tidusjar]
- Fixed the mixed content warnings and the error when removing a album request #2884. [tidusjar]
- Fixed #2910. [tidusjar]
- Fix for broken twitch url in readme file. [PotatoQuality]
- Reverted the global app lock for the db #2750. [tidusjar]
- #2750 stuff. [Jamie Rees]
- More for #2750. [Jamie Rees]
- Removed the auditing, was not used anyway #2750. [Jamie Rees]
- Fixed #2803 in regards to the Request Button showing up. Still need to investiagte the availability side of things. [Jamie Rees]
- Delete the schedules db on startup, we don't want it trying to recover the jobs. [tidusjar]
- Fixed the issue where it was not picking up roles until the JWT was refreshed. [tidusjar]
- Add Gotify as notification provider. [Guillaume Taquet Gasperini]
- Fix cake build by setting Incubator version. [Guillaume Taquet Gasperini]
- Set the View On Emby Url at runtime so the user can configure and change the URL and it will take effect straight away. [Jamie Rees]
- Made use of the global mutex, this should now hopefully work #2750. [Jamie Rees]
- Fixed #2636. [TidusJar]
- Take out the lastlogindate update for now #2750. [tidusjar]
- Fixed build. [Jamie Rees]
- Fixed #2860 When a future series is unknown it should appear as available when we have the other seasons. [Jamie Rees]
- New translations en.json (German) [Jamie]
- New translations en.json (Norwegian) [Jamie]
- Fixed a migration issue. [tidusjar]
- Set the CommandTimeout longer to see if EF can get a handle on the SQLite file when it's locked #2750. [tidusjar]
- Prevented #2848 from erroring out causing further issues. [TidusJar]
- Fixed #2847. [TidusJar]
- Fixed a regression issue where TV Shows couldn't be requested. [TidusJar]
- New translations en.json (Polish) [Jamie]
- New translations en.json (French) [Jamie]
- Fix typo. [Jeff]
- Fixed an issue where the Subscribe button was appearing on available movies. [TidusJar]
- Converted the Plex Jobs to use Quartz. [Jamie]
## v3.0.4256 (2019-02-19)
### **New Features**
- Update CHANGELOG.md. [Jamie]
### **Fixes**
- Fixed #2826. [tidusjar]
## v3.0.4248 (2019-02-18)
### **New Features** ### **New Features**
@ -26,6 +352,22 @@
### **Fixes** ### **Fixes**
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Spanish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (Polish) [Jamie]
- New translations en.json (German) [Jamie]
- Fix: src/Ombi/package.json to reduce vulnerabilities. [snyk-bot] - Fix: src/Ombi/package.json to reduce vulnerabilities. [snyk-bot]
- Fixed #2801 this is when a season is not correctly monitored in sonarr when approved by an admin. [tidusjar] - Fixed #2801 this is when a season is not correctly monitored in sonarr when approved by an admin. [tidusjar]

View file

@ -20,9 +20,8 @@ Follow me developing Ombi!
___ ___
<a href='https://play.google.com/store/apps/details?id=com.tidusjar.Ombi&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img width="150" alt='Get it on Google Play' src='https://play.google.com/intl/en_gb/badges/images/generic/en_badge_web_generic.png'/></a> <a href='https://play.google.com/store/apps/details?id=com.tidusjar.Ombi&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img width="150" alt='Get it on Google Play' src='https://play.google.com/intl/en_gb/badges/images/generic/en_badge_web_generic.png'/></a>
<br>
<a href='https://itunes.apple.com/us/app/ombi/id1335260043?ls=1&mt=8'><img width="150" alt='Get it on App Store' src='https://i.imgur.com/cJFa0M4.png'/></a> _**Note:** There is no longer an iOS app due to complications outside of our control._
___ ___
@ -43,6 +42,7 @@ Here are some of the features Ombi V3 has:
* Now working without crashes on Linux. * Now working without crashes on Linux.
* Lets users request Movies, Music, and TV Shows (whether it being the entire series, an entire season, or even single episodes.) * Lets users request Movies, Music, and TV Shows (whether it being the entire series, an entire season, or even single episodes.)
* Easily manage your requests * Easily manage your requests
* Allows you to set specific users to automatically have requests approved and added to the relevant service (Sonarr/Radarr/Lidarr/Couchpotato etc)
* User management system (supports plex.tv, Emby and local accounts) * User management system (supports plex.tv, Emby and local accounts)
* A landing page that will give you the availability of your Plex/Emby server and also add custom notification text to inform your users of downtime. * A landing page that will give you the availability of your Plex/Emby server and also add custom notification text to inform your users of downtime.
* Allows your users to get custom notifications! * Allows your users to get custom notifications!
@ -50,7 +50,7 @@ Here are some of the features Ombi V3 has:
* Will show if the request is already on plex or even if it's already monitored. * Will show if the request is already on plex or even if it's already monitored.
* Automatically updates the status of requests when they are available on Plex/Emby * Automatically updates the status of requests when they are available on Plex/Emby
* Slick, responsive and mobile friendly UI * Slick, responsive and mobile friendly UI
* Ombi will automatically update itself :) * Ombi will automatically update itself :) (YMMV)
* Very fast! * Very fast!
### Integration ### Integration

View file

@ -16,6 +16,7 @@ namespace Ombi.Api.Emby.Models.Media.Tv
public int ProductionYear { get; set; } public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; } public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; } public int IndexNumber { get; set; }
public int? IndexNumberEnd { get; set; }
public int ParentIndexNumber { get; set; } public int ParentIndexNumber { get; set; }
public bool IsHD { get; set; } public bool IsHD { get; set; }
public bool IsFolder { get; set; } public bool IsFolder { get; set; }

View file

@ -23,6 +23,6 @@ namespace Ombi.Api.Lidarr
Task<List<LanguageProfiles>> GetLanguageProfile(string apiKey, string baseUrl); Task<List<LanguageProfiles>> GetLanguageProfile(string apiKey, string baseUrl);
Task<LidarrStatus> Status(string apiKey, string baseUrl); Task<LidarrStatus> Status(string apiKey, string baseUrl);
Task<CommandResult> AlbumSearch(int[] albumIds, string apiKey, string baseUrl); Task<CommandResult> AlbumSearch(int[] albumIds, string apiKey, string baseUrl);
Task<AlbumResponse> AlbumInformation(string albumId, string apiKey, string baseUrl); Task<AlbumByForeignId> AlbumInformation(string albumId, string apiKey, string baseUrl);
} }
} }

View file

@ -84,7 +84,7 @@ namespace Ombi.Api.Lidarr
public Task<AlbumByArtistResponse> GetAlbumsByArtist(string foreignArtistId) public Task<AlbumByArtistResponse> GetAlbumsByArtist(string foreignArtistId)
{ {
var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v0.3/artist/{foreignArtistId}", var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v0.4/artist/{foreignArtistId}",
HttpMethod.Get) {IgnoreBaseUrlAppend = true}; HttpMethod.Get) {IgnoreBaseUrlAppend = true};
return Api.Request<AlbumByArtistResponse>(request); return Api.Request<AlbumByArtistResponse>(request);
} }
@ -105,14 +105,13 @@ namespace Ombi.Api.Lidarr
return Api.Request<List<AlbumResponse>>(request); return Api.Request<List<AlbumResponse>>(request);
} }
public async Task<AlbumResponse> AlbumInformation(string albumId, string apiKey, string baseUrl) public async Task<AlbumByForeignId> AlbumInformation(string albumId, string apiKey, string baseUrl)
{ {
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get); var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
request.AddQueryString("foreignAlbumId", albumId); request.AddQueryString("foreignAlbumId", albumId);
AddHeaders(request, apiKey); AddHeaders(request, apiKey);
var albums = await Api.Request<List<AlbumResponse>>(request); var albums = await Api.Request<List<AlbumByForeignId>>(request);
return albums.Where(x => x.foreignAlbumId.Equals(albumId, StringComparison.InvariantCultureIgnoreCase)) return albums.FirstOrDefault();
.FirstOrDefault();
} }

View file

@ -0,0 +1,31 @@
using System;
using System.Net.Mime;
namespace Ombi.Api.Lidarr.Models
{
public class AlbumByForeignId
{
public string title { get; set; }
public string disambiguation { get; set; }
public string overview { get; set; }
public int artistId { get; set; }
public string foreignAlbumId { get; set; }
public bool monitored { get; set; }
public bool anyReleaseOk { get; set; }
public int profileId { get; set; }
public int duration { get; set; }
public string albumType { get; set; }
public object[] secondaryTypes { get; set; }
public int mediumCount { get; set; }
public Ratings ratings { get; set; }
public DateTime releaseDate { get; set; }
public Release[] releases { get; set; }
public object[] genres { get; set; }
public Medium[] media { get; set; }
public Artist artist { get; set; }
public Image[] images { get; set; }
public Link[] links { get; set; }
public Statistics statistics { get; set; }
public int id { get; set; }
}
}

View file

@ -2,6 +2,7 @@
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web;
using Ombi.Api.Pushover.Models; using Ombi.Api.Pushover.Models;
namespace Ombi.Api.Pushover namespace Ombi.Api.Pushover
@ -18,11 +19,7 @@ namespace Ombi.Api.Pushover
public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound) public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound)
{ {
if (message.Contains("'")) var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.UrlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
{
message = message.Replace("'", "&#39;");
}
var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
var result = await _api.Request<PushoverResponse>(request); var result = await _api.Request<PushoverResponse>(request);
return result; return result;

View file

@ -73,6 +73,7 @@ namespace Ombi.Api
// do something with the response // do something with the response
var receivedString = await httpResponseMessage.Content.ReadAsStringAsync(); var receivedString = await httpResponseMessage.Content.ReadAsStringAsync();
LogDebugContent(receivedString);
if (request.ContentType == ContentType.Json) if (request.ContentType == ContentType.Json)
{ {
request.OnBeforeDeserialization?.Invoke(receivedString); request.OnBeforeDeserialization?.Invoke(receivedString);
@ -111,7 +112,7 @@ namespace Ombi.Api
} }
// do something with the response // do something with the response
var data = httpResponseMessage.Content; var data = httpResponseMessage.Content;
await LogDebugContent(httpResponseMessage);
return await data.ReadAsStringAsync(); return await data.ReadAsStringAsync();
} }
@ -123,6 +124,7 @@ namespace Ombi.Api
{ {
AddHeadersBody(request, httpRequestMessage); AddHeadersBody(request, httpRequestMessage);
var httpResponseMessage = await _client.SendAsync(httpRequestMessage); var httpResponseMessage = await _client.SendAsync(httpRequestMessage);
await LogDebugContent(httpResponseMessage);
if (!httpResponseMessage.IsSuccessStatusCode) if (!httpResponseMessage.IsSuccessStatusCode)
{ {
if (!request.IgnoreErrors) if (!request.IgnoreErrors)
@ -133,11 +135,12 @@ namespace Ombi.Api
} }
} }
private static void AddHeadersBody(Request request, HttpRequestMessage httpRequestMessage) private void AddHeadersBody(Request request, HttpRequestMessage httpRequestMessage)
{ {
// Add the Json Body // Add the Json Body
if (request.JsonBody != null) if (request.JsonBody != null)
{ {
LogDebugContent("REQUEST: " + request.JsonBody);
httpRequestMessage.Content = new JsonContent(request.JsonBody); httpRequestMessage.Content = new JsonContent(request.JsonBody);
httpRequestMessage.Content.Headers.ContentType = httpRequestMessage.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header
@ -154,11 +157,24 @@ namespace Ombi.Api
{ {
Logger.LogError(LoggingEvents.Api, Logger.LogError(LoggingEvents.Api,
$"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}, RequestUri: {request.FullUri}"); $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}, RequestUri: {request.FullUri}");
await LogDebugContent(httpResponseMessage);
}
private async Task LogDebugContent(HttpResponseMessage message)
{
if (Logger.IsEnabled(LogLevel.Debug)) if (Logger.IsEnabled(LogLevel.Debug))
{ {
var content = await httpResponseMessage.Content.ReadAsStringAsync(); var content = await message.Content.ReadAsStringAsync();
Logger.LogDebug(content); Logger.LogDebug(content);
} }
} }
private void LogDebugContent(string message)
{
if (Logger.IsEnabled(LogLevel.Debug))
{
Logger.LogDebug(message);
}
}
} }
} }

View file

@ -11,7 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Polly" Version="6.1.0" /> <PackageReference Include="Polly" Version="7.1.0" />
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" /> <PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
</ItemGroup> </ItemGroup>

View file

@ -157,7 +157,7 @@ namespace Ombi.Core.Engine
// TODO // TODO
private async Task<SearchAlbumViewModel> MapIntoAlbumVm(AlbumResponse a, LidarrSettings settings) private async Task<SearchAlbumViewModel> MapIntoAlbumVm(AlbumByForeignId a, LidarrSettings settings)
{ {
var vm = new SearchAlbumViewModel var vm = new SearchAlbumViewModel
{ {
@ -167,7 +167,10 @@ namespace Ombi.Core.Engine
ReleaseDate = a.releaseDate, ReleaseDate = a.releaseDate,
Title = a.title, Title = a.title,
Disk = a.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url?.Replace("http", "https"), Disk = a.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url?.Replace("http", "https"),
Genres = a.genres Genres = a.genres,
AlbumType = a.albumType,
ArtistName = a.artist.artistName,
ForeignArtistId = a.artist.foreignArtistId,
}; };
if (a.artistId > 0) if (a.artistId > 0)
{ {
@ -185,10 +188,6 @@ namespace Ombi.Core.Engine
} }
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.Replace("http", "https"); vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.Replace("http", "https");
if (vm.Cover.IsNullOrEmpty())
{
//vm.Cover = a.remoteCover;
}
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum); await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);

View file

@ -1,4 +1,6 @@
using System.Security.Claims; using Ombi.Store.Entities;
using System.IO;
using System.Security.Claims;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -37,16 +39,24 @@ namespace Ombi.Core.Rule.Rules.Request
if (obj.RequestType == RequestType.TvShow) if (obj.RequestType == RequestType.TvShow)
{ {
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv)) if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
return Success();
}
if (obj.RequestType == RequestType.Album)
{ {
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMusic) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
return Success(); return Success();
} }
return Fail("You do not have permissions to Request a TV Show"); return Fail("You do not have permissions to Request a TV Show");
} }
if (obj.RequestType == RequestType.Album)
{
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMusic) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
{
return Success();
}
return Fail("You do not have permissions to Request an Album");
}
throw new InvalidDataException("Permission check failed: unknown RequestType");
}
} }
} }

View file

@ -30,6 +30,7 @@ namespace Ombi.Notifications
_log = log; _log = log;
AlbumRepository = album; AlbumRepository = album;
UserNotificationPreferences = notificationUserPreferences; UserNotificationPreferences = notificationUserPreferences;
Settings.ClearCache();
} }
protected ISettingsService<T> Settings { get; } protected ISettingsService<T> Settings { get; }

View file

@ -78,7 +78,11 @@ namespace Ombi.Schedule.Jobs.Couchpotato
if (movies != null) if (movies != null)
{ {
// Let's remove the old cached data // Let's remove the old cached data
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM CouchPotatoCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM CouchPotatoCache");
tran.Commit();
}
// Save // Save
var movieIds = new List<CouchPotatoCache>(); var movieIds = new List<CouchPotatoCache>();
@ -98,9 +102,14 @@ namespace Ombi.Schedule.Jobs.Couchpotato
_log.LogError("TMDBId is not > 0 for movie {0}", m.title); _log.LogError("TMDBId is not > 0 for movie {0}", m.title);
} }
} }
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.CouchPotatoCache.AddRangeAsync(movieIds); await _ctx.CouchPotatoCache.AddRangeAsync(movieIds);
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
.SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Finished"); .SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Finished");

View file

@ -67,7 +67,7 @@ namespace Ombi.Schedule.Jobs.Emby
// Episodes // Episodes
await OmbiQuartz.TriggerJob(nameof(IEmbyEpisodeSync), "Emby"); await OmbiQuartz.TriggerJob(nameof(IEmbyEpisodeSync), "Emby");
await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "Emby"); await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "System");
} }

View file

@ -126,6 +126,22 @@ namespace Ombi.Schedule.Jobs.Emby
Title = ep.Name, Title = ep.Name,
AddedAt = DateTime.UtcNow AddedAt = DateTime.UtcNow
}); });
if (ep.IndexNumberEnd.HasValue && ep.IndexNumberEnd.Value != ep.IndexNumber)
{
epToAdd.Add(new EmbyEpisode
{
EmbyId = ep.Id,
EpisodeNumber = ep.IndexNumberEnd.Value,
SeasonNumber = ep.ParentIndexNumber,
ParentId = ep.SeriesId,
TvDbId = ep.ProviderIds.Tvdb,
TheMovieDbId = ep.ProviderIds.Tmdb,
ImdbId = ep.ProviderIds.Imdb,
Title = ep.Name,
AddedAt = DateTime.UtcNow
});
}
} }
} }

View file

@ -56,7 +56,11 @@ namespace Ombi.Schedule.Jobs.Lidarr
if (albums != null && albums.Any()) if (albums != null && albums.Any())
{ {
// Let's remove the old cached data // Let's remove the old cached data
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrAlbumCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrAlbumCache");
tran.Commit();
}
var albumCache = new List<LidarrAlbumCache>(); var albumCache = new List<LidarrAlbumCache>();
foreach (var a in albums) foreach (var a in albums)
@ -68,7 +72,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
ArtistId = a.artistId, ArtistId = a.artistId,
ForeignAlbumId = a.foreignAlbumId, ForeignAlbumId = a.foreignAlbumId,
ReleaseDate = a.releaseDate, ReleaseDate = a.releaseDate,
TrackCount = a.currentRelease.trackCount, TrackCount = a.currentRelease?.trackCount ?? 0,
Monitored = a.monitored, Monitored = a.monitored,
Title = a.title, Title = a.title,
PercentOfTracks = a.statistics?.percentOfEpisodes ?? 0m, PercentOfTracks = a.statistics?.percentOfEpisodes ?? 0m,
@ -76,9 +80,14 @@ namespace Ombi.Schedule.Jobs.Lidarr
}); });
} }
} }
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.LidarrAlbumCache.AddRangeAsync(albumCache); await _ctx.LidarrAlbumCache.AddRangeAsync(albumCache);
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }
catch (System.Exception ex) catch (System.Exception ex)

View file

@ -52,7 +52,11 @@ namespace Ombi.Schedule.Jobs.Lidarr
if (artists != null && artists.Any()) if (artists != null && artists.Any())
{ {
// Let's remove the old cached data // Let's remove the old cached data
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrArtistCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrArtistCache");
tran.Commit();
}
var artistCache = new List<LidarrArtistCache>(); var artistCache = new List<LidarrArtistCache>();
foreach (var a in artists) foreach (var a in artists)
@ -68,9 +72,14 @@ namespace Ombi.Schedule.Jobs.Lidarr
}); });
} }
} }
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.LidarrArtistCache.AddRangeAsync(artistCache); await _ctx.LidarrArtistCache.AddRangeAsync(artistCache);
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }
catch (Exception ex) catch (Exception ex)

View file

@ -53,7 +53,6 @@ namespace Ombi.Schedule.Jobs.Ombi
{ {
return; return;
} }
const string episodeSQL = "DELETE FROM EmbyEpisode"; const string episodeSQL = "DELETE FROM EmbyEpisode";
const string mainSql = "DELETE FROM EmbyContent"; const string mainSql = "DELETE FROM EmbyContent";
await _embyRepo.ExecuteSql(episodeSQL); await _embyRepo.ExecuteSql(episodeSQL);

View file

@ -378,7 +378,7 @@ namespace Ombi.Schedule.Jobs.Ombi
if (embySettings.Enable) if (embySettings.Enable)
{ {
await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode); await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
} }
sb.Append("</tr>"); sb.Append("</tr>");
@ -404,7 +404,7 @@ namespace Ombi.Schedule.Jobs.Ombi
if (embySettings.Enable) if (embySettings.Enable)
{ {
await ProcessEmbyTv(embyEp, sb); await ProcessEmbyTv(embyEp, sb, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty);
} }
sb.Append("</tr>"); sb.Append("</tr>");
@ -509,7 +509,7 @@ namespace Ombi.Schedule.Jobs.Ombi
} }
} }
private async Task ProcessEmbyMovies(IQueryable<EmbyContent> embyContent, StringBuilder sb, string defaultLangaugeCode) private async Task ProcessEmbyMovies(IQueryable<EmbyContent> embyContent, StringBuilder sb, string defaultLangaugeCode, string customUrl)
{ {
int count = 0; int count = 0;
var ordered = embyContent.OrderByDescending(x => x.AddedAt); var ordered = embyContent.OrderByDescending(x => x.AddedAt);
@ -530,6 +530,10 @@ namespace Ombi.Schedule.Jobs.Ombi
} }
var mediaurl = content.Url; var mediaurl = content.Url;
if (customUrl.HasValue())
{
mediaurl = customUrl;
}
var info = await _movieApi.GetMovieInformationWithExtraInfo(StringHelper.IntParseLinq(theMovieDbId), defaultLangaugeCode); var info = await _movieApi.GetMovieInformationWithExtraInfo(StringHelper.IntParseLinq(theMovieDbId), defaultLangaugeCode);
if (info == null) if (info == null)
{ {
@ -773,7 +777,7 @@ namespace Ombi.Schedule.Jobs.Ombi
private async Task ProcessEmbyTv(HashSet<EmbyEpisode> embyContent, StringBuilder sb) private async Task ProcessEmbyTv(HashSet<EmbyEpisode> embyContent, StringBuilder sb, string serverUrl)
{ {
var series = new List<EmbyContent>(); var series = new List<EmbyContent>();
foreach (var episode in embyContent) foreach (var episode in embyContent)
@ -828,7 +832,7 @@ namespace Ombi.Schedule.Jobs.Ombi
AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/"); AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/");
} }
AddPosterInsideTable(sb, banner); AddPosterInsideTable(sb, banner);
AddMediaServerUrl(sb, t.Url, banner); AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner);
AddInfoTable(sb); AddInfoTable(sb);
var title = ""; var title = "";

View file

@ -118,10 +118,10 @@ namespace Ombi.Schedule.Jobs.Plex
if ((processedContent?.HasProcessedContent ?? false) && recentlyAddedSearch) if ((processedContent?.HasProcessedContent ?? false) && recentlyAddedSearch)
{ {
// Just check what we send it // Just check what we send it
await OmbiQuartz.TriggerJob(nameof(IMediaDatabaseRefresh), "System"); await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "System");
} }
if ((processedContent?.HasProcessedEpisodes ?? false) && recentlyAddedSearch) if ((processedContent?.HasProcessedContent ?? false) && recentlyAddedSearch)
{ {
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex"); await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
@ -208,10 +208,10 @@ namespace Ombi.Schedule.Jobs.Plex
} }
contentToAdd.Clear(); contentToAdd.Clear();
} }
if (count > 200) if (count > 30)
{ {
await Repo.SaveChangesAsync(); await Repo.SaveChangesAsync();
count = 0;
} }
} }
@ -245,7 +245,7 @@ namespace Ombi.Schedule.Jobs.Plex
} }
contentToAdd.Clear(); contentToAdd.Clear();
} }
if (count > 200) if (count > 30)
{ {
await Repo.SaveChangesAsync(); await Repo.SaveChangesAsync();
} }

View file

@ -47,12 +47,16 @@ namespace Ombi.Schedule.Jobs.Radarr
if (movies != null) if (movies != null)
{ {
// Let's remove the old cached data // Let's remove the old cached data
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM RadarrCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM RadarrCache");
tran.Commit();
}
var movieIds = new List<RadarrCache>(); var movieIds = new List<RadarrCache>();
foreach (var m in movies) foreach (var m in movies)
{ {
if (m.tmdbId > 0) if (m.tmdbId > 0 && m.monitored)
{ {
movieIds.Add(new RadarrCache movieIds.Add(new RadarrCache
{ {
@ -65,9 +69,14 @@ namespace Ombi.Schedule.Jobs.Radarr
Logger.LogError("TMDBId is not > 0 for movie {0}", m.title); Logger.LogError("TMDBId is not > 0 for movie {0}", m.title);
} }
} }
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.RadarrCache.AddRangeAsync(movieIds); await _ctx.RadarrCache.AddRangeAsync(movieIds);
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }
catch (System.Exception ex) catch (System.Exception ex)

View file

@ -46,8 +46,12 @@ namespace Ombi.Schedule.Jobs.SickRage
{ {
var srShows = shows.data.Values; var srShows = shows.data.Values;
var ids = srShows.Select(x => x.tvdbid); var ids = srShows.Select(x => x.tvdbid);
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageCache");
tran.Commit();
}
var entites = ids.Select(id => new SickRageCache { TvDbId = id }).ToList(); var entites = ids.Select(id => new SickRageCache { TvDbId = id }).ToList();
await _ctx.SickRageCache.AddRangeAsync(entites); await _ctx.SickRageCache.AddRangeAsync(entites);
@ -74,8 +78,12 @@ namespace Ombi.Schedule.Jobs.SickRage
} }
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.SickRageEpisodeCache.AddRangeAsync(episodesToAdd); await _ctx.SickRageEpisodeCache.AddRangeAsync(episodesToAdd);
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }
catch (Exception e) catch (Exception e)

View file

@ -48,14 +48,22 @@ namespace Ombi.Schedule.Jobs.Sonarr
{ {
var sonarrSeries = series as ImmutableHashSet<SonarrSeries> ?? series.ToImmutableHashSet(); var sonarrSeries = series as ImmutableHashSet<SonarrSeries> ?? series.ToImmutableHashSet();
var ids = sonarrSeries.Select(x => x.tvdbId); var ids = sonarrSeries.Select(x => x.tvdbId);
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache");
tran.Commit();
}
var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet(); var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet();
await _ctx.SonarrCache.AddRangeAsync(entites); await _ctx.SonarrCache.AddRangeAsync(entites);
entites.Clear(); entites.Clear();
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache"); await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache");
tran.Commit();
}
foreach (var s in sonarrSeries) foreach (var s in sonarrSeries)
{ {
if (!s.monitored) if (!s.monitored)
@ -68,7 +76,10 @@ namespace Ombi.Schedule.Jobs.Sonarr
// Add to DB // Add to DB
_log.LogDebug("We have the episodes, adding to db transaction"); _log.LogDebug("We have the episodes, adding to db transaction");
await _ctx.SonarrEpisodeCache.AddRangeAsync(monitoredEpisodes.Select(episode => new SonarrEpisodeCache using (var tran = await _ctx.Database.BeginTransactionAsync())
{
await _ctx.SonarrEpisodeCache.AddRangeAsync(monitoredEpisodes.Select(episode =>
new SonarrEpisodeCache
{ {
EpisodeNumber = episode.episodeNumber, EpisodeNumber = episode.episodeNumber,
SeasonNumber = episode.seasonNumber, SeasonNumber = episode.seasonNumber,
@ -77,6 +88,8 @@ namespace Ombi.Schedule.Jobs.Sonarr
})); }));
_log.LogDebug("Commiting the transaction"); _log.LogDebug("Commiting the transaction");
await _ctx.SaveChangesAsync(); await _ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }

View file

@ -63,7 +63,12 @@ namespace Ombi.Store.Context
{ {
// VACUUM; // VACUUM;
Database.ExecuteSqlCommand("VACUUM;"); Database.ExecuteSqlCommand("VACUUM;");
using (var tran = Database.BeginTransaction())
{
SaveChanges(); SaveChanges();
tran.Commit();
}
} }
} }
} }

View file

@ -88,6 +88,9 @@ namespace Ombi.Store.Context
public void Seed() public void Seed()
{
using (var tran = Database.BeginTransaction())
{ {
// Make sure we have the API User // Make sure we have the API User
var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase)); var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase));
@ -101,6 +104,8 @@ namespace Ombi.Store.Context
}); });
SaveChanges(); SaveChanges();
tran.Commit();
}
} }
//Check if templates exist //Check if templates exist
@ -237,8 +242,13 @@ namespace Ombi.Store.Context
} }
if (needToSave) if (needToSave)
{
using (var tran = Database.BeginTransaction())
{ {
SaveChanges(); SaveChanges();
tran.Commit();
}
} }
} }
} }

View file

@ -32,6 +32,9 @@ namespace Ombi.Store.Context
} }
public void Seed() public void Seed()
{
using (var tran = Database.BeginTransaction())
{ {
// Add the tokens // Add the tokens
var fanArt = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); var fanArt = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv);
@ -44,6 +47,7 @@ namespace Ombi.Store.Context
}); });
SaveChanges(); SaveChanges();
} }
var movieDb = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); var movieDb = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv);
if (movieDb == null) if (movieDb == null)
{ {
@ -54,7 +58,9 @@ namespace Ombi.Store.Context
}); });
SaveChanges(); SaveChanges();
} }
var notification = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.Notification);
var notification =
ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.Notification);
if (notification == null) if (notification == null)
{ {
ApplicationConfigurations.Add(new ApplicationConfiguration ApplicationConfigurations.Add(new ApplicationConfiguration
@ -64,6 +70,8 @@ namespace Ombi.Store.Context
}); });
SaveChanges(); SaveChanges();
} }
tran.Commit();
}
} }
} }
} }

View file

@ -16,6 +16,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" /> <PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
<PackageReference Include="Polly" Version="7.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.9" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.9" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -23,6 +23,8 @@ namespace Ombi.Store.Repository
} }
public async Task Record(AuditType type, AuditArea area, string description, string user) public async Task Record(AuditType type, AuditArea area, string description, string user)
{
using (var tran = await Ctx.Database.BeginTransactionAsync())
{ {
await Ctx.Audit.AddAsync(new Audit await Ctx.Audit.AddAsync(new Audit
{ {
@ -34,6 +36,8 @@ namespace Ombi.Store.Repository
}); });
await Ctx.SaveChangesAsync(); await Ctx.SaveChangesAsync();
tran.Commit();
}
} }
} }
} }

View file

@ -3,11 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Context; using Ombi.Store.Context;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Polly;
namespace Ombi.Store.Repository namespace Ombi.Store.Repository
{ {
@ -83,7 +85,25 @@ namespace Ombi.Store.Repository
protected async Task<int> InternalSaveChanges() protected async Task<int> InternalSaveChanges()
{ {
return await _ctx.SaveChangesAsync(); var policy = Policy
.Handle<SqliteException>()
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
});
var result = await policy.ExecuteAndCaptureAsync(async () =>
{
using (var tran = await _ctx.Database.BeginTransactionAsync())
{
var r = await _ctx.SaveChangesAsync();
tran.Commit();
return r;
}
});
return result.Result;
} }

View file

@ -8,9 +8,9 @@ using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests namespace Ombi.Store.Repository.Requests
{ {
public class TvRequestRepository : ITvRequestRepository public class TvRequestRepository : BaseRepository<TvRequests, IOmbiContext>, ITvRequestRepository
{ {
public TvRequestRepository(IOmbiContext ctx) public TvRequestRepository(IOmbiContext ctx) : base(ctx)
{ {
Db = ctx; Db = ctx;
} }
@ -151,10 +151,5 @@ namespace Ombi.Store.Repository.Requests
await InternalSaveChanges(); await InternalSaveChanges();
} }
private async Task<int> InternalSaveChanges()
{
return await Db.SaveChangesAsync();
}
} }
} }

View file

@ -24,18 +24,29 @@ namespace Ombi.Store.Repository
public GlobalSettings Insert(GlobalSettings entity) public GlobalSettings Insert(GlobalSettings entity)
{ {
//_cache.Remove(GetName(entity.SettingsName)); //_cache.Remove(GetName(entity.SettingsName));
using (var tran = Db.Database.BeginTransaction())
{
var settings = Db.Settings.Add(entity); var settings = Db.Settings.Add(entity);
Db.SaveChanges(); Db.SaveChanges();
tran.Commit();
return settings.Entity; return settings.Entity;
} }
}
public async Task<GlobalSettings> InsertAsync(GlobalSettings entity) public async Task<GlobalSettings> InsertAsync(GlobalSettings entity)
{
using (var tran = Db.Database.BeginTransaction())
{ {
//_cache.Remove(GetName(entity.SettingsName)); //_cache.Remove(GetName(entity.SettingsName));
var settings = await Db.Settings.AddAsync(entity).ConfigureAwait(false); var settings = await Db.Settings.AddAsync(entity);
await Db.SaveChangesAsync().ConfigureAwait(false); await Db.SaveChangesAsync();
tran.Commit();
return settings.Entity; return settings.Entity;
} }
}
public GlobalSettings Get(string pageName) public GlobalSettings Get(string pageName)
@ -75,15 +86,24 @@ namespace Ombi.Store.Repository
public void Delete(GlobalSettings entity) public void Delete(GlobalSettings entity)
{ {
//_cache.Remove(GetName(entity.SettingsName)); //_cache.Remove(GetName(entity.SettingsName));
using (var tran = Db.Database.BeginTransaction())
{
Db.Settings.Remove(entity); Db.Settings.Remove(entity);
Db.SaveChanges(); Db.SaveChanges();
tran.Commit();
}
} }
public void Update(GlobalSettings entity) public void Update(GlobalSettings entity)
{
using (var tran = Db.Database.BeginTransaction())
{ {
Db.Update(entity); Db.Update(entity);
//_cache.Remove(GetName(entity.SettingsName)); //_cache.Remove(GetName(entity.SettingsName));
Db.SaveChanges(); Db.SaveChanges();
tran.Commit();
}
} }
private string GetName(string entity) private string GetName(string entity)
@ -93,7 +113,13 @@ namespace Ombi.Store.Repository
private async Task<int> InternalSaveChanges() private async Task<int> InternalSaveChanges()
{ {
return await Db.SaveChangesAsync();
using (var tran = Db.Database.BeginTransaction())
{
var r = await Db.SaveChangesAsync();
tran.Commit();
return r;
}
} }
private bool _disposed; private bool _disposed;

View file

@ -8,9 +8,9 @@ using Ombi.Helpers;
namespace Ombi.Store.Repository namespace Ombi.Store.Repository
{ {
public class TokenRepository : ITokenRepository public class TokenRepository : BaseRepository<Tokens, IOmbiContext>, ITokenRepository
{ {
public TokenRepository(IOmbiContext db) public TokenRepository(IOmbiContext db) : base(db)
{ {
Db = db; Db = db;
} }
@ -27,9 +27,5 @@ namespace Ombi.Store.Repository
{ {
return Db.Tokens.Where(x => x.Token == tokenId); return Db.Tokens.Where(x => x.Token == tokenId);
} }
private async Task<int> InternalSaveChanges()
{
return await Db.SaveChangesAsync();
}
} }
} }

View file

@ -198,8 +198,8 @@
</div> </div>
<div *ngIf="isAdmin || isRequestUser(request)"> <div *ngIf="isAdmin || isRequestUser(request)">
<form id="removeBtn"> <form>
<button (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete"> <button id="removeBtn" (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete">
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }} <i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}
</button> </button>
</form> </form>

View file

@ -149,7 +149,14 @@ namespace Ombi.Controllers.V1
} }
user.LastLoggedIn = DateTime.UtcNow; user.LastLoggedIn = DateTime.UtcNow;
try
{
await _userManager.UpdateAsync(user); await _userManager.UpdateAsync(user);
}
catch (Exception)
{
}
return new JsonResult(new return new JsonResult(new
{ {

View file

@ -62,15 +62,25 @@ namespace Ombi
Type = ConfigurationTypes.Url, Type = ConfigurationTypes.Url,
Value = "http://*:5000" Value = "http://*:5000"
}; };
using (var tran = ctx.Database.BeginTransaction())
{
ctx.ApplicationConfigurations.Add(url); ctx.ApplicationConfigurations.Add(url);
ctx.SaveChanges(); ctx.SaveChanges();
tran.Commit();
}
urlValue = url.Value; urlValue = url.Value;
} }
if (!url.Value.Equals(host)) if (!url.Value.Equals(host))
{ {
url.Value = UrlArgs; url.Value = UrlArgs;
using (var tran = ctx.Database.BeginTransaction())
{
ctx.SaveChanges(); ctx.SaveChanges();
tran.Commit();
}
urlValue = url.Value; urlValue = url.Value;
} }
@ -83,14 +93,24 @@ namespace Ombi
Type = ConfigurationTypes.BaseUrl, Type = ConfigurationTypes.BaseUrl,
Value = baseUrl Value = baseUrl
}; };
using (var tran = ctx.Database.BeginTransaction())
{
ctx.ApplicationConfigurations.Add(dbBaseUrl); ctx.ApplicationConfigurations.Add(dbBaseUrl);
ctx.SaveChanges(); ctx.SaveChanges();
tran.Commit();
}
} }
} }
else if (baseUrl.HasValue() && !baseUrl.Equals(dbBaseUrl.Value)) else if (baseUrl.HasValue() && !baseUrl.Equals(dbBaseUrl.Value))
{ {
dbBaseUrl.Value = baseUrl; dbBaseUrl.Value = baseUrl;
using (var tran = ctx.Database.BeginTransaction())
{
ctx.SaveChanges(); ctx.SaveChanges();
tran.Commit();
}
} }
Console.WriteLine($"We are running on {urlValue}"); Console.WriteLine($"We are running on {urlValue}");
@ -129,6 +149,9 @@ namespace Ombi
var settings = new SettingsContext(); var settings = new SettingsContext();
try try
{
using (var tran = settings.Database.BeginTransaction())
{ {
if (ombi.Settings.Any() && !settings.Settings.Any()) if (ombi.Settings.Any() && !settings.Settings.Any())
{ {
@ -149,6 +172,8 @@ namespace Ombi
} }
settings.SaveChanges(); settings.SaveChanges();
tran.Commit();
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -156,16 +181,24 @@ namespace Ombi
throw; throw;
} }
using (var tran = ombi.Database.BeginTransaction())
{
// Now delete the old stuff // Now delete the old stuff
if (doneGlobal) if (doneGlobal)
ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings"); ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings");
if (doneConfig) if (doneConfig)
ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration"); ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration");
tran.Commit();
}
// Now migrate all the external stuff // Now migrate all the external stuff
var external = new ExternalContext(); var external = new ExternalContext();
try try
{
using (var tran = external.Database.BeginTransaction())
{ {
if (ombi.PlexEpisode.Any()) if (ombi.PlexEpisode.Any())
{ {
@ -178,11 +211,13 @@ namespace Ombi
external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList()); external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent"); ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent");
} }
if (ombi.PlexServerContent.Any()) if (ombi.PlexServerContent.Any())
{ {
external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList()); external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent"); ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent");
} }
if (ombi.EmbyEpisode.Any()) if (ombi.EmbyEpisode.Any())
{ {
external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList()); external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList());
@ -194,36 +229,43 @@ namespace Ombi
external.EmbyContent.AddRange(ombi.EmbyContent.ToList()); external.EmbyContent.AddRange(ombi.EmbyContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent"); ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent");
} }
if (ombi.RadarrCache.Any()) if (ombi.RadarrCache.Any())
{ {
external.RadarrCache.AddRange(ombi.RadarrCache.ToList()); external.RadarrCache.AddRange(ombi.RadarrCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache");
} }
if (ombi.SonarrCache.Any()) if (ombi.SonarrCache.Any())
{ {
external.SonarrCache.AddRange(ombi.SonarrCache.ToList()); external.SonarrCache.AddRange(ombi.SonarrCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache");
} }
if (ombi.LidarrAlbumCache.Any()) if (ombi.LidarrAlbumCache.Any())
{ {
external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList()); external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache");
} }
if (ombi.LidarrArtistCache.Any()) if (ombi.LidarrArtistCache.Any())
{ {
external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList()); external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache");
} }
if (ombi.SickRageEpisodeCache.Any()) if (ombi.SickRageEpisodeCache.Any())
{ {
external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList()); external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache");
} }
if (ombi.SickRageCache.Any()) if (ombi.SickRageCache.Any())
{ {
external.SickRageCache.AddRange(ombi.SickRageCache.ToList()); external.SickRageCache.AddRange(ombi.SickRageCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache"); ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache");
} }
if (ombi.CouchPotatoCache.Any()) if (ombi.CouchPotatoCache.Any())
{ {
external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList()); external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList());
@ -231,6 +273,8 @@ namespace Ombi
} }
external.SaveChanges(); external.SaveChanges();
tran.Commit();
}
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -220,8 +220,14 @@ namespace Ombi
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI(c => app.UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1"); if (settings.BaseUrl.HasValue())
c.SwaggerEndpoint("/swagger/v2/swagger.json", "API V2"); {
c.SwaggerEndpoint($"{settings.BaseUrl}/swagger/v1/swagger.json", "My API V1");
}
else
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}
}); });
app.UseSignalR(routes => { routes.MapHub<NotificationHub>("/hubs/notification"); }); app.UseSignalR(routes => { routes.MapHub<NotificationHub>("/hubs/notification"); });

View file

@ -0,0 +1,186 @@
{
"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",
"PartiallyAvailable": "Partially Available",
"Monitored": "Monitored",
"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",
"Vote": "Vote",
"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",
"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",
"MusicTab": "Music",
"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",
"Refine": "Refine",
"SearchBarPlaceholder": "Type Here to Search",
"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",
"MusicTab": "Music",
"RequestedBy": "Requested By:",
"Status": "Status:",
"RequestStatus": "Request status:",
"Denied": " Denied:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"ReleaseDate": "Released: {{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 ▼",
"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"
}
},
"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"
},
"UserManagment": {
"TvRemaining": "TV: {{remaining}}/{{total}} remaining",
"MovieRemaining": "Movies: {{remaining}}/{{total}} remaining",
"MusicRemaining": "Music: {{remaining}}/{{total}} remaining",
"TvDue": "TV: {{date}}",
"MovieDue": "Movie: {{date}}",
"MusicDue": "Music: {{date}}"
},
"Votes": {
"CompletedVotesTab": "Voted",
"VotesTab": "Votes Needed"
}
}

View file

@ -75,6 +75,7 @@
"RequestAdded": "{{title}} er anmodet med succes", "RequestAdded": "{{title}} er anmodet med succes",
"Similar": "Lignende", "Similar": "Lignende",
"Refine": "Refine", "Refine": "Refine",
"SearchBarPlaceholder": "Type Here to Search",
"Movies": { "Movies": {
"PopularMovies": "Populære film", "PopularMovies": "Populære film",
"UpcomingMovies": "Kommende film", "UpcomingMovies": "Kommende film",

View file

@ -75,6 +75,7 @@
"RequestAdded": "Anfrage für {{title}} wurde erfolgreich hinzugefügt", "RequestAdded": "Anfrage für {{title}} wurde erfolgreich hinzugefügt",
"Similar": "Ähnliche", "Similar": "Ähnliche",
"Refine": "Auswahl verfeinern", "Refine": "Auswahl verfeinern",
"SearchBarPlaceholder": "Suchwort eingeben",
"Movies": { "Movies": {
"PopularMovies": "Beliebte Filme", "PopularMovies": "Beliebte Filme",
"UpcomingMovies": "Kommende Filme", "UpcomingMovies": "Kommende Filme",

View file

@ -12,69 +12,70 @@
"Common": { "Common": {
"ContinueButton": "Continuar", "ContinueButton": "Continuar",
"Available": "Disponible", "Available": "Disponible",
"PartiallyAvailable": "Disponible en parte", "PartiallyAvailable": "Disponible parcialmente",
"Monitored": "Monitoreado", "Monitored": "Monitoreado",
"NotAvailable": "No está disponible", "NotAvailable": "No disponible",
"ProcessingRequest": "Procesando solicitud", "ProcessingRequest": "Procesando solicitud",
"PendingApproval": "Pendiente de aprobación", "PendingApproval": "Pendiente de aprobación",
"RequestDenied": "Solicitud denegada", "RequestDenied": "Solicitud denegada",
"NotRequested": "No solicitados", "NotRequested": "No solicitado",
"Requested": "Solicitado", "Requested": "Solicitado",
"Request": "Solicitar", "Request": "Solicitar",
"Denied": "Denegado", "Denied": "Denegado",
"Approve": "Aprobar", "Approve": "Aprobar",
"PartlyAvailable": "Disponible en parte", "PartlyAvailable": "Disponible parcialmente",
"Errors": { "Errors": {
"Validation": "Por favor, comprueba los datos introducidos" "Validation": "Por favor, comprueba los datos introducidos"
} }
}, },
"PasswordReset": { "PasswordReset": {
"EmailAddressPlaceholder": "Correo electrónico", "EmailAddressPlaceholder": "Correo electrónico",
"ResetPasswordButton": "Restablecer Contraseña" "ResetPasswordButton": "Restablecer contraseña"
}, },
"LandingPage": { "LandingPage": {
"OnlineHeading": "En línea", "OnlineHeading": "En línea",
"OnlineParagraph": "El servidor de medios esta en línea", "OnlineParagraph": "El servidor de medios está en línea",
"PartiallyOnlineHeading": "Parcialmente en línea", "PartiallyOnlineHeading": "Parcialmente en línea",
"PartiallyOnlineParagraph": "El servidor de medios está parcialmente en línea.", "PartiallyOnlineParagraph": "El servidor de medios está parcialmente en línea.",
"MultipleServersUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.", "MultipleServersUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.",
"SingleServerUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.", "SingleServerUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.",
"OfflineHeading": "Fuera de línea", "OfflineHeading": "Fuera de línea",
"OfflineParagraph": "El servidor de medios está fuera de línea.", "OfflineParagraph": "El servidor de medios está fuera de línea.",
"CheckPageForUpdates": "Consulte esta página para ver las últimas novedades." "CheckPageForUpdates": "Consulta esta página para ver las últimas novedades."
}, },
"NavigationBar": { "NavigationBar": {
"Search": "Buscar", "Search": "Buscar",
"Requests": "Solicitudes", "Requests": "Solicitudes",
"UserManagement": "Gestión de usuarios", "UserManagement": "Gestión de usuarios",
"Issues": "Incidencias", "Issues": "Problemas",
"Vote": "Votar", "Vote": "Votar",
"Donate": "¡Donar!", "Donate": "¡Donar!",
"DonateLibraryMaintainer": "Donar al mantenedor de la biblioteca", "DonateLibraryMaintainer": "Donar al desarrollador de la biblioteca",
"DonateTooltip": "Así es como convenzo a mi esposa para que me deje pasar mi tiempo libre desarrollando ombi;)", "DonateTooltip": "Así es como convenzo a mi esposa para que me deje pasar mi tiempo libre desarrollando Ombi ;)",
"UpdateAvailableTooltip": "¡Actualización disponible!", "UpdateAvailableTooltip": "¡Actualización disponible!",
"Settings": "Ajustes", "Settings": "Ajustes",
"Welcome": "Bienvenido {{username}}", "Welcome": "Bienvenido {{username}}",
"UpdateDetails": "Editar cuenta usuario", "UpdateDetails": "Editar cuenta usuario",
"Logout": "Cerrar sesión", "Logout": "Cerrar sesión",
"OpenMobileApp": "Abrir aplicación móvil", "OpenMobileApp": "Abrir aplicación móvil",
"RecentlyAdded": "Agregado recientemente" "RecentlyAdded": "Añadido recientemente"
}, },
"Search": { "Search": {
"Title": "Buscar", "Title": "Buscar",
"Paragraph": "¿Quieres ver algo que no está disponible? No hay problema, búscalo y solicítalo!", "Paragraph": "¿Quieres ver algo que no está disponible? ¡No hay problema, búscalo y solicítalo!",
"MoviesTab": "Películas", "MoviesTab": "Películas",
"TvTab": "Series", "TvTab": "Series",
"MusicTab": "Música", "MusicTab": "Música",
"Suggestions": "Sugerencias", "Suggestions": "Sugerencias",
"NoResults": "¡Lo sentimos, no encontramos ningún resultado!", "NoResults": "¡Lo sentimos, no encontramos ningún resultado!",
"DigitalDate": "Versión Digital: {{date}}", "DigitalDate": "Versión digital: {{date}}",
"TheatricalRelease": "Estreno teatral: {{date}}", "TheatricalRelease": "En cines: {{date}}",
"ViewOnPlex": "Ver en Plex", "ViewOnPlex": "Ver en Plex",
"ViewOnEmby": "Ver en Emby", "ViewOnEmby": "Ver en Emby",
"RequestAdded": "La solicitud de {{title}} se ha agregado con éxito", "RequestAdded": "La solicitud de {{title}} se ha añadido correctamente",
"Similar": "Similar", "Similar": "Similar",
"Refine": "Filtros", "Refine": "Filtros",
"SearchBarPlaceholder": "Escribe aquí para buscar",
"Movies": { "Movies": {
"PopularMovies": "Películas populares", "PopularMovies": "Películas populares",
"UpcomingMovies": "Próximas películas", "UpcomingMovies": "Próximas películas",
@ -87,14 +88,14 @@
"Popular": "Popular", "Popular": "Popular",
"Trending": "Tendencias", "Trending": "Tendencias",
"MostWatched": "Más visto", "MostWatched": "Más visto",
"MostAnticipated": "Más Anticipado", "MostAnticipated": "Lo más esperado",
"Results": "Resultados", "Results": "Resultados",
"AirDate": "Fecha de emisión:", "AirDate": "Fecha de emisión:",
"AllSeasons": "Todas las temporadas", "AllSeasons": "Todas las temporadas",
"FirstSeason": "Primera temporada", "FirstSeason": "Primera temporada",
"LatestSeason": "Última temporada", "LatestSeason": "Última temporada",
"Select": "Seleccione...", "Select": "Selecciona...",
"SubmitRequest": "Enviar Solicitud", "SubmitRequest": "Enviar solicitud",
"Season": "Temporada: {{seasonNumber}}", "Season": "Temporada: {{seasonNumber}}",
"SelectAllInSeason": "Seleccionar todo en temporada {{seasonNumber}}" "SelectAllInSeason": "Seleccionar todo en temporada {{seasonNumber}}"
} }
@ -109,15 +110,15 @@
"Status": "Estado:", "Status": "Estado:",
"RequestStatus": "Estado de la solicitud:", "RequestStatus": "Estado de la solicitud:",
"Denied": " Denegado:", "Denied": " Denegado:",
"TheatricalRelease": "Estreno teatral: {{date}}", "TheatricalRelease": "En cines: {{date}}",
"ReleaseDate": "Lanzado el {{date}}", "ReleaseDate": "Publicado: {{date}}",
"TheatricalReleaseSort": "Estreno teatral", "TheatricalReleaseSort": "En cines",
"DigitalRelease": "Presentación Digital: {{date}}", "DigitalRelease": "Versión digital: {{date}}",
"RequestDate": "Fecha de solicitud:", "RequestDate": "Fecha de solicitud:",
"QualityOverride": "Sobreescribir calidad:", "QualityOverride": "Sobreescribir calidad:",
"RootFolderOverride": "Sobreescribir carpeta raíz:", "RootFolderOverride": "Sobreescribir carpeta raíz:",
"ChangeRootFolder": "Cambiar Carpeta Raíz", "ChangeRootFolder": "Carpeta raíz",
"ChangeQualityProfile": "Cambiar Perfil de Calidad", "ChangeQualityProfile": "Perfil de calidad",
"MarkUnavailable": "Marcar como no disponible", "MarkUnavailable": "Marcar como no disponible",
"MarkAvailable": "Marcar como disponible", "MarkAvailable": "Marcar como disponible",
"Remove": "Eliminar", "Remove": "Eliminar",
@ -126,7 +127,7 @@
"GridTitle": "Título", "GridTitle": "Título",
"AirDate": "Fecha de estreno", "AirDate": "Fecha de estreno",
"GridStatus": "Estado", "GridStatus": "Estado",
"ReportIssue": "Informar de Problema", "ReportIssue": "Reportar problema",
"Filter": "Filtrar", "Filter": "Filtrar",
"Sort": "Ordenar", "Sort": "Ordenar",
"SeasonNumberHeading": "Temporada: {seasonNumber}", "SeasonNumberHeading": "Temporada: {seasonNumber}",
@ -138,48 +139,48 @@
"SortStatusDesc": "Estado ▼", "SortStatusDesc": "Estado ▼",
"Remaining": { "Remaining": {
"Quota": "{{remaining}}/{{total}} solicitudes restantes", "Quota": "{{remaining}}/{{total}} solicitudes restantes",
"NextDays": "Se añadirá otra solicitud en {{time}} Días", "NextDays": "Se añadirá otra solicitud en {{time}} días",
"NextHours": "Se añadirá otra solicitud en {{time}} Horas", "NextHours": "Se añadirá otra solicitud en {{time}} horas",
"NextMinutes": "Se añadirá otra solicitud en {{time}} Minutos", "NextMinutes": "Se añadirá otra solicitud en {{time}} minutos",
"NextMinute": "Se añadirá otra solicitud en {{time}} Minuto" "NextMinute": "Se añadirá otra solicitud en {{time}} minuto"
} }
}, },
"Issues": { "Issues": {
"Title": "Incidencias", "Title": "Problemas",
"PendingTitle": "Incidencias pendientes", "PendingTitle": "Problemas pendientes",
"InProgressTitle": "Incidencias en progreso", "InProgressTitle": "Problemas en curso",
"ResolvedTitle": "Incidencias resueltas", "ResolvedTitle": "Problemas resueltos",
"ColumnTitle": "Título", "ColumnTitle": "Título",
"Category": "Categoría", "Category": "Categoría",
"Status": "Estado", "Status": "Estado",
"Details": "Detalles", "Details": "Detalles",
"Description": "Descripción", "Description": "Descripción",
"NoComments": "¡Sin comentarios!", "NoComments": "¡Sin comentarios!",
"MarkInProgress": "Marcar En Proceso", "MarkInProgress": "Marcar en progreso",
"MarkResolved": "Marcar resuelto", "MarkResolved": "Marcar como resuelto",
"SendMessageButton": "Enviar", "SendMessageButton": "Enviar",
"Subject": "Asunto", "Subject": "Asunto",
"Comments": "Comentarios", "Comments": "Comentarios",
"WriteMessagePlaceholder": "Escribe tu mensaje aquí...", "WriteMessagePlaceholder": "Escribe tu mensaje aquí...",
"ReportedBy": "Informado por" "ReportedBy": "Reportado por"
}, },
"Filter": { "Filter": {
"ClearFilter": "Eliminar Filtro", "ClearFilter": "Reiniciar filtro",
"FilterHeaderAvailability": "Disponibilidad", "FilterHeaderAvailability": "Disponibilidad",
"FilterHeaderRequestStatus": "Estado", "FilterHeaderRequestStatus": "Estado",
"Approved": "¡Aprobado!", "Approved": "Aprobado",
"PendingApproval": "Aprobación Pendiente" "PendingApproval": "Pendiente de aprobación"
}, },
"UserManagment": { "UserManagment": {
"TvRemaining": "Música: {{remaining}}/{{total}} Restante", "TvRemaining": "TV: {{remaining}}/{{total}} restantes",
"MovieRemaining": "Música: {{remaining}}/{{total}} Restante", "MovieRemaining": "Películas: {{remaining}}/{{total}} restantes",
"MusicRemaining": "Música: {{remaining}}/{{total}} Restante", "MusicRemaining": "Música: {{remaining}}/{{total}} restantes",
"TvDue": "TV: {{date}}", "TvDue": "TV: {{date}}",
"MovieDue": "Película: {{date}}", "MovieDue": "Película: {{date}}",
"MusicDue": "Música: {{date}}" "MusicDue": "Música: {{date}}"
}, },
"Votes": { "Votes": {
"CompletedVotesTab": "¡Votado!", "CompletedVotesTab": "Votado",
"VotesTab": "Votos necesarios" "VotesTab": "Votos necesarios"
} }
} }

View file

@ -75,6 +75,7 @@
"RequestAdded": "La demande pour {{title}} a été ajoutée avec succès", "RequestAdded": "La demande pour {{title}} a été ajoutée avec succès",
"Similar": "Similaires", "Similar": "Similaires",
"Refine": "Affiner", "Refine": "Affiner",
"SearchBarPlaceholder": "Tapez ici pour rechercher",
"Movies": { "Movies": {
"PopularMovies": "Films populaires", "PopularMovies": "Films populaires",
"UpcomingMovies": "Films à venir", "UpcomingMovies": "Films à venir",

View file

@ -0,0 +1,186 @@
{
"Login": {
"SignInButton": "Bejelentkezés",
"UsernamePlaceholder": "Felhasználónév",
"PasswordPlaceholder": "Jelszó",
"RememberMe": "Emlékezz rám",
"ForgottenPassword": "Elfelejtetted a jelszavad?",
"Errors": {
"IncorrectCredentials": "Helytelen felhasználónév vagy jelszó"
}
},
"Common": {
"ContinueButton": "Tovább",
"Available": "Elérhető",
"PartiallyAvailable": "Részlegesen elérhető",
"Monitored": "Figyelve",
"NotAvailable": "Nem elérhető",
"ProcessingRequest": "Kérés feldolgozása",
"PendingApproval": "Jóváhagyásra vár",
"RequestDenied": "Kérés megtagadva",
"NotRequested": "Nincs kérve",
"Requested": "Kérve",
"Request": "Kérés",
"Denied": "Megtagadva",
"Approve": "Jóváhagyva",
"PartlyAvailable": "Részlegesen elérhető",
"Errors": {
"Validation": "Kérjük, ellenőrizze a beírt értékeket"
}
},
"PasswordReset": {
"EmailAddressPlaceholder": "E-mail cím",
"ResetPasswordButton": "Jelszó visszaállítása"
},
"LandingPage": {
"OnlineHeading": "Jelenleg elérhető",
"OnlineParagraph": "A médiaszerver jelenleg elérhető",
"PartiallyOnlineHeading": "Részben elérhető",
"PartiallyOnlineParagraph": "A médiaszerver részben elérhető.",
"MultipleServersUnavailable": "{{serversUnavailable}} szerver nem érhető el ennyiből: {{totalServers}}.",
"SingleServerUnavailable": "{{serversUnavailable}} szerver nem érhető el ennyiből: {{totalServers}}.",
"OfflineHeading": "Jelenleg nem elérhető",
"OfflineParagraph": "A médiaszerver jelenleg nem elérhető.",
"CheckPageForUpdates": "Látogasd meg ezt az oldalt a frissítésekhez."
},
"NavigationBar": {
"Search": "Keresés",
"Requests": "Kérések",
"UserManagement": "Felhasználók kezelése",
"Issues": "Problémák",
"Vote": "Szavazás",
"Donate": "Adakozás!",
"DonateLibraryMaintainer": "Adakozz a könyvtár fenntartónak",
"DonateTooltip": "Ezzel győzöm meg a feleségem, hogy a szabadidőmben fejleszthessem az Ombi-t ;)",
"UpdateAvailableTooltip": "Frissítés elérhető!",
"Settings": "Beállítások",
"Welcome": "Üdv {{username}}",
"UpdateDetails": "Fiók beállításai",
"Logout": "Kilépés",
"OpenMobileApp": "Mobil app megnyitása",
"RecentlyAdded": "Nemrég hozzáadott"
},
"Search": {
"Title": "Keresés",
"Paragraph": "Szeretnél nézni valamit ami jelenleg nem elérhető? Semmi gond, csak keress rá lentebb és kérd!",
"MoviesTab": "Filmek",
"TvTab": "Sorozatok",
"MusicTab": "Zene",
"Suggestions": "Javaslatok",
"NoResults": "Sajnáljuk, nem találtunk semmit!",
"DigitalDate": "Digitális kiadás: {{date}}",
"TheatricalRelease": "Mozis kiadás: {{date}}",
"ViewOnPlex": "Megnézés Plexen",
"ViewOnEmby": "Megnézés Emby-n",
"RequestAdded": "Kérés sikeresen leadva erre: {{title}}",
"Similar": "Hasonló",
"Refine": "Finomítás",
"SearchBarPlaceholder": "Type Here to Search",
"Movies": {
"PopularMovies": "Népszerű filmek",
"UpcomingMovies": "Közelgő filmek",
"TopRatedMovies": "Legjobbra értékelt filmek",
"NowPlayingMovies": "Most játszott filmek",
"HomePage": "Főoldal",
"Trailer": "Előzetes"
},
"TvShows": {
"Popular": "Népszerű",
"Trending": "Felkapott",
"MostWatched": "Legnézettebb",
"MostAnticipated": "Leginkább várt",
"Results": "Eredmények",
"AirDate": "Bemutató:",
"AllSeasons": "Összes Évad",
"FirstSeason": "Első évad",
"LatestSeason": "Utolsó évad",
"Select": "Kiválasztás...",
"SubmitRequest": "Kérés küldése",
"Season": "Évad: {{seasonNumber}}",
"SelectAllInSeason": "Egész {{seasonNumber}}. évad kiválasztása"
}
},
"Requests": {
"Title": "Kérések",
"Paragraph": "Lentebb láthatod a saját és egyéb kéréseket, valamint a letöltési és jóváhagyási állapotukat.",
"MoviesTab": "Filmek",
"TvTab": "Sorozatok",
"MusicTab": "Zene",
"RequestedBy": "Kérte:",
"Status": "Állapot:",
"RequestStatus": "Kérés állapota:",
"Denied": " Megtagadta:",
"TheatricalRelease": "Mozis kiadás: {{date}}",
"ReleaseDate": "Kiadva: {{date}}",
"TheatricalReleaseSort": "Mozis kiadás",
"DigitalRelease": "Digitális kiadás: {{date}}",
"RequestDate": "Kérés ideje:",
"QualityOverride": "Minőség felülírása:",
"RootFolderOverride": "Gyökér mappa felülírása:",
"ChangeRootFolder": "Gyökér mappa",
"ChangeQualityProfile": "Minőség profil",
"MarkUnavailable": "Megjelölés nem elérhetőnek",
"MarkAvailable": "Megjelölés elérhetőnek",
"Remove": "Törlés",
"Deny": "Elutasítás",
"Season": "Évad:",
"GridTitle": "Cím",
"AirDate": "Bemutató",
"GridStatus": "Állapot",
"ReportIssue": "Probléma jelentése",
"Filter": "Szűrő",
"Sort": "Rendezés",
"SeasonNumberHeading": "Évad: {seasonNumber}",
"SortTitleAsc": "Cím ▲",
"SortTitleDesc": "Cím ▼",
"SortRequestDateAsc": "Kérés ideje ▲",
"SortRequestDateDesc": "Kérés ideje ▼",
"SortStatusAsc": "Állapot ▲",
"SortStatusDesc": "Állapot ▼",
"Remaining": {
"Quota": "{{remaining}}/{{total}} kérés van még",
"NextDays": "Újabb kérés lesz hozzáadva {{time}} nap múlva",
"NextHours": "Újabb kérés lesz hozzáadva {{time}} óra múlva",
"NextMinutes": "Újabb kérés lesz hozzáadva {{time}} perc múlva",
"NextMinute": "Újabb kérés lesz hozzáadva {{time}} perc múlva"
}
},
"Issues": {
"Title": "Problémák",
"PendingTitle": "Várakozó problémák",
"InProgressTitle": "Folyamatban lévő problémák",
"ResolvedTitle": "Megoldott problémák",
"ColumnTitle": "Cím",
"Category": "Kategória",
"Status": "Állapot",
"Details": "Részletek",
"Description": "Leírás",
"NoComments": "Nincs megjegyzés!",
"MarkInProgress": "Folyamatban lévőre jelölés",
"MarkResolved": "Megjelölés megoldottként",
"SendMessageButton": "Küldés",
"Subject": "Tárgy",
"Comments": "Hozzászólások",
"WriteMessagePlaceholder": "Írd ide az üzeneted...",
"ReportedBy": "Jelentette"
},
"Filter": {
"ClearFilter": "Szűrő törlése",
"FilterHeaderAvailability": "Elérhetőség",
"FilterHeaderRequestStatus": "Állapot",
"Approved": "Jóváhagyva",
"PendingApproval": "Jóváhagyásra vár"
},
"UserManagment": {
"TvRemaining": "TV: {{remaining}}/{{total}} maradt",
"MovieRemaining": "Filmek: {{remaining}}/{{total}} maradt",
"MusicRemaining": "Zene: {{remaining}}/{{total}} maradt",
"TvDue": "TV: {{date}}",
"MovieDue": "Film: {{date}}",
"MusicDue": "Zene: {{date}}"
},
"Votes": {
"CompletedVotesTab": "Szavazott",
"VotesTab": "Szavazat szükséges"
}
}

View file

@ -75,6 +75,7 @@
"RequestAdded": "La richiesta per {{title}} è stata aggiunta correttamente", "RequestAdded": "La richiesta per {{title}} è stata aggiunta correttamente",
"Similar": "Similar", "Similar": "Similar",
"Refine": "Refine", "Refine": "Refine",
"SearchBarPlaceholder": "Type Here to Search",
"Movies": { "Movies": {
"PopularMovies": "Film popolari", "PopularMovies": "Film popolari",
"UpcomingMovies": "Film in arrivo", "UpcomingMovies": "Film in arrivo",

View file

@ -13,15 +13,15 @@
"ContinueButton": "Doorgaan", "ContinueButton": "Doorgaan",
"Available": "Beschikbaar", "Available": "Beschikbaar",
"PartiallyAvailable": "Deels Beschikbaar", "PartiallyAvailable": "Deels Beschikbaar",
"Monitored": "Onder toezicht", "Monitored": "Gemonitord",
"NotAvailable": "Niet Beschikbaar", "NotAvailable": "Niet Beschikbaar",
"ProcessingRequest": "Verzoek wordt verwerkt", "ProcessingRequest": "Verzoek wordt verwerkt",
"PendingApproval": "Wacht op goedkeuring", "PendingApproval": "Wacht op goedkeuring",
"RequestDenied": "Verzoek geweigerd", "RequestDenied": "Verzoek geweigerd",
"NotRequested": "Niet verzocht", "NotRequested": "Niet verzocht",
"Requested": "Verzocht", "Requested": "Aangevraagd",
"Request": "Verzoek", "Request": "Aanvragen",
"Denied": "Geweigerd", "Denied": "Afgewezen",
"Approve": "Accepteer", "Approve": "Accepteer",
"PartlyAvailable": "Deels Beschikbaar", "PartlyAvailable": "Deels Beschikbaar",
"Errors": { "Errors": {
@ -37,27 +37,27 @@
"OnlineParagraph": "De mediaserver is momenteel online", "OnlineParagraph": "De mediaserver is momenteel online",
"PartiallyOnlineHeading": "Gedeeltelijk Online", "PartiallyOnlineHeading": "Gedeeltelijk Online",
"PartiallyOnlineParagraph": "De mediaserver is gedeeltelijk online.", "PartiallyOnlineParagraph": "De mediaserver is gedeeltelijk online.",
"MultipleServersUnavailable": "Er zijn {{serversUnavailable}} servers offline van de in totaal {{totalServers}}.", "MultipleServersUnavailable": "Er zijn {{serversUnavailable}} van de {{totalServers}} servers offline.",
"SingleServerUnavailable": "Er is {{serversUnavailable}} server offline uit {{totalServers}}.", "SingleServerUnavailable": "Er is {{serversUnavailable}} van de {{totalServers}} server offline.",
"OfflineHeading": "Op dit moment Offline", "OfflineHeading": "Momenteel Offline",
"OfflineParagraph": "De mediaserver is momenteel offline.", "OfflineParagraph": "De mediaserver is momenteel offline.",
"CheckPageForUpdates": "Controleer deze pagina voor updates." "CheckPageForUpdates": "Controleer deze pagina voor updates."
}, },
"NavigationBar": { "NavigationBar": {
"Search": "Zoeken", "Search": "Zoeken",
"Requests": "Verzoeklijst", "Requests": "Verzoeken",
"UserManagement": "Gebruikersbeheer", "UserManagement": "Gebruikersmanagement",
"Issues": "Problemen", "Issues": "Problemen",
"Vote": "Stem", "Vote": "Stem",
"Donate": "Doneer!", "Donate": "Doneer!",
"DonateLibraryMaintainer": "Doneren aan bibliotheek beheerder", "DonateLibraryMaintainer": "Doneren aan Ombi beheerder",
"DonateTooltip": "Zo heb ik mijn vrouw overtuigd dat ik Ombi mag ontwikkelen ;)", "DonateTooltip": "Zo heb ik mijn vrouw overtuigd dat ik Ombi mag ontwikkelen ;)",
"UpdateAvailableTooltip": "Update beschikbaar!", "UpdateAvailableTooltip": "Update beschikbaar!",
"Settings": "Instellingen", "Settings": "Instellingen",
"Welcome": "Welkom {{username}}", "Welcome": "Welkom {{username}}",
"UpdateDetails": "Update gegevens", "UpdateDetails": "Gegevens updaten",
"Logout": "Afmelden", "Logout": "Afmelden",
"OpenMobileApp": "Open Mobiele App", "OpenMobileApp": "Mobiele App Openen",
"RecentlyAdded": "Onlangs Toegevoegd" "RecentlyAdded": "Onlangs Toegevoegd"
}, },
"Search": { "Search": {
@ -67,7 +67,7 @@
"TvTab": "TV Series", "TvTab": "TV Series",
"MusicTab": "Muziek", "MusicTab": "Muziek",
"Suggestions": "Suggesties", "Suggestions": "Suggesties",
"NoResults": "Sorry, we hebben geen resultaten gevonden!", "NoResults": "Sorry, er zijn geen resultaten gevonden!",
"DigitalDate": "Digitale Uitgave: {{date}}", "DigitalDate": "Digitale Uitgave: {{date}}",
"TheatricalRelease": "Bioscoop Uitgave: {{date}}", "TheatricalRelease": "Bioscoop Uitgave: {{date}}",
"ViewOnPlex": "Bekijk op Plex", "ViewOnPlex": "Bekijk op Plex",
@ -75,11 +75,12 @@
"RequestAdded": "Aanvraag voor {{title}} is succesvol toegevoegd", "RequestAdded": "Aanvraag voor {{title}} is succesvol toegevoegd",
"Similar": "Vergelijkbaar", "Similar": "Vergelijkbaar",
"Refine": "Verfijn", "Refine": "Verfijn",
"SearchBarPlaceholder": "Voer zoekterm in",
"Movies": { "Movies": {
"PopularMovies": "Populaire films", "PopularMovies": "Populaire films",
"UpcomingMovies": "Aankomende Films", "UpcomingMovies": "Aankomende Films",
"TopRatedMovies": "Best Beoordeelde Films", "TopRatedMovies": "Best Beoordeelde Films",
"NowPlayingMovies": "In Cinema Films", "NowPlayingMovies": "Nu in de bioscoop",
"HomePage": "Startpagina", "HomePage": "Startpagina",
"Trailer": "Trailer" "Trailer": "Trailer"
}, },

View file

@ -75,6 +75,7 @@
"RequestAdded": "Forespørsel om {{title}} er lagt til", "RequestAdded": "Forespørsel om {{title}} er lagt til",
"Similar": "Lignende", "Similar": "Lignende",
"Refine": "Refine", "Refine": "Refine",
"SearchBarPlaceholder": "Type Here to Search",
"Movies": { "Movies": {
"PopularMovies": "Populære filmer", "PopularMovies": "Populære filmer",
"UpcomingMovies": "Kommende filmer", "UpcomingMovies": "Kommende filmer",

View file

@ -10,7 +10,7 @@
} }
}, },
"Common": { "Common": {
"ContinueButton": "Dalej", "ContinueButton": "Kontynuuj",
"Available": "Dostępne", "Available": "Dostępne",
"PartiallyAvailable": "Częściowo dostępne", "PartiallyAvailable": "Częściowo dostępne",
"Monitored": "Monitorowane", "Monitored": "Monitorowane",
@ -25,7 +25,7 @@
"Approve": "Zatwierdź", "Approve": "Zatwierdź",
"PartlyAvailable": "Częściowo dostępne", "PartlyAvailable": "Częściowo dostępne",
"Errors": { "Errors": {
"Validation": "Sprawdź wprowadzone dane" "Validation": "Proszę sprawdzić wprowadzone wartości"
} }
}, },
"PasswordReset": { "PasswordReset": {
@ -33,11 +33,11 @@
"ResetPasswordButton": "Zresetuj hasło" "ResetPasswordButton": "Zresetuj hasło"
}, },
"LandingPage": { "LandingPage": {
"OnlineHeading": "Dostępny", "OnlineHeading": "Aktualnie online",
"OnlineParagraph": "Serwer multimediów jest aktualnie online", "OnlineParagraph": "Serwer multimediów jest aktualnie online",
"PartiallyOnlineHeading": "Częściowo online", "PartiallyOnlineHeading": "Częściowo online",
"PartiallyOnlineParagraph": "Serwer multimediów jest częściowo online.", "PartiallyOnlineParagraph": "Serwer multimediów jest częściowo online.",
"MultipleServersUnavailable": "{{serversUnavailable}} serwerów spośród {{totalServers}} jest offline.", "MultipleServersUnavailable": "{{serversUnavailable}} serwery(ów) spośród {{totalServers}} jest offline.",
"SingleServerUnavailable": "{{serversUnavailable}} serwer z {{totalServers}} jest w offline.", "SingleServerUnavailable": "{{serversUnavailable}} serwer z {{totalServers}} jest w offline.",
"OfflineHeading": "Aktualnie offline", "OfflineHeading": "Aktualnie offline",
"OfflineParagraph": "Serwer multimediów jest aktualnie offline.", "OfflineParagraph": "Serwer multimediów jest aktualnie offline.",
@ -51,7 +51,7 @@
"Vote": "Głosowania", "Vote": "Głosowania",
"Donate": "Wesprzyj!", "Donate": "Wesprzyj!",
"DonateLibraryMaintainer": "Wesprzyj właściciela biblioteki", "DonateLibraryMaintainer": "Wesprzyj właściciela biblioteki",
"DonateTooltip": "W ten sposób przekonuję moją żonę by spędzać mój wolny czas rozwijając Ombi ;)", "DonateTooltip": "Tak przekonuję moją żonę, aby pozwalała mi w wolnym czasie rozwijać Ombi ;)",
"UpdateAvailableTooltip": "Dostępna aktualizacja!", "UpdateAvailableTooltip": "Dostępna aktualizacja!",
"Settings": "Ustawienia", "Settings": "Ustawienia",
"Welcome": "Witaj {{username}}", "Welcome": "Witaj {{username}}",
@ -64,20 +64,21 @@
"Title": "Szukaj", "Title": "Szukaj",
"Paragraph": "Chcesz obejrzeć coś, co nie jest obecnie dostępne? Żaden problem, po prostu wyszukaj poniżej i dodaj zgłoszenie!", "Paragraph": "Chcesz obejrzeć coś, co nie jest obecnie dostępne? Żaden problem, po prostu wyszukaj poniżej i dodaj zgłoszenie!",
"MoviesTab": "Filmy", "MoviesTab": "Filmy",
"TvTab": "Programy TV", "TvTab": "Seriale",
"MusicTab": "Muzyka", "MusicTab": "Muzyka",
"Suggestions": "Sugestie", "Suggestions": "Sugestie",
"NoResults": "Niestety nic nie znaleziono!", "NoResults": "Niestety nic nie znaleziono!",
"DigitalDate": "Wydanie cyfrowe: {{date}}", "DigitalDate": "Wydanie cyfrowe: {{date}}",
"TheatricalRelease": "Premiera kinowa: {{date}}", "TheatricalRelease": "Premiera kinowa: {{date}}",
"ViewOnPlex": "Obejrzyj w Plex", "ViewOnPlex": "Obejrzyj w Plex",
"ViewOnEmby": "Obejrzyj na Emby", "ViewOnEmby": "Obejrzyj w Emby",
"RequestAdded": "Zgłoszenie dla {{title}} zostało dodane", "RequestAdded": "Zgłoszenie dla {{title}} zostało pomyślnie dodane",
"Similar": "Podobne", "Similar": "Podobne",
"Refine": "Zawęź", "Refine": "Zawęź",
"SearchBarPlaceholder": "Wpisz tutaj, aby wyszukać",
"Movies": { "Movies": {
"PopularMovies": "Popularne filmy", "PopularMovies": "Popularne filmy",
"UpcomingMovies": "Wkrótce w kinach", "UpcomingMovies": "Nadchodzące filmy",
"TopRatedMovies": "Najwyżej oceniane filmy", "TopRatedMovies": "Najwyżej oceniane filmy",
"NowPlayingMovies": "W kinach", "NowPlayingMovies": "W kinach",
"HomePage": "Strona główna", "HomePage": "Strona główna",
@ -101,9 +102,9 @@
}, },
"Requests": { "Requests": {
"Title": "Zgłoszenia", "Title": "Zgłoszenia",
"Paragraph": "Poniżej są twoje i wszystkie inne zgłoszenia, a także ich status akceptacji i pobierania.", "Paragraph": "Poniżej znajdują się Twoje i wszystkie inne zgłoszenia, a także ich status akceptacji i pobierania.",
"MoviesTab": "Filmy", "MoviesTab": "Filmy",
"TvTab": "Programy TV", "TvTab": "Seriale",
"MusicTab": "Muzyka", "MusicTab": "Muzyka",
"RequestedBy": "Zgłoszone przez:", "RequestedBy": "Zgłoszone przez:",
"Status": "Status:", "Status": "Status:",
@ -117,7 +118,7 @@
"QualityOverride": "Wymuszenie jakości:", "QualityOverride": "Wymuszenie jakości:",
"RootFolderOverride": "Wymuszenie folderu głównego:", "RootFolderOverride": "Wymuszenie folderu głównego:",
"ChangeRootFolder": "Folder główny", "ChangeRootFolder": "Folder główny",
"ChangeQualityProfile": "Wybór jakości", "ChangeQualityProfile": "Profil jakości",
"MarkUnavailable": "Oznacz jako niedostępne", "MarkUnavailable": "Oznacz jako niedostępne",
"MarkAvailable": "Oznacz jako dostępne", "MarkAvailable": "Oznacz jako dostępne",
"Remove": "Usuń", "Remove": "Usuń",
@ -128,7 +129,7 @@
"GridStatus": "Status", "GridStatus": "Status",
"ReportIssue": "Zgłoś problem", "ReportIssue": "Zgłoś problem",
"Filter": "Filtr", "Filter": "Filtr",
"Sort": "Sortowanie", "Sort": "Sortuj",
"SeasonNumberHeading": "Sezon: {seasonNumber}", "SeasonNumberHeading": "Sezon: {seasonNumber}",
"SortTitleAsc": "Tytuł ▲", "SortTitleAsc": "Tytuł ▲",
"SortTitleDesc": "Tytuł ▼", "SortTitleDesc": "Tytuł ▼",
@ -151,7 +152,7 @@
"ResolvedTitle": "Problemy rozwiązane", "ResolvedTitle": "Problemy rozwiązane",
"ColumnTitle": "Tytuł", "ColumnTitle": "Tytuł",
"Category": "Kategoria", "Category": "Kategoria",
"Status": "Stan", "Status": "Status",
"Details": "Szczegóły", "Details": "Szczegóły",
"Description": "Opis", "Description": "Opis",
"NoComments": "Brak komentarzy!", "NoComments": "Brak komentarzy!",
@ -164,17 +165,17 @@
"ReportedBy": "Zgłoszone przez" "ReportedBy": "Zgłoszone przez"
}, },
"Filter": { "Filter": {
"ClearFilter": "Wyczyść fltr", "ClearFilter": "Wyczyść filtr",
"FilterHeaderAvailability": "Dostępność", "FilterHeaderAvailability": "Dostępność",
"FilterHeaderRequestStatus": "Status", "FilterHeaderRequestStatus": "Status",
"Approved": "Zatwierdzone", "Approved": "Zatwierdzone",
"PendingApproval": "Oczekujące na zatwierdzenie" "PendingApproval": "Oczekujące na zatwierdzenie"
}, },
"UserManagment": { "UserManagment": {
"TvRemaining": "TV: pozostało {{remaining}}/{{total}}", "TvRemaining": "Seriale: pozostało {{remaining}}/{{total}}",
"MovieRemaining": "Filmy: pozostało {{remaining}}/{{total}}", "MovieRemaining": "Filmy: pozostało {{remaining}}/{{total}}",
"MusicRemaining": "Muzyka: pozostało {{remaining}}/{{total}}", "MusicRemaining": "Muzyka: pozostało {{remaining}}/{{total}}",
"TvDue": "TV: {{date}}", "TvDue": "Serial: {{date}}",
"MovieDue": "Film: {{date}}", "MovieDue": "Film: {{date}}",
"MusicDue": "Muzyka: {{date}}" "MusicDue": "Muzyka: {{date}}"
}, },

View file

@ -1,12 +1,12 @@
{ {
"Login": { "Login": {
"SignInButton": "Registrar", "SignInButton": "Iniciar sessão",
"UsernamePlaceholder": "Nome de usuário", "UsernamePlaceholder": "Nome de usuário",
"PasswordPlaceholder": "Senha", "PasswordPlaceholder": "Palavra-passe",
"RememberMe": "Lembre-se de mim", "RememberMe": "Guardar a minha autênticação",
"ForgottenPassword": "Esqueceu sua senha?", "ForgottenPassword": "Esqueceu-se da sua palavra-passe?",
"Errors": { "Errors": {
"IncorrectCredentials": "Nome de usuário ou senha incorretos" "IncorrectCredentials": "Nome de usuário ou palavra-passe incorretos"
} }
}, },
"Common": { "Common": {
@ -14,13 +14,13 @@
"Available": "Disponível", "Available": "Disponível",
"PartiallyAvailable": "Parcialmente Disponível", "PartiallyAvailable": "Parcialmente Disponível",
"Monitored": "Monitorado", "Monitored": "Monitorado",
"NotAvailable": "Inisponível", "NotAvailable": "Não Disponível",
"ProcessingRequest": "Processando Solicitação", "ProcessingRequest": "A processar o pedido",
"PendingApproval": "Aprovação Pendente", "PendingApproval": "Aprovação Pendente",
"RequestDenied": "Solicitação Negada", "RequestDenied": "Pedido negado",
"NotRequested": "Não Solicitado", "NotRequested": "Não pedido",
"Requested": "Solicitado", "Requested": "Pedido",
"Request": "Solicitar", "Request": "Pedir",
"Denied": "Negado", "Denied": "Negado",
"Approve": "Aprovar", "Approve": "Aprovar",
"PartlyAvailable": "Parcialmente Disponível", "PartlyAvailable": "Parcialmente Disponível",
@ -30,34 +30,34 @@
}, },
"PasswordReset": { "PasswordReset": {
"EmailAddressPlaceholder": "Endereço de e-mail", "EmailAddressPlaceholder": "Endereço de e-mail",
"ResetPasswordButton": "Redefinir Senha" "ResetPasswordButton": "Redefinir palavra-passe"
}, },
"LandingPage": { "LandingPage": {
"OnlineHeading": "Online Agora", "OnlineHeading": "Online Agora",
"OnlineParagraph": "O servidor de mídia está atualmente online", "OnlineParagraph": "O servidor de media está actualmente online",
"PartiallyOnlineHeading": "Parcialmente Online", "PartiallyOnlineHeading": "Parcialmente Online",
"PartiallyOnlineParagraph": "O servidor de mídia está parcialmente online.", "PartiallyOnlineParagraph": "O servidor de media está parcialmente online.",
"MultipleServersUnavailable": "Existem {{serversUnavailable}} servidores offline em um total de {{totalServers}}.", "MultipleServersUnavailable": "Existem {{serversUnavailable}} servidores offline de um total de {{totalServers}}.",
"SingleServerUnavailable": "Existe {{serversUnavailable}} servidor offline em um total de {{totalServers}}.", "SingleServerUnavailable": "Existe {{serversUnavailable}} servidor offline de um total de {{totalServers}}.",
"OfflineHeading": "Offline Agora", "OfflineHeading": "Actualmente Offline",
"OfflineParagraph": "O servidor de mídia está atualmente offline.", "OfflineParagraph": "O servidor de media está actualmente offline.",
"CheckPageForUpdates": "Verifique esta página para atualizações contínuas do site." "CheckPageForUpdates": "Verifique esta página para acompanhar as atualizações do site."
}, },
"NavigationBar": { "NavigationBar": {
"Search": "Pesquisar", "Search": "Pesquisar",
"Requests": "Solicitações", "Requests": "Pedidos",
"UserManagement": "Gerenciador de Usuário", "UserManagement": "Gestor de utilizadores",
"Issues": "Problemas", "Issues": "Incidentes",
"Vote": "Votar", "Vote": "Votar",
"Donate": "Fazer uma doação!", "Donate": "Fazer uma doação!",
"DonateLibraryMaintainer": "Doar para o Dono da Biblioteca", "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;)", "DonateTooltip": "É assim que eu convenço a minha mulher a deixar-me passar o meu tempo livre a desenvolver o Ombi ;)",
"UpdateAvailableTooltip": "Atualização Disponível!", "UpdateAvailableTooltip": "Atualização Disponível!",
"Settings": "Configurações", "Settings": "Configurações",
"Welcome": "Bem-vindo, {{username}}", "Welcome": "Bem-vindo, {{username}}",
"UpdateDetails": "Detalhes da Atualização", "UpdateDetails": "Detalhes da Actualização",
"Logout": "Sair", "Logout": "Sair",
"OpenMobileApp": "Abrir aplicativo do celular", "OpenMobileApp": "Abrir app móvel",
"RecentlyAdded": "Recentemente adicionado" "RecentlyAdded": "Recentemente adicionado"
}, },
"Search": { "Search": {
@ -75,6 +75,7 @@
"RequestAdded": "Pedido de {{title}} foi adicionado com sucesso", "RequestAdded": "Pedido de {{title}} foi adicionado com sucesso",
"Similar": "Semelhante", "Similar": "Semelhante",
"Refine": "Filtro", "Refine": "Filtro",
"SearchBarPlaceholder": "Digite aqui para pesquisar",
"Movies": { "Movies": {
"PopularMovies": "Filmes populares", "PopularMovies": "Filmes populares",
"UpcomingMovies": "Próximos filmes", "UpcomingMovies": "Próximos filmes",

View file

@ -0,0 +1,186 @@
{
"Login": {
"SignInButton": "Войти",
"UsernamePlaceholder": "Имя пользователя",
"PasswordPlaceholder": "Пароль",
"RememberMe": "Запомнить Меня",
"ForgottenPassword": "Забыли пароль?",
"Errors": {
"IncorrectCredentials": "Неверное имя пользователя или пароль"
}
},
"Common": {
"ContinueButton": "Продолжить",
"Available": "Доступно",
"PartiallyAvailable": "Частично доступно",
"Monitored": "Мониторинг",
"NotAvailable": "Недоступно",
"ProcessingRequest": "Обработка запроса",
"PendingApproval": "Ожидание утверждения",
"RequestDenied": "Запрос отклонен",
"NotRequested": "Не запрошено",
"Requested": "Запрос отправлен",
"Request": "Запрос",
"Denied": "Запрещено",
"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",
"Vote": "Vote",
"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",
"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",
"MusicTab": "Music",
"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",
"Refine": "Refine",
"SearchBarPlaceholder": "Type Here to Search",
"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",
"MusicTab": "Music",
"RequestedBy": "Requested By:",
"Status": "Status:",
"RequestStatus": "Request status:",
"Denied": " Denied:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"ReleaseDate": "Released: {{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 ▼",
"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"
}
},
"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"
},
"UserManagment": {
"TvRemaining": "TV: {{remaining}}/{{total}} remaining",
"MovieRemaining": "Movies: {{remaining}}/{{total}} remaining",
"MusicRemaining": "Music: {{remaining}}/{{total}} remaining",
"TvDue": "TV: {{date}}",
"MovieDue": "Movie: {{date}}",
"MusicDue": "Music: {{date}}"
},
"Votes": {
"CompletedVotesTab": "Voted",
"VotesTab": "Votes Needed"
}
}

View file

@ -75,6 +75,7 @@
"RequestAdded": "Begäran av {{title}} har lagts till", "RequestAdded": "Begäran av {{title}} har lagts till",
"Similar": "Liknande", "Similar": "Liknande",
"Refine": "Förfina", "Refine": "Förfina",
"SearchBarPlaceholder": "Skriv här för att söka",
"Movies": { "Movies": {
"PopularMovies": "Populära filmer", "PopularMovies": "Populära filmer",
"UpcomingMovies": "Kommande filmer", "UpcomingMovies": "Kommande filmer",