diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..b3deb4a73 --- /dev/null +++ b/.github/stale.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2948060..18ce95bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,332 @@ # 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** @@ -26,6 +352,22 @@ ### **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] - Fixed #2801 this is when a season is not correctly monitored in sonarr when approved by an admin. [tidusjar] diff --git a/README.md b/README.md index 4f854cb56..e8e269e7f 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,8 @@ Follow me developing Ombi! ___ Get it on Google Play - -Get it on App Store - +
+_**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. * 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 +* 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) * 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! @@ -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. * Automatically updates the status of requests when they are available on Plex/Emby * Slick, responsive and mobile friendly UI -* Ombi will automatically update itself :) +* Ombi will automatically update itself :) (YMMV) * Very fast! ### Integration diff --git a/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs b/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs index d76915923..83d64ed15 100644 --- a/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs +++ b/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs @@ -16,6 +16,7 @@ namespace Ombi.Api.Emby.Models.Media.Tv public int ProductionYear { get; set; } public bool IsPlaceHolder { get; set; } public int IndexNumber { get; set; } + public int? IndexNumberEnd { get; set; } public int ParentIndexNumber { get; set; } public bool IsHD { get; set; } public bool IsFolder { get; set; } diff --git a/src/Ombi.Api.Lidarr/ILidarrApi.cs b/src/Ombi.Api.Lidarr/ILidarrApi.cs index 0eac960d0..826cfdec3 100644 --- a/src/Ombi.Api.Lidarr/ILidarrApi.cs +++ b/src/Ombi.Api.Lidarr/ILidarrApi.cs @@ -23,6 +23,6 @@ namespace Ombi.Api.Lidarr Task> GetLanguageProfile(string apiKey, string baseUrl); Task Status(string apiKey, string baseUrl); Task AlbumSearch(int[] albumIds, string apiKey, string baseUrl); - Task AlbumInformation(string albumId, string apiKey, string baseUrl); + Task AlbumInformation(string albumId, string apiKey, string baseUrl); } } \ No newline at end of file diff --git a/src/Ombi.Api.Lidarr/LidarrApi.cs b/src/Ombi.Api.Lidarr/LidarrApi.cs index cb8db759e..0f03aa1b0 100644 --- a/src/Ombi.Api.Lidarr/LidarrApi.cs +++ b/src/Ombi.Api.Lidarr/LidarrApi.cs @@ -84,7 +84,7 @@ namespace Ombi.Api.Lidarr public Task 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}; return Api.Request(request); } @@ -105,14 +105,13 @@ namespace Ombi.Api.Lidarr return Api.Request>(request); } - public async Task AlbumInformation(string albumId, string apiKey, string baseUrl) + public async Task AlbumInformation(string albumId, string apiKey, string baseUrl) { var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get); request.AddQueryString("foreignAlbumId", albumId); AddHeaders(request, apiKey); - var albums = await Api.Request>(request); - return albums.Where(x => x.foreignAlbumId.Equals(albumId, StringComparison.InvariantCultureIgnoreCase)) - .FirstOrDefault(); + var albums = await Api.Request>(request); + return albums.FirstOrDefault(); } diff --git a/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs b/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs new file mode 100644 index 000000000..27a479d2f --- /dev/null +++ b/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs @@ -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; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Pushover/PushoverApi.cs b/src/Ombi.Api.Pushover/PushoverApi.cs index 9f91bc7ca..41df0f647 100644 --- a/src/Ombi.Api.Pushover/PushoverApi.cs +++ b/src/Ombi.Api.Pushover/PushoverApi.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; +using System.Web; using Ombi.Api.Pushover.Models; namespace Ombi.Api.Pushover @@ -18,11 +19,7 @@ namespace Ombi.Api.Pushover public async Task PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound) { - if (message.Contains("'")) - { - message = message.Replace("'", "'"); - } - var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post); + var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.UrlEncode(message)}", PushoverEndpoint, HttpMethod.Post); var result = await _api.Request(request); return result; diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index 8ab5bc947..3c7e6967a 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -73,6 +73,7 @@ namespace Ombi.Api // do something with the response var receivedString = await httpResponseMessage.Content.ReadAsStringAsync(); + LogDebugContent(receivedString); if (request.ContentType == ContentType.Json) { request.OnBeforeDeserialization?.Invoke(receivedString); @@ -111,7 +112,7 @@ namespace Ombi.Api } // do something with the response var data = httpResponseMessage.Content; - + await LogDebugContent(httpResponseMessage); return await data.ReadAsStringAsync(); } @@ -123,6 +124,7 @@ namespace Ombi.Api { AddHeadersBody(request, httpRequestMessage); var httpResponseMessage = await _client.SendAsync(httpRequestMessage); + await LogDebugContent(httpResponseMessage); if (!httpResponseMessage.IsSuccessStatusCode) { 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 if (request.JsonBody != null) { + LogDebugContent("REQUEST: " + request.JsonBody); httpRequestMessage.Content = new JsonContent(request.JsonBody); httpRequestMessage.Content.Headers.ContentType = 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, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}, RequestUri: {request.FullUri}"); + await LogDebugContent(httpResponseMessage); + } + + private async Task LogDebugContent(HttpResponseMessage message) + { if (Logger.IsEnabled(LogLevel.Debug)) { - var content = await httpResponseMessage.Content.ReadAsStringAsync(); + var content = await message.Content.ReadAsStringAsync(); Logger.LogDebug(content); } } + + private void LogDebugContent(string message) + { + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.LogDebug(message); + } + } } } diff --git a/src/Ombi.Api/HttpRequestExtnesions.cs b/src/Ombi.Api/HttpRequestExtensions.cs similarity index 100% rename from src/Ombi.Api/HttpRequestExtnesions.cs rename to src/Ombi.Api/HttpRequestExtensions.cs diff --git a/src/Ombi.Api/Ombi.Api.csproj b/src/Ombi.Api/Ombi.Api.csproj index 7c6d5771b..08e8bd5a9 100644 --- a/src/Ombi.Api/Ombi.Api.csproj +++ b/src/Ombi.Api/Ombi.Api.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Ombi.Core/Engine/MusicSearchEngine.cs b/src/Ombi.Core/Engine/MusicSearchEngine.cs index c8d285766..da41d5bf1 100644 --- a/src/Ombi.Core/Engine/MusicSearchEngine.cs +++ b/src/Ombi.Core/Engine/MusicSearchEngine.cs @@ -157,7 +157,7 @@ namespace Ombi.Core.Engine // TODO - private async Task MapIntoAlbumVm(AlbumResponse a, LidarrSettings settings) + private async Task MapIntoAlbumVm(AlbumByForeignId a, LidarrSettings settings) { var vm = new SearchAlbumViewModel { @@ -167,7 +167,10 @@ namespace Ombi.Core.Engine ReleaseDate = a.releaseDate, Title = a.title, 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) { @@ -185,10 +188,6 @@ namespace Ombi.Core.Engine } 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); diff --git a/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs b/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs index a2c70fcc5..2b316cfc5 100644 --- a/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs +++ b/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs @@ -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.Threading.Tasks; using Microsoft.EntityFrameworkCore; @@ -37,16 +39,24 @@ namespace Ombi.Core.Rule.Rules.Request if (obj.RequestType == RequestType.TvShow) { if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv)) + { return Success(); + } + + 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"); } - return Fail("You do not have permissions to Request a TV Show"); + throw new InvalidDataException("Permission check failed: unknown RequestType"); } } -} \ No newline at end of file +} diff --git a/src/Ombi.Notifications/BaseNotification.cs b/src/Ombi.Notifications/BaseNotification.cs index 001f68f45..c9404eb2c 100644 --- a/src/Ombi.Notifications/BaseNotification.cs +++ b/src/Ombi.Notifications/BaseNotification.cs @@ -30,6 +30,7 @@ namespace Ombi.Notifications _log = log; AlbumRepository = album; UserNotificationPreferences = notificationUserPreferences; + Settings.ClearCache(); } protected ISettingsService Settings { get; } diff --git a/src/Ombi.Schedule/IocJobFactory.cs b/src/Ombi.Schedule/IocJobFactory.cs index 83ab5a974..795c1fec5 100644 --- a/src/Ombi.Schedule/IocJobFactory.cs +++ b/src/Ombi.Schedule/IocJobFactory.cs @@ -15,7 +15,7 @@ namespace Ombi.Schedule } public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { - var scopeFactory = _factory.GetService(); + var scopeFactory = _factory.GetService(); var scope = scopeFactory.CreateScope(); var scopedContainer = scope.ServiceProvider; diff --git a/src/Ombi.Schedule/Jobs/Couchpotato/CouchPotatoSync.cs b/src/Ombi.Schedule/Jobs/Couchpotato/CouchPotatoSync.cs index f42d910db..c92de7541 100644 --- a/src/Ombi.Schedule/Jobs/Couchpotato/CouchPotatoSync.cs +++ b/src/Ombi.Schedule/Jobs/Couchpotato/CouchPotatoSync.cs @@ -78,7 +78,11 @@ namespace Ombi.Schedule.Jobs.Couchpotato if (movies != null) { // Let's remove the old cached data - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM CouchPotatoCache"); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM CouchPotatoCache"); + tran.Commit(); + } // Save var movieIds = new List(); @@ -98,9 +102,14 @@ namespace Ombi.Schedule.Jobs.Couchpotato _log.LogError("TMDBId is not > 0 for movie {0}", m.title); } } - await _ctx.CouchPotatoCache.AddRangeAsync(movieIds); - await _ctx.SaveChangesAsync(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.CouchPotatoCache.AddRangeAsync(movieIds); + + await _ctx.SaveChangesAsync(); + tran.Commit(); + } await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) .SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Finished"); diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 0fc24dd81..f52488daa 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -67,7 +67,7 @@ namespace Ombi.Schedule.Jobs.Emby // Episodes await OmbiQuartz.TriggerJob(nameof(IEmbyEpisodeSync), "Emby"); - await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "Emby"); + await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "System"); } diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyEpisodeSync.cs index 2c2944a55..a10e3046c 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyEpisodeSync.cs @@ -126,6 +126,22 @@ namespace Ombi.Schedule.Jobs.Emby Title = ep.Name, 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 + }); + } } } diff --git a/src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs index 3e75a5fdb..371b11374 100644 --- a/src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs +++ b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs @@ -56,7 +56,11 @@ namespace Ombi.Schedule.Jobs.Lidarr if (albums != null && albums.Any()) { // Let's remove the old cached data - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrAlbumCache"); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrAlbumCache"); + tran.Commit(); + } var albumCache = new List(); foreach (var a in albums) @@ -68,7 +72,7 @@ namespace Ombi.Schedule.Jobs.Lidarr ArtistId = a.artistId, ForeignAlbumId = a.foreignAlbumId, ReleaseDate = a.releaseDate, - TrackCount = a.currentRelease.trackCount, + TrackCount = a.currentRelease?.trackCount ?? 0, Monitored = a.monitored, Title = a.title, PercentOfTracks = a.statistics?.percentOfEpisodes ?? 0m, @@ -76,9 +80,14 @@ namespace Ombi.Schedule.Jobs.Lidarr }); } } - await _ctx.LidarrAlbumCache.AddRangeAsync(albumCache); - await _ctx.SaveChangesAsync(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.LidarrAlbumCache.AddRangeAsync(albumCache); + + await _ctx.SaveChangesAsync(); + tran.Commit(); + } } } catch (System.Exception ex) diff --git a/src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs b/src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs index 3d17df2e8..c24451497 100644 --- a/src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs +++ b/src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs @@ -52,7 +52,11 @@ namespace Ombi.Schedule.Jobs.Lidarr if (artists != null && artists.Any()) { // Let's remove the old cached data - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrArtistCache"); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrArtistCache"); + tran.Commit(); + } var artistCache = new List(); foreach (var a in artists) @@ -68,9 +72,14 @@ namespace Ombi.Schedule.Jobs.Lidarr }); } } - await _ctx.LidarrArtistCache.AddRangeAsync(artistCache); - await _ctx.SaveChangesAsync(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.LidarrArtistCache.AddRangeAsync(artistCache); + + await _ctx.SaveChangesAsync(); + tran.Commit(); + } } } catch (Exception ex) diff --git a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs index cadabba4e..cf8cbd831 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs @@ -53,7 +53,6 @@ namespace Ombi.Schedule.Jobs.Ombi { return; } - const string episodeSQL = "DELETE FROM EmbyEpisode"; const string mainSql = "DELETE FROM EmbyContent"; await _embyRepo.ExecuteSql(episodeSQL); diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index b2faeeff3..7fed2b4d8 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -378,7 +378,7 @@ namespace Ombi.Schedule.Jobs.Ombi if (embySettings.Enable) { - await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode); + await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); } sb.Append(""); @@ -404,7 +404,7 @@ namespace Ombi.Schedule.Jobs.Ombi if (embySettings.Enable) { - await ProcessEmbyTv(embyEp, sb); + await ProcessEmbyTv(embyEp, sb, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); } sb.Append(""); @@ -509,7 +509,7 @@ namespace Ombi.Schedule.Jobs.Ombi } } - private async Task ProcessEmbyMovies(IQueryable embyContent, StringBuilder sb, string defaultLangaugeCode) + private async Task ProcessEmbyMovies(IQueryable embyContent, StringBuilder sb, string defaultLangaugeCode, string customUrl) { int count = 0; var ordered = embyContent.OrderByDescending(x => x.AddedAt); @@ -530,6 +530,10 @@ namespace Ombi.Schedule.Jobs.Ombi } var mediaurl = content.Url; + if (customUrl.HasValue()) + { + mediaurl = customUrl; + } var info = await _movieApi.GetMovieInformationWithExtraInfo(StringHelper.IntParseLinq(theMovieDbId), defaultLangaugeCode); if (info == null) { @@ -773,7 +777,7 @@ namespace Ombi.Schedule.Jobs.Ombi - private async Task ProcessEmbyTv(HashSet embyContent, StringBuilder sb) + private async Task ProcessEmbyTv(HashSet embyContent, StringBuilder sb, string serverUrl) { var series = new List(); foreach (var episode in embyContent) @@ -828,7 +832,7 @@ namespace Ombi.Schedule.Jobs.Ombi AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/"); } AddPosterInsideTable(sb, banner); - AddMediaServerUrl(sb, t.Url, banner); + AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner); AddInfoTable(sb); var title = ""; diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index d73e8550d..21e1fbbfd 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -118,10 +118,10 @@ namespace Ombi.Schedule.Jobs.Plex if ((processedContent?.HasProcessedContent ?? false) && recentlyAddedSearch) { // 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"); @@ -208,10 +208,10 @@ namespace Ombi.Schedule.Jobs.Plex } contentToAdd.Clear(); } - if (count > 200) + if (count > 30) { await Repo.SaveChangesAsync(); - + count = 0; } } @@ -245,7 +245,7 @@ namespace Ombi.Schedule.Jobs.Plex } contentToAdd.Clear(); } - if (count > 200) + if (count > 30) { await Repo.SaveChangesAsync(); } diff --git a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs index 8212aad3b..6fa4c1bc8 100644 --- a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs @@ -47,12 +47,16 @@ namespace Ombi.Schedule.Jobs.Radarr if (movies != null) { // Let's remove the old cached data - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM RadarrCache"); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM RadarrCache"); + tran.Commit(); + } var movieIds = new List(); foreach (var m in movies) { - if (m.tmdbId > 0) + if (m.tmdbId > 0 && m.monitored) { movieIds.Add(new RadarrCache { @@ -65,9 +69,14 @@ namespace Ombi.Schedule.Jobs.Radarr Logger.LogError("TMDBId is not > 0 for movie {0}", m.title); } } - await _ctx.RadarrCache.AddRangeAsync(movieIds); - await _ctx.SaveChangesAsync(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.RadarrCache.AddRangeAsync(movieIds); + + await _ctx.SaveChangesAsync(); + tran.Commit(); + } } } catch (System.Exception ex) @@ -111,4 +120,4 @@ namespace Ombi.Schedule.Jobs.Radarr GC.SuppressFinalize(this); } } -} \ No newline at end of file +} diff --git a/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs b/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs index 8c5652f3a..b6cca4c78 100644 --- a/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs +++ b/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs @@ -46,8 +46,12 @@ namespace Ombi.Schedule.Jobs.SickRage { var srShows = shows.data.Values; var ids = srShows.Select(x => x.tvdbid); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageCache"); + tran.Commit(); + } - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageCache"); var entites = ids.Select(id => new SickRageCache { TvDbId = id }).ToList(); await _ctx.SickRageCache.AddRangeAsync(entites); @@ -74,8 +78,12 @@ namespace Ombi.Schedule.Jobs.SickRage } - await _ctx.SickRageEpisodeCache.AddRangeAsync(episodesToAdd); - await _ctx.SaveChangesAsync(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.SickRageEpisodeCache.AddRangeAsync(episodesToAdd); + await _ctx.SaveChangesAsync(); + tran.Commit(); + } } } catch (Exception e) diff --git a/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs b/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs index eaa285cc7..f375ef064 100644 --- a/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs @@ -48,14 +48,22 @@ namespace Ombi.Schedule.Jobs.Sonarr { var sonarrSeries = series as ImmutableHashSet ?? series.ToImmutableHashSet(); var ids = sonarrSeries.Select(x => x.tvdbId); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache"); + tran.Commit(); + } - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache"); var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet(); await _ctx.SonarrCache.AddRangeAsync(entites); entites.Clear(); + using (var tran = await _ctx.Database.BeginTransactionAsync()) + { + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache"); + tran.Commit(); + } - await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache"); foreach (var s in sonarrSeries) { if (!s.monitored) @@ -68,15 +76,20 @@ namespace Ombi.Schedule.Jobs.Sonarr // Add to DB _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()) { - EpisodeNumber = episode.episodeNumber, - SeasonNumber = episode.seasonNumber, - TvDbId = s.tvdbId, - HasFile = episode.hasFile - })); - _log.LogDebug("Commiting the transaction"); - await _ctx.SaveChangesAsync(); + await _ctx.SonarrEpisodeCache.AddRangeAsync(monitoredEpisodes.Select(episode => + new SonarrEpisodeCache + { + EpisodeNumber = episode.episodeNumber, + SeasonNumber = episode.seasonNumber, + TvDbId = s.tvdbId, + HasFile = episode.hasFile + })); + _log.LogDebug("Commiting the transaction"); + await _ctx.SaveChangesAsync(); + tran.Commit(); + } } } diff --git a/src/Ombi.Store/Context/ExternalContext.cs b/src/Ombi.Store/Context/ExternalContext.cs index ff0581091..19cb77fc4 100644 --- a/src/Ombi.Store/Context/ExternalContext.cs +++ b/src/Ombi.Store/Context/ExternalContext.cs @@ -63,7 +63,12 @@ namespace Ombi.Store.Context { // VACUUM; Database.ExecuteSqlCommand("VACUUM;"); - SaveChanges(); + + using (var tran = Database.BeginTransaction()) + { + SaveChanges(); + tran.Commit(); + } } } } \ No newline at end of file diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index 98f4cd9c3..ea61b253f 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -89,18 +89,23 @@ namespace Ombi.Store.Context public void Seed() { - // Make sure we have the API User - var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase)); - if (!apiUserExists) - { - Users.Add(new OmbiUser - { - UserName = "Api", - UserType = UserType.SystemUser, - NormalizedUserName = "API", - }); - SaveChanges(); + using (var tran = Database.BeginTransaction()) + { + // Make sure we have the API User + var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase)); + if (!apiUserExists) + { + Users.Add(new OmbiUser + { + UserName = "Api", + UserType = UserType.SystemUser, + NormalizedUserName = "API", + + }); + SaveChanges(); + tran.Commit(); + } } //Check if templates exist @@ -238,7 +243,12 @@ namespace Ombi.Store.Context if (needToSave) { - SaveChanges(); + + using (var tran = Database.BeginTransaction()) + { + SaveChanges(); + tran.Commit(); + } } } } diff --git a/src/Ombi.Store/Context/SettingsContext.cs b/src/Ombi.Store/Context/SettingsContext.cs index 926f8cdba..163f8f50d 100644 --- a/src/Ombi.Store/Context/SettingsContext.cs +++ b/src/Ombi.Store/Context/SettingsContext.cs @@ -33,36 +33,44 @@ namespace Ombi.Store.Context public void Seed() { - // Add the tokens - var fanArt = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); - if (fanArt == null) + + using (var tran = Database.BeginTransaction()) { - ApplicationConfigurations.Add(new ApplicationConfiguration + // Add the tokens + var fanArt = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); + if (fanArt == null) { - Type = ConfigurationTypes.FanartTv, - Value = "4b6d983efa54d8f45c68432521335f15" - }); - SaveChanges(); - } - var movieDb = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); - if (movieDb == null) - { - ApplicationConfigurations.Add(new ApplicationConfiguration + ApplicationConfigurations.Add(new ApplicationConfiguration + { + Type = ConfigurationTypes.FanartTv, + Value = "4b6d983efa54d8f45c68432521335f15" + }); + SaveChanges(); + } + + var movieDb = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.FanartTv); + if (movieDb == null) { - Type = ConfigurationTypes.TheMovieDb, - Value = "b8eabaf5608b88d0298aa189dd90bf00" - }); - SaveChanges(); - } - var notification = ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.Notification); - if (notification == null) - { - ApplicationConfigurations.Add(new ApplicationConfiguration + ApplicationConfigurations.Add(new ApplicationConfiguration + { + Type = ConfigurationTypes.TheMovieDb, + Value = "b8eabaf5608b88d0298aa189dd90bf00" + }); + SaveChanges(); + } + + var notification = + ApplicationConfigurations.FirstOrDefault(x => x.Type == ConfigurationTypes.Notification); + if (notification == null) { - Type = ConfigurationTypes.Notification, - Value = "4f0260c4-9c3d-41ab-8d68-27cb5a593f0e" - }); - SaveChanges(); + ApplicationConfigurations.Add(new ApplicationConfiguration + { + Type = ConfigurationTypes.Notification, + Value = "4f0260c4-9c3d-41ab-8d68-27cb5a593f0e" + }); + SaveChanges(); + } + tran.Commit(); } } } diff --git a/src/Ombi.Store/Ombi.Store.csproj b/src/Ombi.Store/Ombi.Store.csproj index 33fc9289a..f5df80da9 100644 --- a/src/Ombi.Store/Ombi.Store.csproj +++ b/src/Ombi.Store/Ombi.Store.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Ombi.Store/Repository/AuditRepository.cs b/src/Ombi.Store/Repository/AuditRepository.cs index a6fc42c3f..858cd0eaf 100644 --- a/src/Ombi.Store/Repository/AuditRepository.cs +++ b/src/Ombi.Store/Repository/AuditRepository.cs @@ -24,16 +24,20 @@ namespace Ombi.Store.Repository public async Task Record(AuditType type, AuditArea area, string description, string user) { - await Ctx.Audit.AddAsync(new Audit + using (var tran = await Ctx.Database.BeginTransactionAsync()) { - User = user, - AuditArea = area, - AuditType = type, - DateTime = DateTime.UtcNow, - Description = description - }); + await Ctx.Audit.AddAsync(new Audit + { + User = user, + AuditArea = area, + AuditType = type, + DateTime = DateTime.UtcNow, + Description = description + }); - await Ctx.SaveChangesAsync(); + await Ctx.SaveChangesAsync(); + tran.Commit(); + } } } } diff --git a/src/Ombi.Store/Repository/BaseRepository.cs b/src/Ombi.Store/Repository/BaseRepository.cs index 0741a79b6..82661e0c3 100644 --- a/src/Ombi.Store/Repository/BaseRepository.cs +++ b/src/Ombi.Store/Repository/BaseRepository.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities; +using Polly; namespace Ombi.Store.Repository { @@ -83,7 +85,25 @@ namespace Ombi.Store.Repository protected async Task InternalSaveChanges() { - return await _ctx.SaveChangesAsync(); + var policy = Policy + .Handle() + .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; } diff --git a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs index 91e885b37..6528f0969 100644 --- a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs @@ -8,9 +8,9 @@ using Ombi.Store.Entities.Requests; namespace Ombi.Store.Repository.Requests { - public class TvRequestRepository : ITvRequestRepository + public class TvRequestRepository : BaseRepository, ITvRequestRepository { - public TvRequestRepository(IOmbiContext ctx) + public TvRequestRepository(IOmbiContext ctx) : base(ctx) { Db = ctx; } @@ -151,10 +151,5 @@ namespace Ombi.Store.Repository.Requests await InternalSaveChanges(); } - - private async Task InternalSaveChanges() - { - return await Db.SaveChangesAsync(); - } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/SettingsJsonRepository.cs b/src/Ombi.Store/Repository/SettingsJsonRepository.cs index 909a68480..622e32997 100644 --- a/src/Ombi.Store/Repository/SettingsJsonRepository.cs +++ b/src/Ombi.Store/Repository/SettingsJsonRepository.cs @@ -24,17 +24,28 @@ namespace Ombi.Store.Repository public GlobalSettings Insert(GlobalSettings entity) { //_cache.Remove(GetName(entity.SettingsName)); - var settings = Db.Settings.Add(entity); - Db.SaveChanges(); - return settings.Entity; + + using (var tran = Db.Database.BeginTransaction()) + { + var settings = Db.Settings.Add(entity); + Db.SaveChanges(); + tran.Commit(); + return settings.Entity; + } } public async Task InsertAsync(GlobalSettings entity) { - //_cache.Remove(GetName(entity.SettingsName)); - var settings = await Db.Settings.AddAsync(entity).ConfigureAwait(false); - await Db.SaveChangesAsync().ConfigureAwait(false); - return settings.Entity; + + using (var tran = Db.Database.BeginTransaction()) + { + //_cache.Remove(GetName(entity.SettingsName)); + var settings = await Db.Settings.AddAsync(entity); + await Db.SaveChangesAsync(); + tran.Commit(); + + return settings.Entity; + } } @@ -43,8 +54,8 @@ namespace Ombi.Store.Repository //return _cache.GetOrCreate(GetName(pageName), entry => //{ // entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(1); - var entity = Db.Settings.AsNoTracking().FirstOrDefault(x => x.SettingsName == pageName); - return entity; + var entity = Db.Settings.AsNoTracking().FirstOrDefault(x => x.SettingsName == pageName); + return entity; //}); } @@ -52,9 +63,9 @@ namespace Ombi.Store.Repository { //return await _cache.GetOrCreateAsync(GetName(settingsName), async entry => //{ - //entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(1); - var obj = await Db.Settings.AsNoTracking().FirstOrDefaultAsync(x => x.SettingsName == settingsName); - return obj; + //entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(1); + var obj = await Db.Settings.AsNoTracking().FirstOrDefaultAsync(x => x.SettingsName == settingsName); + return obj; //}); } @@ -75,15 +86,24 @@ namespace Ombi.Store.Repository public void Delete(GlobalSettings entity) { //_cache.Remove(GetName(entity.SettingsName)); - Db.Settings.Remove(entity); - Db.SaveChanges(); + + using (var tran = Db.Database.BeginTransaction()) + { + Db.Settings.Remove(entity); + Db.SaveChanges(); + tran.Commit(); + } } public void Update(GlobalSettings entity) { - Db.Update(entity); - //_cache.Remove(GetName(entity.SettingsName)); - Db.SaveChanges(); + using (var tran = Db.Database.BeginTransaction()) + { + Db.Update(entity); + //_cache.Remove(GetName(entity.SettingsName)); + Db.SaveChanges(); + tran.Commit(); + } } private string GetName(string entity) @@ -93,7 +113,13 @@ namespace Ombi.Store.Repository private async Task InternalSaveChanges() { - return await Db.SaveChangesAsync(); + + using (var tran = Db.Database.BeginTransaction()) + { + var r = await Db.SaveChangesAsync(); + tran.Commit(); + return r; + } } private bool _disposed; diff --git a/src/Ombi.Store/Repository/TokenRepository.cs b/src/Ombi.Store/Repository/TokenRepository.cs index d0a501bd5..4e35b0aa8 100644 --- a/src/Ombi.Store/Repository/TokenRepository.cs +++ b/src/Ombi.Store/Repository/TokenRepository.cs @@ -8,9 +8,9 @@ using Ombi.Helpers; namespace Ombi.Store.Repository { - public class TokenRepository : ITokenRepository + public class TokenRepository : BaseRepository, ITokenRepository { - public TokenRepository(IOmbiContext db) + public TokenRepository(IOmbiContext db) : base(db) { Db = db; } @@ -27,9 +27,5 @@ namespace Ombi.Store.Repository { return Db.Tokens.Where(x => x.Token == tokenId); } - private async Task InternalSaveChanges() - { - return await Db.SaveChangesAsync(); - } } } diff --git a/src/Ombi/ClientApp/src/app/requests/movierequests.component.html b/src/Ombi/ClientApp/src/app/requests/movierequests.component.html index 6f3b4dd00..3f8485fce 100644 --- a/src/Ombi/ClientApp/src/app/requests/movierequests.component.html +++ b/src/Ombi/ClientApp/src/app/requests/movierequests.component.html @@ -198,8 +198,8 @@
-
-
@@ -285,4 +285,4 @@ - \ No newline at end of file + diff --git a/src/Ombi/Controllers/V1/TokenController.cs b/src/Ombi/Controllers/V1/TokenController.cs index 723431968..d706434f8 100644 --- a/src/Ombi/Controllers/V1/TokenController.cs +++ b/src/Ombi/Controllers/V1/TokenController.cs @@ -149,7 +149,14 @@ namespace Ombi.Controllers.V1 } user.LastLoggedIn = DateTime.UtcNow; - await _userManager.UpdateAsync(user); + try + { + await _userManager.UpdateAsync(user); + } + catch (Exception) + { + + } return new JsonResult(new { diff --git a/src/Ombi/Program.cs b/src/Ombi/Program.cs index 2365f6748..dd0baa8d4 100644 --- a/src/Ombi/Program.cs +++ b/src/Ombi/Program.cs @@ -62,15 +62,25 @@ namespace Ombi Type = ConfigurationTypes.Url, Value = "http://*:5000" }; + using (var tran = ctx.Database.BeginTransaction()) + { + ctx.ApplicationConfigurations.Add(url); + ctx.SaveChanges(); + tran.Commit(); + } - ctx.ApplicationConfigurations.Add(url); - ctx.SaveChanges(); urlValue = url.Value; } if (!url.Value.Equals(host)) { url.Value = UrlArgs; - ctx.SaveChanges(); + + using (var tran = ctx.Database.BeginTransaction()) + { + ctx.SaveChanges(); + tran.Commit(); + } + urlValue = url.Value; } @@ -83,16 +93,26 @@ namespace Ombi Type = ConfigurationTypes.BaseUrl, Value = baseUrl }; - ctx.ApplicationConfigurations.Add(dbBaseUrl); - ctx.SaveChanges(); + + using (var tran = ctx.Database.BeginTransaction()) + { + ctx.ApplicationConfigurations.Add(dbBaseUrl); + ctx.SaveChanges(); + tran.Commit(); + } } } else if (baseUrl.HasValue() && !baseUrl.Equals(dbBaseUrl.Value)) { dbBaseUrl.Value = baseUrl; - ctx.SaveChanges(); + + using (var tran = ctx.Database.BeginTransaction()) + { + ctx.SaveChanges(); + tran.Commit(); + } } - + Console.WriteLine($"We are running on {urlValue}"); CreateWebHostBuilder(args).Build().Run(); @@ -130,25 +150,30 @@ namespace Ombi try { - if (ombi.Settings.Any() && !settings.Settings.Any()) + + using (var tran = settings.Database.BeginTransaction()) { - // OK migrate it! - var allSettings = ombi.Settings.ToList(); - settings.Settings.AddRange(allSettings); - doneGlobal = true; + if (ombi.Settings.Any() && !settings.Settings.Any()) + { + // OK migrate it! + var allSettings = ombi.Settings.ToList(); + settings.Settings.AddRange(allSettings); + doneGlobal = true; + } + + // Check for any application settings + + if (ombi.ApplicationConfigurations.Any() && !settings.ApplicationConfigurations.Any()) + { + // OK migrate it! + var allSettings = ombi.ApplicationConfigurations.ToList(); + settings.ApplicationConfigurations.AddRange(allSettings); + doneConfig = true; + } + + settings.SaveChanges(); + tran.Commit(); } - - // Check for any application settings - - if (ombi.ApplicationConfigurations.Any() && !settings.ApplicationConfigurations.Any()) - { - // OK migrate it! - var allSettings = ombi.ApplicationConfigurations.ToList(); - settings.ApplicationConfigurations.AddRange(allSettings); - doneConfig = true; - } - - settings.SaveChanges(); } catch (Exception e) { @@ -156,81 +181,100 @@ namespace Ombi throw; } - // Now delete the old stuff - if (doneGlobal) - ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings"); - if (doneConfig) - ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration"); + + using (var tran = ombi.Database.BeginTransaction()) + { + // Now delete the old stuff + if (doneGlobal) + ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings"); + if (doneConfig) + ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration"); + tran.Commit(); + } // Now migrate all the external stuff var external = new ExternalContext(); try { - if (ombi.PlexEpisode.Any()) - { - external.PlexEpisode.AddRange(ombi.PlexEpisode.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM PlexEpisode"); - } - if (ombi.PlexSeasonsContent.Any()) + using (var tran = external.Database.BeginTransaction()) { - external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent"); - } - if (ombi.PlexServerContent.Any()) - { - external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent"); - } - if (ombi.EmbyEpisode.Any()) - { - external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyEpisode"); - } + if (ombi.PlexEpisode.Any()) + { + external.PlexEpisode.AddRange(ombi.PlexEpisode.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM PlexEpisode"); + } - if (ombi.EmbyContent.Any()) - { - external.EmbyContent.AddRange(ombi.EmbyContent.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent"); - } - if (ombi.RadarrCache.Any()) - { - external.RadarrCache.AddRange(ombi.RadarrCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache"); - } - if (ombi.SonarrCache.Any()) - { - external.SonarrCache.AddRange(ombi.SonarrCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache"); - } - if (ombi.LidarrAlbumCache.Any()) - { - external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache"); - } - if (ombi.LidarrArtistCache.Any()) - { - external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache"); - } - if (ombi.SickRageEpisodeCache.Any()) - { - external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache"); - } - if (ombi.SickRageCache.Any()) - { - external.SickRageCache.AddRange(ombi.SickRageCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache"); - } - if (ombi.CouchPotatoCache.Any()) - { - external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList()); - ombi.Database.ExecuteSqlCommand("DELETE FROM CouchPotatoCache"); - } + if (ombi.PlexSeasonsContent.Any()) + { + external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent"); + } - external.SaveChanges(); + if (ombi.PlexServerContent.Any()) + { + external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent"); + } + + if (ombi.EmbyEpisode.Any()) + { + external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyEpisode"); + } + + if (ombi.EmbyContent.Any()) + { + external.EmbyContent.AddRange(ombi.EmbyContent.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent"); + } + + if (ombi.RadarrCache.Any()) + { + external.RadarrCache.AddRange(ombi.RadarrCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache"); + } + + if (ombi.SonarrCache.Any()) + { + external.SonarrCache.AddRange(ombi.SonarrCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache"); + } + + if (ombi.LidarrAlbumCache.Any()) + { + external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache"); + } + + if (ombi.LidarrArtistCache.Any()) + { + external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache"); + } + + if (ombi.SickRageEpisodeCache.Any()) + { + external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache"); + } + + if (ombi.SickRageCache.Any()) + { + external.SickRageCache.AddRange(ombi.SickRageCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache"); + } + + if (ombi.CouchPotatoCache.Any()) + { + external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList()); + ombi.Database.ExecuteSqlCommand("DELETE FROM CouchPotatoCache"); + } + + external.SaveChanges(); + tran.Commit(); + } } catch (Exception e) { diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index bef289236..b6d41d934 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -220,8 +220,14 @@ namespace Ombi app.UseSwagger(); app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1"); - c.SwaggerEndpoint("/swagger/v2/swagger.json", "API V2"); + if (settings.BaseUrl.HasValue()) + { + 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("/hubs/notification"); }); diff --git a/src/Ombi/wwwroot/translations/bg.json b/src/Ombi/wwwroot/translations/bg.json new file mode 100644 index 000000000..7fabf59d9 --- /dev/null +++ b/src/Ombi/wwwroot/translations/bg.json @@ -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" + } +} diff --git a/src/Ombi/wwwroot/translations/da.json b/src/Ombi/wwwroot/translations/da.json index af63d607e..a37e925fa 100644 --- a/src/Ombi/wwwroot/translations/da.json +++ b/src/Ombi/wwwroot/translations/da.json @@ -75,6 +75,7 @@ "RequestAdded": "{{title}} er anmodet med succes", "Similar": "Lignende", "Refine": "Refine", + "SearchBarPlaceholder": "Type Here to Search", "Movies": { "PopularMovies": "Populære film", "UpcomingMovies": "Kommende film", diff --git a/src/Ombi/wwwroot/translations/de.json b/src/Ombi/wwwroot/translations/de.json index b3e93f306..55356306f 100644 --- a/src/Ombi/wwwroot/translations/de.json +++ b/src/Ombi/wwwroot/translations/de.json @@ -75,6 +75,7 @@ "RequestAdded": "Anfrage für {{title}} wurde erfolgreich hinzugefügt", "Similar": "Ähnliche", "Refine": "Auswahl verfeinern", + "SearchBarPlaceholder": "Suchwort eingeben", "Movies": { "PopularMovies": "Beliebte Filme", "UpcomingMovies": "Kommende Filme", diff --git a/src/Ombi/wwwroot/translations/es.json b/src/Ombi/wwwroot/translations/es.json index d510600ad..61087033d 100644 --- a/src/Ombi/wwwroot/translations/es.json +++ b/src/Ombi/wwwroot/translations/es.json @@ -12,69 +12,70 @@ "Common": { "ContinueButton": "Continuar", "Available": "Disponible", - "PartiallyAvailable": "Disponible en parte", + "PartiallyAvailable": "Disponible parcialmente", "Monitored": "Monitoreado", - "NotAvailable": "No está disponible", + "NotAvailable": "No disponible", "ProcessingRequest": "Procesando solicitud", "PendingApproval": "Pendiente de aprobación", "RequestDenied": "Solicitud denegada", - "NotRequested": "No solicitados", + "NotRequested": "No solicitado", "Requested": "Solicitado", "Request": "Solicitar", "Denied": "Denegado", "Approve": "Aprobar", - "PartlyAvailable": "Disponible en parte", + "PartlyAvailable": "Disponible parcialmente", "Errors": { "Validation": "Por favor, comprueba los datos introducidos" } }, "PasswordReset": { "EmailAddressPlaceholder": "Correo electrónico", - "ResetPasswordButton": "Restablecer Contraseña" + "ResetPasswordButton": "Restablecer contraseña" }, "LandingPage": { "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", "PartiallyOnlineParagraph": "El servidor de medios está parcialmente en línea.", "MultipleServersUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.", "SingleServerUnavailable": "Hay {{serversUnavailable}} de {{totalServers}} servidores fuera de línea.", "OfflineHeading": "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": { "Search": "Buscar", "Requests": "Solicitudes", "UserManagement": "Gestión de usuarios", - "Issues": "Incidencias", + "Issues": "Problemas", "Vote": "Votar", "Donate": "¡Donar!", - "DonateLibraryMaintainer": "Donar al mantenedor de la biblioteca", - "DonateTooltip": "Así es como convenzo a mi esposa para que me deje pasar mi tiempo libre desarrollando ombi;)", + "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 ;)", "UpdateAvailableTooltip": "¡Actualización disponible!", "Settings": "Ajustes", "Welcome": "Bienvenido {{username}}", "UpdateDetails": "Editar cuenta usuario", "Logout": "Cerrar sesión", "OpenMobileApp": "Abrir aplicación móvil", - "RecentlyAdded": "Agregado recientemente" + "RecentlyAdded": "Añadido recientemente" }, "Search": { "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", "TvTab": "Series", "MusicTab": "Música", "Suggestions": "Sugerencias", "NoResults": "¡Lo sentimos, no encontramos ningún resultado!", - "DigitalDate": "Versión Digital: {{date}}", - "TheatricalRelease": "Estreno teatral: {{date}}", + "DigitalDate": "Versión digital: {{date}}", + "TheatricalRelease": "En cines: {{date}}", "ViewOnPlex": "Ver en Plex", "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", "Refine": "Filtros", + "SearchBarPlaceholder": "Escribe aquí para buscar", "Movies": { "PopularMovies": "Películas populares", "UpcomingMovies": "Próximas películas", @@ -87,14 +88,14 @@ "Popular": "Popular", "Trending": "Tendencias", "MostWatched": "Más visto", - "MostAnticipated": "Más Anticipado", + "MostAnticipated": "Lo más esperado", "Results": "Resultados", "AirDate": "Fecha de emisión:", "AllSeasons": "Todas las temporadas", "FirstSeason": "Primera temporada", "LatestSeason": "Última temporada", - "Select": "Seleccione...", - "SubmitRequest": "Enviar Solicitud", + "Select": "Selecciona...", + "SubmitRequest": "Enviar solicitud", "Season": "Temporada: {{seasonNumber}}", "SelectAllInSeason": "Seleccionar todo en temporada {{seasonNumber}}" } @@ -109,15 +110,15 @@ "Status": "Estado:", "RequestStatus": "Estado de la solicitud:", "Denied": " Denegado:", - "TheatricalRelease": "Estreno teatral: {{date}}", - "ReleaseDate": "Lanzado el {{date}}", - "TheatricalReleaseSort": "Estreno teatral", - "DigitalRelease": "Presentación Digital: {{date}}", + "TheatricalRelease": "En cines: {{date}}", + "ReleaseDate": "Publicado: {{date}}", + "TheatricalReleaseSort": "En cines", + "DigitalRelease": "Versión digital: {{date}}", "RequestDate": "Fecha de solicitud:", "QualityOverride": "Sobreescribir calidad:", "RootFolderOverride": "Sobreescribir carpeta raíz:", - "ChangeRootFolder": "Cambiar Carpeta Raíz", - "ChangeQualityProfile": "Cambiar Perfil de Calidad", + "ChangeRootFolder": "Carpeta raíz", + "ChangeQualityProfile": "Perfil de calidad", "MarkUnavailable": "Marcar como no disponible", "MarkAvailable": "Marcar como disponible", "Remove": "Eliminar", @@ -126,7 +127,7 @@ "GridTitle": "Título", "AirDate": "Fecha de estreno", "GridStatus": "Estado", - "ReportIssue": "Informar de Problema", + "ReportIssue": "Reportar problema", "Filter": "Filtrar", "Sort": "Ordenar", "SeasonNumberHeading": "Temporada: {seasonNumber}", @@ -138,48 +139,48 @@ "SortStatusDesc": "Estado ▼", "Remaining": { "Quota": "{{remaining}}/{{total}} solicitudes restantes", - "NextDays": "Se añadirá otra solicitud en {{time}} Días", - "NextHours": "Se añadirá otra solicitud en {{time}} Horas", - "NextMinutes": "Se añadirá otra solicitud en {{time}} Minutos", - "NextMinute": "Se añadirá otra solicitud en {{time}} Minuto" + "NextDays": "Se añadirá otra solicitud en {{time}} días", + "NextHours": "Se añadirá otra solicitud en {{time}} horas", + "NextMinutes": "Se añadirá otra solicitud en {{time}} minutos", + "NextMinute": "Se añadirá otra solicitud en {{time}} minuto" } }, "Issues": { - "Title": "Incidencias", - "PendingTitle": "Incidencias pendientes", - "InProgressTitle": "Incidencias en progreso", - "ResolvedTitle": "Incidencias resueltas", + "Title": "Problemas", + "PendingTitle": "Problemas pendientes", + "InProgressTitle": "Problemas en curso", + "ResolvedTitle": "Problemas resueltos", "ColumnTitle": "Título", "Category": "Categoría", "Status": "Estado", "Details": "Detalles", "Description": "Descripción", "NoComments": "¡Sin comentarios!", - "MarkInProgress": "Marcar En Proceso", - "MarkResolved": "Marcar resuelto", + "MarkInProgress": "Marcar en progreso", + "MarkResolved": "Marcar como resuelto", "SendMessageButton": "Enviar", "Subject": "Asunto", "Comments": "Comentarios", "WriteMessagePlaceholder": "Escribe tu mensaje aquí...", - "ReportedBy": "Informado por" + "ReportedBy": "Reportado por" }, "Filter": { - "ClearFilter": "Eliminar Filtro", + "ClearFilter": "Reiniciar filtro", "FilterHeaderAvailability": "Disponibilidad", "FilterHeaderRequestStatus": "Estado", - "Approved": "¡Aprobado!", - "PendingApproval": "Aprobación Pendiente" + "Approved": "Aprobado", + "PendingApproval": "Pendiente de aprobación" }, "UserManagment": { - "TvRemaining": "Música: {{remaining}}/{{total}} Restante", - "MovieRemaining": "Música: {{remaining}}/{{total}} Restante", - "MusicRemaining": "Música: {{remaining}}/{{total}} Restante", + "TvRemaining": "TV: {{remaining}}/{{total}} restantes", + "MovieRemaining": "Películas: {{remaining}}/{{total}} restantes", + "MusicRemaining": "Música: {{remaining}}/{{total}} restantes", "TvDue": "TV: {{date}}", "MovieDue": "Película: {{date}}", "MusicDue": "Música: {{date}}" }, "Votes": { - "CompletedVotesTab": "¡Votado!", + "CompletedVotesTab": "Votado", "VotesTab": "Votos necesarios" } } diff --git a/src/Ombi/wwwroot/translations/fr.json b/src/Ombi/wwwroot/translations/fr.json index d4e23e278..2f98728e5 100644 --- a/src/Ombi/wwwroot/translations/fr.json +++ b/src/Ombi/wwwroot/translations/fr.json @@ -75,6 +75,7 @@ "RequestAdded": "La demande pour {{title}} a été ajoutée avec succès", "Similar": "Similaires", "Refine": "Affiner", + "SearchBarPlaceholder": "Tapez ici pour rechercher", "Movies": { "PopularMovies": "Films populaires", "UpcomingMovies": "Films à venir", diff --git a/src/Ombi/wwwroot/translations/hu.json b/src/Ombi/wwwroot/translations/hu.json new file mode 100644 index 000000000..1414f0ea0 --- /dev/null +++ b/src/Ombi/wwwroot/translations/hu.json @@ -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" + } +} diff --git a/src/Ombi/wwwroot/translations/it.json b/src/Ombi/wwwroot/translations/it.json index f106b1a6b..38fbf4b99 100644 --- a/src/Ombi/wwwroot/translations/it.json +++ b/src/Ombi/wwwroot/translations/it.json @@ -75,6 +75,7 @@ "RequestAdded": "La richiesta per {{title}} è stata aggiunta correttamente", "Similar": "Similar", "Refine": "Refine", + "SearchBarPlaceholder": "Type Here to Search", "Movies": { "PopularMovies": "Film popolari", "UpcomingMovies": "Film in arrivo", diff --git a/src/Ombi/wwwroot/translations/nl.json b/src/Ombi/wwwroot/translations/nl.json index fdf70aad1..7bacfd142 100644 --- a/src/Ombi/wwwroot/translations/nl.json +++ b/src/Ombi/wwwroot/translations/nl.json @@ -13,15 +13,15 @@ "ContinueButton": "Doorgaan", "Available": "Beschikbaar", "PartiallyAvailable": "Deels Beschikbaar", - "Monitored": "Onder toezicht", + "Monitored": "Gemonitord", "NotAvailable": "Niet Beschikbaar", "ProcessingRequest": "Verzoek wordt verwerkt", "PendingApproval": "Wacht op goedkeuring", "RequestDenied": "Verzoek geweigerd", "NotRequested": "Niet verzocht", - "Requested": "Verzocht", - "Request": "Verzoek", - "Denied": "Geweigerd", + "Requested": "Aangevraagd", + "Request": "Aanvragen", + "Denied": "Afgewezen", "Approve": "Accepteer", "PartlyAvailable": "Deels Beschikbaar", "Errors": { @@ -37,27 +37,27 @@ "OnlineParagraph": "De mediaserver is momenteel online", "PartiallyOnlineHeading": "Gedeeltelijk Online", "PartiallyOnlineParagraph": "De mediaserver is gedeeltelijk online.", - "MultipleServersUnavailable": "Er zijn {{serversUnavailable}} servers offline van de in totaal {{totalServers}}.", - "SingleServerUnavailable": "Er is {{serversUnavailable}} server offline uit {{totalServers}}.", - "OfflineHeading": "Op dit moment Offline", + "MultipleServersUnavailable": "Er zijn {{serversUnavailable}} van de {{totalServers}} servers offline.", + "SingleServerUnavailable": "Er is {{serversUnavailable}} van de {{totalServers}} server offline.", + "OfflineHeading": "Momenteel Offline", "OfflineParagraph": "De mediaserver is momenteel offline.", "CheckPageForUpdates": "Controleer deze pagina voor updates." }, "NavigationBar": { "Search": "Zoeken", - "Requests": "Verzoeklijst", - "UserManagement": "Gebruikersbeheer", + "Requests": "Verzoeken", + "UserManagement": "Gebruikersmanagement", "Issues": "Problemen", "Vote": "Stem", "Donate": "Doneer!", - "DonateLibraryMaintainer": "Doneren aan bibliotheek beheerder", + "DonateLibraryMaintainer": "Doneren aan Ombi beheerder", "DonateTooltip": "Zo heb ik mijn vrouw overtuigd dat ik Ombi mag ontwikkelen ;)", "UpdateAvailableTooltip": "Update beschikbaar!", "Settings": "Instellingen", "Welcome": "Welkom {{username}}", - "UpdateDetails": "Update gegevens", + "UpdateDetails": "Gegevens updaten", "Logout": "Afmelden", - "OpenMobileApp": "Open Mobiele App", + "OpenMobileApp": "Mobiele App Openen", "RecentlyAdded": "Onlangs Toegevoegd" }, "Search": { @@ -67,7 +67,7 @@ "TvTab": "TV Series", "MusicTab": "Muziek", "Suggestions": "Suggesties", - "NoResults": "Sorry, we hebben geen resultaten gevonden!", + "NoResults": "Sorry, er zijn geen resultaten gevonden!", "DigitalDate": "Digitale Uitgave: {{date}}", "TheatricalRelease": "Bioscoop Uitgave: {{date}}", "ViewOnPlex": "Bekijk op Plex", @@ -75,11 +75,12 @@ "RequestAdded": "Aanvraag voor {{title}} is succesvol toegevoegd", "Similar": "Vergelijkbaar", "Refine": "Verfijn", + "SearchBarPlaceholder": "Voer zoekterm in", "Movies": { "PopularMovies": "Populaire films", "UpcomingMovies": "Aankomende Films", "TopRatedMovies": "Best Beoordeelde Films", - "NowPlayingMovies": "In Cinema Films", + "NowPlayingMovies": "Nu in de bioscoop", "HomePage": "Startpagina", "Trailer": "Trailer" }, diff --git a/src/Ombi/wwwroot/translations/no.json b/src/Ombi/wwwroot/translations/no.json index b65c9b53c..51d55b2c5 100644 --- a/src/Ombi/wwwroot/translations/no.json +++ b/src/Ombi/wwwroot/translations/no.json @@ -75,6 +75,7 @@ "RequestAdded": "Forespørsel om {{title}} er lagt til", "Similar": "Lignende", "Refine": "Refine", + "SearchBarPlaceholder": "Type Here to Search", "Movies": { "PopularMovies": "Populære filmer", "UpcomingMovies": "Kommende filmer", diff --git a/src/Ombi/wwwroot/translations/pl.json b/src/Ombi/wwwroot/translations/pl.json index af5f83efb..f309e6a86 100644 --- a/src/Ombi/wwwroot/translations/pl.json +++ b/src/Ombi/wwwroot/translations/pl.json @@ -10,7 +10,7 @@ } }, "Common": { - "ContinueButton": "Dalej", + "ContinueButton": "Kontynuuj", "Available": "Dostępne", "PartiallyAvailable": "Częściowo dostępne", "Monitored": "Monitorowane", @@ -18,14 +18,14 @@ "ProcessingRequest": "Przetwarzanie zgłoszenia", "PendingApproval": "Oczekujące na zatwierdzenie", "RequestDenied": "Zgłoszenie odrzucone", - "NotRequested": "Nie zgłoszone", + "NotRequested": "Niezgłoszone", "Requested": "Zgłoszone", "Request": "Zgłoszenie", "Denied": "Odrzucone", "Approve": "Zatwierdź", "PartlyAvailable": "Częściowo dostępne", "Errors": { - "Validation": "Sprawdź wprowadzone dane" + "Validation": "Proszę sprawdzić wprowadzone wartości" } }, "PasswordReset": { @@ -33,11 +33,11 @@ "ResetPasswordButton": "Zresetuj hasło" }, "LandingPage": { - "OnlineHeading": "Dostępny", + "OnlineHeading": "Aktualnie online", "OnlineParagraph": "Serwer multimediów jest aktualnie online", "PartiallyOnlineHeading": "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.", "OfflineHeading": "Aktualnie offline", "OfflineParagraph": "Serwer multimediów jest aktualnie offline.", @@ -51,7 +51,7 @@ "Vote": "Głosowania", "Donate": "Wesprzyj!", "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!", "Settings": "Ustawienia", "Welcome": "Witaj {{username}}", @@ -64,20 +64,21 @@ "Title": "Szukaj", "Paragraph": "Chcesz obejrzeć coś, co nie jest obecnie dostępne? Żaden problem, po prostu wyszukaj poniżej i dodaj zgłoszenie!", "MoviesTab": "Filmy", - "TvTab": "Programy TV", + "TvTab": "Seriale", "MusicTab": "Muzyka", "Suggestions": "Sugestie", "NoResults": "Niestety nic nie znaleziono!", "DigitalDate": "Wydanie cyfrowe: {{date}}", "TheatricalRelease": "Premiera kinowa: {{date}}", "ViewOnPlex": "Obejrzyj w Plex", - "ViewOnEmby": "Obejrzyj na Emby", - "RequestAdded": "Zgłoszenie dla {{title}} zostało dodane", + "ViewOnEmby": "Obejrzyj w Emby", + "RequestAdded": "Zgłoszenie dla {{title}} zostało pomyślnie dodane", "Similar": "Podobne", "Refine": "Zawęź", + "SearchBarPlaceholder": "Wpisz tutaj, aby wyszukać", "Movies": { "PopularMovies": "Popularne filmy", - "UpcomingMovies": "Wkrótce w kinach", + "UpcomingMovies": "Nadchodzące filmy", "TopRatedMovies": "Najwyżej oceniane filmy", "NowPlayingMovies": "W kinach", "HomePage": "Strona główna", @@ -101,9 +102,9 @@ }, "Requests": { "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", - "TvTab": "Programy TV", + "TvTab": "Seriale", "MusicTab": "Muzyka", "RequestedBy": "Zgłoszone przez:", "Status": "Status:", @@ -117,7 +118,7 @@ "QualityOverride": "Wymuszenie jakości:", "RootFolderOverride": "Wymuszenie folderu głównego:", "ChangeRootFolder": "Folder główny", - "ChangeQualityProfile": "Wybór jakości", + "ChangeQualityProfile": "Profil jakości", "MarkUnavailable": "Oznacz jako niedostępne", "MarkAvailable": "Oznacz jako dostępne", "Remove": "Usuń", @@ -128,7 +129,7 @@ "GridStatus": "Status", "ReportIssue": "Zgłoś problem", "Filter": "Filtr", - "Sort": "Sortowanie", + "Sort": "Sortuj", "SeasonNumberHeading": "Sezon: {seasonNumber}", "SortTitleAsc": "Tytuł ▲", "SortTitleDesc": "Tytuł ▼", @@ -151,7 +152,7 @@ "ResolvedTitle": "Problemy rozwiązane", "ColumnTitle": "Tytuł", "Category": "Kategoria", - "Status": "Stan", + "Status": "Status", "Details": "Szczegóły", "Description": "Opis", "NoComments": "Brak komentarzy!", @@ -164,17 +165,17 @@ "ReportedBy": "Zgłoszone przez" }, "Filter": { - "ClearFilter": "Wyczyść fltr", + "ClearFilter": "Wyczyść filtr", "FilterHeaderAvailability": "Dostępność", "FilterHeaderRequestStatus": "Status", "Approved": "Zatwierdzone", "PendingApproval": "Oczekujące na zatwierdzenie" }, "UserManagment": { - "TvRemaining": "TV: pozostało {{remaining}}/{{total}}", + "TvRemaining": "Seriale: pozostało {{remaining}}/{{total}}", "MovieRemaining": "Filmy: pozostało {{remaining}}/{{total}}", "MusicRemaining": "Muzyka: pozostało {{remaining}}/{{total}}", - "TvDue": "TV: {{date}}", + "TvDue": "Serial: {{date}}", "MovieDue": "Film: {{date}}", "MusicDue": "Muzyka: {{date}}" }, diff --git a/src/Ombi/wwwroot/translations/pt.json b/src/Ombi/wwwroot/translations/pt.json index aecd9903f..b0b3783ef 100644 --- a/src/Ombi/wwwroot/translations/pt.json +++ b/src/Ombi/wwwroot/translations/pt.json @@ -1,12 +1,12 @@ { "Login": { - "SignInButton": "Registrar", + "SignInButton": "Iniciar sessão", "UsernamePlaceholder": "Nome de usuário", - "PasswordPlaceholder": "Senha", - "RememberMe": "Lembre-se de mim", - "ForgottenPassword": "Esqueceu sua senha?", + "PasswordPlaceholder": "Palavra-passe", + "RememberMe": "Guardar a minha autênticação", + "ForgottenPassword": "Esqueceu-se da sua palavra-passe?", "Errors": { - "IncorrectCredentials": "Nome de usuário ou senha incorretos" + "IncorrectCredentials": "Nome de usuário ou palavra-passe incorretos" } }, "Common": { @@ -14,13 +14,13 @@ "Available": "Disponível", "PartiallyAvailable": "Parcialmente Disponível", "Monitored": "Monitorado", - "NotAvailable": "Inisponível", - "ProcessingRequest": "Processando Solicitação", + "NotAvailable": "Não Disponível", + "ProcessingRequest": "A processar o pedido", "PendingApproval": "Aprovação Pendente", - "RequestDenied": "Solicitação Negada", - "NotRequested": "Não Solicitado", - "Requested": "Solicitado", - "Request": "Solicitar", + "RequestDenied": "Pedido negado", + "NotRequested": "Não pedido", + "Requested": "Pedido", + "Request": "Pedir", "Denied": "Negado", "Approve": "Aprovar", "PartlyAvailable": "Parcialmente Disponível", @@ -30,34 +30,34 @@ }, "PasswordReset": { "EmailAddressPlaceholder": "Endereço de e-mail", - "ResetPasswordButton": "Redefinir Senha" + "ResetPasswordButton": "Redefinir palavra-passe" }, "LandingPage": { "OnlineHeading": "Online Agora", - "OnlineParagraph": "O servidor de mídia está atualmente online", + "OnlineParagraph": "O servidor de media está actualmente online", "PartiallyOnlineHeading": "Parcialmente Online", - "PartiallyOnlineParagraph": "O servidor de mídia está parcialmente online.", - "MultipleServersUnavailable": "Existem {{serversUnavailable}} servidores offline em um total de {{totalServers}}.", - "SingleServerUnavailable": "Existe {{serversUnavailable}} servidor offline em um total de {{totalServers}}.", - "OfflineHeading": "Offline Agora", - "OfflineParagraph": "O servidor de mídia está atualmente offline.", - "CheckPageForUpdates": "Verifique esta página para atualizações contínuas do site." + "PartiallyOnlineParagraph": "O servidor de media está parcialmente online.", + "MultipleServersUnavailable": "Existem {{serversUnavailable}} servidores offline de um total de {{totalServers}}.", + "SingleServerUnavailable": "Existe {{serversUnavailable}} servidor offline de um total de {{totalServers}}.", + "OfflineHeading": "Actualmente Offline", + "OfflineParagraph": "O servidor de media está actualmente offline.", + "CheckPageForUpdates": "Verifique esta página para acompanhar as atualizações do site." }, "NavigationBar": { "Search": "Pesquisar", - "Requests": "Solicitações", - "UserManagement": "Gerenciador de Usuário", - "Issues": "Problemas", + "Requests": "Pedidos", + "UserManagement": "Gestor de utilizadores", + "Issues": "Incidentes", "Vote": "Votar", "Donate": "Fazer uma doação!", "DonateLibraryMaintainer": "Doar para o Dono da Biblioteca", - "DonateTooltip": "É assim que eu convenço a minha mulher a deixar-me passar o meu tempo livre desenvolvendo Ombi;)", + "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!", "Settings": "Configurações", "Welcome": "Bem-vindo, {{username}}", - "UpdateDetails": "Detalhes da Atualização", + "UpdateDetails": "Detalhes da Actualização", "Logout": "Sair", - "OpenMobileApp": "Abrir aplicativo do celular", + "OpenMobileApp": "Abrir app móvel", "RecentlyAdded": "Recentemente adicionado" }, "Search": { @@ -75,6 +75,7 @@ "RequestAdded": "Pedido de {{title}} foi adicionado com sucesso", "Similar": "Semelhante", "Refine": "Filtro", + "SearchBarPlaceholder": "Digite aqui para pesquisar", "Movies": { "PopularMovies": "Filmes populares", "UpcomingMovies": "Próximos filmes", diff --git a/src/Ombi/wwwroot/translations/ru.json b/src/Ombi/wwwroot/translations/ru.json new file mode 100644 index 000000000..7cf9f1702 --- /dev/null +++ b/src/Ombi/wwwroot/translations/ru.json @@ -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" + } +} diff --git a/src/Ombi/wwwroot/translations/sv.json b/src/Ombi/wwwroot/translations/sv.json index 78ea25051..766804ba9 100644 --- a/src/Ombi/wwwroot/translations/sv.json +++ b/src/Ombi/wwwroot/translations/sv.json @@ -75,6 +75,7 @@ "RequestAdded": "Begäran av {{title}} har lagts till", "Similar": "Liknande", "Refine": "Förfina", + "SearchBarPlaceholder": "Skriv här för att söka", "Movies": { "PopularMovies": "Populära filmer", "UpcomingMovies": "Kommande filmer",