From e297f863a9975b6297d68472f6d3cb3ddc38390e Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 18 May 2023 13:28:38 +0100 Subject: [PATCH] Update (#4937) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update pr.yml [skip ci] * Update label.yml [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.19.0 * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish a series * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish movie * chore(release): :rocket: v4.19.1 * feat(discover): Show more relevant shows in upcoming TV * chore(release): :rocket: v4.20.0 * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes * perf(sync): Emby+Jellyfin - use a more reliable filter to missing items * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes [skip ci] * fix: added media type tag to media type text (#4638) [skip ci] * fix(sickrage): Fixed issue with incorrect handling of SiCKRAGE episode results returned during episode status changes, now expects array of objects from data path if present (#4648) [skip ci] * fix: Missing Poster broken link fix (#4637) [skip ci] * 🌐 Translations Update (#4622) [skip ci] * Update launch.json (#4650) [skip ci] * fix: Improve Swagger documentation (#4652) * Upgrade Swashbuckle dependency * Document /token response * Add support for Newtonsoft annotations in Swagger * Remove unecessary ActionResult [skip ci] * fix(API): Fix pagination in some edge cases (#4649) [skip ci] * 🌐 Translations Update (#4655) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): Carousel touch not working when scrolling page and recommendations and similar movie navigation (#4633) * fixed touch not working on carousels * fixed touch not working * Movie details component fixes Fixed recommendations and similar not changing the data on the component by calling the init function again on param change Moved the ngif results > 0 to the mat-expansion panel to avoid rendering the entire element if it doesn't have any results instead of having an empty panel. * removed unused line, added scroll to top on init * updated recommendation refresh implementation Changed the implementation to use the router instead in order to reload the component instead of just reloading the data. This implementation makes sure the component gets destroyed on navigation eliminating any memory leaks, reloading CSS in case of having animations on page load and generally a continuation of the experience you get when you browse into a movie from the discover page. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.20.1 [skip ci] * fix: :bug: Fixed the Request on Behalf of having blanks (#4667) * chore(release): :rocket: v4.20.2 [skip ci] * fix(plex): 🐛 Fixed an issue with the Plex Sync * chore(release): :rocket: v4.20.3 [skip ci] * fix (technical): Improved some of the date time parsing handling * fix: fixed build * chore(release): :rocket: v4.20.4 [skip ci] * feat: Upgrade to Angular14 (#4668) * refactor: :fire: removed angular-bootstrap-md dependancy * chore: update tsconfig * yeah * ng14 upgrade * refactor: migration changes * fix: fixed CLI * test: Fixed automation * chore: :busts_in_silhouette: Updated Contributors [skip ci] * perf: stop populating obsolete subscribe fields (#4625) * chore(release): :rocket: v4.21.0 [skip ci] * fix(images): Retry images with a backoff when we get a Too Many requests from TheMovieDb #4685 * chore(release): :rocket: v4.21.1 [skip ci] * 🌐 Translations Update (#4683) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Landing and Login page improvements (#4690) * chore(release): :rocket: v4.21.2 [skip ci] * feat(discover): ✨ Added infinite scroll on advanced search results * feat(discover): :sparkles: Added infinite scroll on advanced search results * chore(release): :rocket: v4.22.0 [skip ci] * 🌐 Translations Update (#4694) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): :bug: Created new Image component to handle 429's from TMDB (#4698) and fixed #4635 (#4699) * chore(release): :rocket: v4.22.1 [skip ci] * fix: fixed an issue where I broke images for some users * chore(release): :rocket: v4.22.2 [skip ci] * ci(Mergify): configuration update (#4701) Signed-off-by: Jamie [skip ci] * fix: Override Sonarr V3 Profiles endpoint (#4678) * Override Sonarr V3 Profiles endpoint [skip ci] * fix(4K) :4K request fixes (#4702) * GetRequestsByStatus wasn't implementing the MovieRequests object correctly for 4K quality requests with the ProcessingRequest status. * Fixed 4K requests not getting automatically approved if the user has the "Auto Approve Movie" role flag enabled. * Fixed "Request Date" values for the "left-panel-details" div class. Previously when the movie was exclusively 4K (regular request was absent), then "Request Date" equaled DateTime.MinValue (January 1, 0001). * Fixed "Request Status" evaluation in the "left-panel-details" div class. Now it shows the appropriate status instead of an empty spot. "Request Status" displays both regular and 4K statuses at the same time if needed. Added a comma to the end of the "RequestStatus" label to maintain design consistency with the other labels. Also added a "Denied Reason" element for 4K requests. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.3 [skip ci] * chore: Storybook (#4700) [skip ci] * chore: Translations [skip ci] * 🌐 Translations Update (#4704) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4713) * build: Run automation tests in docker (#4715) [skip ci] * fix: fixed trakt image not loading when base url present (#4711) [skip ci] * fix: :bug: Fixed missing externals (#4712) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.4 [skip ci] * test: fixed automationt tests [skip ci] * fix: Log Microsoft warnings to log file (#4723) [skip ci] * feat: ✨ Recently Requested on Discover Page (#4387) * chore(release): :rocket: v4.23.0 [skip ci] * fix: Localize recently requested on discover page (#4729) [skip ci] * 🌐 Translations Update (#4731) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * Fix: Ombi.Api.Lidarr: Remove unused fields from ArtistAdd (#4727) When an artist is not found in Lidarr as part of requesting an album, MusicSender will make a POST request against the /api/v1/artist endpoint to add such artist. Not all fields defined in ArtistAdd are initialized, and those uninitialized will be `null` values in the JSON body of the request, as shown in this intercepted request: ``` { "addOptions": { "AlbumsToMonitor": [ "e5c48b66-44ef-3685-ad53-45dbcd7294c0" ], "monitor": 6, "monitored": true, "searchForMissingAlbums": false }, "added": "2022-08-10T06:49:32.4374278+00:00", "albumFolder": true, "artistName": "Manolo García", "cleanName": "manologarcía", "disambiguation": null, "discogsId": 0, "ended": false, "foreignArtistId": "1c8309da-9789-40bf-b9c2-e20064263820", "images": [], "links": [], "metadataProfileId": 1, "monitored": true, "overview": null, "qualityProfileId": 3, "ratings": null, "remotePoster": null, "rootFolderPath": "/media/music/", "sortName": null, "statistics": null, "status": null, "tadbId": 0, "tags": null } ``` This request will fail and Lidarr will return a 400 BadRequest error with the following message: ``` 2022-08-10 01:45:52.458 +00:00 [Error] StatusCode: BadRequest, Reason: Bad Request, RequestUri: http://lidarr:8686/api/v1/artist 2022-08-10 01:45:52.459 +00:00 [Debug] { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-52e01b322a05d7c6633eca2488ef2a5c-06345b3bb8c4bb6c-00", "errors": { "$.status": [ "The JSON value could not be converted to NzbDrone.Core.Music.ArtistStatusType. Path: $.status | LineNumber: 0 | BytePositionInLine: 14." ] } } ``` Removing all the `null` fields from the JSON body fixes the problem and correctly adds the artist to Lidarr. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.23.1 [skip ci] * fix: Fix conflicting property name for Swagger (#4733) * chore(release): :rocket: v4.23.2 [skip ci] * feat: add crew on movie page (#4722) * add crew on movie page * order by director, add default image and fix click Co-authored-by: tidusjar * 🌐 Translations Update (#4736) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * chore(release): :rocket: v4.24.0 [skip ci] * feat: Watchlist history errors(#4741) [skip ci] * fix: fixed stats controller (#4742) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.25.0 [skip ci] * fix(webhook): Remove added trailing slash from webhook URL #4710 * chore(release): :rocket: v4.25.1 [skip ci] * feat(notifications): Add more curly variables for partially available notification * feat: Add more curly variables for partially available notification * test: Fix newly added test * chore(release): :rocket: v4.26.0 [skip ci] * feat: Recently requested improvements (#4755) * feat(discover): :sparkles: Admins can now approve the Recently Requested list * feat(discover): :zap: Images for the recently requested area are now loading faster and just better all around * test: :white_check_mark: Added automation for the new feature * chore(release): :rocket: v4.27.0 [skip ci] * fix(plex): stop the plex sync from deleting episodes when we can't find the plex key * chore(release): :rocket: v4.27.1 [skip ci] * refactor: Encapsulate common TV availability checker logic (#4753) [skip ci] * fix(sonarr): :bug: Cleaned up and removed Sonarr v3 option, sonarr v3 is now the default. This allows us to get ready for the upcoming Sonarr v4 (#4764) * chore(release): :rocket: v4.27.2 [skip ci] * 🌐 Translations Update (#4739) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(availability): 🐛 Fixed a issue with the availability checker after the previous update. Added full test coverage around that area * chore(release): :rocket: v4.27.3 [skip ci] * test: 🧪 added full test coverage to the plex availability checker, also fixed a small few bugs in there at the same time * chore(release): :rocket: v4.27.4 [skip ci] * fix(importer): 🐛 Allow you to only import Plex Admins without the Plex Users * chore(release): :rocket: v4.27.5 [skip ci] * fix(notifications): Fixed the error when sending multiple test notifications. Added more logging when Discord complains the message is invalid * chore(release): :rocket: v4.27.6 [skip ci] * fix: Fixes default image for recently requested items. (#4767) * chore(release): :rocket: v4.27.7 [skip ci] * refactor: Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. (#4769) * Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. * Fixes the last few build warnings. * chore(release): :rocket: v4.27.8 [skip ci] * refactor: Rework the Plex Settings Page (#4772) [skip ci] * feat(plex): ✨ Added the ability to configure the watchlist to request the whole TV show rather than latest season (#4774) * chore(release): :rocket: v4.28.0 [skip ci] * 🌐 Translations Update (#4771) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * 🌐 Translations Update (#4775) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Reworked the version check (#4719) (#4781) [skip ci] * fix(plex): :bug: Fixed not being able to enable watchlist requests in the Plex settings * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.28.1 [skip ci] * feat: Provide a flag for missing users on Plex Server (#4688) (#4778) [skip ci] * fix: Unable to Delete Jellyfin Server (#4705) (#4780) [skip ci] * fix: Partially Available prevents further TV requests (#4768) (#4779) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.29.0 [skip ci] * fix: Consistently reset loading flag when requesting movies on discover page. (#4777) [skip ci] * fix(sonarr): :bug: Fixed an issue where the language list didn't correctly load for power users in the advanced options #4782 * chore(release): :rocket: v4.29.1 [skip ci] * fix(plex): Fixed an issue where sometimes the availability checker would throw an exception when checking episodes * chore: fixed tests * chore(release): :rocket: v4.29.2 [skip ci] * fix: Only log error messages from Microsoft (#4787) [skip ci] * 🌐 Translations Update (#4784) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(notifications): Fixed the Partially TV notifications going to the admin #4797 (#4799) * chore(release): :rocket: v4.29.3 [skip ci] * feat(sonarr): :sparkles: Add the username to a Sonarr tag when sent to Sonarr (#4802) * chore(release): :rocket: v4.30.0 [skip ci] * feat(sonarr): Added the ability to add default tags when sending to Sonarr (#4803) * chore(release): :rocket: v4.31.0 [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4801) * feat(plex): Rework the Plex Settings page (#4805) * chore(release): :rocket: v4.32.0 [skip ci] * fix(plex): :bug: Fixed the issue where you couldn't add a new server on a fresh setup after the settings page rework * chore(release): :rocket: v4.32.1 [skip ci] * fix(sonarr): :bug: Sonarr V4 should work now (#4810) * fix(sonarr): :bug: Sonarr V4 should work now Auto detect the sonarr version and adjust the UI depending on V3 or V4 (Lang profiles) * fix: Fixed the load error * chore(release): :rocket: v4.32.2 [skip ci] * fix(sonarr): V4 actually works this time around * chore(release): :rocket: v4.32.3 [skip ci] * feat: Angular 15 and Dependency upgrades (#4818) * chore(release): :rocket: v4.33.0 [skip ci] * fix(plex): Added the watchlist request whole show back into the settings * chore: undid * fixed (#4833) * chore(release): :rocket: v4.33.1 [skip ci] * chore: add logo [skip ci] * feat: Radarr tags (#4815) * chore(release): :rocket: v4.34.0 [skip ci] * fix(plex-watchlist): Lookup the ID from different sources when Plex doesn't contain the metadata (#4843) * chore(release): :rocket: v4.34.1 [skip ci] * feat: Add the option for header authentication to create users (#4841) * feat: allow SSO to create new users automatically * feat: apply default user settings to SSO users * feat: add warnings to header auth toggles * chore(release): :rocket: v4.35.0 [skip ci] * fix(plex-watchlist): Index out of bounds error * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.1 [skip ci] * fix(database): Just some tweaks, shouldn't notice any difference, maybe a less error in the log * chore(release): :rocket: v4.35.2 [skip ci] * fix(#4847): Invalid Discord request fixed, also fixed an issue where App Only users would not show as logged in on the user management page (#4848) * chore(release): :rocket: v4.35.3 [skip ci] * bug(#4854): 🐛 Fixed the Recently Requested showing requests when it should be hidden * fix(discover): :bug: Fixed the default poster not taking into account the base url in some scenarios #4845 * fix(Hide music from navbar and request list when not enabled): :bug: * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.4 [skip ci] * fix(radarr-settings): 🐛 Fixed a typo * chore(release): :rocket: v4.35.5 [skip ci] * fix: Fixed the issue where the login page is still present after logging in with oauth * chore(release): :rocket: v4.35.6 [skip ci] * fix(wizard): :bug: Stop access to the wizard when you have already setup ombi (#4866) * chore(release): :rocket: v4.35.7 [skip ci] * fix(plex-oauth): 🐛 Fixed an issue where using OAuth you could log in as a Ombi Local user #4835 * chore(release): :rocket: v4.35.8 [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * fixed bad merge * chore(release): :rocket: v4.35.9 [skip ci] * Update .gitignore * Fixed automation * fix(sonarr): :bug: Improved the error handling in the sonarr settings page in the UI This should hopefully prevent some odd situations where the settings are in a odd state #4877 * chore: update deps * chore: more deps * bump * chore(release): :rocket: v4.35.12 [skip ci] * fix(sonarr): :bug: Added some more error handling and information around testing sonarr #4877 * chore(release): :rocket: v4.35.13 [skip ci] * fix: Some minor tweaks to the movie info panel (#4883) * fix: Hide denied reason label if there is no value * fix: Movie would show as pending approval when denied * chore(release): :rocket: v4.35.14 [skip ci] * fix(sonarr): :bug: Stop the sonarr version endpoint from breaking when Sonarr is down #4895 * chore(release): :rocket: v4.35.15 [skip ci] * fix: Support duplicates in Emby/JF collections (#4902) Support same movie that belongs in different collections in Emby or Jellyfin * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.16 [skip ci] * fix(discover): Fix denied requests displayed as approved (#4901) * fix: Fix denied movie shown as 'processing request' in details view (#4900) * chore(release): :rocket: v4.35.17 [skip ci] * fix(#4906): :bug: Fixed an issue with power users and permissions * chore(release): :rocket: v4.35.18 [skip ci] * fix(radarr): Fixed an issue where the radarr sync would break * chore(release): :rocket: v4.35.19 [skip ci] * feat(discover): Add deny option to recently requested (#4907) * chore(release): :rocket: v4.36.0 [skip ci] * fix(healthchecks): Removed redundant ping check * chore(release): :rocket: v4.36.1 [skip ci] * feat: Search by genre [skip-ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.37.0 [skip ci] * fix(discover): :children_crossing: Improved the new Genre buttons, it now includes TV results * chore: :busts_in_silhouette: Updated Contributors [skip ci] * fix: Cron Validation (#4842) * Add Cron Next Time Validation The cron job can't be created if the year is more than 100 years in the future. Getting the next valid time will return null if this is the case. * add next cron validation to api * add next cron validation to job settings page * Add Missing Import * chore: :busts_in_silhouette: Updated Contributors [skip ci] * 🌐 Translations Update (#4806) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(lidarr): Change monitor to Existing to properly add artist #3597 Discussed and tested manually in https://github.com/Lidarr/Lidarr/issues/3597#issuecomment-1530804055 * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.37.1 [skip ci] * fix(jellyfin): Fixed an issue where the sync could stop working. Removed unused properties so the deseralization no longer fails * chore(release): :rocket: v4.37.2 [skip ci] * fix: Show the ApiAlias in the requests-list * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.37.3 [skip ci] * feat(emby): Show watched status for Movie requests * First step towards played sync * Change TMDB id format to integer This will better integrate with TMDB id type in the request model * Display played state in the requests list * Fix played status filter * Run played sync job after content sync instead of on its own * Add a toggle to activate played sync * Hoovering * FIx played sync job not being triggered * Expose played state according to hide requests setting * Fix tests * Fix tests for real * Add MySql migrations [skip ci] * fix: remove sort header * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.38.0 [skip ci] * fix(notificaitons): Add the RequestedByAlias field to the Notification Message * chore: :busts_in_silhouette: Updated Contributors [skip ci] * 🌐 Translations Update (#4921) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(API): Allow RequestOnBehalf rights if requested from the API (#4919) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.38.1 [skip ci] * Merge pull request from GHSA-28j3-84m7-gpjp * chore(release): :rocket: v4.38.2 [skip ci] * Develop master (#4930) * Update (#4871) * Remove dead code * Localize TV requests messages on TV details page * Transform buttons with link into anchors * Sonarr sync: stop using seasonpass API * chore(release): :rocket: v4.16.13 * Fix requests when 4k available and 4k disabled Fixes #4610 * chore(release): :rocket: v4.16.14 * Hide subscribe button when request is available * Hide subscribe button when request is denied * Add Title to Partially Available Message If the Title of the show is not menitoned it can be unclear what Episodes are now available. * Better error message when test email fails due to missing recipient * feat(discover): Add original language filter * chore(release): :rocket: v4.16.15 * fix(4616): :bug: fixed mandatory fields * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.16.16 * added test results into the PR pipeline * chore(release): :rocket: v4.16.17 * Add information about cache refresh * Update pr.yml [skip ci] * Update pr.yml [skip ci] * Update pr.yml [skip ci] * chore(release): :rocket: v4.17.0 * feat(discover): Add new trending source experimental feature * fix(settings): Allow toggling features when there are more than one * fix(discover): Fix new trending feature detection * fix(discover): Fix cache mix up * refactor(discover): Move movie trending feature toggle to backend * feat(discover): Default trending source to new logic * chore(release): :rocket: v4.18.0 * feat(sync): Detect reidentified movies in Emby and Jellyfin * feat(sync): Detect reidentified series in Emby and Jellyfin * Fix sync log criticity * Update pr.yml [skip ci] * Update label.yml [skip ci] * Fix formatting * Update pr.yml [skip ci] * Update label.yml [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.19.0 * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish a series * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish movie * chore(release): :rocket: v4.19.1 * feat(discover): Show more relevant shows in upcoming TV * chore(release): :rocket: v4.20.0 * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes * perf(sync): Emby+Jellyfin - use a more reliable filter to missing items * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes [skip ci] * fix: added media type tag to media type text (#4638) [skip ci] * fix(sickrage): Fixed issue with incorrect handling of SiCKRAGE episode results returned during episode status changes, now expects array of objects from data path if present (#4648) [skip ci] * fix: Missing Poster broken link fix (#4637) [skip ci] * 🌐 Translations Update (#4622) [skip ci] * Update launch.json (#4650) [skip ci] * fix: Improve Swagger documentation (#4652) * Upgrade Swashbuckle dependency * Document /token response * Add support for Newtonsoft annotations in Swagger * Remove unecessary ActionResult [skip ci] * fix(API): Fix pagination in some edge cases (#4649) [skip ci] * 🌐 Translations Update (#4655) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): Carousel touch not working when scrolling page and recommendations and similar movie navigation (#4633) * fixed touch not working on carousels * fixed touch not working * Movie details component fixes Fixed recommendations and similar not changing the data on the component by calling the init function again on param change Moved the ngif results > 0 to the mat-expansion panel to avoid rendering the entire element if it doesn't have any results instead of having an empty panel. * removed unused line, added scroll to top on init * updated recommendation refresh implementation Changed the implementation to use the router instead in order to reload the component instead of just reloading the data. This implementation makes sure the component gets destroyed on navigation eliminating any memory leaks, reloading CSS in case of having animations on page load and generally a continuation of the experience you get when you browse into a movie from the discover page. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.20.1 [skip ci] * fix: :bug: Fixed the Request on Behalf of having blanks (#4667) * chore(release): :rocket: v4.20.2 [skip ci] * fix(plex): 🐛 Fixed an issue with the Plex Sync * chore(release): :rocket: v4.20.3 [skip ci] * fix (technical): Improved some of the date time parsing handling * fix: fixed build * chore(release): :rocket: v4.20.4 [skip ci] * feat: Upgrade to Angular14 (#4668) * refactor: :fire: removed angular-bootstrap-md dependancy * chore: update tsconfig * yeah * ng14 upgrade * refactor: migration changes * fix: fixed CLI * test: Fixed automation * chore: :busts_in_silhouette: Updated Contributors [skip ci] * perf: stop populating obsolete subscribe fields (#4625) * chore(release): :rocket: v4.21.0 [skip ci] * fix(images): Retry images with a backoff when we get a Too Many requests from TheMovieDb #4685 * chore(release): :rocket: v4.21.1 [skip ci] * 🌐 Translations Update (#4683) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Landing and Login page improvements (#4690) * chore(release): :rocket: v4.21.2 [skip ci] * feat(discover): ✨ Added infinite scroll on advanced search results * feat(discover): :sparkles: Added infinite scroll on advanced search results * chore(release): :rocket: v4.22.0 [skip ci] * 🌐 Translations Update (#4694) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): :bug: Created new Image component to handle 429's from TMDB (#4698) and fixed #4635 (#4699) * chore(release): :rocket: v4.22.1 [skip ci] * fix: fixed an issue where I broke images for some users * chore(release): :rocket: v4.22.2 [skip ci] * ci(Mergify): configuration update (#4701) Signed-off-by: Jamie [skip ci] * fix: Override Sonarr V3 Profiles endpoint (#4678) * Override Sonarr V3 Profiles endpoint [skip ci] * fix(4K) :4K request fixes (#4702) * GetRequestsByStatus wasn't implementing the MovieRequests object correctly for 4K quality requests with the ProcessingRequest status. * Fixed 4K requests not getting automatically approved if the user has the "Auto Approve Movie" role flag enabled. * Fixed "Request Date" values for the "left-panel-details" div class. Previously when the movie was exclusively 4K (regular request was absent), then "Request Date" equaled DateTime.MinValue (January 1, 0001). * Fixed "Request Status" evaluation in the "left-panel-details" div class. Now it shows the appropriate status instead of an empty spot. "Request Status" displays both regular and 4K statuses at the same time if needed. Added a comma to the end of the "RequestStatus" label to maintain design consistency with the other labels. Also added a "Denied Reason" element for 4K requests. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.3 [skip ci] * chore: Storybook (#4700) [skip ci] * chore: Translations [skip ci] * 🌐 Translations Update (#4704) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4713) * build: Run automation tests in docker (#4715) [skip ci] * fix: fixed trakt image not loading when base url present (#4711) [skip ci] * fix: :bug: Fixed missing externals (#4712) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.4 [skip ci] * test: fixed automationt tests [skip ci] * fix: Log Microsoft warnings to log file (#4723) [skip ci] * feat: ✨ Recently Requested on Discover Page (#4387) * chore(release): :rocket: v4.23.0 [skip ci] * fix: Localize recently requested on discover page (#4729) [skip ci] * 🌐 Translations Update (#4731) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * Fix: Ombi.Api.Lidarr: Remove unused fields from ArtistAdd (#4727) When an artist is not found in Lidarr as part of requesting an album, MusicSender will make a POST request against the /api/v1/artist endpoint to add such artist. Not all fields defined in ArtistAdd are initialized, and those uninitialized will be `null` values in the JSON body of the request, as shown in this intercepted request: ``` { "addOptions": { "AlbumsToMonitor": [ "e5c48b66-44ef-3685-ad53-45dbcd7294c0" ], "monitor": 6, "monitored": true, "searchForMissingAlbums": false }, "added": "2022-08-10T06:49:32.4374278+00:00", "albumFolder": true, "artistName": "Manolo García", "cleanName": "manologarcía", "disambiguation": null, "discogsId": 0, "ended": false, "foreignArtistId": "1c8309da-9789-40bf-b9c2-e20064263820", "images": [], "links": [], "metadataProfileId": 1, "monitored": true, "overview": null, "qualityProfileId": 3, "ratings": null, "remotePoster": null, "rootFolderPath": "/media/music/", "sortName": null, "statistics": null, "status": null, "tadbId": 0, "tags": null } ``` This request will fail and Lidarr will return a 400 BadRequest error with the following message: ``` 2022-08-10 01:45:52.458 +00:00 [Error] StatusCode: BadRequest, Reason: Bad Request, RequestUri: http://lidarr:8686/api/v1/artist 2022-08-10 01:45:52.459 +00:00 [Debug] { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-52e01b322a05d7c6633eca2488ef2a5c-06345b3bb8c4bb6c-00", "errors": { "$.status": [ "The JSON value could not be converted to NzbDrone.Core.Music.ArtistStatusType. Path: $.status | LineNumber: 0 | BytePositionInLine: 14." ] } } ``` Removing all the `null` fields from the JSON body fixes the problem and correctly adds the artist to Lidarr. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.23.1 [skip ci] * fix: Fix conflicting property name for Swagger (#4733) * chore(release): :rocket: v4.23.2 [skip ci] * feat: add crew on movie page (#4722) * add crew on movie page * order by director, add default image and fix click Co-authored-by: tidusjar * 🌐 Translations Update (#4736) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * chore(release): :rocket: v4.24.0 [skip ci] * feat: Watchlist history errors(#4741) [skip ci] * fix: fixed stats controller (#4742) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.25.0 [skip ci] * fix(webhook): Remove added trailing slash from webhook URL #4710 * chore(release): :rocket: v4.25.1 [skip ci] * feat(notifications): Add more curly variables for partially available notification * feat: Add more curly variables for partially available notification * test: Fix newly added test * chore(release): :rocket: v4.26.0 [skip ci] * feat: Recently requested improvements (#4755) * feat(discover): :sparkles: Admins can now approve the Recently Requested list * feat(discover): :zap: Images for the recently requested area are now loading faster and just better all around * test: :white_check_mark: Added automation for the new feature * chore(release): :rocket: v4.27.0 [skip ci] * fix(plex): stop the plex sync from deleting episodes when we can't find the plex key * chore(release): :rocket: v4.27.1 [skip ci] * refactor: Encapsulate common TV availability checker logic (#4753) [skip ci] * fix(sonarr): :bug: Cleaned up and removed Sonarr v3 option, sonarr v3 is now the default. This allows us to get ready for the upcoming Sonarr v4 (#4764) * chore(release): :rocket: v4.27.2 [skip ci] * 🌐 Translations Update (#4739) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(availability): 🐛 Fixed a issue with the availability checker after the previous update. Added full test coverage around that area * chore(release): :rocket: v4.27.3 [skip ci] * test: 🧪 added full test coverage to the plex availability checker, also fixed a small few bugs in there at the same time * chore(release): :rocket: v4.27.4 [skip ci] * fix(importer): 🐛 Allow you to only import Plex Admins without the Plex Users * chore(release): :rocket: v4.27.5 [skip ci] * fix(notifications): Fixed the error when sending multiple test notifications. Added more logging when Discord complains the message is invalid * chore(release): :rocket: v4.27.6 [skip ci] * fix: Fixes default image for recently requested items. (#4767) * chore(release): :rocket: v4.27.7 [skip ci] * refactor: Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. (#4769) * Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. * Fixes the last few build warnings. * chore(release): :rocket: v4.27.8 [skip ci] * refactor: Rework the Plex Settings Page (#4772) [skip ci] * feat(plex): ✨ Added the ability to configure the watchlist to request the whole TV show rather than latest season (#4774) * chore(release): :rocket: v4.28.0 [skip ci] * 🌐 Translations Update (#4771) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * 🌐 Translations Update (#4775) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Reworked the version check (#4719) (#4781) [skip ci] * fix(plex): :bug: Fixed not being able to enable watchlist requests in the Plex settings * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.28.1 [skip ci] * feat: Provide a flag for missing users on Plex Server (#4688) (#4778) [skip ci] * fix: Unable to Delete Jellyfin Server (#4705) (#4780) [skip ci] * fix: Partially Available prevents further TV requests (#4768) (#4779) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.29.0 [skip ci] * fix: Consistently reset loading flag when requesting movies on discover page. (#4777) [skip ci] * fix(sonarr): :bug: Fixed an issue where the language list didn't correctly load for power users in the advanced options #4782 * chore(release): :rocket: v4.29.1 [skip ci] * fix(plex): Fixed an issue where sometimes the availability checker would throw an exception when checking episodes * chore: fixed tests * chore(release): :rocket: v4.29.2 [skip ci] * fix: Only log error messages from Microsoft (#4787) [skip ci] * 🌐 Translations Update (#4784) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(notifications): Fixed the Partially TV notifications going to the admin #4797 (#4799) * chore(release): :rocket: v4.29.3 [skip ci] * feat(sonarr): :sparkles: Add the username to a Sonarr tag when sent to Sonarr (#4802) * chore(release): :rocket: v4.30.0 [skip ci] * feat(sonarr): Added the ability to add default tags when sending to Sonarr (#4803) * chore(release): :rocket: v4.31.0 [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4801) * feat(plex): Rework the Plex Settings page (#4805) * chore(release): :rocket: v4.32.0 [skip ci] * fix(plex): :bug: Fixed the issue where you couldn't add a new server on a fresh setup after the settings page rework * chore(release): :rocket: v4.32.1 [skip ci] * fix(sonarr): :bug: Sonarr V4 should work now (#4810) * fix(sonarr): :bug: Sonarr V4 should work now Auto detect the sonarr version and adjust the UI depending on V3 or V4 (Lang profiles) * fix: Fixed the load error * chore(release): :rocket: v4.32.2 [skip ci] * fix(sonarr): V4 actually works this time around * chore(release): :rocket: v4.32.3 [skip ci] * feat: Angular 15 and Dependency upgrades (#4818) * chore(release): :rocket: v4.33.0 [skip ci] * fix(plex): Added the watchlist request whole show back into the settings * chore: undid * fixed (#4833) * chore(release): :rocket: v4.33.1 [skip ci] * chore: add logo [skip ci] * feat: Radarr tags (#4815) * chore(release): :rocket: v4.34.0 [skip ci] * fix(plex-watchlist): Lookup the ID from different sources when Plex doesn't contain the metadata (#4843) * chore(release): :rocket: v4.34.1 [skip ci] * feat: Add the option for header authentication to create users (#4841) * feat: allow SSO to create new users automatically * feat: apply default user settings to SSO users * feat: add warnings to header auth toggles * chore(release): :rocket: v4.35.0 [skip ci] * fix(plex-watchlist): Index out of bounds error * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.1 [skip ci] * fix(database): Just some tweaks, shouldn't notice any difference, maybe a less error in the log * chore(release): :rocket: v4.35.2 [skip ci] * fix(#4847): Invalid Discord request fixed, also fixed an issue where App Only users would not show as logged in on the user management page (#4848) * chore(release): :rocket: v4.35.3 [skip ci] * bug(#4854): 🐛 Fixed the Recently Requested showing requests when it should be hidden * fix(discover): :bug: Fixed the default poster not taking into account the base url in some scenarios #4845 * fix(Hide music from navbar and request list when not enabled): :bug: * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.4 [skip ci] * fix(radarr-settings): 🐛 Fixed a typo * chore(release): :rocket: v4.35.5 [skip ci] * fix: Fixed the issue where the login page is still present after logging in with oauth * chore(release): :rocket: v4.35.6 [skip ci] * fix(wizard): :bug: Stop access to the wizard when you have already setup ombi (#4866) * chore(release): :rocket: v4.35.7 [skip ci] * fix(plex-oauth): 🐛 Fixed an issue where using OAuth you could log in as a Ombi Local user #4835 * chore(release): :rocket: v4.35.8 [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * fixed bad merge * chore(release): :rocket: v4.35.9 [skip ci] * Update .gitignore * Fixed automation --------- Signed-off-by: Jamie [skip ci] Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: Conventional Changelog Action Co-authored-by: Teifun2 Co-authored-by: contrib-readme-bot Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges Co-authored-by: Lucane Co-authored-by: mkgeeky Co-authored-by: Miguel A Vico Moya Co-authored-by: Hadrien <26697460+ketsapiwiq@users.noreply.github.com> Co-authored-by: Victor Usoltsev Co-authored-by: Wesley King Co-authored-by: Lea * chore(release): :rocket: v4.35.10 [skip ci] --------- Signed-off-by: Jamie [skip ci] Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: Conventional Changelog Action Co-authored-by: Teifun2 Co-authored-by: contrib-readme-bot Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges Co-authored-by: Lucane Co-authored-by: mkgeeky Co-authored-by: Miguel A Vico Moya Co-authored-by: Hadrien <26697460+ketsapiwiq@users.noreply.github.com> Co-authored-by: Victor Usoltsev Co-authored-by: Wesley King Co-authored-by: Lea * Develop master (#4931) [skip ci] * Update (#4871) * Remove dead code * Localize TV requests messages on TV details page * Transform buttons with link into anchors * Sonarr sync: stop using seasonpass API * chore(release): :rocket: v4.16.13 * Fix requests when 4k available and 4k disabled Fixes #4610 * chore(release): :rocket: v4.16.14 * Hide subscribe button when request is available * Hide subscribe button when request is denied * Add Title to Partially Available Message If the Title of the show is not menitoned it can be unclear what Episodes are now available. * Better error message when test email fails due to missing recipient * feat(discover): Add original language filter * chore(release): :rocket: v4.16.15 * fix(4616): :bug: fixed mandatory fields * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.16.16 * added test results into the PR pipeline * chore(release): :rocket: v4.16.17 * Add information about cache refresh * Update pr.yml [skip ci] * Update pr.yml [skip ci] * Update pr.yml [skip ci] * chore(release): :rocket: v4.17.0 * feat(discover): Add new trending source experimental feature * fix(settings): Allow toggling features when there are more than one * fix(discover): Fix new trending feature detection * fix(discover): Fix cache mix up * refactor(discover): Move movie trending feature toggle to backend * feat(discover): Default trending source to new logic * chore(release): :rocket: v4.18.0 * feat(sync): Detect reidentified movies in Emby and Jellyfin * feat(sync): Detect reidentified series in Emby and Jellyfin * Fix sync log criticity * Update pr.yml [skip ci] * Update label.yml [skip ci] * Fix formatting * Update pr.yml [skip ci] * Update label.yml [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.19.0 * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish a series * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish movie * chore(release): :rocket: v4.19.1 * feat(discover): Show more relevant shows in upcoming TV * chore(release): :rocket: v4.20.0 * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes * perf(sync): Emby+Jellyfin - use a more reliable filter to missing items * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes [skip ci] * fix: added media type tag to media type text (#4638) [skip ci] * fix(sickrage): Fixed issue with incorrect handling of SiCKRAGE episode results returned during episode status changes, now expects array of objects from data path if present (#4648) [skip ci] * fix: Missing Poster broken link fix (#4637) [skip ci] * 🌐 Translations Update (#4622) [skip ci] * Update launch.json (#4650) [skip ci] * fix: Improve Swagger documentation (#4652) * Upgrade Swashbuckle dependency * Document /token response * Add support for Newtonsoft annotations in Swagger * Remove unecessary ActionResult [skip ci] * fix(API): Fix pagination in some edge cases (#4649) [skip ci] * 🌐 Translations Update (#4655) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): Carousel touch not working when scrolling page and recommendations and similar movie navigation (#4633) * fixed touch not working on carousels * fixed touch not working * Movie details component fixes Fixed recommendations and similar not changing the data on the component by calling the init function again on param change Moved the ngif results > 0 to the mat-expansion panel to avoid rendering the entire element if it doesn't have any results instead of having an empty panel. * removed unused line, added scroll to top on init * updated recommendation refresh implementation Changed the implementation to use the router instead in order to reload the component instead of just reloading the data. This implementation makes sure the component gets destroyed on navigation eliminating any memory leaks, reloading CSS in case of having animations on page load and generally a continuation of the experience you get when you browse into a movie from the discover page. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.20.1 [skip ci] * fix: :bug: Fixed the Request on Behalf of having blanks (#4667) * chore(release): :rocket: v4.20.2 [skip ci] * fix(plex): 🐛 Fixed an issue with the Plex Sync * chore(release): :rocket: v4.20.3 [skip ci] * fix (technical): Improved some of the date time parsing handling * fix: fixed build * chore(release): :rocket: v4.20.4 [skip ci] * feat: Upgrade to Angular14 (#4668) * refactor: :fire: removed angular-bootstrap-md dependancy * chore: update tsconfig * yeah * ng14 upgrade * refactor: migration changes * fix: fixed CLI * test: Fixed automation * chore: :busts_in_silhouette: Updated Contributors [skip ci] * perf: stop populating obsolete subscribe fields (#4625) * chore(release): :rocket: v4.21.0 [skip ci] * fix(images): Retry images with a backoff when we get a Too Many requests from TheMovieDb #4685 * chore(release): :rocket: v4.21.1 [skip ci] * 🌐 Translations Update (#4683) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Landing and Login page improvements (#4690) * chore(release): :rocket: v4.21.2 [skip ci] * feat(discover): ✨ Added infinite scroll on advanced search results * feat(discover): :sparkles: Added infinite scroll on advanced search results * chore(release): :rocket: v4.22.0 [skip ci] * 🌐 Translations Update (#4694) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): :bug: Created new Image component to handle 429's from TMDB (#4698) and fixed #4635 (#4699) * chore(release): :rocket: v4.22.1 [skip ci] * fix: fixed an issue where I broke images for some users * chore(release): :rocket: v4.22.2 [skip ci] * ci(Mergify): configuration update (#4701) Signed-off-by: Jamie [skip ci] * fix: Override Sonarr V3 Profiles endpoint (#4678) * Override Sonarr V3 Profiles endpoint [skip ci] * fix(4K) :4K request fixes (#4702) * GetRequestsByStatus wasn't implementing the MovieRequests object correctly for 4K quality requests with the ProcessingRequest status. * Fixed 4K requests not getting automatically approved if the user has the "Auto Approve Movie" role flag enabled. * Fixed "Request Date" values for the "left-panel-details" div class. Previously when the movie was exclusively 4K (regular request was absent), then "Request Date" equaled DateTime.MinValue (January 1, 0001). * Fixed "Request Status" evaluation in the "left-panel-details" div class. Now it shows the appropriate status instead of an empty spot. "Request Status" displays both regular and 4K statuses at the same time if needed. Added a comma to the end of the "RequestStatus" label to maintain design consistency with the other labels. Also added a "Denied Reason" element for 4K requests. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.3 [skip ci] * chore: Storybook (#4700) [skip ci] * chore: Translations [skip ci] * 🌐 Translations Update (#4704) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4713) * build: Run automation tests in docker (#4715) [skip ci] * fix: fixed trakt image not loading when base url present (#4711) [skip ci] * fix: :bug: Fixed missing externals (#4712) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.4 [skip ci] * test: fixed automationt tests [skip ci] * fix: Log Microsoft warnings to log file (#4723) [skip ci] * feat: ✨ Recently Requested on Discover Page (#4387) * chore(release): :rocket: v4.23.0 [skip ci] * fix: Localize recently requested on discover page (#4729) [skip ci] * 🌐 Translations Update (#4731) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * Fix: Ombi.Api.Lidarr: Remove unused fields from ArtistAdd (#4727) When an artist is not found in Lidarr as part of requesting an album, MusicSender will make a POST request against the /api/v1/artist endpoint to add such artist. Not all fields defined in ArtistAdd are initialized, and those uninitialized will be `null` values in the JSON body of the request, as shown in this intercepted request: ``` { "addOptions": { "AlbumsToMonitor": [ "e5c48b66-44ef-3685-ad53-45dbcd7294c0" ], "monitor": 6, "monitored": true, "searchForMissingAlbums": false }, "added": "2022-08-10T06:49:32.4374278+00:00", "albumFolder": true, "artistName": "Manolo García", "cleanName": "manologarcía", "disambiguation": null, "discogsId": 0, "ended": false, "foreignArtistId": "1c8309da-9789-40bf-b9c2-e20064263820", "images": [], "links": [], "metadataProfileId": 1, "monitored": true, "overview": null, "qualityProfileId": 3, "ratings": null, "remotePoster": null, "rootFolderPath": "/media/music/", "sortName": null, "statistics": null, "status": null, "tadbId": 0, "tags": null } ``` This request will fail and Lidarr will return a 400 BadRequest error with the following message: ``` 2022-08-10 01:45:52.458 +00:00 [Error] StatusCode: BadRequest, Reason: Bad Request, RequestUri: http://lidarr:8686/api/v1/artist 2022-08-10 01:45:52.459 +00:00 [Debug] { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-52e01b322a05d7c6633eca2488ef2a5c-06345b3bb8c4bb6c-00", "errors": { "$.status": [ "The JSON value could not be converted to NzbDrone.Core.Music.ArtistStatusType. Path: $.status | LineNumber: 0 | BytePositionInLine: 14." ] } } ``` Removing all the `null` fields from the JSON body fixes the problem and correctly adds the artist to Lidarr. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.23.1 [skip ci] * fix: Fix conflicting property name for Swagger (#4733) * chore(release): :rocket: v4.23.2 [skip ci] * feat: add crew on movie page (#4722) * add crew on movie page * order by director, add default image and fix click Co-authored-by: tidusjar * 🌐 Translations Update (#4736) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * chore(release): :rocket: v4.24.0 [skip ci] * feat: Watchlist history errors(#4741) [skip ci] * fix: fixed stats controller (#4742) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.25.0 [skip ci] * fix(webhook): Remove added trailing slash from webhook URL #4710 * chore(release): :rocket: v4.25.1 [skip ci] * feat(notifications): Add more curly variables for partially available notification * feat: Add more curly variables for partially available notification * test: Fix newly added test * chore(release): :rocket: v4.26.0 [skip ci] * feat: Recently requested improvements (#4755) * feat(discover): :sparkles: Admins can now approve the Recently Requested list * feat(discover): :zap: Images for the recently requested area are now loading faster and just better all around * test: :white_check_mark: Added automation for the new feature * chore(release): :rocket: v4.27.0 [skip ci] * fix(plex): stop the plex sync from deleting episodes when we can't find the plex key * chore(release): :rocket: v4.27.1 [skip ci] * refactor: Encapsulate common TV availability checker logic (#4753) [skip ci] * fix(sonarr): :bug: Cleaned up and removed Sonarr v3 option, sonarr v3 is now the default. This allows us to get ready for the upcoming Sonarr v4 (#4764) * chore(release): :rocket: v4.27.2 [skip ci] * 🌐 Translations Update (#4739) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(availability): 🐛 Fixed a issue with the availability checker after the previous update. Added full test coverage around that area * chore(release): :rocket: v4.27.3 [skip ci] * test: 🧪 added full test coverage to the plex availability checker, also fixed a small few bugs in there at the same time * chore(release): :rocket: v4.27.4 [skip ci] * fix(importer): 🐛 Allow you to only import Plex Admins without the Plex Users * chore(release): :rocket: v4.27.5 [skip ci] * fix(notifications): Fixed the error when sending multiple test notifications. Added more logging when Discord complains the message is invalid * chore(release): :rocket: v4.27.6 [skip ci] * fix: Fixes default image for recently requested items. (#4767) * chore(release): :rocket: v4.27.7 [skip ci] * refactor: Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. (#4769) * Upgrades nuget packages. Removes deprecated packages. Fixes build warnings. * Fixes the last few build warnings. * chore(release): :rocket: v4.27.8 [skip ci] * refactor: Rework the Plex Settings Page (#4772) [skip ci] * feat(plex): ✨ Added the ability to configure the watchlist to request the whole TV show rather than latest season (#4774) * chore(release): :rocket: v4.28.0 [skip ci] * 🌐 Translations Update (#4771) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * 🌐 Translations Update (#4775) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Reworked the version check (#4719) (#4781) [skip ci] * fix(plex): :bug: Fixed not being able to enable watchlist requests in the Plex settings * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.28.1 [skip ci] * feat: Provide a flag for missing users on Plex Server (#4688) (#4778) [skip ci] * fix: Unable to Delete Jellyfin Server (#4705) (#4780) [skip ci] * fix: Partially Available prevents further TV requests (#4768) (#4779) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.29.0 [skip ci] * fix: Consistently reset loading flag when requesting movies on discover page. (#4777) [skip ci] * fix(sonarr): :bug: Fixed an issue where the language list didn't correctly load for power users in the advanced options #4782 * chore(release): :rocket: v4.29.1 [skip ci] * fix(plex): Fixed an issue where sometimes the availability checker would throw an exception when checking episodes * chore: fixed tests * chore(release): :rocket: v4.29.2 [skip ci] * fix: Only log error messages from Microsoft (#4787) [skip ci] * 🌐 Translations Update (#4784) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(notifications): Fixed the Partially TV notifications going to the admin #4797 (#4799) * chore(release): :rocket: v4.29.3 [skip ci] * feat(sonarr): :sparkles: Add the username to a Sonarr tag when sent to Sonarr (#4802) * chore(release): :rocket: v4.30.0 [skip ci] * feat(sonarr): Added the ability to add default tags when sending to Sonarr (#4803) * chore(release): :rocket: v4.31.0 [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4801) * feat(plex): Rework the Plex Settings page (#4805) * chore(release): :rocket: v4.32.0 [skip ci] * fix(plex): :bug: Fixed the issue where you couldn't add a new server on a fresh setup after the settings page rework * chore(release): :rocket: v4.32.1 [skip ci] * fix(sonarr): :bug: Sonarr V4 should work now (#4810) * fix(sonarr): :bug: Sonarr V4 should work now Auto detect the sonarr version and adjust the UI depending on V3 or V4 (Lang profiles) * fix: Fixed the load error * chore(release): :rocket: v4.32.2 [skip ci] * fix(sonarr): V4 actually works this time around * chore(release): :rocket: v4.32.3 [skip ci] * feat: Angular 15 and Dependency upgrades (#4818) * chore(release): :rocket: v4.33.0 [skip ci] * fix(plex): Added the watchlist request whole show back into the settings * chore: undid * fixed (#4833) * chore(release): :rocket: v4.33.1 [skip ci] * chore: add logo [skip ci] * feat: Radarr tags (#4815) * chore(release): :rocket: v4.34.0 [skip ci] * fix(plex-watchlist): Lookup the ID from different sources when Plex doesn't contain the metadata (#4843) * chore(release): :rocket: v4.34.1 [skip ci] * feat: Add the option for header authentication to create users (#4841) * feat: allow SSO to create new users automatically * feat: apply default user settings to SSO users * feat: add warnings to header auth toggles * chore(release): :rocket: v4.35.0 [skip ci] * fix(plex-watchlist): Index out of bounds error * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.1 [skip ci] * fix(database): Just some tweaks, shouldn't notice any difference, maybe a less error in the log * chore(release): :rocket: v4.35.2 [skip ci] * fix(#4847): Invalid Discord request fixed, also fixed an issue where App Only users would not show as logged in on the user management page (#4848) * chore(release): :rocket: v4.35.3 [skip ci] * bug(#4854): 🐛 Fixed the Recently Requested showing requests when it should be hidden * fix(discover): :bug: Fixed the default poster not taking into account the base url in some scenarios #4845 * fix(Hide music from navbar and request list when not enabled): :bug: * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.35.4 [skip ci] * fix(radarr-settings): 🐛 Fixed a typo * chore(release): :rocket: v4.35.5 [skip ci] * fix: Fixed the issue where the login page is still present after logging in with oauth * chore(release): :rocket: v4.35.6 [skip ci] * fix(wizard): :bug: Stop access to the wizard when you have already setup ombi (#4866) * chore(release): :rocket: v4.35.7 [skip ci] * fix(plex-oauth): 🐛 Fixed an issue where using OAuth you could log in as a Ombi Local user #4835 * chore(release): :rocket: v4.35.8 [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * fixed bad merge * chore(release): :rocket: v4.35.9 [skip ci] * Update .gitignore * Fixed automation --------- Signed-off-by: Jamie [skip ci] Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: Conventional Changelog Action Co-authored-by: Teifun2 Co-authored-by: contrib-readme-bot Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges Co-authored-by: Lucane Co-authored-by: mkgeeky Co-authored-by: Miguel A Vico Moya Co-authored-by: Hadrien <26697460+ketsapiwiq@users.noreply.github.com> Co-authored-by: Victor Usoltsev Co-authored-by: Wesley King Co-authored-by: Lea * chore(release): :rocket: v4.35.10 [skip ci] --------- Signed-off-by: Jamie [skip ci] Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: Conventional Changelog Action Co-authored-by: Teifun2 Co-authored-by: contrib-readme-bot Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges Co-authored-by: Lucane Co-authored-by: mkgeeky Co-authored-by: Miguel A Vico Moya Co-authored-by: Hadrien <26697460+ketsapiwiq@users.noreply.github.com> Co-authored-by: Victor Usoltsev Co-authored-by: Wesley King Co-authored-by: Lea * fix(emby): Fix Emby played sync running a full sync during recently added sync (#4932) * feat: Hide watched status when request is not available (#4934) * chore(release): :rocket: v4.39.0 [skip ci] * ignore flaky test --------- Signed-off-by: Jamie [skip ci] Co-authored-by: contrib-readme-bot Co-authored-by: Conventional Changelog Action Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges Co-authored-by: Lucane Co-authored-by: mkgeeky Co-authored-by: Miguel A Vico Moya Co-authored-by: Hadrien <26697460+ketsapiwiq@users.noreply.github.com> Co-authored-by: Victor Usoltsev Co-authored-by: Wesley King Co-authored-by: Lea Co-authored-by: ryan-c44 <54028283+ryan-c44@users.noreply.github.com> Co-authored-by: Alexander Russell Co-authored-by: Grygon <647846+Grygon@users.noreply.github.com> Co-authored-by: phildups7 <60622768+phildups7@users.noreply.github.com> Co-authored-by: Teifun2 --- CHANGELOG.md | 308 +++++----- README.md | 123 ++-- src/Ombi.Api.Emby/EmbyApi.cs | 32 + src/Ombi.Api.Emby/IBaseEmbyApi.cs | 2 + .../Models/Media/Movie/EmbyMovie.cs | 22 - .../Models/Media/Movie/JellyfinMovie.cs | 22 - src/Ombi.Api.Sonarr/Models/SystemStatus.cs | 17 - .../Engine/MovieRequestEngineTests.cs | 1 + .../Engine/V2/MovieRequestEngineTests.cs | 3 +- .../Services/RecentlyRequestedServiceTests.cs | 1 + src/Ombi.Core/Engine/MovieRequestEngine.cs | 46 +- src/Ombi.Core/Engine/TvRequestEngine.cs | 2 +- .../Models/Requests/RecentlyRequestedModel.cs | 1 + src/Ombi.Core/Models/TesterResultModel.cs | 1 + src/Ombi.Core/Senders/MusicSender.cs | 4 +- .../Services/RecentlyRequestedService.cs | 3 + src/Ombi.DependencyInjection/IocExtensions.cs | 2 + .../Checks/OmbiPingHealthCheck.cs | 47 -- .../Checks/OmbiPingHealthCheckOptions.cs | 16 - .../Checks/PlexHealthCheck.cs | 2 +- .../HealthCheckExtensions.cs | 31 - src/Ombi.I18n/Resources/Texts.hu.resx | 14 +- src/Ombi.I18n/Resources/Texts.nl.resx | 4 +- src/Ombi.I18n/Resources/Texts.no.resx | 18 +- .../NotificationMessageCurlys.cs | 3 + .../Jobs/Emby/EmbyContentSync.cs | 146 +---- .../Jobs/Emby/EmbyLibrarySync.cs | 146 +++++ src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs | 110 ++++ .../Jobs/Emby/IEmbyPlayedSync.cs | 6 + .../Jobs/Jellyfin/JellyfinContentSync.cs | 7 +- .../Jobs/Ombi/MediaDatabaseRefresh.cs | 29 +- src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs | 2 +- src/Ombi.Schedule/OmbiScheduler.cs | 1 + .../Settings/Models/FeatureSettings.cs | 1 + .../Settings/Models/JobSettingsHelper.cs | 5 +- src/Ombi.Store/Context/ExternalContext.cs | 1 + .../Entities/Requests/MovieRequests.cs | 5 + src/Ombi.Store/Entities/UserPlayedMovie.cs | 8 + ...20230406152218_MovieUserPlayed.Designer.cs | 566 ++++++++++++++++++ .../20230406152218_MovieUserPlayed.cs | 35 ++ .../ExternalMySqlContextModelSnapshot.cs | 19 +- ...20230310130339_MovieUserPlayed.Designer.cs | 564 +++++++++++++++++ .../20230310130339_MovieUserPlayed.cs | 32 + .../ExternalSqliteContextModelSnapshot.cs | 19 +- .../Repository/IUserPlayedMovieRepository.cs | 13 + .../Repository/UserPlayedMovieRepository.cs | 27 + src/Ombi/ClientApp/.yarnrc.yml | 4 + src/Ombi/ClientApp/package.json | 26 +- .../detailed-card.component.html | 18 +- .../detailed-card.component.scss | 4 + .../detailed-card/detailed-card.component.ts | 11 + .../discover/discover.component.html | 5 +- .../genre/genre-button-select.component.html | 13 + .../genre/genre-button-select.component.scss | 35 ++ .../genre/genre-button-select.component.ts | 49 ++ .../src/app/discover/components/index.ts | 2 + .../recently-requested-list.component.html | 9 +- .../recently-requested-list.component.ts | 19 +- .../search-results.component.html | 2 +- .../search-results.component.scss | 2 +- .../src/app/interfaces/IRecentlyRequested.ts | 1 + .../src/app/interfaces/IRequestModel.ts | 4 +- .../ClientApp/src/app/interfaces/ITester.ts | 1 + .../movie-information-panel.component.html | 19 +- .../movie-information-panel.component.ts | 24 + .../src/app/my-nav/nav-search.component.scss | 1 + .../movies-grid/movies-grid.component.html | 19 +- .../movies-grid/movies-grid.component.ts | 37 +- .../components/tv-grid/tv-grid.component.html | 4 +- .../app/settings/sonarr/sonarr.component.ts | 52 +- .../src/app/state/features/features.facade.ts | 4 +- .../app/state/features/features.selectors.ts | 7 +- .../src/app/state/radarr/radarr.state.ts | 2 +- .../src/app/state/sonarr/sonarr.state.ts | 4 +- src/Ombi/ClientApp/yarn.lock | 250 ++++---- .../V1/External/SonarrController.cs | 19 +- .../V1/External/TesterController.cs | 24 + src/Ombi/Controllers/V1/SettingsController.cs | 4 +- src/Ombi/Controllers/V2/SystemController.cs | 24 +- src/Ombi/wwwroot/translations/bg.json | 5 + src/Ombi/wwwroot/translations/ca.json | 5 + src/Ombi/wwwroot/translations/cs.json | 5 + src/Ombi/wwwroot/translations/da.json | 5 + src/Ombi/wwwroot/translations/de.json | 5 + src/Ombi/wwwroot/translations/en.json | 5 + src/Ombi/wwwroot/translations/es.json | 5 + src/Ombi/wwwroot/translations/fr.json | 5 + src/Ombi/wwwroot/translations/hu.json | 15 +- src/Ombi/wwwroot/translations/it.json | 7 +- src/Ombi/wwwroot/translations/nl.json | 225 +++---- src/Ombi/wwwroot/translations/no.json | 413 ++++++------- src/Ombi/wwwroot/translations/pl.json | 5 + src/Ombi/wwwroot/translations/pt-BR.json | 5 + src/Ombi/wwwroot/translations/pt.json | 5 + src/Ombi/wwwroot/translations/ru.json | 5 + src/Ombi/wwwroot/translations/sk.json | 5 + src/Ombi/wwwroot/translations/sv.json | 5 + src/Ombi/wwwroot/translations/zh-TW.json | 5 + src/Ombi/wwwroot/translations/zh.json | 5 + version.json | 2 +- 100 files changed, 2896 insertions(+), 1012 deletions(-) delete mode 100644 src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs delete mode 100644 src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs create mode 100644 src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs create mode 100644 src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs create mode 100644 src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs create mode 100644 src/Ombi.Store/Entities/UserPlayedMovie.cs create mode 100644 src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.Designer.cs create mode 100644 src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.cs create mode 100644 src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.Designer.cs create mode 100644 src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.cs create mode 100644 src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs create mode 100644 src/Ombi.Store/Repository/UserPlayedMovieRepository.cs create mode 100644 src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.html create mode 100644 src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.scss create mode 100644 src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a04f84d869..863e0ccbcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,345 +1,375 @@ -## [4.35.11](https://github.com/Ombi-app/Ombi/compare/v4.35.10...v4.35.11) (2023-05-17) +# [4.39.0](https://github.com/Ombi-app/Ombi/compare/v4.38.2...v4.39.0) (2023-05-17) +### Bug Fixes -## [4.35.10](https://github.com/Ombi-app/Ombi/compare/v4.22.5...v4.35.10) (2023-02-25) +* **emby:** Fix Emby played sync running a full sync during recently added sync ([#4932](https://github.com/Ombi-app/Ombi/issues/4932)) ([9424586](https://github.com/Ombi-app/Ombi/commit/9424586e9c1b622b6475aeb8ee3cf4a8f346da6e)) +### Features -## [4.22.5](https://github.com/Ombi-app/Ombi/compare/v4.16.12...v4.22.5) (2022-08-05) +* Hide watched status when request is not available ([#4934](https://github.com/Ombi-app/Ombi/issues/4934)) ([82c7f1c](https://github.com/Ombi-app/Ombi/commit/82c7f1c44fd7c87d57cc2b0c34a10fcda7628f4e)) -## [4.16.12](https://github.com/Ombi-app/Ombi/compare/v4.16.11...v4.16.12) (2022-04-19) +## [4.38.2](https://github.com/Ombi-app/Ombi/compare/v4.38.1...v4.38.2) (2023-05-17) -## [4.16.11](https://github.com/Ombi-app/Ombi/compare/v4.16.10...v4.16.11) (2022-04-14) +## [4.38.1](https://github.com/Ombi-app/Ombi/compare/v4.38.0...v4.38.1) (2023-05-09) ### Bug Fixes -* Set the default job for the watchlist import to hourly instead of daily ([75906af](https://github.com/Ombi-app/Ombi/commit/75906af0adee3e3c68d825c3aaa8f7b918461b1f)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([0e8a64b](https://github.com/Ombi-app/Ombi/commit/0e8a64b8ca00d210fbe843ac2c3f6af218d80cbc)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([7b0ad61](https://github.com/Ombi-app/Ombi/commit/7b0ad61bfcff3986b33180dc64022cba7ea8eefb)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([4fc2c1f](https://github.com/Ombi-app/Ombi/commit/4fc2c1f24534085a783a3d5791f5533b68272153)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([76ab733](https://github.com/Ombi-app/Ombi/commit/76ab733b91791e4d93d184f3c7d0779c6a388695)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([06e4cef](https://github.com/Ombi-app/Ombi/commit/06e4cefa7b4e55b860da9a64f461f6ec8fa17367)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([c12d89d](https://github.com/Ombi-app/Ombi/commit/c12d89d6781a337520977ad285f8d08c93f434dd)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([bc0c2f6](https://github.com/Ombi-app/Ombi/commit/bc0c2f622e34fb5a2711039d9ed7aad34f982b15)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([e4b00e6](https://github.com/Ombi-app/Ombi/commit/e4b00e6b3468bd9389eeb02fc6ad7daf27abc3b3)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d1998d3](https://github.com/Ombi-app/Ombi/commit/d1998d326f999a38586d0a351a20c5448df95842)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([bee4ccb](https://github.com/Ombi-app/Ombi/commit/bee4ccb804594e7385b1fbdc9fe2ef5c42e0d21f)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([80233ed](https://github.com/Ombi-app/Ombi/commit/80233ed560cc976e83570d0655c3472f20171fb3)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([8a78adc](https://github.com/Ombi-app/Ombi/commit/8a78adc9bb62f277f2b213dcb3847ed6d0089fcb)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d04c60a](https://github.com/Ombi-app/Ombi/commit/d04c60aa5909b47ba6bffa6f66b03079cbd43521)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([92a785e](https://github.com/Ombi-app/Ombi/commit/92a785e736fa4b72a45270da2d0f4661df433078)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([634982d](https://github.com/Ombi-app/Ombi/commit/634982df2661cefab5ea9f5163fe04a005cc0171)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([b404baa](https://github.com/Ombi-app/Ombi/commit/b404baad6d0aeaa1561701e0db8db4e78613a364)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d14f11e](https://github.com/Ombi-app/Ombi/commit/d14f11e0eb20ab0a68e765ee77968b3b3e54e995)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([7cf64f9](https://github.com/Ombi-app/Ombi/commit/7cf64f909d78908edaabeffb8a39a7d02e73fe7e)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([0c9e1ec](https://github.com/Ombi-app/Ombi/commit/0c9e1ec090827080cc8f7393e5e91456ff37d691)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([3b0b730](https://github.com/Ombi-app/Ombi/commit/3b0b730cb02efe24f6d4026e5fdb20d37e495119)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([6ed1a03](https://github.com/Ombi-app/Ombi/commit/6ed1a03b7ff4077f09ea9e13394b18b0d138f4c3)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([2941acd](https://github.com/Ombi-app/Ombi/commit/2941acd3b2ec74a5e6aeea275ab5a39d2653f37f)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([c075a1a](https://github.com/Ombi-app/Ombi/commit/c075a1a66784d975eaf60f2dfbbcbe048f2f63d7)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([76bd81c](https://github.com/Ombi-app/Ombi/commit/76bd81c3ca55a98c6ec944a838dc01294a6193a6)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([0d38275](https://github.com/Ombi-app/Ombi/commit/0d3827507e002bcf58f673e97ffcc3bd25dcf337)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([5c99601](https://github.com/Ombi-app/Ombi/commit/5c99601b07aec1a65d0186a4c4327440811e64c6)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([01546a0](https://github.com/Ombi-app/Ombi/commit/01546a0f7f86379528b486463246ef9bdfb9033e)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d7fea78](https://github.com/Ombi-app/Ombi/commit/d7fea7843aaaab7ddff8dc31ca6d2a9117471dcc)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([1a6b95d](https://github.com/Ombi-app/Ombi/commit/1a6b95d45c220310213b8d811272a63f0f6ff42b)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([fa10174](https://github.com/Ombi-app/Ombi/commit/fa1017422c4efd4b0897871bd3c671151774d7c3)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([0c31e62](https://github.com/Ombi-app/Ombi/commit/0c31e628df376aac6d56ae67c7c705a9a4a7c080)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([6399643](https://github.com/Ombi-app/Ombi/commit/63996437a02fe10ffae6822ffa15369bec0a6b36)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([5826e2d](https://github.com/Ombi-app/Ombi/commit/5826e2d9a1c3f1210a87fa270dc0c81bac32944a)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d434514](https://github.com/Ombi-app/Ombi/commit/d43451405be489254d7cdc7755d5f516a1e495a5)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([0b9596d](https://github.com/Ombi-app/Ombi/commit/0b9596d807178f5e071113ec0347868ec7f0960b)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([8c4c0b2](https://github.com/Ombi-app/Ombi/commit/8c4c0b262978c1303767af360d802c4b4c2b4d24)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([289ab77](https://github.com/Ombi-app/Ombi/commit/289ab77b0e04aae235b6f6cebc86e0a8d1f0cf2b)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([30e3417](https://github.com/Ombi-app/Ombi/commit/30e3417285a4eed18d429d7776f0e74096e834c0)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([6c0a5da](https://github.com/Ombi-app/Ombi/commit/6c0a5dadd4b8f37760252eb0fe7f88908f55506d)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d5bf969](https://github.com/Ombi-app/Ombi/commit/d5bf9692ce1fc0ccfe7beca6dd200c78be177bdc)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([8a9e7ea](https://github.com/Ombi-app/Ombi/commit/8a9e7ea588aefbcd73ed82625887e3614e1703ea)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([01047a3](https://github.com/Ombi-app/Ombi/commit/01047a3fd67153f3ff16f860d2c7b50213e8d9b2)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([698a23f](https://github.com/Ombi-app/Ombi/commit/698a23fb83f323cdd1dd57cb49803079d44214a7)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([24eb842](https://github.com/Ombi-app/Ombi/commit/24eb842fc4424f7bcc3ec2949d7f5472492e96f6)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([ac8b16a](https://github.com/Ombi-app/Ombi/commit/ac8b16a3051ad71dbd54a8973c7dd847b564a515)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([f428ce6](https://github.com/Ombi-app/Ombi/commit/f428ce6a700c081437703839bc84d2f2b1138bcc)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([94b16df](https://github.com/Ombi-app/Ombi/commit/94b16dfe09bf1d2cd6286777d74eb5d4496abbbb)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([4881775](https://github.com/Ombi-app/Ombi/commit/4881775eda69a8f136ce0d8fbbf970e3d0406dc9)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([8297db9](https://github.com/Ombi-app/Ombi/commit/8297db91e85da308bde6fb09ad78347dee063630)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([d1152ab](https://github.com/Ombi-app/Ombi/commit/d1152ab7674243daa528c524c0cdc87d81ad49c9)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([eb2788b](https://github.com/Ombi-app/Ombi/commit/eb2788b761b55c487a59a049427ca08f6c10e836)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([21a794c](https://github.com/Ombi-app/Ombi/commit/21a794cbc0a5fa735ca0347c8f7f1ac04a487fbc)) - - - -## [4.10.2](https://github.com/Ombi-app/Ombi/compare/v4.10.1...v4.10.2) (2022-01-22) - - - -## [4.16.10](https://github.com/Ombi-app/Ombi/compare/v4.16.9...v4.16.10) (2022-04-13) - - - -## [4.16.9](https://github.com/Ombi-app/Ombi/compare/v4.16.8...v4.16.9) (2022-04-13) +* **API:** Allow RequestOnBehalf rights if requested from the API ([#4919](https://github.com/Ombi-app/Ombi/issues/4919)) ([bb6dedd](https://github.com/Ombi-app/Ombi/commit/bb6deddfaecb3d6c7c3c6970414444b619bb9106)) +* **notificaitons:** Add the RequestedByAlias field to the Notification Message ([7e9c8be](https://github.com/Ombi-app/Ombi/commit/7e9c8bec6b02bb4e11f8db50394e493d4dd07723)) + + + +# [4.38.0](https://github.com/Ombi-app/Ombi/compare/v4.37.3...v4.38.0) (2023-05-07) ### Bug Fixes -* **plex-watchlist:** Only request the latest season when importing from the watchlist ([77a47ff](https://github.com/Ombi-app/Ombi/commit/77a47ff157c6c5feafe3f2a29a3fcba8df4fdfef)) +* remove sort header ([969bc7b](https://github.com/Ombi-app/Ombi/commit/969bc7bb25ea900ab9199509b079b36843e5bd6f)) +### Features -## [4.16.8](https://github.com/Ombi-app/Ombi/compare/v4.16.7...v4.16.8) (2022-04-13) +* **emby:** Show watched status for Movie requests ([9cfb10b](https://github.com/Ombi-app/Ombi/commit/9cfb10bb1ee69067a6f47bd2c8a72d4e6834350e)) + + + +## [4.37.3](https://github.com/Ombi-app/Ombi/compare/v4.37.2...v4.37.3) (2023-05-07) ### Bug Fixes -* **availability:** Fixed an issue where we wouldn't mark a available 4k movie as available (when 4K request feature is disabled) ([b492699](https://github.com/Ombi-app/Ombi/commit/b49269961d4830a530e3054976a47f519524948b)) +* Show the ApiAlias in the requests-list ([9ff624c](https://github.com/Ombi-app/Ombi/commit/9ff624ce4646815b239fbb8327117947f0a90e4b)) -## [4.16.7](https://github.com/Ombi-app/Ombi/compare/v4.16.6...v4.16.7) (2022-04-12) +## [4.37.2](https://github.com/Ombi-app/Ombi/compare/v4.37.1...v4.37.2) (2023-05-03) +### Bug Fixes -## [4.16.6](https://github.com/Ombi-app/Ombi/compare/v4.16.5...v4.16.6) (2022-04-11) +* **jellyfin:** Fixed an issue where the sync could stop working. Removed unused properties so the deseralization no longer fails ([0e5e0ad](https://github.com/Ombi-app/Ombi/commit/0e5e0adf862701d0f672beff14ec0aa75e4b5220)) -## [4.16.5](https://github.com/Ombi-app/Ombi/compare/v4.16.4...v4.16.5) (2022-04-08) +## [4.37.1](https://github.com/Ombi-app/Ombi/compare/v4.37.0...v4.37.1) (2023-05-02) ### Bug Fixes -* **watchlist:** actually fixed it this time... ([d962a32](https://github.com/Ombi-app/Ombi/commit/d962a3211eca29520662ddce962676e3aea17ec5)) +* Cron Validation ([#4842](https://github.com/Ombi-app/Ombi/issues/4842)) ([97cc42f](https://github.com/Ombi-app/Ombi/commit/97cc42ffa8672e7d0d0996b5fbda7f7fe699da2d)) +* **discover:** :children_crossing: Improved the new Genre buttons, it now includes TV results ([b087d60](https://github.com/Ombi-app/Ombi/commit/b087d606ff36565208e564f8856903f2a4098db5)) +* **lidarr:** Change monitor to Existing to properly add artist [#3597](https://github.com/Ombi-app/Ombi/issues/3597) ([506f607](https://github.com/Ombi-app/Ombi/commit/506f60773bf1031d0be51ccd34289b855a04ea40)), closes [/github.com/Lidarr/Lidarr/issues/3597#issuecomment-1530804055](https://github.com//github.com/Lidarr/Lidarr/issues/3597/issues/issuecomment-1530804055) -## [4.16.4](https://github.com/Ombi-app/Ombi/compare/v4.16.3...v4.16.4) (2022-04-08) +# [4.37.0](https://github.com/Ombi-app/Ombi/compare/v4.36.1...v4.37.0) (2023-04-24) +### Features -## [4.16.3](https://github.com/Ombi-app/Ombi/compare/v4.16.2...v4.16.3) (2022-04-08) +* Search by genre ([1837419](https://github.com/Ombi-app/Ombi/commit/18374198f9f2462ba85c5781b0fcc05892728b21)) + + + +## [4.36.1](https://github.com/Ombi-app/Ombi/compare/v4.36.0...v4.36.1) (2023-04-20) ### Bug Fixes -* **plex-watchlist:** :bug: Fixed the issue where the watchlist didn't work for users logging in via OAuth ([6398f6a](https://github.com/Ombi-app/Ombi/commit/6398f6a4f7755281ebeac537e3ff623df5cfa0f3)) +* **healthchecks:** Removed redundant ping check ([1751305](https://github.com/Ombi-app/Ombi/commit/1751305064176d2c0135f867773ccc46b03915ec)) + + + +# [4.36.0](https://github.com/Ombi-app/Ombi/compare/v4.35.19...v4.36.0) (2023-04-20) + + +### Features + +* **discover:** Add deny option to recently requested ([#4907](https://github.com/Ombi-app/Ombi/issues/4907)) ([78f340e](https://github.com/Ombi-app/Ombi/commit/78f340ee5f309c55690497170897533801957668)) -## [4.16.2](https://github.com/Ombi-app/Ombi/compare/v4.16.1...v4.16.2) (2022-04-07) +## [4.35.19](https://github.com/Ombi-app/Ombi/compare/v4.35.18...v4.35.19) (2023-04-20) ### Bug Fixes -* **wizard:** Fixed an issue when using Plex OAuth it could fail setting up ([b743cf4](https://github.com/Ombi-app/Ombi/commit/b743cf4fafa7341ad1b163276f006d7ab0e9dcff)) +* **radarr:** Fixed an issue where the radarr sync would break ([de4baad](https://github.com/Ombi-app/Ombi/commit/de4baade9f87248d77106ff1a313a498870f4fb3)) -## [4.16.1](https://github.com/Ombi-app/Ombi/compare/v4.16.0...v4.16.1) (2022-04-07) +## [4.35.18](https://github.com/Ombi-app/Ombi/compare/v4.35.17...v4.35.18) (2023-04-15) +### Bug Fixes + +* **#4906:** :bug: Fixed an issue with power users and permissions ([80884bc](https://github.com/Ombi-app/Ombi/commit/80884bcd725c329867c278ad235cd4096cd4fe7a)) + + + +## [4.35.17](https://github.com/Ombi-app/Ombi/compare/v4.35.16...v4.35.17) (2023-04-15) -# [4.16.0](https://github.com/Ombi-app/Ombi/compare/v4.15.6...v4.16.0) (2022-04-07) + +### Bug Fixes + +* **discover:** Fix denied requests displayed as approved ([#4901](https://github.com/Ombi-app/Ombi/issues/4901)) ([1e87f20](https://github.com/Ombi-app/Ombi/commit/1e87f2010491b0f3fdda70d2b19d9afd94438df7)) +* Fix denied movie shown as 'processing request' in details view ([#4900](https://github.com/Ombi-app/Ombi/issues/4900)) ([0069bfd](https://github.com/Ombi-app/Ombi/commit/0069bfdf54e0785bad45c832ca052f19fd4b940b)) -## [4.15.6](https://github.com/Ombi-app/Ombi/compare/v4.15.5...v4.15.6) (2022-04-07) +## [4.35.16](https://github.com/Ombi-app/Ombi/compare/v4.35.15...v4.35.16) (2023-04-13) ### Bug Fixes -* **radarr:** Fixed an issue where we couldn't sync radarr content [#4577](https://github.com/Ombi-app/Ombi/issues/4577) ([a5355a3](https://github.com/Ombi-app/Ombi/commit/a5355a3023e6900c4dd1b0da4722d7596c03907f)) +* Support duplicates in Emby/JF collections ([#4902](https://github.com/Ombi-app/Ombi/issues/4902)) ([141f96d](https://github.com/Ombi-app/Ombi/commit/141f96da5e45d5b3fa5f496806b102e473da6607)) + + +## [4.35.15](https://github.com/Ombi-app/Ombi/compare/v4.35.14...v4.35.15) (2023-04-06) -## [4.15.5](https://github.com/Ombi-app/Ombi/compare/v4.15.4...v4.15.5) (2022-04-06) +### Bug Fixes + +* **sonarr:** :bug: Stop the sonarr version endpoint from breaking when Sonarr is down [#4895](https://github.com/Ombi-app/Ombi/issues/4895) ([7bb8bec](https://github.com/Ombi-app/Ombi/commit/7bb8becfb140ef6012356752a71d53b5b404e482)) -## [4.15.4](https://github.com/Ombi-app/Ombi/compare/v4.15.3...v4.15.4) (2022-03-29) +## [4.35.14](https://github.com/Ombi-app/Ombi/compare/v4.35.13...v4.35.14) (2023-04-06) +### Bug Fixes -## [4.15.3](https://github.com/Ombi-app/Ombi/compare/v4.15.2...v4.15.3) (2022-03-24) +* Some minor tweaks to the movie info panel ([#4883](https://github.com/Ombi-app/Ombi/issues/4883)) ([1244487](https://github.com/Ombi-app/Ombi/commit/12444871df2f7602200f73971fce962f06b4a80b)) -## [4.15.2](https://github.com/Ombi-app/Ombi/compare/v4.15.1...v4.15.2) (2022-03-23) +## [4.35.13](https://github.com/Ombi-app/Ombi/compare/v4.35.12...v4.35.13) (2023-03-28) ### Bug Fixes -* **metadata:** improved the metadata job to also lookup the media in Plex to see if it has any more uptodate metadata ([83d1a15](https://github.com/Ombi-app/Ombi/commit/83d1a15cc9d0ee91be73bd91c4672cf1bcf2728a)) +* **sonarr:** :bug: Added some more error handling and information around testing sonarr ([bd2c2d3](https://github.com/Ombi-app/Ombi/commit/bd2c2d3901e239393010fd582b207f1571fb4b7e)), closes [#4877](https://github.com/Ombi-app/Ombi/issues/4877) -## [4.15.1](https://github.com/Ombi-app/Ombi/compare/v4.15.0...v4.15.1) (2022-03-18) +## [4.35.12](https://github.com/Ombi-app/Ombi/compare/v4.35.9...v4.35.12) (2023-03-25) ### Bug Fixes -* **mediaserver:** fixed an issue where we were not detecting available content correctly [#4542](https://github.com/Ombi-app/Ombi/issues/4542) ([9cdd6f4](https://github.com/Ombi-app/Ombi/commit/9cdd6f41cdab8825a984905c089611409c53c753)) +* **sonarr:** :bug: Improved the error handling in the sonarr settings page in the UI ([fcd78fe](https://github.com/Ombi-app/Ombi/commit/fcd78fee619d10ec7d78e8c8ec6c3ac4b0a361a1)), closes [#4877](https://github.com/Ombi-app/Ombi/issues/4877) + + +## [4.35.9](https://github.com/Ombi-app/Ombi/compare/v4.35.8...v4.35.9) (2023-02-24) -# [4.15.0](https://github.com/Ombi-app/Ombi/compare/v4.14.4...v4.15.0) (2022-03-17) + +## [4.22.5](https://github.com/Ombi-app/Ombi/compare/v4.22.4...v4.22.5) (2022-08-05) + + + +## [4.35.8](https://github.com/Ombi-app/Ombi/compare/v4.35.7...v4.35.8) (2023-02-17) ### Bug Fixes -* **jellyfin:** :bug: Fixed an issue where Jellyfin content was showing the Play on Emby button ([18b167d](https://github.com/Ombi-app/Ombi/commit/18b167d16a3d682b5060ee36dedbbb069bef09de)), closes [#4542](https://github.com/Ombi-app/Ombi/issues/4542) +* **plex-oauth:** 🐛 Fixed an issue where using OAuth you could log in as a Ombi Local user [#4835](https://github.com/Ombi-app/Ombi/issues/4835) ([4098da3](https://github.com/Ombi-app/Ombi/commit/4098da305aaea9dae9a552644268a4fed7204cfe)) -## [4.14.4](https://github.com/Ombi-app/Ombi/compare/v4.14.3...v4.14.4) (2022-03-10) +## [4.35.7](https://github.com/Ombi-app/Ombi/compare/v4.35.6...v4.35.7) (2023-02-10) ### Bug Fixes -* :bug: Fixed the Request On Behalf autocomplete not filtering correctly ([a8ba2f3](https://github.com/Ombi-app/Ombi/commit/a8ba2f3544a1c01c57f217c4036a277ab0e67a09)), closes [#4539](https://github.com/Ombi-app/Ombi/issues/4539) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([356c742](https://github.com/Ombi-app/Ombi/commit/356c7424e0ce8c1c5063b04bc6ed9b809f214d65)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([6fcaecf](https://github.com/Ombi-app/Ombi/commit/6fcaecf80b766f2d43ac7082d74364238e1638b7)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([132f4d4](https://github.com/Ombi-app/Ombi/commit/132f4d4e609b7fb7e37f38ee2f395926e2911abe)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([f292006](https://github.com/Ombi-app/Ombi/commit/f292006a08894a8d0ba899c8c6e9fe863e558dda)) +* **wizard:** :bug: Stop access to the wizard when you have already setup ombi ([#4866](https://github.com/Ombi-app/Ombi/issues/4866)) ([353de98](https://github.com/Ombi-app/Ombi/commit/353de981a462e1753288d225ec4644a44a62d2bc)) -## [4.14.3](https://github.com/Ombi-app/Ombi/compare/v4.14.2...v4.14.3) (2022-03-06) +## [4.35.6](https://github.com/Ombi-app/Ombi/compare/v4.35.5...v4.35.6) (2023-01-31) ### Bug Fixes -* **availability:** :bug: Fixed an issue where with 4k content, we could repeat notifications ([f9ebc1c](https://github.com/Ombi-app/Ombi/commit/f9ebc1cc2e13c7cd335121cd86295b10eda529ba)) +* Fixed the issue where the login page is still present after logging in with oauth ([aca4ee3](https://github.com/Ombi-app/Ombi/commit/aca4ee37915a28200e5233be3dc711ccc4a5aee9)) -## [4.14.2](https://github.com/Ombi-app/Ombi/compare/v4.14.1...v4.14.2) (2022-03-05) +## [4.35.5](https://github.com/Ombi-app/Ombi/compare/v4.35.4...v4.35.5) (2023-01-24) ### Bug Fixes -* **Sonarr:** :bug: Fixed an issue where some seasons were not being monitored correctly in sonarr ([60cfd41](https://github.com/Ombi-app/Ombi/commit/60cfd41f68e9006555c1a419dcff1aaa24b3e09f)), closes [#4506](https://github.com/Ombi-app/Ombi/issues/4506) +* **radarr-settings:** 🐛 Fixed a typo ([4a50a00](https://github.com/Ombi-app/Ombi/commit/4a50a00d4729d99f4359874b9af4dbc58a0c220b)) -## [4.14.1](https://github.com/Ombi-app/Ombi/compare/v4.14.0...v4.14.1) (2022-03-03) +## [4.35.4](https://github.com/Ombi-app/Ombi/compare/v4.35.3...v4.35.4) (2023-01-22) +### Bug Fixes -# [4.14.0](https://github.com/Ombi-app/Ombi/compare/v4.13.2...v4.14.0) (2022-03-02) +* **discover:** :bug: Fixed the default poster not taking into account the base url in some scenarios [#4845](https://github.com/Ombi-app/Ombi/issues/4845) ([8eda250](https://github.com/Ombi-app/Ombi/commit/8eda250367953183daec03ccb5cdf9fe94275b27)) +* **Hide music from navbar and request list when not enabled:** :bug: ([5123a76](https://github.com/Ombi-app/Ombi/commit/5123a76954e9f81d58c05e31afc7a29aec19cb7a)) -## [4.13.2](https://github.com/Ombi-app/Ombi/compare/v4.13.1...v4.13.2) (2022-03-01) +## [4.35.3](https://github.com/Ombi-app/Ombi/compare/v4.35.2...v4.35.3) (2023-01-13) ### Bug Fixes -* **requests:** :bug: Fixed an issue where you couldn't approve movies from the request list ([1611ef9](https://github.com/Ombi-app/Ombi/commit/1611ef9198befbb7a4db50a4f0953e50f29a788f)) +* **#4847:** Invalid Discord request fixed, also fixed an issue where App Only users would not show as logged in on the user management page ([#4848](https://github.com/Ombi-app/Ombi/issues/4848)) ([f229d88](https://github.com/Ombi-app/Ombi/commit/f229d88bd744bc5253b5d3db69ae5ef22d014230)) -## [4.13.1](https://github.com/Ombi-app/Ombi/compare/v4.13.0...v4.13.1) (2022-03-01) +## [4.35.2](https://github.com/Ombi-app/Ombi/compare/v4.35.1...v4.35.2) (2023-01-08) ### Bug Fixes -* **details:** :bug: Fixed the missing Play on Media server button for 4k content [#4529](https://github.com/Ombi-app/Ombi/issues/4529) ([68600f3](https://github.com/Ombi-app/Ombi/commit/68600f3b45376e12dd2ef263d81ca4040c84cbca)) -* **discover:** :bug: Fixed the issue where there was an option on the discover to request 4k shows (that's not supported currently) ([dcfd688](https://github.com/Ombi-app/Ombi/commit/dcfd688c8d2337e55fa9c6c33b7c3e80fc560cda)) -* **requests:** :bug: Fixed the issue where we could no longer approve TV Requests from the requests list ([19fe4e3](https://github.com/Ombi-app/Ombi/commit/19fe4e342efe5578c26ab8ba7ee2f2e64bbc9418)) -* **translations:** 🌐 New translations from Crowdin [skip ci] ([#4526](https://github.com/Ombi-app/Ombi/issues/4526)) ([7e9f54f](https://github.com/Ombi-app/Ombi/commit/7e9f54fc80a09c938184e6be40ce5f49ce9673ef)) +* **database:** Just some tweaks, shouldn't notice any difference, maybe a less error in the log ([67fb992](https://github.com/Ombi-app/Ombi/commit/67fb9921c0c025025286eb6c0a9d09fd01b18465)) -# [4.13.0](https://github.com/Ombi-app/Ombi/compare/v4.12.7...v4.13.0) (2022-02-25) +## [4.35.1](https://github.com/Ombi-app/Ombi/compare/v4.35.0...v4.35.1) (2023-01-06) ### Bug Fixes -* **4k:** Hide 'Has 4K Request' column list if 4k feature is disabled ([#4521](https://github.com/Ombi-app/Ombi/issues/4521)) ([a9a6067](https://github.com/Ombi-app/Ombi/commit/a9a60678e74d22fa7ba34051a2645db86b600b4a)) -* **issues:** Fix label ID in chatbox page ([#4520](https://github.com/Ombi-app/Ombi/issues/4520)) ([76882ad](https://github.com/Ombi-app/Ombi/commit/76882adf231f92e1cdd396239933c13467c112b3)) -* **localisation:** Localize request types in notifications ([#4516](https://github.com/Ombi-app/Ombi/issues/4516)) ([e09435d](https://github.com/Ombi-app/Ombi/commit/e09435da455b12fc429f129372de31e0654da797)) -* **notifications:** Remove generic admin email in favour of admins' email ([#4519](https://github.com/Ombi-app/Ombi/issues/4519)) ([b90fc5f](https://github.com/Ombi-app/Ombi/commit/b90fc5fea771a83e6cf576c71a307066efd59ea4)) -* **tv:** Display TV show as requested if all episodes are requested ([#4518](https://github.com/Ombi-app/Ombi/issues/4518)) ([2ed8c48](https://github.com/Ombi-app/Ombi/commit/2ed8c48d128a69f0d144c5d332286dbf3b0bdf28)) +* **plex-watchlist:** Index out of bounds error ([8cd556e](https://github.com/Ombi-app/Ombi/commit/8cd556e268931596b9c1d1ae0ce533bfaaf330f4)) + + + +# [4.35.0](https://github.com/Ombi-app/Ombi/compare/v4.34.1...v4.35.0) (2023-01-04) ### Features -* **email-notifications:** Add a link to Ombi details page in email notifications ([#4517](https://github.com/Ombi-app/Ombi/issues/4517)) ([a3e97b3](https://github.com/Ombi-app/Ombi/commit/a3e97b31e2298d95e7deebd71268095b8ed5e9dc)) -* **media-details:** Add Trakt to social icons ([#4522](https://github.com/Ombi-app/Ombi/issues/4522)) ([d6ae79c](https://github.com/Ombi-app/Ombi/commit/d6ae79ce9eddbd5b7b888ab1b9f7e342d9d9ff9e)) +* Add the option for header authentication to create users ([#4841](https://github.com/Ombi-app/Ombi/issues/4841)) ([e6c9ce5](https://github.com/Ombi-app/Ombi/commit/e6c9ce5ad0056608ecda8273fb8124ed292e2942)) + + + +## [4.34.1](https://github.com/Ombi-app/Ombi/compare/v4.34.0...v4.34.1) (2023-01-04) + + +### Bug Fixes + +* **plex-watchlist:** Lookup the ID from different sources when Plex doesn't contain the metadata ([#4843](https://github.com/Ombi-app/Ombi/issues/4843)) ([a2cc23b](https://github.com/Ombi-app/Ombi/commit/a2cc23b351c4a568c44e6c855f94db9f71ad084a)) -## [4.12.7](https://github.com/Ombi-app/Ombi/compare/v4.12.6...v4.12.7) (2022-02-23) +# [4.34.0](https://github.com/Ombi-app/Ombi/compare/v4.33.1...v4.34.0) (2023-01-04) +### Features + +* Radarr tags ([#4815](https://github.com/Ombi-app/Ombi/issues/4815)) ([6fa5064](https://github.com/Ombi-app/Ombi/commit/6fa506491fe867cdeef9df79991ae49319d71c3d)) + -## [4.12.6](https://github.com/Ombi-app/Ombi/compare/v4.12.5...v4.12.6) (2022-02-22) + +## [4.33.1](https://github.com/Ombi-app/Ombi/compare/v4.33.0...v4.33.1) (2022-12-22) ### Bug Fixes -* **emby/jellyfin:** :bug: Fixed another issue where we were not correctly displaying the correct status' for movies ([5c0556e](https://github.com/Ombi-app/Ombi/commit/5c0556e6f44b8997a611f3a4d8e9e4e05d08bd13)) -* **mediaserver:** fixed some more issues in the media server sync and availability checks ([f3ea979](https://github.com/Ombi-app/Ombi/commit/f3ea979b8bd77842780ce8e6928b16237dd779cf)) +* **plex:** Added the watchlist request whole show back into the settings ([10701c4](https://github.com/Ombi-app/Ombi/commit/10701c4a0b6190eebb75c5d8b18224f3d0bc8502)) + + + +# [4.33.0](https://github.com/Ombi-app/Ombi/compare/v4.32.3...v4.33.0) (2022-12-01) + + +### Features + +* Angular 15 and Dependency upgrades ([#4818](https://github.com/Ombi-app/Ombi/issues/4818)) ([4816acf](https://github.com/Ombi-app/Ombi/commit/4816acf6f94443d23ebef6091d4cfcbca580f9ca)) -## [4.12.5](https://github.com/Ombi-app/Ombi/compare/v4.12.4...v4.12.5) (2022-02-21) +## [4.32.3](https://github.com/Ombi-app/Ombi/compare/v4.32.2...v4.32.3) (2022-11-24) ### Bug Fixes -* **emby:** :bug: Fixed the emby content sync [#4513](https://github.com/Ombi-app/Ombi/issues/4513) ([2927504](https://github.com/Ombi-app/Ombi/commit/2927504f0e0b4e7251e69b44e0e30c7ec9519980)) -* **emby:** :bug: Fixed the emby content sync [#4513](https://github.com/Ombi-app/Ombi/issues/4513) ([bd441cb](https://github.com/Ombi-app/Ombi/commit/bd441cb54fd77d6befb03fae321dc36c29f0de2e)) +* **sonarr:** V4 actually works this time around ([f62e70f](https://github.com/Ombi-app/Ombi/commit/f62e70fc493c7971da5e4508ce10522f5df0bbf7)) -## [4.12.4](https://github.com/Ombi-app/Ombi/compare/v4.12.3...v4.12.4) (2022-02-17) +## [4.32.2](https://github.com/Ombi-app/Ombi/compare/v4.32.1...v4.32.2) (2022-11-23) +### Bug Fixes -## [4.12.3](https://github.com/Ombi-app/Ombi/compare/v4.12.2...v4.12.3) (2022-02-16) +* **sonarr:** :bug: Sonarr V4 should work now ([#4810](https://github.com/Ombi-app/Ombi/issues/4810)) ([37655af](https://github.com/Ombi-app/Ombi/commit/37655aff9d3d133b42f5664bc9445d6571e966d6)) -## [4.12.2](https://github.com/Ombi-app/Ombi/compare/v4.12.1...v4.12.2) (2022-02-16) +## [4.32.1](https://github.com/Ombi-app/Ombi/compare/v4.32.0...v4.32.1) (2022-11-21) ### Bug Fixes -* **requests:** :bug: Fixed the approve 4k option on the requests list not working as expected ([c0189da](https://github.com/Ombi-app/Ombi/commit/c0189dad478ea375beda61ba3bee3f029a39b8e5)) +* **plex:** :bug: Fixed the issue where you couldn't add a new server on a fresh setup after the settings page rework ([187b18d](https://github.com/Ombi-app/Ombi/commit/187b18d5c01f6a13831e4a410b5d7c349e27d847)) -## [4.12.1](https://github.com/Ombi-app/Ombi/compare/v4.12.0...v4.12.1) (2022-02-16) +# [4.32.0](https://github.com/Ombi-app/Ombi/compare/v4.31.0...v4.32.0) (2022-11-18) ### Bug Fixes -* **requests:** :bug: Fixed the issue where Approving a 4K Request wouldn't send it to the correct 4K radarr instance ([87cb990](https://github.com/Ombi-app/Ombi/commit/87cb9903db30e1dead25ee8c5ea34305eb084a03)), closes [#4509](https://github.com/Ombi-app/Ombi/issues/4509) +* **translations:** 🌐 New translations from Crowdin [skip ci] ([#4801](https://github.com/Ombi-app/Ombi/issues/4801)) ([4692003](https://github.com/Ombi-app/Ombi/commit/46920032baed04675b2ffbe1700afdc0740a4ac4)) + + +### Features + +* **plex:** Rework the Plex Settings page ([#4805](https://github.com/Ombi-app/Ombi/issues/4805)) ([1b8c47f](https://github.com/Ombi-app/Ombi/commit/1b8c47f3163f618851d4904732cb07015e1e93ff)) + + + +# [4.31.0](https://github.com/Ombi-app/Ombi/compare/v4.30.0...v4.31.0) (2022-11-18) + + +### Features + +* **sonarr:** Added the ability to add default tags when sending to Sonarr ([#4803](https://github.com/Ombi-app/Ombi/issues/4803)) ([ecfbb8e](https://github.com/Ombi-app/Ombi/commit/ecfbb8eda91e1a90239dcf8be847afcc2394a78e)) -# [4.12.0](https://github.com/Ombi-app/Ombi/compare/v4.11.8...v4.12.0) (2022-02-14) +# [4.30.0](https://github.com/Ombi-app/Ombi/compare/v4.29.3...v4.30.0) (2022-11-17) ### Features -* **radarr:** 4K Requests and Radarr 4K support ([ba88848](https://github.com/Ombi-app/Ombi/commit/ba88848866b0a9dedb1e79b55c4d81a0fd453843)) +* **sonarr:** :sparkles: Add the username to a Sonarr tag when sent to Sonarr ([#4802](https://github.com/Ombi-app/Ombi/issues/4802)) ([1d5fabd](https://github.com/Ombi-app/Ombi/commit/1d5fabd317e3ce8f6dd31f06d15dc81277f39dbd)) + + + +## [4.29.3](https://github.com/Ombi-app/Ombi/compare/v4.29.2...v4.29.3) (2022-11-14) + + +### Bug Fixes + +* **notifications:** Fixed the Partially TV notifications going to the admin [#4797](https://github.com/Ombi-app/Ombi/issues/4797) ([#4799](https://github.com/Ombi-app/Ombi/issues/4799)) ([bcb3e7f](https://github.com/Ombi-app/Ombi/commit/bcb3e7f00380a4c4278f59dc55febf43e6d05d47)) +* Only log error messages from Microsoft ([#4787](https://github.com/Ombi-app/Ombi/issues/4787)) ([c614e0c](https://github.com/Ombi-app/Ombi/commit/c614e0ca5fe5023cbe7ced326145273cd75be85d)) -## [4.11.8](https://github.com/Ombi-app/Ombi/compare/v4.11.7...v4.11.8) (2022-02-13) +## [4.29.2](https://github.com/Ombi-app/Ombi/compare/v4.29.1...v4.29.2) (2022-10-24) ### Bug Fixes -* **settings:** :bug: Fixed an issue where we were not displaying the excluded keyworks correctly in the TheMovieDbSettings page ([d3b3316](https://github.com/Ombi-app/Ombi/commit/d3b3316cbac18356b2f6b0912a3deb2c183e6534)) +* **plex:** Fixed an issue where sometimes the availability checker would throw an exception when checking episodes ([17ba202](https://github.com/Ombi-app/Ombi/commit/17ba2020ee0950c2c0e0e03fdb7835b579da75a9)) diff --git a/README.md b/README.md index c42059e789..ec40a056f1 100644 --- a/README.md +++ b/README.md @@ -85,13 +85,6 @@ Here are some of the features Ombi has: Twan Ariens - - - Drewster727 -
- Drew -
- sephrat @@ -112,15 +105,15 @@ Here are some of the features Ombi has:
Magikarp Lvl 4
- - + MrTopCat
James Carty
- + + smcpeck @@ -155,15 +148,15 @@ Here are some of the features Ombi has:
Joshua M. Boniface
- - + bruvv
Bruvv
- + + louis-lau @@ -198,15 +191,15 @@ Here are some of the features Ombi has:
Jim MacKenize
- - + Unimatrix0
Avi
- + + kitzin @@ -241,15 +234,15 @@ Here are some of the features Ombi has:
Francesco Servida
- - + Patricol
Patrick Collins
- + + xweskingx @@ -284,15 +277,15 @@ Here are some of the features Ombi has:
Aptalca
- - + dr3am37
Dr3amer
- + + mhann @@ -307,6 +300,13 @@ Here are some of the features Ombi has: Ombi-bot + + + phildups7 +
+ Phildups7 +
+ snyk-bot @@ -415,6 +415,13 @@ Here are some of the features Ombi has: + + + aj3x +
+ Alexander Russell +
+ XanderStrike @@ -449,15 +456,15 @@ Here are some of the features Ombi has:
Calvin
- + + origamirobot
Chris Lees
- - + cdemi @@ -492,15 +499,15 @@ Here are some of the features Ombi has:
David Torosyan
- + + onedr0p
Devin Buhl
- - + elisspace @@ -515,6 +522,13 @@ Here are some of the features Ombi has: Fish2 + + + Grygon +
+ Grygon +
+ ketsapiwiq @@ -528,7 +542,8 @@ Here are some of the features Ombi has:
Haries Ramdhani
- + + comigor @@ -542,8 +557,7 @@ Here are some of the features Ombi has:
Imgbot
- - + JPyke3 @@ -571,7 +585,8 @@ Here are some of the features Ombi has:
Joe Harvey
- + + jonbloom @@ -585,8 +600,7 @@ Here are some of the features Ombi has:
Jono Cairns
- - + krisklosterman @@ -614,7 +628,8 @@ Here are some of the features Ombi has:
Lightkeeper
- + + Lucane @@ -628,8 +643,7 @@ Here are some of the features Ombi has:
Madeleine Schönemann
- - + marleypowell @@ -657,7 +671,8 @@ Here are some of the features Ombi has:
Micky
- + + mvicomoya @@ -671,8 +686,7 @@ Here are some of the features Ombi has:
Nathan Miller
- - + cqxmzz @@ -700,7 +714,8 @@ Here are some of the features Ombi has:
Sean Callinan
- + + shoghicp @@ -714,8 +729,7 @@ Here are some of the features Ombi has:
Teifun2
- - + thomasvt1 @@ -743,7 +757,8 @@ Here are some of the features Ombi has:
Torkil
- + + bybeet @@ -757,8 +772,7 @@ Here are some of the features Ombi has:
Xirg
- - + bazhip @@ -786,7 +800,8 @@ Here are some of the features Ombi has:
Michael DiStaula
- + + baikunz @@ -800,8 +815,7 @@ Here are some of the features Ombi has:
Echel0n
- - + m4tta @@ -829,6 +843,14 @@ Here are some of the features Ombi has:
Mkgeeky
+ + + + + ryan-c44 +
+ Ryan-c44 +
@@ -843,8 +865,7 @@ Here are some of the features Ombi has:
Tdorsey
- - + thegame3202 diff --git a/src/Ombi.Api.Emby/EmbyApi.cs b/src/Ombi.Api.Emby/EmbyApi.cs index e9e5f0fca7..d8691d9845 100644 --- a/src/Ombi.Api.Emby/EmbyApi.cs +++ b/src/Ombi.Api.Emby/EmbyApi.cs @@ -248,5 +248,37 @@ private static void AddHeaders(Request req, string apiKey) req.AddContentHeader("Content-Type", "application/json"); req.AddHeader("Device", "Ombi"); } + + public async Task> GetMoviesPlayed(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri) + { + return await GetPlayed("Movie", apiKey, userId, baseUri, startIndex, count, parentIdFilder); + } + + private async Task> GetPlayed(string type, string apiKey, string userId, string baseUri, int startIndex, int count, string parentIdFilder = default) + { + var request = new Request($"emby/items", baseUri, HttpMethod.Get); + + request.AddQueryString("Recursive", true.ToString()); + request.AddQueryString("IncludeItemTypes", type); + request.AddQueryString("Fields", "ProviderIds"); + request.AddQueryString("UserId", userId); + request.AddQueryString("isPlayed", true.ToString()); + + // paginate and display recently played items first + request.AddQueryString("sortBy", "DatePlayed"); + request.AddQueryString("SortOrder", "Descending"); + request.AddQueryString("startIndex", startIndex.ToString()); + request.AddQueryString("limit", count.ToString()); + + if (!string.IsNullOrEmpty(parentIdFilder)) + { + request.AddQueryString("ParentId", parentIdFilder); + } + + AddHeaders(request, apiKey); + + var obj = await Api.Request>(request); + return obj; + } } } diff --git a/src/Ombi.Api.Emby/IBaseEmbyApi.cs b/src/Ombi.Api.Emby/IBaseEmbyApi.cs index 248c0a88f9..582eac0c91 100644 --- a/src/Ombi.Api.Emby/IBaseEmbyApi.cs +++ b/src/Ombi.Api.Emby/IBaseEmbyApi.cs @@ -32,5 +32,7 @@ Task> GetCollection(string mediaId, Task> RecentlyAddedMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri); Task> RecentlyAddedEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri); Task> RecentlyAddedShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri); + + Task> GetMoviesPlayed(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri); } } \ No newline at end of file diff --git a/src/Ombi.Api.Emby/Models/Media/Movie/EmbyMovie.cs b/src/Ombi.Api.Emby/Models/Media/Movie/EmbyMovie.cs index e127f75f62..3e8f5407e8 100644 --- a/src/Ombi.Api.Emby/Models/Media/Movie/EmbyMovie.cs +++ b/src/Ombi.Api.Emby/Models/Media/Movie/EmbyMovie.cs @@ -5,30 +5,8 @@ namespace Ombi.Api.Emby.Models.Movie public class EmbyMovie { public string Name { get; set; } - public string ServerId { get; set; } public string Id { get; set; } - public string Container { get; set; } - public DateTime PremiereDate { get; set; } - public object[] ProductionLocations { get; set; } - public string OfficialRating { get; set; } - public float CommunityRating { get; set; } - public long RunTimeTicks { get; set; } - public string PlayAccess { get; set; } - public int ProductionYear { get; set; } - public bool IsPlaceHolder { get; set; } - public bool IsHD { get; set; } - public bool IsFolder { get; set; } public string Type { get; set; } - public int LocalTrailerCount { get; set; } - public EmbyUserdata UserData { get; set; } - public string VideoType { get; set; } - public EmbyImagetags ImageTags { get; set; } - public string[] BackdropImageTags { get; set; } - public string LocationType { get; set; } - public string MediaType { get; set; } - public bool HasSubtitles { get; set; } - public int CriticRating { get; set; } - public string Overview { get; set; } public EmbyProviderids ProviderIds { get; set; } public EmbyMediastream[] MediaStreams { get; set; } } diff --git a/src/Ombi.Api.Jellyfin/Models/Media/Movie/JellyfinMovie.cs b/src/Ombi.Api.Jellyfin/Models/Media/Movie/JellyfinMovie.cs index a83e1f0879..7368c194e4 100644 --- a/src/Ombi.Api.Jellyfin/Models/Media/Movie/JellyfinMovie.cs +++ b/src/Ombi.Api.Jellyfin/Models/Media/Movie/JellyfinMovie.cs @@ -5,30 +5,8 @@ namespace Ombi.Api.Jellyfin.Models.Movie public class JellyfinMovie { public string Name { get; set; } - public string ServerId { get; set; } public string Id { get; set; } - public string Container { get; set; } - public DateTime PremiereDate { get; set; } - public object[] ProductionLocations { get; set; } - public string OfficialRating { get; set; } - public float CommunityRating { get; set; } - public long RunTimeTicks { get; set; } - public string PlayAccess { get; set; } - public int ProductionYear { get; set; } - public bool IsPlaceHolder { get; set; } - public bool IsHD { get; set; } - public bool IsFolder { get; set; } public string Type { get; set; } - public int LocalTrailerCount { get; set; } - public JellyfinUserdata UserData { get; set; } - public string VideoType { get; set; } - public JellyfinImagetags ImageTags { get; set; } - public string[] BackdropImageTags { get; set; } - public string LocationType { get; set; } - public string MediaType { get; set; } - public bool HasSubtitles { get; set; } - public int CriticRating { get; set; } - public string Overview { get; set; } public JellyfinProviderids ProviderIds { get; set; } public JellyfinMediastream[] MediaStreams { get; set; } } diff --git a/src/Ombi.Api.Sonarr/Models/SystemStatus.cs b/src/Ombi.Api.Sonarr/Models/SystemStatus.cs index 778570a4c7..a784293289 100644 --- a/src/Ombi.Api.Sonarr/Models/SystemStatus.cs +++ b/src/Ombi.Api.Sonarr/Models/SystemStatus.cs @@ -3,23 +3,6 @@ namespace Ombi.Api.Sonarr public class SystemStatus { public string version { get; set; } - public string buildTime { get; set; } - public bool isDebug { get; set; } - public bool isProduction { get; set; } - public bool isAdmin { get; set; } - public bool isUserInteractive { get; set; } - public string startupPath { get; set; } - public string appData { get; set; } - public string osVersion { get; set; } - public bool isMonoRuntime { get; set; } - public bool isMono { get; set; } - public bool isLinux { get; set; } - public bool isOsx { get; set; } - public bool isWindows { get; set; } - public string branch { get; set; } - public string authentication { get; set; } - public string sqliteVersion { get; set; } public string urlBase { get; set; } - public string runtimeVersion { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs b/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs index 8418cddbca..c55d76e8f0 100644 --- a/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs +++ b/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs @@ -52,6 +52,7 @@ public void Setup() _subject = _mocker.CreateInstance(); var list = DbHelper.GetQueryableMockDbSet(new RequestSubscription()); _mocker.Setup, IQueryable>(x => x.GetAll()).Returns(new List().AsQueryable().BuildMock()); + _mocker.Setup>(x => x.GetAll()).Returns(new List().AsQueryable().BuildMock()); } [Test] diff --git a/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs b/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs index 16b7cb8117..c483d81ba5 100644 --- a/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs +++ b/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs @@ -46,8 +46,9 @@ public void Setup() var requestSubs = new Mock>(); var mediaCache = new Mock(); var featureService = new Mock(); + var userPlayedMovieRepository = new Mock(); _engine = new MovieRequestEngine(movieApi.Object, requestService.Object, user.Object, notificationHelper.Object, rules.Object, movieSender.Object, - logger.Object, userManager.Object, requestLogRepo.Object, cache.Object, ombiSettings.Object, requestSubs.Object, mediaCache.Object, featureService.Object); + logger.Object, userManager.Object, requestLogRepo.Object, cache.Object, ombiSettings.Object, requestSubs.Object, mediaCache.Object, featureService.Object, userPlayedMovieRepository.Object); } [Test] diff --git a/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs b/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs index 7e1046ca5a..dc748e0d91 100644 --- a/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs +++ b/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs @@ -173,6 +173,7 @@ public async Task GetRecentlyRequested() [Test] + [Ignore("Flaky")] public async Task GetRecentlyRequested_HideUsernames() { _mocker.Setup, Task>(x => x.GetSettingsAsync()) diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 109460ff95..4d3cd2cf9f 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -33,7 +33,8 @@ public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestServi INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger log, OmbiUserManager manager, IRepository rl, ICacheService cache, ISettingsService ombiSettings, IRepository sub, IMediaCacheService mediaCacheService, - IFeatureService featureService) + IFeatureService featureService, + IUserPlayedMovieRepository userPlayedMovieRepository) : base(user, requestService, r, manager, cache, ombiSettings, sub) { MovieApi = movieApi; @@ -43,6 +44,7 @@ public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestServi _requestLog = rl; _mediaCacheService = mediaCacheService; _featureService = featureService; + _userPlayedMovieRepository = userPlayedMovieRepository; } private IMovieDbApi MovieApi { get; } @@ -52,6 +54,7 @@ public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestServi private readonly IRepository _requestLog; private readonly IMediaCacheService _mediaCacheService; private readonly IFeatureService _featureService; + protected readonly IUserPlayedMovieRepository _userPlayedMovieRepository; /// /// Requests the movie. @@ -77,7 +80,8 @@ public async Task RequestMovie(MovieRequestViewModel model) var userDetails = await GetUser(); var canRequestOnBehalf = model.RequestOnBehalf.HasValue(); - var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) + var isAdmin = Username.Equals("API", StringComparison.CurrentCultureIgnoreCase) + || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin); if (canRequestOnBehalf && !isAdmin) { @@ -252,7 +256,7 @@ public async Task> GetRequests(int count, int p var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) .ToListAsync(); - await CheckForSubscription(shouldHide.UserId, requests); + await FillAdditionalFields(shouldHide, requests); return new RequestsViewModel { Collection = requests, @@ -296,7 +300,7 @@ public async Task> GetRequests(int count, int p var total = requests.Count(); requests = requests.Skip(position).Take(count).ToList(); - await CheckForSubscription(shouldHide.UserId, requests); + await FillAdditionalFields(shouldHide, requests); return new RequestsViewModel { Collection = requests, @@ -381,7 +385,7 @@ public async Task> GetRequestsByStatus(int coun // TODO fix this so we execute this on the server requests = requests.Skip(position).Take(count).ToList(); - await CheckForSubscription(shouldHide.UserId, requests); + await FillAdditionalFields(shouldHide, requests); return new RequestsViewModel { Collection = requests, @@ -424,7 +428,7 @@ public async Task> GetUnavailableRequests(int c var total = requests.Count(); requests = requests.Skip(position).Take(count).ToList(); - await CheckForSubscription(shouldHide.UserId, requests); + await FillAdditionalFields(shouldHide, requests); return new RequestsViewModel { Collection = requests, @@ -506,18 +510,25 @@ public async Task> GetRequests() allRequests = await MovieRepository.GetWithUser().ToListAsync(); } - await CheckForSubscription(shouldHide.UserId, allRequests); + await FillAdditionalFields(shouldHide, allRequests); return allRequests; } public async Task GetRequest(int requestId) { + var shouldHide = await HideFromOtherUsers(); + // TODO: this query should return the request only if the user is allowed to see it (see shouldHide implementations) var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync(); - await CheckForSubscription((await GetUser()).Id, new List { request }); + await FillAdditionalFields(shouldHide, new List { request }); return request; } + private async Task FillAdditionalFields(HideResult shouldHide, List requests) + { + await CheckForSubscription(shouldHide.UserId, requests); + await CheckForPlayed(shouldHide, requests); + } private async Task CheckForSubscription(string UserId, List movieRequests) { @@ -543,6 +554,23 @@ private async Task CheckForSubscription(string UserId, List movie } } } + + private async Task CheckForPlayed(HideResult shouldHide, List movieRequests) + { + var theMovieDbIds = movieRequests.Select(x => x.TheMovieDbId); + var plays = await _userPlayedMovieRepository.GetAll().Where(x => + theMovieDbIds.Contains(x.TheMovieDbId)) + .ToListAsync(); + foreach (var request in movieRequests) + { + request.WatchedByRequestedUser = plays.Exists(x => x.TheMovieDbId == request.TheMovieDbId && x.UserId == request.RequestedUserId); + + if (!shouldHide.Hide) + { + request.PlayedByUsersCount = plays.Count(x => x.TheMovieDbId == request.TheMovieDbId); + } + } + } /// /// Searches the movie request. @@ -563,7 +591,7 @@ public async Task> SearchMovieRequest(string search) } var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); - await CheckForSubscription(shouldHide.UserId, results); + await FillAdditionalFields(shouldHide, results); return results; } diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index 8ccc6d17e8..5ebce95863 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -161,7 +161,7 @@ public async Task RequestTvShow(TvRequestViewModelV2 tv) var user = await GetUser(); var canRequestOnBehalf = tv.RequestOnBehalf.HasValue(); - var isAdmin = await UserManager.IsInRoleAsync(user, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(user, OmbiRoles.Admin); + var isAdmin = Username.Equals("API", StringComparison.CurrentCultureIgnoreCase) || await UserManager.IsInRoleAsync(user, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(user, OmbiRoles.Admin); if (tv.RequestOnBehalf.HasValue() && !isAdmin) { return new RequestEngineResult diff --git a/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs b/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs index 4296c2cc1a..daab65e71f 100644 --- a/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs +++ b/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs @@ -16,6 +16,7 @@ public class RecentlyRequestedModel public string Overview { get; set; } public DateTime ReleaseDate { get; set; } public bool Approved { get; set; } + public bool Denied { get; set; } public string MediaId { get; set; } public string PosterPath { get; set; } diff --git a/src/Ombi.Core/Models/TesterResultModel.cs b/src/Ombi.Core/Models/TesterResultModel.cs index 563fa5cb20..945e0e2619 100644 --- a/src/Ombi.Core/Models/TesterResultModel.cs +++ b/src/Ombi.Core/Models/TesterResultModel.cs @@ -5,5 +5,6 @@ public class TesterResultModel public bool IsValid { get; set; } public string Version { get; set; } public string ExpectedSubDir { get; set; } + public string AdditionalInformation { get; set; } } } diff --git a/src/Ombi.Core/Senders/MusicSender.cs b/src/Ombi.Core/Senders/MusicSender.cs index 260b008feb..57bf4ab685 100644 --- a/src/Ombi.Core/Senders/MusicSender.cs +++ b/src/Ombi.Core/Senders/MusicSender.cs @@ -100,7 +100,7 @@ private async Task SendToLidarr(AlbumRequest model, LidarrSettings addOptions = new Addoptions { monitored = true, - monitor = MonitorTypes.None, + monitor = MonitorTypes.Existing, searchForMissingAlbums = false, AlbumsToMonitor = new[] {model.ForeignAlbumId} }, @@ -199,4 +199,4 @@ private async Task SetupAlbum(AlbumRequest model, ArtistResult art return new SenderResult { Message = "Could not set album to monitored", Sent = false, Success = false }; } } -} \ No newline at end of file +} diff --git a/src/Ombi.Core/Services/RecentlyRequestedService.cs b/src/Ombi.Core/Services/RecentlyRequestedService.cs index 6628dd8b89..26d873c4d7 100644 --- a/src/Ombi.Core/Services/RecentlyRequestedService.cs +++ b/src/Ombi.Core/Services/RecentlyRequestedService.cs @@ -88,6 +88,7 @@ public async Task> GetRecentlyRequested(Canc Title = item.Title, Type = RequestType.Movie, Approved = item.Approved, + Denied = item.Denied ?? false, UserId = item.RequestedUserId, Username = item.RequestedUser.UserAlias, MediaId = item.TheMovieDbId.ToString(), @@ -108,6 +109,7 @@ public async Task> GetRecentlyRequested(Canc Available = item.Available, Overview = item.ArtistName, Approved = item.Approved, + Denied = item.Denied ?? false, ReleaseDate = item.ReleaseDate, RequestDate = item.RequestedDate, Title = item.Title, @@ -135,6 +137,7 @@ public async Task> GetRecentlyRequested(Canc Overview = item.ParentRequest.Overview, ReleaseDate = item.ParentRequest.ReleaseDate, Approved = item.Approved, + Denied = item.Denied ?? false, RequestDate = item.RequestedDate, TvPartiallyAvailable = partialAvailability, Title = item.ParentRequest.Title, diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 09d99d4b76..c9bcc13d37 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -197,6 +197,7 @@ public static void RegisterStore(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -244,6 +245,7 @@ public static void RegisterJobs(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs deleted file mode 100644 index 726d020788..0000000000 --- a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs +++ /dev/null @@ -1,47 +0,0 @@ -using HealthChecks.Network; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using System; -using System.Collections.Generic; -using System.Net.NetworkInformation; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Ombi.HealthChecks.Checks -{ - public class OmbiPingHealthCheck - : IHealthCheck - { - private readonly OmbiPingHealthCheckOptions _options; - public OmbiPingHealthCheck(OmbiPingHealthCheckOptions options) - { - _options = options ?? throw new ArgumentNullException(nameof(options)); - } - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) - { - var configuredHosts = _options.ConfiguredHosts.Values; - - try - { - foreach (var (host, timeout, status) in configuredHosts) - { - using (var ping = new Ping()) - { - var pingReply = await ping.SendPingAsync(host, timeout); - - if (pingReply.Status != IPStatus.Success) - { - return new HealthCheckResult(status, description: $"Ping check for host {host} is failed with status reply:{pingReply.Status}"); - } - } - } - - return HealthCheckResult.Healthy(); - } - catch (Exception ex) - { - return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); - } - } - } -} diff --git a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs deleted file mode 100644 index f89c71a522..0000000000 --- a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Diagnostics.HealthChecks; -using System.Collections.Generic; - -namespace Ombi.HealthChecks.Checks -{ - public class OmbiPingHealthCheckOptions - { - internal Dictionary ConfiguredHosts { get; } = new Dictionary(); - - public OmbiPingHealthCheckOptions AddHost(string host, int timeout, HealthStatus status) - { - ConfiguredHosts.Add(host, (host, timeout, status)); - return this; - } - } -} diff --git a/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs b/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs index 182c1b2f84..bc90c47569 100644 --- a/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs +++ b/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs @@ -27,7 +27,7 @@ public override async Task CheckHealthAsync( var settings = await settingsProvider.GetSettingsAsync(); if (settings == null) { - return HealthCheckResult.Healthy("Plex is not confiured."); + return HealthCheckResult.Healthy("Plex is not configured."); } var taskResult = new List>(); diff --git a/src/Ombi.HealthChecks/HealthCheckExtensions.cs b/src/Ombi.HealthChecks/HealthCheckExtensions.cs index 2f80378ff1..21b9d5dde6 100644 --- a/src/Ombi.HealthChecks/HealthCheckExtensions.cs +++ b/src/Ombi.HealthChecks/HealthCheckExtensions.cs @@ -18,39 +18,8 @@ public static IHealthChecksBuilder AddOmbiHealthChecks(this IHealthChecksBuilder builder.AddCheck("Radarr", tags: new string[] { "DVR" }); builder.AddCheck("CouchPotato", tags: new string[] { "DVR" }); builder.AddCheck("SickRage", tags: new string[] { "DVR" }); - builder.AddOmbiPingHealthCheck(options => - { - options.AddHost("www.google.co.uk", 5000, HealthStatus.Unhealthy); - options.AddHost("www.google.com", 3000, HealthStatus.Degraded); - }, "External Ping", tags: new string[] { "System" }); return builder; } - - /// - /// Add a health check for network ping. - /// - /// The . - /// The action to configure the ping parameters. - /// The health check name. Optional. If null the type name 'ping' will be used for the name. - /// - /// The that should be reported when the health check fails. Optional. If null then - /// the default status of will be reported. - /// - /// A list of tags that can be used to filter sets of health checks. Optional. - /// An optional System.TimeSpan representing the timeout of the check. - /// The . - public static IHealthChecksBuilder AddOmbiPingHealthCheck(this IHealthChecksBuilder builder, Action setup, string name = default, HealthStatus? failureStatus = default, IEnumerable tags = default, TimeSpan? timeout = default) - { - var options = new OmbiPingHealthCheckOptions(); - setup?.Invoke(options); - - return builder.Add(new HealthCheckRegistration( - name, - sp => new OmbiPingHealthCheck(options), - failureStatus, - tags, - timeout)); - } } } diff --git a/src/Ombi.I18n/Resources/Texts.hu.resx b/src/Ombi.I18n/Resources/Texts.hu.resx index 4e7cebcfdb..bd9f1a19e7 100644 --- a/src/Ombi.I18n/Resources/Texts.hu.resx +++ b/src/Ombi.I18n/Resources/Texts.hu.resx @@ -118,13 +118,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - New Albums + Új album - New Movies + Új film - New TV + Új sorozat Műfaj: @@ -139,18 +139,18 @@ Epizódok: - Powered by + Biztosítja a(z) - Unsubscribe + Leiratkozás Album - Movie + Film - TV Show + Sorozat \ No newline at end of file diff --git a/src/Ombi.I18n/Resources/Texts.nl.resx b/src/Ombi.I18n/Resources/Texts.nl.resx index e785eb4946..873d68ac2f 100644 --- a/src/Ombi.I18n/Resources/Texts.nl.resx +++ b/src/Ombi.I18n/Resources/Texts.nl.resx @@ -148,9 +148,9 @@ Album - Movie + Film - TV Show + TV-serie \ No newline at end of file diff --git a/src/Ombi.I18n/Resources/Texts.no.resx b/src/Ombi.I18n/Resources/Texts.no.resx index bf0daa4561..b3fd2fe8ea 100644 --- a/src/Ombi.I18n/Resources/Texts.no.resx +++ b/src/Ombi.I18n/Resources/Texts.no.resx @@ -118,16 +118,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - New Albums + Nye Album - New Movies + Nye filmer - New TV + Nye TV-serier - Genres: + Sjangere: Type: @@ -136,21 +136,21 @@ Sesong: - Episodes: + Episoder: - Powered by + Drevet av - Unsubscribe + Avslutt abonnement Album - Movie + Film - TV Show + TV-serie \ No newline at end of file diff --git a/src/Ombi.Notifications/NotificationMessageCurlys.cs b/src/Ombi.Notifications/NotificationMessageCurlys.cs index f079c03a3f..c1fecb00cb 100644 --- a/src/Ombi.Notifications/NotificationMessageCurlys.cs +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -153,6 +153,7 @@ private void LoadCommon(BaseRequest req, CustomizationSettings s, UserNotificati RequestedUser = req?.RequestedUser?.UserName; RequestedDate = req?.RequestedDate.ToString("D"); DetailsUrl = GetDetailsUrl(s, req); + RequestedByAlias = req?.RequestedByAlias; if (Type.IsNullOrEmpty()) { @@ -276,6 +277,7 @@ private void CalculateRequestStatus(BaseRequest req) // User Defined public string RequestId { get; set; } public string RequestedUser { get; set; } + public string RequestedByAlias { get; set; } public string UserName { get; set; } public string IssueUser => UserName; public string Alias { get; set; } @@ -339,6 +341,7 @@ private void CalculateRequestStatus(BaseRequest req) { nameof(IssueUser), IssueUser }, { nameof(UserName), UserName }, { nameof(Alias), Alias }, + { nameof(RequestedByAlias), RequestedByAlias }, { nameof(UserPreference), UserPreference }, { nameof(DenyReason), DenyReason }, { nameof(AvailableDate), AvailableDate }, diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 35cc66be47..7b301d4eda 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -8,10 +8,12 @@ using Ombi.Api.Emby.Models; using Ombi.Api.Emby.Models.Media.Tv; using Ombi.Api.Emby.Models.Movie; +using Ombi.Core.Services; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Hubs; +using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; using Ombi.Store.Repository; using Quartz; @@ -19,108 +21,43 @@ namespace Ombi.Schedule.Jobs.Emby { - public class EmbyContentSync : IEmbyContentSync + public class EmbyContentSync : EmbyLibrarySync, IEmbyContentSync { - public EmbyContentSync(ISettingsService settings, IEmbyApiFactory api, ILogger logger, - IEmbyContentRepository repo, INotificationHubService notification) + public EmbyContentSync( + ISettingsService settings, + IEmbyApiFactory api, + ILogger logger, + IEmbyContentRepository repo, + INotificationHubService notification, + IFeatureService feature): + base(settings, api, logger, notification) { - _logger = logger; - _settings = settings; - _apiFactory = api; _repo = repo; - _notification = notification; + _feature = feature; } - private readonly ILogger _logger; - private readonly ISettingsService _settings; - private readonly IEmbyApiFactory _apiFactory; private readonly IEmbyContentRepository _repo; - private readonly INotificationHubService _notification; + private readonly IFeatureService _feature; - private const int AmountToTake = 100; - private IEmbyApi Api { get; set; } - - public async Task Execute(IJobExecutionContext context) + public async override Task Execute(IJobExecutionContext context) { - JobDataMap dataMap = context.JobDetail.JobDataMap; - var recentlyAddedSearch = false; - if (dataMap.TryGetValue(JobDataKeys.EmbyRecentlyAddedSearch, out var recentlyAddedObj)) - { - recentlyAddedSearch = Convert.ToBoolean(recentlyAddedObj); - } - - var embySettings = await _settings.GetSettingsAsync(); - if (!embySettings.Enable) - return; - - Api = _apiFactory.CreateClient(embySettings); - - await _notification.SendNotificationToAdmins(recentlyAddedSearch ? "Emby Recently Added Started" : "Emby Content Sync Started"); - foreach (var server in embySettings.Servers) - { - try - { - await StartServerCache(server, recentlyAddedSearch); - } - catch (Exception e) - { - await _notification.SendNotificationToAdmins("Emby Content Sync Failed"); - _logger.LogError(e, "Exception when caching Emby for server {0}", server.Name); - } - } + await base.Execute(context); - await _notification.SendNotificationToAdmins("Emby Content Sync Finished"); // Episodes + await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyEpisodeSync), "Emby"), new JobDataMap(new Dictionary { { JobDataKeys.EmbyRecentlyAddedSearch, recentlyAdded.ToString() } })); - - await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyEpisodeSync), "Emby"), new JobDataMap(new Dictionary { { JobDataKeys.EmbyRecentlyAddedSearch, recentlyAddedSearch.ToString() } })); - } - - - private async Task StartServerCache(EmbyServers server, bool recentlyAdded) - { - if (!ValidateSettings(server)) - { - return; - } - - - if (server.EmbySelectedLibraries.Any() && server.EmbySelectedLibraries.Any(x => x.Enabled)) - { - var movieLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "movies"); - - foreach (var movieParentIdFilder in movieLibsToFilter) - { - _logger.LogInformation($"Scanning Lib '{movieParentIdFilder.Title}'"); - await ProcessMovies(server, recentlyAdded, movieParentIdFilder.Key); - } - - var tvLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "tvshows"); - foreach (var tvParentIdFilter in tvLibsToFilter) - { - _logger.LogInformation($"Scanning Lib '{tvParentIdFilter.Title}'"); - await ProcessTv(server, recentlyAdded, tvParentIdFilter.Key); - } - - - var mixedLibs = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "mixed"); - foreach (var m in mixedLibs) - { - _logger.LogInformation($"Scanning Lib '{m.Title}'"); - await ProcessTv(server, recentlyAdded, m.Key); - await ProcessMovies(server, recentlyAdded, m.Key); - } - } - else + // Played state + var isPlayedSyncEnabled = await _feature.FeatureEnabled(FeatureNames.PlayedSync); + if(isPlayedSyncEnabled) { - await ProcessMovies(server, recentlyAdded); - await ProcessTv(server, recentlyAdded); + await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyPlayedSync), "Emby"), new JobDataMap(new Dictionary { { JobDataKeys.EmbyRecentlyAddedSearch, recentlyAdded.ToString() } })); } } - private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string parentId = default) + + protected async override Task ProcessTv(EmbyServers server, string parentId = default) { // TV Time var mediaToAdd = new HashSet(); @@ -196,7 +133,7 @@ private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string pare await _repo.AddRange(mediaToAdd); } - private async Task ProcessMovies(EmbyServers server, bool recentlyAdded, string parentId = default) + protected override async Task ProcessMovies(EmbyServers server, string parentId = default) { EmbyItemContainer movies; if (recentlyAdded) @@ -263,7 +200,12 @@ private async Task ProcessMovies(EmbyMovie movieInfo, ICollection c // Check if it exists var existingMovie = await _repo.GetByEmbyId(movieInfo.Id); var alreadyGoingToAdd = content.Any(x => x.EmbyId == movieInfo.Id); - if (existingMovie == null && !alreadyGoingToAdd) + if (alreadyGoingToAdd) + { + _logger.LogDebug($"Detected duplicate for {movieInfo.Name}"); + return; + } + if (existingMovie == null) { if (!movieInfo.ProviderIds.Any()) { @@ -319,36 +261,6 @@ private void MapEmbyContent(EmbyContent content, EmbyMovie movieInfo, EmbyServer content.Quality = has4K ? null : quality; content.Has4K = has4K; } - - private bool ValidateSettings(EmbyServers server) - { - if (server?.Ip == null || string.IsNullOrEmpty(server?.ApiKey)) - { - _logger.LogInformation(LoggingEvents.EmbyContentCacher, $"Server {server?.Name} is not configured correctly"); - return false; - } - - return true; - } - - private bool _disposed; - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - //_settings?.Dispose(); - } - _disposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } } } diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs new file mode 100644 index 0000000000..095364037a --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs @@ -0,0 +1,146 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.Emby; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Helpers; +using Ombi.Hubs; +using Quartz; + +namespace Ombi.Schedule.Jobs.Emby +{ + public abstract class EmbyLibrarySync + { + public EmbyLibrarySync(ISettingsService settings, IEmbyApiFactory api, ILogger logger, + INotificationHubService notification) + { + _logger = logger; + _settings = settings; + _apiFactory = api; + _notification = notification; + } + + protected readonly ILogger _logger; + protected readonly ISettingsService _settings; + protected readonly IEmbyApiFactory _apiFactory; + protected bool recentlyAdded; + protected readonly INotificationHubService _notification; + + protected const int AmountToTake = 100; + + protected IEmbyApi Api { get; set; } + + public virtual async Task Execute(IJobExecutionContext context) + { + + JobDataMap dataMap = context.MergedJobDataMap; + if (dataMap.TryGetValue(JobDataKeys.EmbyRecentlyAddedSearch, out var recentlyAddedObj)) + { + recentlyAdded = Convert.ToBoolean(recentlyAddedObj); + } + + await _notification.SendNotificationToAdmins(recentlyAdded ? "Emby Recently Added Started" : "Emby Content Sync Started"); + + + var embySettings = await _settings.GetSettingsAsync(); + if (!embySettings.Enable) + return; + + Api = _apiFactory.CreateClient(embySettings); + + foreach (var server in embySettings.Servers) + { + try + { + await StartServerCache(server); + } + catch (Exception e) + { + await _notification.SendNotificationToAdmins("Emby Content Sync Failed"); + _logger.LogError(e, "Exception when caching Emby for server {0}", server.Name); + } + } + + await _notification.SendNotificationToAdmins("Emby Content Sync Finished"); + } + + + private async Task StartServerCache(EmbyServers server) + { + if (!ValidateSettings(server)) + { + return; + } + + + if (server.EmbySelectedLibraries.Any() && server.EmbySelectedLibraries.Any(x => x.Enabled)) + { + var movieLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "movies"); + + foreach (var movieParentIdFilder in movieLibsToFilter) + { + _logger.LogInformation($"Scanning Lib '{movieParentIdFilder.Title}'"); + await ProcessMovies(server, movieParentIdFilder.Key); + } + + var tvLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "tvshows"); + foreach (var tvParentIdFilter in tvLibsToFilter) + { + _logger.LogInformation($"Scanning Lib '{tvParentIdFilter.Title}'"); + await ProcessTv(server, tvParentIdFilter.Key); + } + + + var mixedLibs = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "mixed"); + foreach (var m in mixedLibs) + { + _logger.LogInformation($"Scanning Lib '{m.Title}'"); + await ProcessTv(server, m.Key); + await ProcessMovies(server, m.Key); + } + } + else + { + await ProcessMovies(server); + await ProcessTv(server); + } + } + + protected abstract Task ProcessTv(EmbyServers server, string parentId = default); + + protected abstract Task ProcessMovies(EmbyServers server, string parentId = default); + + private bool ValidateSettings(EmbyServers server) + { + if (server?.Ip == null || string.IsNullOrEmpty(server?.ApiKey)) + { + _logger.LogInformation(LoggingEvents.EmbyContentCacher, $"Server {server?.Name} is not configured correctly"); + return false; + } + + return true; + } + + private bool _disposed; + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + //_settings?.Dispose(); + } + _disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + +} diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs new file mode 100644 index 0000000000..5af5a97568 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Ombi.Api.Emby; +using Ombi.Api.Emby.Models; +using Ombi.Api.Emby.Models.Movie; +using Ombi.Core.Authentication; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Helpers; +using Ombi.Hubs; +using Ombi.Store.Entities; +using Ombi.Store.Repository; + +namespace Ombi.Schedule.Jobs.Emby +{ + public class EmbyPlayedSync : EmbyLibrarySync, IEmbyPlayedSync + { + public EmbyPlayedSync(ISettingsService settings, IEmbyApiFactory api, ILogger logger, + IUserPlayedMovieRepository repo, INotificationHubService notification, OmbiUserManager user) : base(settings, api, logger, notification) + { + _userManager = user; + _repo = repo; + } + private OmbiUserManager _userManager { get; } + + private readonly IUserPlayedMovieRepository _repo; + + protected override Task ProcessTv(EmbyServers server, string parentId = default) + { + // TODO + return Task.CompletedTask; + } + + protected async override Task ProcessMovies(EmbyServers server, string parentId = default) + { + + var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.EmbyUser || x.UserType == UserType.EmbyConnectUser).ToListAsync(); + foreach (var user in allUsers) + { + await ProcessMoviesUser(server, user, parentId); + } + } + + + private async Task ProcessMoviesUser(EmbyServers server, OmbiUser user, string parentId = default) + { + EmbyItemContainer movies; + if (recentlyAdded) + { + var recentlyAddedAmountToTake = 5; // to be adjusted? + movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, 0, recentlyAddedAmountToTake, user.ProviderUserId, server.FullUri); + // Setting this so we don't attempt to grab more than we need + if (movies.TotalRecordCount > recentlyAddedAmountToTake) + { + movies.TotalRecordCount = recentlyAddedAmountToTake; + } + } + else + { + movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, 0, AmountToTake, user.ProviderUserId, server.FullUri); + } + var totalCount = movies.TotalRecordCount; + var processed = 0; + var mediaToAdd = new HashSet(); + + while (processed < totalCount) + { + foreach (var movie in movies.Items) + { + await ProcessMovie(movie, user, mediaToAdd, server); + processed++; + } + + // Get the next batch + // Recently Added should never be checked as the TotalRecords should equal the amount to take + if (!recentlyAdded) + { + movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, processed, AmountToTake, user.ProviderUserId, server.FullUri); + } + await _repo.AddRange(mediaToAdd); + mediaToAdd.Clear(); + } + } + + private async Task ProcessMovie(EmbyMovie movieInfo, OmbiUser user, ICollection content, EmbyServers server) + { + if (movieInfo.ProviderIds.Tmdb.IsNullOrEmpty()) + { + _logger.LogWarning($"Movie {movieInfo.Name} has no relevant metadata. Skipping."); + return; + } + var userPlayedMovie = new UserPlayedMovie() + { + TheMovieDbId = int.Parse(movieInfo.ProviderIds.Tmdb), + UserId = user.Id + }; + // Check if it exists + var existingMovie = await _repo.Get(userPlayedMovie.TheMovieDbId, userPlayedMovie.UserId); + var alreadyGoingToAdd = content.Any(x => x.TheMovieDbId == userPlayedMovie.TheMovieDbId && x.UserId == userPlayedMovie.UserId); + if (existingMovie == null && !alreadyGoingToAdd) + { + content.Add(userPlayedMovie); + } + } + } + +} diff --git a/src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs b/src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs new file mode 100644 index 0000000000..80434bddba --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs @@ -0,0 +1,6 @@ +namespace Ombi.Schedule.Jobs.Emby +{ + public interface IEmbyPlayedSync : IBaseJob + { + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs index 58dacaed5a..3eab17a356 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -228,7 +228,12 @@ private async Task ProcessMovies(JellyfinMovie movieInfo, ICollection x.JellyfinId == movieInfo.Id); - if (existingMovie == null && !alreadyGoingToAdd) + if (alreadyGoingToAdd) + { + _logger.LogDebug($"Detected duplicate for {movieInfo.Name}"); + return; + } + if (existingMovie == null) { if (!movieInfo.ProviderIds.Any()) { diff --git a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs index 46f3a7e568..e3573e6c86 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/MediaDatabaseRefresh.cs @@ -15,15 +15,22 @@ namespace Ombi.Schedule.Jobs.Ombi { public class MediaDatabaseRefresh : IMediaDatabaseRefresh { - public MediaDatabaseRefresh(ISettingsService s, ILogger log, - IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo, IJellyfinContentRepository jellyfinRepo, - ISettingsService embySettings, ISettingsService jellyfinSettings) + public MediaDatabaseRefresh( + ISettingsService s, + ILogger log, + IPlexContentRepository plexRepo, + IEmbyContentRepository embyRepo, + IJellyfinContentRepository jellyfinRepo, + IUserPlayedMovieRepository userPlayedRepo, + ISettingsService embySettings, + ISettingsService jellyfinSettings) { _plexSettings = s; _log = log; _plexRepo = plexRepo; _embyRepo = embyRepo; _jellyfinRepo = jellyfinRepo; + _userPlayedRepo = userPlayedRepo; _embySettings = embySettings; _jellyfinSettings = jellyfinSettings; _plexSettings.ClearCache(); @@ -34,6 +41,7 @@ public MediaDatabaseRefresh(ISettingsService s, ILogger _embySettings; private readonly ISettingsService _jellyfinSettings; @@ -41,6 +49,7 @@ public async Task Execute(IJobExecutionContext job) { try { + await RemovePlayedData(); await RemovePlexData(); await RemoveEmbyData(); await RemoveJellyfinData(); @@ -52,6 +61,20 @@ public async Task Execute(IJobExecutionContext job) } + private async Task RemovePlayedData() + { + try + { + const string movieSql = "DELETE FROM UserPlayedMovie"; + await _userPlayedRepo.ExecuteSql(movieSql); + } + catch (Exception e) + { + _log.LogError(LoggingEvents.MediaReferesh, e, "Refreshing Played Data Failed"); + } + } + + private async Task RemoveEmbyData() { try diff --git a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs index ef29750570..3eaf0154a3 100644 --- a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs @@ -46,8 +46,8 @@ public async Task Execute(IJobExecutionContext job) await tran.CommitAsync(); var radarrSettings = _radarrSettings.GetSettingsAsync(); - var radarr4kSettings = _radarr4kSettings.GetSettingsAsync(); await Process(await radarrSettings); + var radarr4kSettings = _radarr4kSettings.GetSettingsAsync(); await Process(await radarr4kSettings); } catch (Exception) diff --git a/src/Ombi.Schedule/OmbiScheduler.cs b/src/Ombi.Schedule/OmbiScheduler.cs index 41602f6413..3b4f6316f6 100644 --- a/src/Ombi.Schedule/OmbiScheduler.cs +++ b/src/Ombi.Schedule/OmbiScheduler.cs @@ -99,6 +99,7 @@ private static async Task AddEmby(JobSettings s) await OmbiQuartz.Instance.AddJob(nameof(IEmbyContentSync), "Emby", JobSettingsHelper.EmbyContent(s)); await OmbiQuartz.Instance.AddJob(nameof(IEmbyContentSync) + "RecentlyAdded", "Emby", JobSettingsHelper.EmbyRecentlyAddedSync(s), new Dictionary { { JobDataKeys.EmbyRecentlyAddedSearch, "true" } }); await OmbiQuartz.Instance.AddJob(nameof(IEmbyEpisodeSync), "Emby", null); + await OmbiQuartz.Instance.AddJob(nameof(IEmbyPlayedSync), "Emby", null); await OmbiQuartz.Instance.AddJob(nameof(IEmbyAvaliabilityChecker), "Emby", null); await OmbiQuartz.Instance.AddJob(nameof(IEmbyUserImporter), "Emby", JobSettingsHelper.UserImporter(s)); } diff --git a/src/Ombi.Settings/Settings/Models/FeatureSettings.cs b/src/Ombi.Settings/Settings/Models/FeatureSettings.cs index 9d0149e5d4..f541d1e0d0 100644 --- a/src/Ombi.Settings/Settings/Models/FeatureSettings.cs +++ b/src/Ombi.Settings/Settings/Models/FeatureSettings.cs @@ -21,5 +21,6 @@ public static class FeatureNames { public const string Movie4KRequests = nameof(Movie4KRequests); public const string OldTrendingSource = nameof(OldTrendingSource); + public const string PlayedSync = nameof(PlayedSync); } } diff --git a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs index b80943cc5d..fb51ae1477 100644 --- a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs +++ b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs @@ -1,5 +1,6 @@ using Ombi.Helpers; using Quartz; +using System; namespace Ombi.Settings.Settings.Models { @@ -104,7 +105,9 @@ private static string Get(string settings, string defaultCron) private static string ValidateCron(string cron) { - if (CronExpression.IsValidExpression(cron)) + CronExpression expression = new CronExpression(cron); + DateTimeOffset? nextFireUTCTime = expression.GetNextValidTimeAfter(DateTime.Now); + if (CronExpression.IsValidExpression(cron) && nextFireUTCTime != null) { return cron; } diff --git a/src/Ombi.Store/Context/ExternalContext.cs b/src/Ombi.Store/Context/ExternalContext.cs index f13c1e74fb..c54c39bebd 100644 --- a/src/Ombi.Store/Context/ExternalContext.cs +++ b/src/Ombi.Store/Context/ExternalContext.cs @@ -41,6 +41,7 @@ protected ExternalContext(DbContextOptions options) public DbSet SonarrEpisodeCache { get; set; } public DbSet SickRageCache { get; set; } public DbSet SickRageEpisodeCache { get; set; } + public DbSet UserPlayedMovie { get; set; } protected override void OnModelCreating(ModelBuilder builder) { diff --git a/src/Ombi.Store/Entities/Requests/MovieRequests.cs b/src/Ombi.Store/Entities/Requests/MovieRequests.cs index 415efded20..3c3c75893e 100644 --- a/src/Ombi.Store/Entities/Requests/MovieRequests.cs +++ b/src/Ombi.Store/Entities/Requests/MovieRequests.cs @@ -84,5 +84,10 @@ public string RequestStatus { [NotMapped] public override bool CanApprove => !Approved && !Available || !Approved4K && !Available4K; + + [NotMapped] + public bool WatchedByRequestedUser { get; set; } + [NotMapped] + public int PlayedByUsersCount { get; set; } } } diff --git a/src/Ombi.Store/Entities/UserPlayedMovie.cs b/src/Ombi.Store/Entities/UserPlayedMovie.cs new file mode 100644 index 0000000000..7f28e9d991 --- /dev/null +++ b/src/Ombi.Store/Entities/UserPlayedMovie.cs @@ -0,0 +1,8 @@ +namespace Ombi.Store.Entities +{ + public class UserPlayedMovie : Entity + { + public int TheMovieDbId { get; set; } + public string UserId { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.Designer.cs b/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.Designer.cs new file mode 100644 index 0000000000..0e2e290b72 --- /dev/null +++ b/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.Designer.cs @@ -0,0 +1,566 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Ombi.Store.Context.MySql; + +#nullable disable + +namespace Ombi.Store.Migrations.ExternalMySql +{ + [DbContext(typeof(ExternalMySqlContext))] + [Migration("20230406152218_MovieUserPlayed")] + partial class MovieUserPlayed + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("CouchPotatoCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("EmbyId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("Has4K") + .HasColumnType("tinyint(1)"); + + b.Property("ImdbId") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("longtext"); + + b.Property("Quality") + .HasColumnType("longtext"); + + b.Property("TheMovieDbId") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TvDbId") + .HasColumnType("longtext"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("EmbyId") + .HasColumnType("longtext"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("ImdbId") + .HasColumnType("longtext"); + + b.Property("ParentId") + .HasColumnType("varchar(255)"); + + b.Property("ProviderId") + .HasColumnType("longtext"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TvDbId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("Has4K") + .HasColumnType("tinyint(1)"); + + b.Property("ImdbId") + .HasColumnType("longtext"); + + b.Property("JellyfinId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("ProviderId") + .HasColumnType("longtext"); + + b.Property("Quality") + .HasColumnType("longtext"); + + b.Property("TheMovieDbId") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TvDbId") + .HasColumnType("longtext"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("JellyfinContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("ImdbId") + .HasColumnType("longtext"); + + b.Property("JellyfinId") + .HasColumnType("longtext"); + + b.Property("ParentId") + .HasColumnType("varchar(255)"); + + b.Property("ProviderId") + .HasColumnType("longtext"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TvDbId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("JellyfinEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("ArtistId") + .HasColumnType("int"); + + b.Property("ForeignAlbumId") + .HasColumnType("longtext"); + + b.Property("Monitored") + .HasColumnType("tinyint(1)"); + + b.Property("PercentOfTracks") + .HasColumnType("decimal(65,30)"); + + b.Property("ReleaseDate") + .HasColumnType("datetime(6)"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TrackCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("LidarrAlbumCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ArtistId") + .HasColumnType("int"); + + b.Property("ArtistName") + .HasColumnType("longtext"); + + b.Property("ForeignArtistId") + .HasColumnType("longtext"); + + b.Property("Monitored") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("LidarrArtistCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("GrandparentKey") + .HasColumnType("varchar(255)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("ParentKey") + .HasColumnType("longtext"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ParentKey") + .HasColumnType("longtext"); + + b.Property("PlexContentId") + .HasColumnType("longtext"); + + b.Property("PlexServerContentId") + .HasColumnType("int"); + + b.Property("SeasonKey") + .HasColumnType("longtext"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PlexServerContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddedAt") + .HasColumnType("datetime(6)"); + + b.Property("Has4K") + .HasColumnType("tinyint(1)"); + + b.Property("ImdbId") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("Quality") + .HasColumnType("longtext"); + + b.Property("ReleaseYear") + .HasColumnType("longtext"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("longtext"); + + b.Property("Title") + .HasColumnType("longtext"); + + b.Property("TvDbId") + .HasColumnType("longtext"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PlexServerContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TmdbId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PlexWatchlistHistory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Has4K") + .HasColumnType("tinyint(1)"); + + b.Property("HasFile") + .HasColumnType("tinyint(1)"); + + b.Property("HasRegular") + .HasColumnType("tinyint(1)"); + + b.Property("TheMovieDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TvDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SickRageCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("TvDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SickRageEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("int"); + + b.Property("TvDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("EpisodeNumber") + .HasColumnType("int"); + + b.Property("HasFile") + .HasColumnType("tinyint(1)"); + + b.Property("MovieDbId") + .HasColumnType("int"); + + b.Property("SeasonNumber") + .HasColumnType("int"); + + b.Property("TvDbId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SonarrEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("UserPlayedMovie"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b => + { + b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("JellyfinId"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", null) + .WithMany("Seasons") + .HasForeignKey("PlexServerContentId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Navigation("Episodes"); + + b.Navigation("Seasons"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.cs b/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.cs new file mode 100644 index 0000000000..48336a03db --- /dev/null +++ b/src/Ombi.Store/Migrations/ExternalMySql/20230406152218_MovieUserPlayed.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Ombi.Store.Migrations.ExternalMySql +{ + public partial class MovieUserPlayed : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserPlayedMovie", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + TheMovieDbId = table.Column(type: "int", nullable: false), + UserId = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_UserPlayedMovie", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserPlayedMovie"); + } + } +} diff --git a/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs b/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs index 1e86ddf7b2..0121a99ba1 100644 --- a/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("ProductVersion", "6.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => @@ -488,6 +488,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("SonarrEpisodeCache"); }); + modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("TheMovieDbId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("UserPlayedMovie"); + }); + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => { b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") diff --git a/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.Designer.cs b/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.Designer.cs new file mode 100644 index 0000000000..f1162e20f4 --- /dev/null +++ b/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.Designer.cs @@ -0,0 +1,564 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Ombi.Store.Context.Sqlite; + +#nullable disable + +namespace Ombi.Store.Migrations.ExternalSqlite +{ + [DbContext(typeof(ExternalSqliteContext))] + [Migration("20230310130339_MovieUserPlayed")] + partial class MovieUserPlayed + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.9"); + + modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("CouchPotatoCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("EmbyId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Has4K") + .HasColumnType("INTEGER"); + + b.Property("ImdbId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("Quality") + .HasColumnType("TEXT"); + + b.Property("TheMovieDbId") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TvDbId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Url") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("EmbyId") + .HasColumnType("TEXT"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("ImdbId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TvDbId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("Has4K") + .HasColumnType("INTEGER"); + + b.Property("ImdbId") + .HasColumnType("TEXT"); + + b.Property("JellyfinId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("Quality") + .HasColumnType("TEXT"); + + b.Property("TheMovieDbId") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TvDbId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Url") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("JellyfinContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("ImdbId") + .HasColumnType("TEXT"); + + b.Property("JellyfinId") + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TvDbId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("JellyfinEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("ArtistId") + .HasColumnType("INTEGER"); + + b.Property("ForeignAlbumId") + .HasColumnType("TEXT"); + + b.Property("Monitored") + .HasColumnType("INTEGER"); + + b.Property("PercentOfTracks") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TrackCount") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("LidarrAlbumCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArtistId") + .HasColumnType("INTEGER"); + + b.Property("ArtistName") + .HasColumnType("TEXT"); + + b.Property("ForeignArtistId") + .HasColumnType("TEXT"); + + b.Property("Monitored") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("LidarrArtistCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("GrandparentKey") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("ParentKey") + .HasColumnType("TEXT"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ParentKey") + .HasColumnType("TEXT"); + + b.Property("PlexContentId") + .HasColumnType("TEXT"); + + b.Property("PlexServerContentId") + .HasColumnType("INTEGER"); + + b.Property("SeasonKey") + .HasColumnType("TEXT"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlexServerContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddedAt") + .HasColumnType("TEXT"); + + b.Property("Has4K") + .HasColumnType("INTEGER"); + + b.Property("ImdbId") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Quality") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TvDbId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Url") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("PlexServerContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TmdbId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("PlexWatchlistHistory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Has4K") + .HasColumnType("INTEGER"); + + b.Property("HasFile") + .HasColumnType("INTEGER"); + + b.Property("HasRegular") + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TvDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SickRageCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("TvDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SickRageEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("INTEGER"); + + b.Property("TvDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EpisodeNumber") + .HasColumnType("INTEGER"); + + b.Property("HasFile") + .HasColumnType("INTEGER"); + + b.Property("MovieDbId") + .HasColumnType("INTEGER"); + + b.Property("SeasonNumber") + .HasColumnType("INTEGER"); + + b.Property("TvDbId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SonarrEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("UserPlayedMovie"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b => + { + b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("JellyfinId"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", null) + .WithMany("Seasons") + .HasForeignKey("PlexServerContentId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Navigation("Episodes"); + + b.Navigation("Seasons"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.cs b/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.cs new file mode 100644 index 0000000000..23345e7a1f --- /dev/null +++ b/src/Ombi.Store/Migrations/ExternalSqlite/20230310130339_MovieUserPlayed.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Ombi.Store.Migrations.ExternalSqlite +{ + public partial class MovieUserPlayed : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserPlayedMovie", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + TheMovieDbId = table.Column(type: "INTEGER", nullable: false), + UserId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserPlayedMovie", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserPlayedMovie"); + } + } +} diff --git a/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs b/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs index 2f5de33820..857259ab1c 100644 --- a/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs @@ -15,7 +15,7 @@ partial class ExternalSqliteContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + modelBuilder.HasAnnotation("ProductVersion", "6.0.9"); modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => { @@ -486,6 +486,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("SonarrEpisodeCache"); }); + modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TheMovieDbId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("UserPlayedMovie"); + }); + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => { b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") diff --git a/src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs b/src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs new file mode 100644 index 0000000000..966171b3a7 --- /dev/null +++ b/src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public interface IUserPlayedMovieRepository : IExternalRepository + { + Task Get(int theMovieDbId, string userId); + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/UserPlayedMovieRepository.cs b/src/Ombi.Store/Repository/UserPlayedMovieRepository.cs new file mode 100644 index 0000000000..aaff5f2b1a --- /dev/null +++ b/src/Ombi.Store/Repository/UserPlayedMovieRepository.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Ombi.Store.Context; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public class UserPlayedMovieRepository : ExternalRepository, IUserPlayedMovieRepository + { + protected ExternalContext Db { get; } + public UserPlayedMovieRepository(ExternalContext db) : base(db) + { + Db = db; + } + + public async Task Get(int theMovieDbId, string userId) + { + return await Db.UserPlayedMovie.FirstOrDefaultAsync(x => x.TheMovieDbId == theMovieDbId && x.UserId == userId); + + } + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/.yarnrc.yml b/src/Ombi/ClientApp/.yarnrc.yml index 3186f3f079..e55ce3b3ce 100644 --- a/src/Ombi/ClientApp/.yarnrc.yml +++ b/src/Ombi/ClientApp/.yarnrc.yml @@ -1 +1,5 @@ nodeLinker: node-modules + +plugins: + - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs + spec: "@yarnpkg/plugin-interactive-tools" diff --git a/src/Ombi/ClientApp/package.json b/src/Ombi/ClientApp/package.json index 5d2f1886dd..701d58f80c 100644 --- a/src/Ombi/ClientApp/package.json +++ b/src/Ombi/ClientApp/package.json @@ -13,26 +13,26 @@ }, "private": true, "dependencies": { - "@angular/animations": "^15.0.1", + "@angular/animations": "^15.0.4", "@angular/cdk": "^14.2.7", - "@angular/common": "^15.0.1", - "@angular/compiler": "^15.0.1", - "@angular/core": "^15.0.1", - "@angular/forms": "^15.0.1", - "@angular/localize": "^15.0.1", + "@angular/common": "^15.0.4", + "@angular/compiler": "^15.0.4", + "@angular/core": "^15.0.4", + "@angular/forms": "^15.0.4", + "@angular/localize": "^15.0.4", "@angular/material": "^14.2.7", - "@angular/platform-browser": "^15.0.1", - "@angular/platform-browser-dynamic": "^15.0.1", - "@angular/platform-server": "^15.0.1", - "@angular/router": "^15.0.1", + "@angular/platform-browser": "^15.0.4", + "@angular/platform-browser-dynamic": "^15.0.4", + "@angular/platform-server": "^15.0.4", + "@angular/router": "^15.0.4", "@angularclass/hmr": "^3.0.0", "@auth0/angular-jwt": "^5.0.2", "@fortawesome/fontawesome-free": "^6.0.0", "@microsoft/signalr": "^6.0.7", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@ngxs/devtools-plugin": "^3.7.3", - "@ngxs/store": "^3.7.3", + "@ngxs/devtools-plugin": "3.7.3", + "@ngxs/store": "3.7.3", "@types/jquery": "^3.5.14", "@yellowspot/ng-truncate": "^2.0.0", "angular-router-loader": "^0.8.5", @@ -58,7 +58,7 @@ "devDependencies": { "@angular-devkit/build-angular": "^15.0.2", "@angular/cli": "^15.0.2", - "@angular/compiler-cli": "^15.0.1", + "@angular/compiler-cli": "^15.0.4", "@babel/core": "^7.18.9", "@compodoc/compodoc": "^1.1.19", "@storybook/angular": "^6.5.9", diff --git a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.html b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.html index 454874490f..29ac3699ef 100644 --- a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.html +++ b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.html @@ -22,7 +22,23 @@

{{request.title}}

- +
+ + +
diff --git a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.scss b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.scss index 3580331a38..7dd442aa4e 100644 --- a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.scss +++ b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.scss @@ -50,5 +50,9 @@ position: absolute; } } + + .action-items button { + margin: 4px; + } } diff --git a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts index 0892bc9b27..270a6eb2f7 100644 --- a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts +++ b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts @@ -22,6 +22,7 @@ export class DetailedCardComponent implements OnInit, OnDestroy { @Input() public isAdmin: boolean = false; @Output() public onClick: EventEmitter = new EventEmitter(); @Output() public onApprove: EventEmitter = new EventEmitter(); + @Output() public onDeny: EventEmitter = new EventEmitter(); public RequestType = RequestType; public loading: false; @@ -41,6 +42,9 @@ export class DetailedCardComponent implements OnInit, OnDestroy { } public getStatus(request: IRecentlyRequested) { + if (request.denied) { + return "Common.Denied"; + } if (request.available) { return "Common.Available"; } @@ -62,7 +66,14 @@ export class DetailedCardComponent implements OnInit, OnDestroy { this.onApprove.emit(); } + public deny() { + this.onDeny.emit(); + } + public getClass(request: IRecentlyRequested) { + if (request.denied) { + return "danger"; + } if (request.available || request.tvPartiallyAvailable) { return "success"; } diff --git a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html index da0b1af41d..81ecb21dd6 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html +++ b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html @@ -1,5 +1,8 @@
- +
+

{{'Discovery.Genres' | translate}}

+ +

{{'Discovery.RecentlyRequestedTab' | translate}}

diff --git a/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.html b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.html new file mode 100644 index 0000000000..688634dc71 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.html @@ -0,0 +1,13 @@ +
+ + {{genre.name}} + +
+
+ + {{genre.name}} + + +
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.scss b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.scss new file mode 100644 index 0000000000..65dcc4d988 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.scss @@ -0,0 +1,35 @@ + +h2{ + margin-top:40px; + margin-left:40px; + font-size: 24px; +} + +.discover-filter-buttons-group { + border: 1px solid #293a4c; + border-radius: 15px; + color:#fff; + margin-bottom:5px; + margin-right: 5px; + + .discover-filter-button{ + + transform: scale(0.9); + background:inherit; + color:inherit; + padding:0 0px; + border-radius: 30px; + padding-left: 10px; + padding-right: 10px; + border-left:none; + } +} + +.button-active{ + background:#293a4c; + } + +.genre-container { + margin-left: 35px; +} + \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.ts b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.ts new file mode 100644 index 0000000000..4dbf7233c5 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/discover/components/genre/genre-button-select.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit } from "@angular/core"; +import { SearchV2Service } from "../../../services"; +import { MatButtonToggleChange } from "@angular/material/button-toggle"; +import { RequestType } from "../../../interfaces"; +import { AdvancedSearchDialogDataService } from "app/shared/advanced-search-dialog/advanced-search-dialog-data.service"; +import { Router } from "@angular/router"; +import { map, Observable } from "rxjs"; + +interface IGenreSelect { + name: string; + id: number; + type: "movie"|"tv"; +} +@Component({ + selector: "genre-button-select", + templateUrl: "./genre-button-select.component.html", + styleUrls: ["./genre-button-select.component.scss"], +}) +export class GenreButtonSelectComponent implements OnInit { + public movieGenreList$: Observable = null; + public tvGenreList$: Observable = null; + + isLoading: boolean = false; + + constructor(private searchService: SearchV2Service, + private advancedSearchService: AdvancedSearchDialogDataService, + private router: Router) { } + + public ngOnInit(): void { + this.movieGenreList$ = this.searchService.getGenres("movie").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "movie" })))); + this.tvGenreList$ = this.searchService.getGenres("tv").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "tv" })))); + } + + public async toggleChanged(event: MatButtonToggleChange, type: "movie"|"tv") { + this.isLoading = true; + + const genres: number[] = [event.value]; + const data = await this.searchService.advancedSearch({ + watchProviders: [], + genreIds: genres, + keywordIds: [], + type: type, + }, 0, 30); + + this.advancedSearchService.setData(data, type == "movie" ? RequestType.movie : RequestType.tvShow); + this.advancedSearchService.setOptions([], genres, [], null, type == "movie" ? RequestType.movie : RequestType.tvShow, 30); + this.router.navigate([`discover/advanced/search`]); + } +} diff --git a/src/Ombi/ClientApp/src/app/discover/components/index.ts b/src/Ombi/ClientApp/src/app/discover/components/index.ts index 3b3993d39f..4ae524f7bb 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/index.ts +++ b/src/Ombi/ClientApp/src/app/discover/components/index.ts @@ -12,6 +12,7 @@ import { MatDialog } from "@angular/material/dialog"; import { RequestServiceV2 } from "../../services/requestV2.service"; import { Routes } from "@angular/router"; import { DetailedCardComponent } from "app/components"; +import { GenreButtonSelectComponent } from "./genre/genre-button-select.component"; export const components: any[] = [ DiscoverComponent, @@ -22,6 +23,7 @@ export const components: any[] = [ CarouselListComponent, RecentlyRequestedListComponent, DetailedCardComponent, + GenreButtonSelectComponent ]; export const providers: any[] = [ diff --git a/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.html b/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.html index f73b74752e..93d66de360 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.html +++ b/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.html @@ -3,8 +3,13 @@ - + +
diff --git a/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.ts b/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.ts index e869abc134..d30b4b66da 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.ts +++ b/src/Ombi/ClientApp/src/app/discover/components/recently-requested-list/recently-requested-list.component.ts @@ -8,6 +8,8 @@ import { Router } from "@angular/router"; import { AuthService } from "app/auth/auth.service"; import { NotificationService, RequestService } from "app/services"; import { TranslateService } from "@ngx-translate/core"; +import { DenyDialogComponent } from '../../../media-details/components/shared/deny-dialog/deny-dialog.component'; +import { MatDialog } from "@angular/material/dialog"; export enum DiscoverType { Upcoming, @@ -42,7 +44,8 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy { private router: Router, private authService: AuthService, private notificationService: NotificationService, - private translateService: TranslateService) { + private translateService: TranslateService, + public dialog: MatDialog) { Carousel.prototype.onTouchMove = () => {}; this.responsiveOptions = ResponsiveOptions; } @@ -81,6 +84,20 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy { } } + public deny(request: IRecentlyRequested) { + const dialogRef = this.dialog.open(DenyDialogComponent, { + width: '250px', + data: { requestId: request.requestId, is4K: false, requestType: request.type } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.notificationService.success(this.translateService.instant("Requests.SuccessfullyDenied")); + request.denied = true; + } + }); + } + private handleApproval(result: IRequestEngineResult, request: IRecentlyRequested) { if (result.result) { this.notificationService.success(this.translateService.instant("Requests.SuccessfullyApproved")); diff --git a/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.html b/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.html index 97ff038a0d..dcaec3f557 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.html +++ b/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.html @@ -9,7 +9,7 @@ [infiniteScrollDistance]="3" [infiniteScrollThrottle]="200" (scrolled)="onScroll()"> -
+
diff --git a/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.scss b/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.scss index 728ff23c51..0c617ca8c5 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.scss +++ b/src/Ombi/ClientApp/src/app/discover/components/search-results/search-results.component.scss @@ -16,4 +16,4 @@ .loading-spinner { margin: 10%; -} \ No newline at end of file +} diff --git a/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts b/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts index 9cd5dc76e9..67da557835 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts @@ -11,6 +11,7 @@ export interface IRecentlyRequested { overview: string; releaseDate: Date; approved: boolean; + denied: boolean; mediaId: string; type: RequestType; diff --git a/src/Ombi/ClientApp/src/app/interfaces/IRequestModel.ts b/src/Ombi/ClientApp/src/app/interfaces/IRequestModel.ts index 36b75adb6c..6031e97966 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/IRequestModel.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/IRequestModel.ts @@ -23,6 +23,8 @@ export interface IMovieRequests extends IFullBaseRequest { deniedReason4K: string; requestedDate4k: Date; requestedDate: Date; + watchedByRequestedUser: boolean; + playedByUsersCount: number; // For the UI rootPathOverrideTitle: string; @@ -212,4 +214,4 @@ export class BaseRequestOptions { requestOnBehalf: string | undefined; rootFolderOverride: number | undefined; qualityPathOverride: number | undefined; -} \ No newline at end of file +} diff --git a/src/Ombi/ClientApp/src/app/interfaces/ITester.ts b/src/Ombi/ClientApp/src/app/interfaces/ITester.ts index b5615aae74..6bca107f2d 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ITester.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ITester.ts @@ -2,4 +2,5 @@ export interface ITesterResult { isValid: boolean; version?: string; expectedSubDir?: string; + additionalInformation?: string; } diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.html b/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.html index 29d2c6beb3..db6a78b5a3 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.html +++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.html @@ -36,18 +36,7 @@
{{'MediaDetails.RequestStatus' | translate }} -
-
{{'Common.RequestDenied' | translate}}
-
{{'Common.ProcessingRequest' | translate}}
-
{{'Common.PendingApproval' | translate}}
- -
-
-
{{'Common.RequestDenied4K' | translate}}
-
{{'Common.ProcessingRequest4K' | translate}}
-
{{'Common.PendingApproval4K' | translate}}
- -
+
{{getStatus(movie) | translate}}
@@ -66,12 +55,12 @@ {{RequestSource[request.source]}}
-
+
{{'MediaDetails.DeniedReason' | translate }} -
+
{{request.deniedReason}}
-
+
{{request.deniedReason4K}}
diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.ts index ade256a82a..4838dff512 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/panels/movie-information-panel.component.ts @@ -34,4 +34,28 @@ export class MovieInformationPanelComponent implements OnInit { this.searchService.getMovieStreams(this.movie.id).subscribe(x => this.streams = x); } + + public getStatus(movie: ISearchMovieResultV2) { + if (!movie.available && movie.requested) { + if (movie.denied) { + return "Common.RequestDenied"; + } + if (movie.approved) { + return "Common.ProcessingRequest"; + } else { + return "Common.PendingApproval"; + } + } + + if (!movie.available4K && movie.has4KRequest) { + if (movie.denied4K) { + return "Common.RequestDenied4K"; + } + if (movie.approved4K) { + return "Common.ProcessingRequest4K"; + } else { + return "Common.PendingApproval4K"; + } + } + } } diff --git a/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.scss b/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.scss index 9780f5b5da..7b0500f77f 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.scss +++ b/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.scss @@ -63,6 +63,7 @@ $ombi-accent: #258a6d; ::ng-deep .discoverResults{ margin-top:40px; + margin-left: 35px; } ::ng-deep button:focus{ diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html index 26da475241..0e91ce5e3c 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html @@ -52,7 +52,7 @@ {{'Requests.RequestedBy' | translate}} - {{element.requestedUser?.userAlias}} + {{element.requestedByAlias ? element.requestedByAlias : element.requestedUser?.userAlias}} @@ -80,6 +80,23 @@ {{element.requestStatus | translate}} + + + {{ 'Requests.Watched' | translate}} + + + + + + + diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts index ca36a5d622..4b0b0ebb4c 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts @@ -24,10 +24,11 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public dataSource: MatTableDataSource; public resultsLength: number; public isLoadingResults = true; - public displayedColumns: string[] = ['title', 'requestedUser.requestedBy', 'status', 'requestStatus','requestedDate', 'actions']; + public displayedColumns: string[]; public gridCount: string = "15"; public isAdmin: boolean; public is4kEnabled = false; + public isPlayedSyncEnabled = false; public manageOwnRequests: boolean; public defaultSort: string = "requestedDate"; public defaultOrder: string = "desc"; @@ -60,15 +61,10 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public ngOnInit() { this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); this.manageOwnRequests = this.auth.hasRole("ManageOwnRequests") - if (this.isAdmin) { - this.displayedColumns.unshift('select'); - } this.is4kEnabled = this.featureFacade.is4kEnabled(); - if ((this.isAdmin || this.auth.hasRole("Request4KMovie")) - && this.is4kEnabled) { - this.displayedColumns.splice(4, 0, 'has4kRequest'); - } + this.isPlayedSyncEnabled = this.featureFacade.isPlayedSyncEnabled(); + const defaultCount = this.storageService.get(this.storageKeyGridCount); const defaultSort = this.storageService.get(this.storageKey); @@ -88,8 +84,31 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { } } + setDisplayedColumns() { + this.displayedColumns = ['title', 'requestedUser.requestedBy', 'status', 'requestStatus','requestedDate']; + + if (this.isAdmin) { + this.displayedColumns.unshift('select'); + } + + if ((this.isAdmin || this.auth.hasRole("Request4KMovie")) + && this.is4kEnabled) { + this.displayedColumns.splice(4, 0, 'has4kRequest'); + } + + if (this.isPlayedSyncEnabled + && ( this.currentFilter == RequestFilterType.All || this.currentFilter == RequestFilterType.Available ) ) { + this.displayedColumns.push('watchedByRequestedUser'); + } + + // always put the actions column at the end + this.displayedColumns.push('actions'); + } + public async ngAfterViewInit() { + this.setDisplayedColumns(); + this.storageService.save(this.storageKeyGridCount, this.gridCount); this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString()); @@ -263,4 +282,4 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { } return request.requestedDate; } -} \ No newline at end of file +} diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html index 7eb4b56340..d7045665a3 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html @@ -38,7 +38,7 @@ {{'Requests.RequestedBy' | translate}} - {{element.requestedUser.userAlias}} + {{element.requestedByAlias ? element.requestedByAlias : element.requestedUser.userAlias}} @@ -73,4 +73,4 @@ -
\ No newline at end of file +
diff --git a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts index 573463cf0c..749be6ff65 100644 --- a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; -import { UntypedFormBuilder, FormControl, UntypedFormGroup, Validators } from "@angular/forms"; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; import { SonarrFacade } from "app/state/sonarr/sonarr.facade"; -import { finalize, map } from "rxjs"; +import { catchError, finalize, map, of } from "rxjs"; import { ILanguageProfiles, ISonarrProfile, ISonarrRootFolder, ITag } from "../../interfaces"; @@ -95,7 +95,7 @@ export class SonarrComponent implements OnInit { this.tags = []; this.animeTags = []; - if (version.length > 0) { + if (version?.length > 0) { this.sonarrVersion = version[0]; } @@ -132,11 +132,19 @@ export class SonarrComponent implements OnInit { public getProfiles(form: UntypedFormGroup) { this.profilesRunning = true; this.sonarrService.getQualityProfiles(form.value) + .pipe(catchError((_) => { + this.notificationService.error("Could not load Quality Profiles"); + return of([]); + })) .subscribe(x => { + this.profilesRunning = false; + if (x.length === 0) { + return; + } this.qualities = x; this.qualitiesAnime = x; this.qualities.unshift({ name: "Please Select", id: -1 }); - this.profilesRunning = false; + this.notificationService.success("Successfully retrieved the Quality Profiles"); }); } @@ -144,12 +152,19 @@ export class SonarrComponent implements OnInit { public getRootFolders(form: UntypedFormGroup) { this.rootFoldersRunning = true; this.sonarrService.getRootFolders(form.value) + .pipe(catchError((_) => { + this.notificationService.error("Could not load Root Folders"); + return of([]); + })) .subscribe(x => { + this.rootFoldersRunning = false; + if (x.length === 0) { + return; + } this.rootFolders = x; this.rootFolders.unshift({ path: "Please Select", id: -1 }); this.rootFoldersAnime = x; - this.rootFoldersRunning = false; this.notificationService.success("Successfully retrieved the Root Folders"); }); } @@ -157,11 +172,18 @@ export class SonarrComponent implements OnInit { public getLanguageProfiles(form: UntypedFormGroup) { this.langRunning = true; this.sonarrService.getV3LanguageProfiles(form.value) + .pipe(catchError((_) => { + this.notificationService.error("Could not load Language Profiles"); + return of([]); + })) .subscribe(x => { + this.langRunning = false; + if (x.length === 0) { + return; + } this.languageProfiles = x; this.languageProfilesAnime = x; - this.langRunning = false; this.notificationService.success("Successfully retrieved the Language Profiles"); }); } @@ -169,11 +191,18 @@ export class SonarrComponent implements OnInit { public getTags(form: UntypedFormGroup) { this.tagsRunning = true; this.sonarrService.getTags(form.value).pipe( + catchError((_) => { + this.notificationService.error("Could not load Tags"); + return of([]); + }), finalize(() => { this.tagsRunning = false; + if (this.tags.length === 0) { + return; + } this.animeTags.unshift({ label: "None", id: -1 }); this.tags.unshift({ label: "None", id: -1 }); - this.notificationService.success("Successfully retrieved the Tags"); + this.notificationService.success("Successfully retrieved the Tags") }), map(result => { this.tags = result; @@ -191,7 +220,11 @@ export class SonarrComponent implements OnInit { } else if (result.expectedSubDir) { this.notificationService.error("Your Sonarr Base URL must be set to " + result.expectedSubDir); } else { - this.notificationService.error("We could not connect to Sonarr!"); + if (result.additionalInformation) { + this.notificationService.error(result.additionalInformation); + } else { + this.notificationService.error("We could not connect to Sonarr!"); + } } }); } @@ -204,16 +237,19 @@ export class SonarrComponent implements OnInit { if (form.controls.defaultQualityProfile) { if (form.controls.defaultQualityProfile.value === "-1") { this.notificationService.error("Please check your entered values"); + return; } } if (form.controls.defaultRootPath) { if (form.controls.defaultRootPath.value === "Please Select") { this.notificationService.error("Please check your entered values"); + return; } } if (form.controls.languageProfile) { if (form.controls.languageProfile.value === "Please Select") { this.notificationService.error("Please check your entered values"); + return; } } if (form.controls.animeTag.value == -1) { diff --git a/src/Ombi/ClientApp/src/app/state/features/features.facade.ts b/src/Ombi/ClientApp/src/app/state/features/features.facade.ts index 10e229ebad..9b5091cba0 100644 --- a/src/Ombi/ClientApp/src/app/state/features/features.facade.ts +++ b/src/Ombi/ClientApp/src/app/state/features/features.facade.ts @@ -23,4 +23,6 @@ export class FeaturesFacade { public is4kEnabled = (): boolean => this.store.selectSnapshot(FeaturesSelectors.is4kEnabled); -} \ No newline at end of file + public isPlayedSyncEnabled = (): boolean => this.store.selectSnapshot(FeaturesSelectors.isPlayedSyncEnabled); + +} diff --git a/src/Ombi/ClientApp/src/app/state/features/features.selectors.ts b/src/Ombi/ClientApp/src/app/state/features/features.selectors.ts index 143dfb8758..bbea921e5e 100644 --- a/src/Ombi/ClientApp/src/app/state/features/features.selectors.ts +++ b/src/Ombi/ClientApp/src/app/state/features/features.selectors.ts @@ -15,4 +15,9 @@ export class FeaturesSelectors { return features.filter(x => x.name === "Movie4KRequests")[0].enabled; } -} \ No newline at end of file + @Selector([FeaturesSelectors.features]) + public static isPlayedSyncEnabled(features: IFeatureEnablement[]): boolean { + return features.filter(x => x.name === "PlayedSync")[0].enabled; + } + +} diff --git a/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts b/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts index b59faa6246..20bf3fe9c1 100644 --- a/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts +++ b/src/Ombi/ClientApp/src/app/state/radarr/radarr.state.ts @@ -18,7 +18,7 @@ export class RadarrSettingsState { @Action(LoadSettings) public load({ setState }: StateContext): Observable { - const isAdmin = this.authService.isAdmin(); + const isAdmin = this.authService.hasRole("Admin"); const calls = isAdmin ? [this.settingsService.getRadarr()] : [of({})]; return combineLatest(calls).pipe( diff --git a/src/Ombi/ClientApp/src/app/state/sonarr/sonarr.state.ts b/src/Ombi/ClientApp/src/app/state/sonarr/sonarr.state.ts index 4f08896f85..218dd912c3 100644 --- a/src/Ombi/ClientApp/src/app/state/sonarr/sonarr.state.ts +++ b/src/Ombi/ClientApp/src/app/state/sonarr/sonarr.state.ts @@ -18,7 +18,7 @@ export class SonarrSettingsState { @Action(LoadSettings) public load({ setState }: StateContext): Observable { - const isAdmin = this.authService.isAdmin(); + const isAdmin = this.authService.hasRole("Admin"); const calls = isAdmin ? [this.sonarrService.getVersion(), this.settingsService.getSonarr()] : [of(""), of({})]; return combineLatest(calls).pipe( @@ -31,7 +31,7 @@ export class SonarrSettingsState { } @Action(UpdateSettings) - public enable(ctx: StateContext, { settings }: UpdateSettings): Observable { + public update(ctx: StateContext, { settings }: UpdateSettings): Observable { const state = ctx.getState(); return this.settingsService.saveSonarr(settings).pipe( tap((_) => ctx.setState({...state, settings})), diff --git a/src/Ombi/ClientApp/yarn.lock b/src/Ombi/ClientApp/yarn.lock index 276f789967..8fc0a3a7e1 100644 --- a/src/Ombi/ClientApp/yarn.lock +++ b/src/Ombi/ClientApp/yarn.lock @@ -204,14 +204,14 @@ __metadata: languageName: node linkType: hard -"@angular/animations@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/animations@npm:15.0.1" +"@angular/animations@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/animations@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/core": 15.0.1 - checksum: 88b75c0c93acd462a793ab82f26463dc0868dcfd2552ede91ef76f72ec9d8723a48a15e026050b741944befb969461c4b1b18494dac2f926a1decee290caee3d + "@angular/core": 15.2.4 + checksum: 8fe91a126cac08f1bda95fe7d78bf789e61255211e545dfdd0378eb9f52e0a4a3c4683f1fc925fceed2bfaf9146ce872a7df11f73e92b184fc042565a41609b3 languageName: node linkType: hard @@ -260,98 +260,98 @@ __metadata: languageName: node linkType: hard -"@angular/common@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/common@npm:15.0.1" +"@angular/common@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/common@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/core": 15.0.1 + "@angular/core": 15.2.4 rxjs: ^6.5.3 || ^7.4.0 - checksum: 8cc0f0df94e92c83fffeb72b11e2b8f4d322cdcaedfc9b94cddaef9f2ef7a1a48a8db8db386c41245f9cffba922bec423f30674cb62d7f53262cdaea5a4198aa + checksum: 089436758dc98d7a653bcf0301d090f588ee931d142033c06de5da569db2fd5e924ee84e8baac4fd8bdebdbd1d20b8af1611cc2b2a9bc4f7c7e7c2e9606f1934 languageName: node linkType: hard -"@angular/compiler-cli@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/compiler-cli@npm:15.0.1" +"@angular/compiler-cli@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/compiler-cli@npm:15.2.4" dependencies: - "@babel/core": ^7.17.2 + "@babel/core": 7.19.3 + "@jridgewell/sourcemap-codec": ^1.4.14 chokidar: ^3.0.0 convert-source-map: ^1.5.1 dependency-graph: ^0.11.0 - magic-string: ^0.26.0 + magic-string: ^0.27.0 reflect-metadata: ^0.1.2 semver: ^7.0.0 - sourcemap-codec: ^1.4.8 tslib: ^2.3.0 yargs: ^17.2.1 peerDependencies: - "@angular/compiler": 15.0.1 - typescript: ">=4.8.2 <4.9" + "@angular/compiler": 15.2.4 + typescript: ">=4.8.2 <5.0" bin: ng-xi18n: bundles/src/bin/ng_xi18n.js ngc: bundles/src/bin/ngc.js ngcc: bundles/ngcc/main-ngcc.js - checksum: f92b6f579d72b7159ad33e5240e1dd87c109bee3628bb4a8c0dc8dd263dd021547eb6fbcd8ec7a4b7bec162b464cd8a40829c3d20cba649b0ee1685330591f62 + checksum: 9ef61841627f336c5c40d0c3e3ef505390b2171f26d36dd242a00bef7c30c985b0edf198ca2d965ad1a2c779caab27204452d88dc865993af0e395023e261a53 languageName: node linkType: hard -"@angular/compiler@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/compiler@npm:15.0.1" +"@angular/compiler@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/compiler@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/core": 15.0.1 + "@angular/core": 15.2.4 peerDependenciesMeta: "@angular/core": optional: true - checksum: 3c0d932805cd7e4164accdf6d8d00899dff286c85ab75f30434277a7ba8f92f2cbbbfc4dc1074dc49ce8c6250adb2e12e4f357a439c8ffe71fae14da3612898d + checksum: f47676eb0160be35b5f44e625a3bea43e51fc84c3aa05a9bbebd1fcd357fa73331dc4de32af2dbec7e1f254fb0e65ed9e149e8e7cf61eb81464453c666ff78d1 languageName: node linkType: hard -"@angular/core@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/core@npm:15.0.1" +"@angular/core@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/core@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: rxjs: ^6.5.3 || ^7.4.0 - zone.js: ~0.11.4 || ~0.12.0 - checksum: c87fbbd4fefe237e311901d48f84e7790788acde30ee489af3e763f2423446a0010a4bc25d1e659b1170f8c1597ca306ae95e2e6956e93e02a7a708a1acb233b + zone.js: ~0.11.4 || ~0.12.0 || ~0.13.0 + checksum: ab7ad7b6b55fe24ff1f390ea09c04d52301146075488fc4ee4700d77e9f24ad8b3a03f3ca48b6f4306f6b2106e22b541b23bfb5df3fca94606b94fd95b20df7b languageName: node linkType: hard -"@angular/forms@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/forms@npm:15.0.1" +"@angular/forms@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/forms@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/common": 15.0.1 - "@angular/core": 15.0.1 - "@angular/platform-browser": 15.0.1 + "@angular/common": 15.2.4 + "@angular/core": 15.2.4 + "@angular/platform-browser": 15.2.4 rxjs: ^6.5.3 || ^7.4.0 - checksum: fd60fb50a8af40bbe4f725391b4b6c8f454953f980e3b50493b9d3cd637dd5f8d51ae30871661ab369996a7d8df37297eb816252447b87650ea32ca56b35d180 + checksum: cc23288506d62f2e1e86e22ab795176b46d63aa0f821515b9549bb10b583975e45b67667d14d1eb52c24a645ad81e7e8693855d5d7f521c27ab4ef0ee871791b languageName: node linkType: hard -"@angular/localize@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/localize@npm:15.0.1" +"@angular/localize@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/localize@npm:15.2.4" dependencies: "@babel/core": 7.19.3 - glob: 8.0.3 + glob: 8.1.0 yargs: ^17.2.1 peerDependencies: - "@angular/compiler": 15.0.1 - "@angular/compiler-cli": 15.0.1 + "@angular/compiler": 15.2.4 + "@angular/compiler-cli": 15.2.4 bin: localize-extract: tools/bundles/src/extract/cli.js localize-migrate: tools/bundles/src/migrate/cli.js localize-translate: tools/bundles/src/translate/cli.js - checksum: b03f50c4540a6c00e646ab67483ae732aeed57ec1d7c5a301031b6ca3304ec2a4846ae8911d8d3c6ca21fb2b59d33688a5c0f55bdff499abd529664206610697 + checksum: 999976488ea1aacfd61f738bbb4933dff7e6b144bf066e3ede2ebd1bf267e70c8fffaeb8ef8666fe0c823827f35fc597dfb222014237c87cba92c06e753d0db5 languageName: node linkType: hard @@ -372,65 +372,65 @@ __metadata: languageName: node linkType: hard -"@angular/platform-browser-dynamic@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/platform-browser-dynamic@npm:15.0.1" +"@angular/platform-browser-dynamic@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/platform-browser-dynamic@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/common": 15.0.1 - "@angular/compiler": 15.0.1 - "@angular/core": 15.0.1 - "@angular/platform-browser": 15.0.1 - checksum: 8e8c9645b6d662f79ed769b96cd9c8da3edd536532d6accae53e69054dfd77841b449e76c271e756adae679ee0e4b2bc3f3ee06aec1133db50d067db3e2575df + "@angular/common": 15.2.4 + "@angular/compiler": 15.2.4 + "@angular/core": 15.2.4 + "@angular/platform-browser": 15.2.4 + checksum: e48fe83b1d9723ee26a1b4343d7dfd1537027e01f559382b819174f4f25e700ff46c0390fc35dbc4550fa374d37a6d449f7a9504c55d0d7b8e7f90e2785c2048 languageName: node linkType: hard -"@angular/platform-browser@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/platform-browser@npm:15.0.1" +"@angular/platform-browser@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/platform-browser@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/animations": 15.0.1 - "@angular/common": 15.0.1 - "@angular/core": 15.0.1 + "@angular/animations": 15.2.4 + "@angular/common": 15.2.4 + "@angular/core": 15.2.4 peerDependenciesMeta: "@angular/animations": optional: true - checksum: 87ceb94dea9f9d4de3a444bcc307e15f8a7b53218143ae7dc30886cc64eba9e9a9b430e96a70d7f37b6d06aacb9a2e33c17dffac87452576c52b8099e02a3a0e + checksum: 67a52b676362614840df1056a579daf9f3763bacec9c2e4fff64109070624b3d2daa3bd2bb8fad776a79e65239f90c9227aa97de3a1b22e8ac397b84038c02e9 languageName: node linkType: hard -"@angular/platform-server@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/platform-server@npm:15.0.1" +"@angular/platform-server@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/platform-server@npm:15.2.4" dependencies: domino: ^2.1.2 tslib: ^2.3.0 xhr2: ^0.2.0 peerDependencies: - "@angular/animations": 15.0.1 - "@angular/common": 15.0.1 - "@angular/compiler": 15.0.1 - "@angular/core": 15.0.1 - "@angular/platform-browser": 15.0.1 - "@angular/platform-browser-dynamic": 15.0.1 - checksum: bfbb51013f21a6c889c39ba200573b922f58390dd8a86f1803a9f24d2ad984e5ab890e38dbcec612c5a35298aca92287de48d16a5762807972c3fe67a4fc3d1a + "@angular/animations": 15.2.4 + "@angular/common": 15.2.4 + "@angular/compiler": 15.2.4 + "@angular/core": 15.2.4 + "@angular/platform-browser": 15.2.4 + "@angular/platform-browser-dynamic": 15.2.4 + checksum: e6f3d0b6222356c4af9201e8d8747e4657f1977beb223d39ab7ef60634937d49d89c0826db11ed3d8b46b92bf8dda38dffc1bb001195266ed1618edc8f378d96 languageName: node linkType: hard -"@angular/router@npm:^15.0.1": - version: 15.0.1 - resolution: "@angular/router@npm:15.0.1" +"@angular/router@npm:^15.0.4": + version: 15.2.4 + resolution: "@angular/router@npm:15.2.4" dependencies: tslib: ^2.3.0 peerDependencies: - "@angular/common": 15.0.1 - "@angular/core": 15.0.1 - "@angular/platform-browser": 15.0.1 + "@angular/common": 15.2.4 + "@angular/core": 15.2.4 + "@angular/platform-browser": 15.2.4 rxjs: ^6.5.3 || ^7.4.0 - checksum: f9a8b80398cf8024dfac30c2b36d1870c25b4f1f07df8e8039226e975fc7c7b977ca9e5c050dc707e8e2036f1577f799d74796c15dead8f256fa8c0199e6bd1a + checksum: ef98f2f22e78379fdaf6dd6f4732c161aa6e596d236e8f7e8e893ab488342f28e3f76127b2b24076697800073dccaea29a6c6c376082cd2354be859f3faa273d languageName: node linkType: hard @@ -568,7 +568,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.17.2, @babel/core@npm:^7.17.5, @babel/core@npm:^7.18.9": +"@babel/core@npm:^7.17.5, @babel/core@npm:^7.18.9": version: 7.18.10 resolution: "@babel/core@npm:7.18.10" dependencies: @@ -2391,7 +2391,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10": +"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 @@ -2508,28 +2508,28 @@ __metadata: languageName: node linkType: hard -"@ngxs/devtools-plugin@npm:^3.7.3": - version: 3.7.6 - resolution: "@ngxs/devtools-plugin@npm:3.7.6" +"@ngxs/devtools-plugin@npm:3.7.3": + version: 3.7.3 + resolution: "@ngxs/devtools-plugin@npm:3.7.3" dependencies: tslib: ^1.9.0 peerDependencies: - "@angular/core": ">=6.1.0 <16.0.0" - "@ngxs/store": ^3.7.6 || ^3.7.6-dev + "@angular/core": ">=6.1.0 <14.0.0" + "@ngxs/store": ^3.7.3 || ^3.7.3-dev rxjs: ">=6.5.5" - checksum: f20a5ecf0cdfb7af17ff3075819f7eb6c324dce07f4b111d518d66e573037d3f3f842f3ee4f4ec7a1b8603e8293355c9e5e3455ca532749e2bdcc7ac4fed5c00 + checksum: c6c4bcbda46be3d73bbece2c6f9f5002df2564850d2bb6ab66f66751e3b54d6aba4363a29e26ca0f205b509468ec5d8a82c25409b3eb377d4efe3026663baa6c languageName: node linkType: hard -"@ngxs/store@npm:^3.7.3": - version: 3.7.6 - resolution: "@ngxs/store@npm:3.7.6" +"@ngxs/store@npm:3.7.3": + version: 3.7.3 + resolution: "@ngxs/store@npm:3.7.3" dependencies: tslib: ^1.9.0 peerDependencies: - "@angular/core": ">=6.1.0 <16.0.0" + "@angular/core": ">=6.1.0 <14.0.0" rxjs: ">=6.5.5" - checksum: b1582d5157f36dfe1700d9f41ec6a935c794d732d474e998d3a276d6a5005e725071124e5137b83248ced2e1591c10b1fbff97c5db5d5fac21e3fc5bb70cb55b + checksum: 756c47c3463a30bb0dc97a62d9a22928fbd4de1f15e05735457b3dfc0dadd6292273c5e8e71bf4b06f2ea9b339e995143284094264fa5136b82317c46ed61ae0 languageName: node linkType: hard @@ -2674,6 +2674,13 @@ __metadata: languageName: node linkType: hard +"@scarf/scarf@npm:^1.1.0": + version: 1.1.1 + resolution: "@scarf/scarf@npm:1.1.1" + checksum: f3205e7a76fed1ec3328643a5f276f4aab5c67d0e17ca0a414755aacae529f4a3492b44607f9ad066470ecb3ee003e72b3d9581f58dc6c507c18180611ff113e + languageName: node + linkType: hard + "@schematics/angular@npm:15.0.2": version: 15.0.2 resolution: "@schematics/angular@npm:15.0.2" @@ -9221,6 +9228,19 @@ cors@latest: languageName: node linkType: hard +"glob@npm:8.1.0": + version: 8.1.0 + resolution: "glob@npm:8.1.0" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^5.0.1 + once: ^1.3.0 + checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 + languageName: node + linkType: hard + "glob@npm:^7.0.3, glob@npm:^7.0.6, glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -11425,12 +11445,12 @@ cors@latest: languageName: node linkType: hard -"magic-string@npm:^0.26.0": - version: 0.26.2 - resolution: "magic-string@npm:0.26.2" +"magic-string@npm:^0.27.0": + version: 0.27.0 + resolution: "magic-string@npm:0.27.0" dependencies: - sourcemap-codec: ^1.4.8 - checksum: b4db4e2b370ac8d9ffc6443a2b591b75364bf1fc9121b5a4068d5b89804abff6709d1fa4a0e0c2d54f2e61e0e44db83efdfe219a5ab0ba6d25ee1f2b51fbed55 + "@jridgewell/sourcemap-codec": ^1.4.13 + checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e languageName: node linkType: hard @@ -12223,15 +12243,13 @@ cors@latest: languageName: node linkType: hard -"ngx-infinite-scroll@npm:^14.0.0": - version: 14.0.1 - resolution: "ngx-infinite-scroll@npm:14.0.1" +"ngx-infinite-scroll@npm:^9.0.0": + version: 9.1.0 + resolution: "ngx-infinite-scroll@npm:9.1.0" dependencies: - tslib: ^2.3.0 - peerDependencies: - "@angular/common": ">=14.0.0 <15.0.0" - "@angular/core": ">=14.0.0 <15.0.0" - checksum: 7df67fc87a6638d4fa3ade5ea83549ccaf4ecf28e68eb2da81d8f8aec96c2edd69d7452de842f23d558f414cfb424738602aef509310ec25117eb25005056b75 + "@scarf/scarf": ^1.1.0 + opencollective-postinstall: ^2.0.2 + checksum: c1cb914ed49d377daeddce346485d2228826a22af418f9b72f6aa02823f50feb85b248fde04664bb2075c64070b6c8958e4f06a61ec0f0c153a75a4edfff4945 languageName: node linkType: hard @@ -12773,20 +12791,20 @@ cors@latest: resolution: "ombi@workspace:." dependencies: "@angular-devkit/build-angular": ^15.0.2 - "@angular/animations": ^15.0.1 + "@angular/animations": ^15.0.4 "@angular/cdk": ^14.2.7 "@angular/cli": ^15.0.2 - "@angular/common": ^15.0.1 - "@angular/compiler": ^15.0.1 - "@angular/compiler-cli": ^15.0.1 - "@angular/core": ^15.0.1 - "@angular/forms": ^15.0.1 - "@angular/localize": ^15.0.1 + "@angular/common": ^15.0.4 + "@angular/compiler": ^15.0.4 + "@angular/compiler-cli": ^15.0.4 + "@angular/core": ^15.0.4 + "@angular/forms": ^15.0.4 + "@angular/localize": ^15.0.4 "@angular/material": ^14.2.7 - "@angular/platform-browser": ^15.0.1 - "@angular/platform-browser-dynamic": ^15.0.1 - "@angular/platform-server": ^15.0.1 - "@angular/router": ^15.0.1 + "@angular/platform-browser": ^15.0.4 + "@angular/platform-browser-dynamic": ^15.0.4 + "@angular/platform-server": ^15.0.4 + "@angular/router": ^15.0.4 "@angularclass/hmr": ^3.0.0 "@auth0/angular-jwt": ^5.0.2 "@babel/core": ^7.18.9 @@ -12795,8 +12813,8 @@ cors@latest: "@microsoft/signalr": ^6.0.7 "@ngx-translate/core": ^14.0.0 "@ngx-translate/http-loader": ^7.0.0 - "@ngxs/devtools-plugin": ^3.7.3 - "@ngxs/store": ^3.7.3 + "@ngxs/devtools-plugin": 3.7.3 + "@ngxs/store": 3.7.3 "@storybook/angular": ^6.5.9 "@types/jquery": ^3.5.14 "@yellowspot/ng-truncate": ^2.0.0 @@ -12810,7 +12828,7 @@ cors@latest: moment: ^2.29.1 ng2-cookies: ^1.0.12 ngx-clipboard: ^12.1.0 - ngx-infinite-scroll: ^14.0.0 + ngx-infinite-scroll: ^9.0.0 ngx-moment: ^3.0.1 ngx-order-pipe: ^2.2.0 popper.js: ^1.14.3 @@ -12898,7 +12916,7 @@ cors@latest: languageName: node linkType: hard -"opencollective-postinstall@npm:^2.0.3": +"opencollective-postinstall@npm:^2.0.2, opencollective-postinstall@npm:^2.0.3": version: 2.0.3 resolution: "opencollective-postinstall@npm:2.0.3" bin: diff --git a/src/Ombi/Controllers/V1/External/SonarrController.cs b/src/Ombi/Controllers/V1/External/SonarrController.cs index 1d63c60137..0bcd39c557 100644 --- a/src/Ombi/Controllers/V1/External/SonarrController.cs +++ b/src/Ombi/Controllers/V1/External/SonarrController.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -59,6 +60,7 @@ public Task> GetRootFolders([FromBody] SonarrSetti [PowerUser] public async Task> GetProfiles() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -75,6 +77,7 @@ public async Task> GetProfiles() [PowerUser] public async Task> GetRootFolders() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -92,6 +95,7 @@ public async Task> GetRootFolders() [PowerUser] public async Task> GetLanguageProfiles() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -147,6 +151,7 @@ public async Task> GetLanguageProfiles([FromBody] [PowerUser] public async Task Enabled() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); return settings.Enabled; } @@ -155,13 +160,21 @@ public async Task Enabled() [PowerUser] public async Task SonarrVersion() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (!settings.Enabled) { return string.Empty; } - var status = await SonarrV3Api.SystemStatus(settings.ApiKey, settings.FullUri); - return status.version; + try + { + var status = await SonarrV3Api.SystemStatus(settings.ApiKey, settings.FullUri); + return status.version; + } + catch (Exception) + { + return string.Empty; + } } } } \ No newline at end of file diff --git a/src/Ombi/Controllers/V1/External/TesterController.cs b/src/Ombi/Controllers/V1/External/TesterController.cs index 79a0083221..a244fd0fbe 100644 --- a/src/Ombi/Controllers/V1/External/TesterController.cs +++ b/src/Ombi/Controllers/V1/External/TesterController.cs @@ -410,6 +410,30 @@ public async Task Sonarr([FromBody] SonarrSettings settings) { try { + if (string.IsNullOrEmpty(settings.ApiKey)) + { + return new TesterResultModel + { + IsValid = false, + AdditionalInformation = "NullApiKey" + }; + } + if (string.IsNullOrEmpty(settings.Ip)) + { + return new TesterResultModel + { + IsValid = false, + AdditionalInformation = "NullIp" + }; + } + if (settings.Port <= 0) + { + return new TesterResultModel + { + IsValid = false, + AdditionalInformation = "BadPort" + }; + } var result = await SonarrApi.SystemStatus(settings.ApiKey, settings.FullUri); return new TesterResultModel diff --git a/src/Ombi/Controllers/V1/SettingsController.cs b/src/Ombi/Controllers/V1/SettingsController.cs index 0892b1ddaa..c77913e485 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -652,7 +652,9 @@ public async Task JobSettings([FromBody]JobSettings settin try { var isValid = CronExpression.IsValidExpression(expression); - if (!isValid) + CronExpression cron = new CronExpression(expression); + DateTimeOffset? nextFireUTCTime = cron.GetNextValidTimeAfter(DateTime.Now); + if (!isValid || nextFireUTCTime == null) { return new JobSettingsViewModel { diff --git a/src/Ombi/Controllers/V2/SystemController.cs b/src/Ombi/Controllers/V2/SystemController.cs index 6b76d053d4..b2aed3f44a 100644 --- a/src/Ombi/Controllers/V2/SystemController.cs +++ b/src/Ombi/Controllers/V2/SystemController.cs @@ -44,25 +44,33 @@ public IActionResult GetLogFiles() } [HttpGet("logs/{logFileName}")] - public async Task ReadLogFile(string logFileName, CancellationToken token) + public async Task ReadLogFile(string logFileName) { - var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName); - using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - using (StreamReader reader = new StreamReader(fs)) + var logsFolder = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs"); + var files = Directory.EnumerateFiles(logsFolder); + var matchingFile = files.FirstOrDefault(x => Path.GetFileName(x).Equals(logFileName)); + if (matchingFile != null) { + using var fs = new FileStream(matchingFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + using StreamReader reader = new(fs); return Ok(await reader.ReadToEndAsync()); } + return NotFound(); } [HttpGet("logs/download/{logFileName}")] - public IActionResult Download(string logFileName, CancellationToken token) + public IActionResult Download(string logFileName) { - var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName); - using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - using (StreamReader reader = new StreamReader(fs)) + var logsFolder = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs"); + var files = Directory.EnumerateFiles(logsFolder); + var matchingFile = files.FirstOrDefault(x => Path.GetFileName(x).Equals(logFileName)); + if (matchingFile != null) { + using var fs = new FileStream(matchingFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + using StreamReader reader = new(fs); return File(reader.BaseStream, "application/octet-stream", logFileName); } + return NotFound(); } } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/bg.json b/src/Ombi/wwwroot/translations/bg.json index 1a9618e47d..9f66f52f59 100644 --- a/src/Ombi/wwwroot/translations/bg.json +++ b/src/Ombi/wwwroot/translations/bg.json @@ -159,6 +159,9 @@ "RequestedBy": "Заявено от", "Status": "Състояние", "RequestStatus": "Състояние на заявката", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Отказано:", "TheatricalRelease": "Кино премиера: {{date}}", "ReleaseDate": "Премиера: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Successfully Approved", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Request successfully deleted", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Филми", "Combined": "Комбинирано", "Tv": "Телевизия", + "Genres": "Genres", "CardDetails": { "Availability": "Наличност", "Studio": "Студио", diff --git a/src/Ombi/wwwroot/translations/ca.json b/src/Ombi/wwwroot/translations/ca.json index 57fcc6b495..39aba51f8e 100644 --- a/src/Ombi/wwwroot/translations/ca.json +++ b/src/Ombi/wwwroot/translations/ca.json @@ -159,6 +159,9 @@ "RequestedBy": "Sol·licitat per", "Status": "Estat", "RequestStatus": "Estat de la sol·licitud", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Denegat:", "TheatricalRelease": "En cines: {{date}}", "ReleaseDate": "Llançament: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Els elements seleccionats s'han denegat correctament" }, "SuccessfullyApproved": "Aprovat correctament", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "La sol·licitud s'ha suprimit correctament", "NowAvailable": "La sol·licitud ja està disponible", "NowUnavailable": "La sol·licitud ja no està disponible", @@ -403,6 +407,7 @@ "Movies": "Pel·lícules", "Combined": "Combinat", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Disponibilitat", "Studio": "Estudi", diff --git a/src/Ombi/wwwroot/translations/cs.json b/src/Ombi/wwwroot/translations/cs.json index 4b99105395..db4d7e435f 100644 --- a/src/Ombi/wwwroot/translations/cs.json +++ b/src/Ombi/wwwroot/translations/cs.json @@ -159,6 +159,9 @@ "RequestedBy": "Požadováno od", "Status": "Stav", "RequestStatus": "Stav požadavku", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Zamítnuto:", "TheatricalRelease": "V kinech od: {{date}}", "ReleaseDate": "Vydáno: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Úspěšně schváleno", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Požadavek byl úspěšně odstraněn", "NowAvailable": "Požadavek je nyní k dispozici", "NowUnavailable": "Požadavek je nyní nedostupný", @@ -403,6 +407,7 @@ "Movies": "Filmy", "Combined": "Kombinované", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Dostupnost", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/da.json b/src/Ombi/wwwroot/translations/da.json index 8777affb9f..9c72bdc326 100644 --- a/src/Ombi/wwwroot/translations/da.json +++ b/src/Ombi/wwwroot/translations/da.json @@ -159,6 +159,9 @@ "RequestedBy": "Anmodet af", "Status": "Status", "RequestStatus": "Status for anmodning", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Afvist:", "TheatricalRelease": "Biografudgivelse: {{date}}", "ReleaseDate": "Udgivet: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Godkendt", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Anmodningen blev slettet", "NowAvailable": "Anmodningen er nu tilgængelig", "NowUnavailable": "Anmodningen er nu utilgængelig", @@ -403,6 +407,7 @@ "Movies": "Film", "Combined": "Kombineret", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Tilgængelighed", "Studio": "Studie", diff --git a/src/Ombi/wwwroot/translations/de.json b/src/Ombi/wwwroot/translations/de.json index a9e78199e8..f140f46344 100644 --- a/src/Ombi/wwwroot/translations/de.json +++ b/src/Ombi/wwwroot/translations/de.json @@ -159,6 +159,9 @@ "RequestedBy": "Angefordert von", "Status": "Status", "RequestStatus": "Anfrage Status", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Abgelehnt:", "TheatricalRelease": "Kinostart: {{date}}", "ReleaseDate": "Veröffentlicht: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Ausgewählte Elemente erfolgreich abgelehnt" }, "SuccessfullyApproved": "Erfolgreich genehmigt", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Anfrage erfolgreich gelöscht", "NowAvailable": "Anfrage ist jetzt verfügbar", "NowUnavailable": "Anfrage ist jetzt verfügbar", @@ -403,6 +407,7 @@ "Movies": "Filme", "Combined": "Kombiniert", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Verfügbarkeit", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index f3e2813a93..ed09c1b648 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -159,6 +159,9 @@ "RequestedBy": "Requested By", "Status": "Status", "RequestStatus": "Request status", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Denied:", "TheatricalRelease": "Theatrical Release: {{date}}", "ReleaseDate": "Released: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Successfully Approved", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Request successfully deleted", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Movies", "Combined": "Combined", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Availability", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/es.json b/src/Ombi/wwwroot/translations/es.json index 97bd73cb8c..aacf225cd7 100644 --- a/src/Ombi/wwwroot/translations/es.json +++ b/src/Ombi/wwwroot/translations/es.json @@ -159,6 +159,9 @@ "RequestedBy": "Solicitado por", "Status": "Estado", "RequestStatus": "Estado de la solicitud", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Denegado:", "TheatricalRelease": "En cines: {{date}}", "ReleaseDate": "Publicado: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Elementos seleccionados rechazados con éxito" }, "SuccessfullyApproved": "Se ha aprobado con éxito", + "SuccessfullyDenied": "Denegado Correctamente", "SuccessfullyDeleted": "Solicitud eliminada con éxito", "NowAvailable": "La solicitud está disponible", "NowUnavailable": "La solicitud no está disponible", @@ -403,6 +407,7 @@ "Movies": "Películas", "Combined": "Combinado", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Disponibilidad", "Studio": "Estudio", diff --git a/src/Ombi/wwwroot/translations/fr.json b/src/Ombi/wwwroot/translations/fr.json index e70ca1e230..0359a04113 100644 --- a/src/Ombi/wwwroot/translations/fr.json +++ b/src/Ombi/wwwroot/translations/fr.json @@ -159,6 +159,9 @@ "RequestedBy": "Demandé par", "Status": "Statut", "RequestStatus": "Statut de la demande", + "Watched": "Vu", + "WatchedTooltip": "L'utilisateur qui a fait la demande l'a regardé", + "WatchedByUsersCount": "{{count}} utilisateurs l'ont regardé.", "Denied": " Refusé :", "TheatricalRelease": "Sortie en salle : {{date}}", "ReleaseDate": "Sortie : {{date}}", @@ -221,6 +224,7 @@ "Denied": "Les éléments sélectionnés ont été refusés" }, "SuccessfullyApproved": "Approuvée avec succès", + "SuccessfullyDenied": "Refusé avec succès", "SuccessfullyDeleted": "Demande supprimée avec succès", "NowAvailable": "La demande est maintenant disponible", "NowUnavailable": "La demande est maintenant indisponible", @@ -403,6 +407,7 @@ "Movies": "Films", "Combined": "Tous", "Tv": "Séries", + "Genres": "Genres", "CardDetails": { "Availability": "Disponibilité", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/hu.json b/src/Ombi/wwwroot/translations/hu.json index 96b702d503..de0d004e4a 100644 --- a/src/Ombi/wwwroot/translations/hu.json +++ b/src/Ombi/wwwroot/translations/hu.json @@ -14,7 +14,7 @@ "Common": { "ContinueButton": "Tovább", "Available": "Elérhető", - "Available4K": "Available 4K", + "Available4K": "Elérhető 4K", "Approved": "Jóváhagyva", "Approve4K": "Approve 4K", "Pending": "Függőben", @@ -24,7 +24,7 @@ "ProcessingRequest": "Kérés feldolgozása", "ProcessingRequest4K": "Processing Request 4K", "PendingApproval": "Jóváhagyásra vár", - "PendingApproval4K": "Pending Approval 4K", + "PendingApproval4K": "Függőben 4K", "RequestDenied": "Kérés megtagadva", "RequestDenied4K": "Request Denied 4K", "NotRequested": "Nincs kérve", @@ -159,6 +159,9 @@ "RequestedBy": "Kérte", "Status": "Állapot", "RequestStatus": "Kérés állapota", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Megtagadta:", "TheatricalRelease": "Mozis kiadás: {{date}}", "ReleaseDate": "Kiadva: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Sikeresen jóváhagyva", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Kérés sikeresen törölve", "NowAvailable": "Kérés elérhető", "NowUnavailable": "Kérés nem elérhető", @@ -312,7 +316,7 @@ }, "MediaDetails": { "Denied": "Megtagadva", - "Denied4K": "Denied 4K", + "Denied4K": "Megtagadva 4K", "Trailers": "Előzetesek", "RecommendationsTitle": "Ajánlások", "SimilarTitle": "Hasonló", @@ -365,7 +369,7 @@ "CastTitle": "Szereplők" }, "Crews": { - "CrewTitle": "Crew" + "CrewTitle": "Stáb" }, "EpisodeSelector": { "AllSeasonsTooltip": "Ezzel kérni fogja a sorozat összes évadát", @@ -392,7 +396,7 @@ "StartDate": "Kezdés dátuma:", "EndDate": "Befejezés dátuma:" }, - "RequestSource": "Source:" + "RequestSource": "Forrás:" }, "Discovery": { "PopularTab": "Népszerű", @@ -403,6 +407,7 @@ "Movies": "Filmek", "Combined": "Kombinált", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Elérhetőség", "Studio": "Stúdió", diff --git a/src/Ombi/wwwroot/translations/it.json b/src/Ombi/wwwroot/translations/it.json index af7b221049..c5d8bd0510 100644 --- a/src/Ombi/wwwroot/translations/it.json +++ b/src/Ombi/wwwroot/translations/it.json @@ -159,6 +159,9 @@ "RequestedBy": "Richiesta da", "Status": "Stato", "RequestStatus": "Stato della richiesta", + "Watched": "Visti", + "WatchedTooltip": "L'utente che ha fatto la richiesta l'ha visto", + "WatchedByUsersCount": "Visto da {{count}} utenti.", "Denied": "Negata:", "TheatricalRelease": "Uscita nei cinema: {{date}}", "ReleaseDate": "Rilasciato il {{date}}", @@ -221,6 +224,7 @@ "Denied": "Elementi selezionati rifiutati con successo" }, "SuccessfullyApproved": "Approvata", + "SuccessfullyDenied": "Negata Con Successo", "SuccessfullyDeleted": "Richiesta eliminata correttamente", "NowAvailable": "Richiesta ora disponibile", "NowUnavailable": "Richiesta ora non disponibile", @@ -365,7 +369,7 @@ "CastTitle": "Trasmetti" }, "Crews": { - "CrewTitle": "Crew" + "CrewTitle": "Gruppo" }, "EpisodeSelector": { "AllSeasonsTooltip": "Richiederà tutte le stagioni per questa serie", @@ -403,6 +407,7 @@ "Movies": "Film", "Combined": "Combinato", "Tv": "TV", + "Genres": "Generi", "CardDetails": { "Availability": "Disponibilità", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/nl.json b/src/Ombi/wwwroot/translations/nl.json index 097292cf13..c0ac0930b4 100644 --- a/src/Ombi/wwwroot/translations/nl.json +++ b/src/Ombi/wwwroot/translations/nl.json @@ -30,10 +30,10 @@ "NotRequested": "Niet verzocht", "NotRequested4K": "Niet aangevraagd 4K", "Requested": "Aangevraagd", - "Requested4K": "Requested 4K", + "Requested4K": "Aangevraagd 4K", "Search": "Zoeken", "Request": "Aanvragen", - "Request4K": "Request 4K", + "Request4K": "Aanvragen 4K", "Denied": "Afgewezen", "Approve": "Accepteer", "PartlyAvailable": "Deels Beschikbaar", @@ -43,7 +43,7 @@ }, "Cancel": "Annuleren", "Submit": "Verzenden", - "Update": "Update", + "Update": "Bijwerken", "tvShow": "Tv programma", "movie": "Film", "album": "Album" @@ -64,14 +64,14 @@ "CheckPageForUpdates": "Controleer deze pagina voor updates." }, "ErrorPages": { - "NotFound": "Page not found", - "SomethingWentWrong": "Something went wrong!" + "NotFound": "Pagina niet gevonden", + "SomethingWentWrong": "Sorry, er ging iets mis!" }, "NavigationBar": { "Discover": "Ontdekken", "Search": "Zoeken", "Requests": "Verzoeken", - "UserManagement": "Gebruikersmanagement", + "UserManagement": "Gebruikers", "Issues": "Problemen", "Vote": "Stem", "Donate": "Doneer!", @@ -87,7 +87,7 @@ "ChangeTheme": "Thema wijzigen", "Calendar": "Agenda", "UserPreferences": "Instellingen", - "FeatureSuggestion": "Feature Suggestion", + "FeatureSuggestion": "Ideeën delen", "FeatureSuggestionTooltip": "Heb je een geweldig nieuw idee? Stel het hier voor!", "Filter": { "Movies": "Films", @@ -105,8 +105,8 @@ "MoviesTab": "Films", "TvTab": "TV Series", "MusicTab": "Muziek", - "AdvancedSearch": "You can fill in any of the below to discover new media. All of the results are sorted by popularity", - "AdvancedSearchHeader": "Advanced Search", + "AdvancedSearch": "Je kunt hieronder een van de onderstaande invullen om nieuwe media te ontdekken. Alle resultaten zijn gesorteerd op populariteit", + "AdvancedSearchHeader": "Geavanceerd Zoeken", "Suggestions": "Suggesties", "NoResults": "Sorry, er zijn geen resultaten gevonden!", "DigitalDate": "Digitale Uitgave: {{date}}", @@ -141,12 +141,12 @@ "Season": "Seizoen {{seasonNumber}}", "SelectAllInSeason": "Selecteer Alles in het Seizoen {{seasonNumber}}" }, - "AdvancedSearchInstructions": "Please choose what type of media you are searching for:", - "YearOfRelease": "Year of Release", - "SearchGenre": "Search Genre", - "SearchKeyword": "Search Keyword", - "SearchProvider": "Search Provider", - "KeywordSearchingDisclaimer": "Please note that Keyword Searching is very hit and miss due to the inconsistent data in TheMovieDb" + "AdvancedSearchInstructions": "Kies naar welk type media je zoekt:", + "YearOfRelease": "Jaar van de uitgave", + "SearchGenre": "Zoeken op genre", + "SearchKeyword": "Trefwoorden zoeken", + "SearchProvider": "Zoekmachine", + "KeywordSearchingDisclaimer": "Houd er rekening mee dat het zoeken naar trefwoord erg hit en miss is door de inconsistente gegevens in TheMovieDb" }, "Requests": { "Title": "Verzoeken", @@ -159,6 +159,9 @@ "RequestedBy": "Verzocht Door", "Status": "Status", "RequestStatus": "Aanvraagstatus", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Geweigerd:", "TheatricalRelease": "Cinema Uitgave: {{date}}", "ReleaseDate": "Uitgekomen: {{date}}", @@ -170,15 +173,15 @@ "ChangeRootFolder": "Hoofdmap wijzigen", "ChangeQualityProfile": "Kwaliteitsprofiel wijzigen", "MarkUnavailable": "Markeren als onbeschikbaar", - "MarkUnavailable4K": "Mark Unavailable 4K", + "MarkUnavailable4K": "Markeer niet beschikbaar 4K", "MarkAvailable": "Markeren als beschikbaar", - "MarkAvailable4K": "Mark Available 4K", + "MarkAvailable4K": "Markeer beschikbaar 4K", "Remove": "Verwijderen", "Deny": "Weigeren", - "Deny4K": "Deny 4K", - "Has4KRequest": "Has 4K Request", + "Deny4K": "Weiger 4K", + "Has4KRequest": "Heeft 4K verzoek", "DenyReason": "Reden van afwijzing", - "DeniedReason": "Denied Reason", + "DeniedReason": "Reden van afwijzing", "Season": "Seizoen", "GridTitle": "Titel", "AirDate": "Uitzenddatum", @@ -212,52 +215,53 @@ "RequestPanel": { "Delete": "Verwijder Verzoek", "Approve": "Verzoek Goedkeuren", - "Deny": "Deny Request", - "Approve4K": "Approve 4K Request", - "Deny4K": "Deny 4K Request", + "Deny": "Aanvraag weigeren", + "Approve4K": "4K Verzoek Goedkeuren", + "Deny4K": "4K Verzoek Weigeren", "ChangeAvailability": "Markeer beschikbaar", - "Deleted": "Successfully deleted selected items", - "Approved": "Successfully approved selected items", - "Denied": "Successfully denied selected items" + "Deleted": "Geselecteerde items succesvol verwijderd", + "Approved": "Geselecteerde items succesvol goedgekeurd", + "Denied": "Geselecteerde items succesvol afgekeurd" }, - "SuccessfullyApproved": "Successfully Approved", - "SuccessfullyDeleted": "Request successfully deleted", - "NowAvailable": "Request is now available", - "NowUnavailable": "Request is now unavailable", - "SuccessfullyReprocessed": "Successfully Re-processed the request", - "DeniedRequest": "Denied Request", - "RequestCollection": "Request Collection", - "CollectionSuccesfullyAdded": "The collection {{name}} has been successfully added!", - "NeedToSelectEpisodes": "You need to select some episodes!", + "SuccessfullyApproved": "Succesvol goedgekeurd", + "SuccessfullyDenied": "Successfully Denied", + "SuccessfullyDeleted": "Verzoek succesvol verwijderd", + "NowAvailable": "Verzoek is nu beschikbaar", + "NowUnavailable": "Verzoek is nu niet beschikbaar", + "SuccessfullyReprocessed": "De aanvraag is met succes opnieuw verwerkt", + "DeniedRequest": "Geweigerde verzoek(en)", + "RequestCollection": "Collectie aanvragen", + "CollectionSuccesfullyAdded": "De collectie {{name}} is succesvol toegevoegd!", + "NeedToSelectEpisodes": "Je moet enkele afleveringen selecteren!", "RequestAddedSuccessfully": "Aanvraag voor {{title}} is succesvol toegevoegd", "ErrorCodes": { - "AlreadyRequested": "This has already been requested", - "EpisodesAlreadyRequested": "We already have episodes requested from this series", - "NoPermissionsOnBehalf": "You do not have the correct permissions to request on behalf of users!", - "NoPermissions": "You do not have the correct permissions!", - "RequestDoesNotExist": "Request does not exist", + "AlreadyRequested": "Dit is reeds aangevraagd", + "EpisodesAlreadyRequested": "We hebben al aanvragen voor deze serie", + "NoPermissionsOnBehalf": "Je hebt niet de juiste rechten om namens gebruikers aan te vragen!", + "NoPermissions": "Je hebt de juiste rechten niet!", + "RequestDoesNotExist": "Verzoek bestaat niet", "ChildRequestDoesNotExist": "Child Request does not exist", - "NoPermissionsRequestMovie": "You do not have permissions to Request a Movie", - "NoPermissionsRequestTV": "You do not have permissions to Request a TV Show", - "NoPermissionsRequestAlbum": "You do not have permissions to Request an Album", - "MovieRequestQuotaExceeded": "You have exceeded your Movie request quota!", - "TvRequestQuotaExceeded": "You have exceeded your Episode request quota!", - "AlbumRequestQuotaExceeded": "You have exceeded your Album request quota!" + "NoPermissionsRequestMovie": "Je bent niet gemachtigd om een film aan te vragen", + "NoPermissionsRequestTV": "Je bent niet gemachtigd om een serie aan te vragen", + "NoPermissionsRequestAlbum": "Je bent niet gemachtigd om een album aan te vragen", + "MovieRequestQuotaExceeded": "Je hebt het maximale aantal film aanvragen bereikt!", + "TvRequestQuotaExceeded": "Je hebt het maximale aantal afleveringen aanvragen bereikt!", + "AlbumRequestQuotaExceeded": "Je hebt het maximale aantal albums aanvragen bereikt!" }, - "Notify": "Notify", - "RemoveNotification": "Remove Notifications", - "SuccessfulNotify": "You will now be notified for title {{title}}", - "SuccessfulUnNotify": "You will no longer be notified for title {{title}}", - "CouldntNotify": "Couldn't notify title {{title}}" + "Notify": "Notificatie", + "RemoveNotification": "Notificaties verwijderen", + "SuccessfulNotify": "Je krijgt nu een melding voor titel {{title}}", + "SuccessfulUnNotify": "Je wordt niet langer op de hoogte gehouden voor titel {{title}}", + "CouldntNotify": "Kan titel {{title}} niet melden" }, "Issues": { "Title": "Problemen", - "IssuesForTitle": "Issues for {{title}}", + "IssuesForTitle": "Problemen voor {{title}}", "PendingTitle": "Onopgeloste Problemen", "InProgressTitle": "Problemen in Behandeling", "ResolvedTitle": "Opgeloste Problemen", "ColumnTitle": "Titel", - "Count": "Count", + "Count": "Aantal", "Category": "Categorie", "Status": "Status", "Details": "Details", @@ -284,10 +288,10 @@ "MarkedAsInProgress": "Dit probleem is nu gemarkeerd als in behandeling!", "Delete": "Verwijder probleem", "DeletedIssue": "Probleem is verwijderd", - "Chat": "Chat", - "EnterYourMessage": "Enter Your Message", + "Chat": "Chatten", + "EnterYourMessage": "Voer je bericht in", "Requested": "Aangevraagd", - "UserOnDate": "{{user}} on {{date}}" + "UserOnDate": "{{user}} op {{date}}" }, "Filter": { "ClearFilter": "Verwijder Filter", @@ -295,8 +299,8 @@ "FilterHeaderRequestStatus": "Status", "Approved": "Goedgekeurd", "PendingApproval": "In afwachting van goedkeuring", - "WatchProviders": "Watch Providers", - "Keywords": "Keywords" + "WatchProviders": "Bekijk aanbieders", + "Keywords": "Trefwoorden" }, "UserManagment": { "TvRemaining": "Tv: {{remaining}}/{{total}} Resterend", @@ -312,7 +316,7 @@ }, "MediaDetails": { "Denied": "Afgewezen", - "Denied4K": "Denied 4K", + "Denied4K": "Geweigerd 4K", "Trailers": "Trailers", "RecommendationsTitle": "Aanbevelingen", "SimilarTitle": "Vergelijkbaar", @@ -324,28 +328,28 @@ "ViewCollection": "Bekijk collectie", "NotEnoughInfo": "Helaas is er nog niet genoeg informatie over deze tv-serie!", "AdvancedOptions": "Geavanceerde opties", - "AutoApproveOptions": "You can configure the request here, once requested it will be sent to your DVR application and will be auto approved! Please note, this is optional, just press Request to skip!", - "AutoApproveOptionsTv": "You can configure the request here, once requested it will be sent to your DVR application and will be auto approved! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it! Please note, this is optional, just press Request to skip!", - "AutoApproveOptionsTvShort": "You can configure the request here, once requested it will be sent to your DVR application! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it! Please note, this is optional, just press Request to skip!", + "AutoApproveOptions": "U kunt het verzoek hier configureren, eenmaal gevraagd zal het naar uw DVR-applicatie worden gestuurd en automatisch worden goedgekeurd! Let op, dit is optioneel, druk op Verzoek om over te slaan!", + "AutoApproveOptionsTv": "U kunt het verzoek hier configureren, eenmaal gevraagd zal het naar uw DVR-applicatie worden gestuurd en automatisch worden goedgekeurd! Als het verzoek al in Sonarr is, zullen we de hoofdmap of het kwaliteitsprofiel niet wijzigen als je het instelt! Let op, dit is optioneel, druk op Verzoek om over te slaan!", + "AutoApproveOptionsTvShort": "U kunt het verzoek hier configureren, eenmaal gevraagd zal het naar uw DVR-applicatie worden gestuurd en automatisch worden goedgekeurd! Als het verzoek al in Sonarr is, zullen we de hoofdmap of het kwaliteitsprofiel niet wijzigen als je het instelt! Let op, dit is optioneel, druk op Verzoek om over te slaan!", "QualityProfilesSelect": "Selecteer een kwaliteitsprofiel", "RootFolderSelect": "Selecteer een hoofdmap", - "LanguageProfileSelect": "Select A Language Profile", + "LanguageProfileSelect": "Selecteer een taalprofiel", "Status": "Status:", "StatusValues": { - "Rumored": "Rumored", - "Planned": "Planned", - "In Production": "In Production", - "Post Production": "Post Production", - "Released": "Released", - "Running": "Running", - "Returning Series": "Returning Series", - "Ended": "Ended", - "Canceled": "Canceled" + "Rumored": "Geruchten", + "Planned": "Gepland", + "In Production": "In productie", + "Post Production": "Postproductie", + "Released": "Uitgebracht", + "Running": "Lopende series", + "Returning Series": "Terugkerende series", + "Ended": "Beëindigd", + "Canceled": "Geannuleerd" }, - "Seasons": "Seasons:", + "Seasons": "Seizoenen:", "Episodes": "Afleveringen:", "Availability": "Beschikbaarheid:", - "RequestStatus": "Request Status:", + "RequestStatus": "Aanvraag status:", "Quality": "Kwaliteit:", "RootFolderOverride": "Hoofdmap overschrijven:", "QualityOverride": "Kwaliteit overschrijven:", @@ -371,7 +375,7 @@ "AllSeasonsTooltip": "Dit verzoekt ieder seizoen van deze serie", "FirstSeasonTooltip": "Dit verzoekt alleen het eerste seizoen van deze serie", "LatestSeasonTooltip": "Dit verzoekt alleen het laatste seizoen van deze show", - "NoEpisodes": "There unfortunately is no episode data for this show yet!", + "NoEpisodes": "Er zijn helaas nog geen aflevering gegevens voor deze TV-serie!", "SeasonNumber": "Seizoen {{number}}" }, "SonarrConfiguration": "Sonarr configuratie", @@ -380,29 +384,30 @@ "PleaseSelectUser": "Selecteer een gebruiker", "StreamingOn": "Streamt op:", "RequestedBy": "Verzocht Door:", - "OnDate": "On:", - "RequestedByOn": "Requested By {{user}} on {{date}}", + "OnDate": "Op:", + "RequestedByOn": "Aangevraagd door {{user}} op {{date}}", "RequestDate": "Aanvraag Datum:", - "DeniedReason": "Denied Reason:", - "ReProcessRequest": "Re-Process Request", - "ReProcessRequest4K": "Re-Process 4K Request", + "DeniedReason": "Reden van afwijzing:", + "ReProcessRequest": "Aanvraag opnieuw verwerken", + "ReProcessRequest4K": "Aanvraag opnieuw verwerken", "Music": { "Type": "Type:", - "Country": "Country:", - "StartDate": "Start Date:", - "EndDate": "EndDate:" + "Country": "Land:", + "StartDate": "Startdatum:", + "EndDate": "Einddatum:" }, - "RequestSource": "Source:" + "RequestSource": "Bron:" }, "Discovery": { "PopularTab": "Populair", "TrendingTab": "Populair", "UpcomingTab": "Aankomend", - "SeasonalTab": "Seasonal", - "RecentlyRequestedTab": "Recently Requested", + "SeasonalTab": "Seizoen", + "RecentlyRequestedTab": "Recente verzoeken", "Movies": "Films", "Combined": "Gecombineerd", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Beschikbaarheid", "Studio": "Studio", @@ -423,37 +428,37 @@ "DarkMode": "Donkere Modus", "Updated": "Succesvol bijgewerkt", "StreamingCountry": "Streaming Land", - "StreamingCountryDescription": "This is the country code that we will display streaming information for. If you are in the US please select US and you will get US related streaming information.", + "StreamingCountryDescription": "Dit is de landcode waarvoor we streaming informatie tonen. Als u in de VS bent, selecteer dan US en u krijgt Amerikaanse gerelateerde streaming informatie.", "LanguageDescription": "Dit is de taal waarin Ombi in wordt weergegeven.", "MobileQRCode": "QR code voor mobiel", "LegacyApp": "Start legacy app", - "NoQrCode": "Please contact your administrator to enable QR codes", - "UserType": "User Type:", - "ChangeDetails": "Change Details", - "NeedCurrentPassword": "You need your current password to make any changes here", - "CurrentPassword": "Current Password", + "NoQrCode": "Neem contact op met de beheerder om QR-codes in te schakelen", + "UserType": "Gebruikerstype:", + "ChangeDetails": "Gegevens wijzigen", + "NeedCurrentPassword": "Je hebt je huidige wachtwoord nodig om hier wijzigingen aan te brengen", + "CurrentPassword": "Huidige wachtwoord", "EmailAddress": "E-mail adres", - "NewPassword": "New Password", - "NewPasswordConfirm": "New Password Confirm", - "Security": "Security", - "Profile": "Profile", - "UpdatedYourInformation": "Updated your information", - "Unsubscribed": "Unsubscribed!" + "NewPassword": "Nieuw Wachtwoord", + "NewPasswordConfirm": "Nieuw wachtwoord bevestigen", + "Security": "Beveiliging", + "Profile": "Profiel", + "UpdatedYourInformation": "Gegevens bijgewerkt", + "Unsubscribed": "Afgemeld!" }, "UserTypeLabel": { - "1": "Local User", - "2": "Plex User", - "3": "Emby User", - "4": "Emby Connect User", - "5": "Jellyfin User" + "1": "Lokale gebruiker", + "2": "Plex gebruiker", + "3": "Emby gebruiker", + "4": "Emby Connect gebruiker", + "5": "Jellyfin gebruiker" }, "Paginator": { - "itemsPerPageLabel": "Items per page:", - "nextPageLabel": "Next page", - "previousPageLabel": "Previous page", - "firstPageLabel": "First page", - "lastPageLabel": "Last page", - "rangePageLabel1": "0 of {{length}}", - "rangePageLabel2": "{{startIndex}} – {{endIndex}} of {{length}}" + "itemsPerPageLabel": "Items per pagina:", + "nextPageLabel": "Volgende pagina", + "previousPageLabel": "Vorige pagina", + "firstPageLabel": "Eerste pagina", + "lastPageLabel": "Laatste pagina", + "rangePageLabel1": "0 van {{length}}", + "rangePageLabel2": "{{startIndex}} - {{endIndex}} van {{length}}" } } diff --git a/src/Ombi/wwwroot/translations/no.json b/src/Ombi/wwwroot/translations/no.json index edf0df0fa8..6bf644c15a 100644 --- a/src/Ombi/wwwroot/translations/no.json +++ b/src/Ombi/wwwroot/translations/no.json @@ -14,26 +14,26 @@ "Common": { "ContinueButton": "Gå videre", "Available": "Tilgjengelig", - "Available4K": "Available 4K", + "Available4K": "Tilgjengelig i 4K", "Approved": "Godkjent", - "Approve4K": "Approve 4K", - "Pending": "Pending", + "Approve4K": "Godkjenn 4K", + "Pending": "Ventende", "PartiallyAvailable": "Delvis tilgjengelig", "Monitored": "Overvåket", "NotAvailable": "Ikke tilgjengelig", "ProcessingRequest": "Behandler forespørsel", - "ProcessingRequest4K": "Processing Request 4K", + "ProcessingRequest4K": "Behandler Forespørsel 4K", "PendingApproval": "Venter på godkjenning", - "PendingApproval4K": "Pending Approval 4K", + "PendingApproval4K": "Venter på godkjenning 4K", "RequestDenied": "Forespørsel avslått", - "RequestDenied4K": "Request Denied 4K", + "RequestDenied4K": "Forespørsel Avvist 4K", "NotRequested": "Ikke forespurt", - "NotRequested4K": "Not Requested 4K", + "NotRequested4K": "Ikke Forespurt 4K", "Requested": "Forespurt", - "Requested4K": "Requested 4K", + "Requested4K": "Forespurt 4K", "Search": "Søk", "Request": "Forespørsel", - "Request4K": "Request 4K", + "Request4K": "Forespørsel 4K", "Denied": "Avslått", "Approve": "Godkjenn", "PartlyAvailable": "Delvis tilgjengelig", @@ -42,10 +42,10 @@ "Validation": "Kontroller de angitte verdiene" }, "Cancel": "Avbryt", - "Submit": "Submit", - "Update": "Update", - "tvShow": "TV Show", - "movie": "Movie", + "Submit": "Send", + "Update": "Oppdater", + "tvShow": "TV Serie", + "movie": "Film", "album": "Album" }, "PasswordReset": { @@ -64,11 +64,11 @@ "CheckPageForUpdates": "Sjekk denne siden for kontinuerlige oppdateringer." }, "ErrorPages": { - "NotFound": "Page not found", - "SomethingWentWrong": "Something went wrong!" + "NotFound": "Siden ble ikke funnet", + "SomethingWentWrong": "Noe gikk galt!" }, "NavigationBar": { - "Discover": "Discover", + "Discover": "Oppdag", "Search": "Søk", "Requests": "Forespørsler", "UserManagement": "Brukeradministrasjon", @@ -84,20 +84,20 @@ "Logout": "Logg av", "OpenMobileApp": "Åpne mobilapp", "RecentlyAdded": "Nylig lagt til", - "ChangeTheme": "Change Theme", - "Calendar": "Calendar", - "UserPreferences": "Preferences", + "ChangeTheme": "Endre Tema", + "Calendar": "Kalender", + "UserPreferences": "Brukervalg", "FeatureSuggestion": "Feature Suggestion", - "FeatureSuggestionTooltip": "Have a great new idea? Suggest it here!", + "FeatureSuggestionTooltip": "Har du en god idé? Foreslå den her!", "Filter": { "Movies": "Filmer", "TvShows": "TV serier", "Music": "Musikk", - "People": "People" + "People": "Personer" }, - "MorningWelcome": "Good morning!", - "AfternoonWelcome": "Good afternoon!", - "EveningWelcome": "Good evening!" + "MorningWelcome": "God morgen!", + "AfternoonWelcome": "God ettermiddag!", + "EveningWelcome": "God kveld!" }, "Search": { "Title": "Søk", @@ -105,15 +105,15 @@ "MoviesTab": "Filmer", "TvTab": "TV serier", "MusicTab": "Musikk", - "AdvancedSearch": "You can fill in any of the below to discover new media. All of the results are sorted by popularity", - "AdvancedSearchHeader": "Advanced Search", + "AdvancedSearch": "Du kan fylle ut hvilket som helst av punktene nedenfor for å oppdage nye medier. Alle resultatene er sortert etter popularitet", + "AdvancedSearchHeader": "Avansert Søk", "Suggestions": "Forslag", "NoResults": "Beklager, vi fant ingen resultater!", "DigitalDate": "Digital utgivelse: {{date}}", "TheatricalRelease": "Kinopremiere: {{date}}", "ViewOnPlex": "Spill av på Plex", "ViewOnEmby": "Spill av på Emby", - "ViewOnJellyfin": "Play On Jellyfin", + "ViewOnJellyfin": "Spill av i Jellyfin", "RequestAdded": "Forespørsel om {{title}} er lagt til", "Similar": "Lignende", "Refine": "Spesifiser", @@ -141,24 +141,27 @@ "Season": "Sesong {{seasonNumber}}", "SelectAllInSeason": "Velg alle i sesong {{seasonNumber}}" }, - "AdvancedSearchInstructions": "Please choose what type of media you are searching for:", - "YearOfRelease": "Year of Release", - "SearchGenre": "Search Genre", - "SearchKeyword": "Search Keyword", - "SearchProvider": "Search Provider", - "KeywordSearchingDisclaimer": "Please note that Keyword Searching is very hit and miss due to the inconsistent data in TheMovieDb" + "AdvancedSearchInstructions": "Velg medietypen du søker etter:", + "YearOfRelease": "Utgitt", + "SearchGenre": "Søk etter Sjanger", + "SearchKeyword": "Søk etter nøkkelord", + "SearchProvider": "Søkeleverandør", + "KeywordSearchingDisclaimer": "Vær oppmerksom på at nøkkelordsøk kan gi varierende kvalitet i resultater grunnet inkonsekvente data i TheMovieDb" }, "Requests": { "Title": "Forespørsler", "Paragraph": "Nedenfor kan du se dine og alle andres forespørsler, du ser også status for nedlasting og godkjenning.", "MoviesTab": "Filmer", "ArtistName": "Artist", - "AlbumName": "Album Name", + "AlbumName": "Albumnavn", "TvTab": "TV serier", "MusicTab": "Musikk", "RequestedBy": "Etterspurt av", "Status": "Status", "RequestStatus": "Status for forespørsel", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Avslått:", "TheatricalRelease": "Kinopremiere: {{date}}", "ReleaseDate": "Utgitt: {{date}}", @@ -170,15 +173,15 @@ "ChangeRootFolder": "Endre rotmappe", "ChangeQualityProfile": "Endre kvalitetsprofil", "MarkUnavailable": "Merk utilgjengelig", - "MarkUnavailable4K": "Mark Unavailable 4K", + "MarkUnavailable4K": "Merk Utilgjengelig 4K", "MarkAvailable": "Merk tilgjengelig", - "MarkAvailable4K": "Mark Available 4K", + "MarkAvailable4K": "Merk Tilgjengelig 4K", "Remove": "Fjern", "Deny": "Avslå", - "Deny4K": "Deny 4K", - "Has4KRequest": "Has 4K Request", - "DenyReason": "Deny Reason", - "DeniedReason": "Denied Reason", + "Deny4K": "Avvis 4K", + "Has4KRequest": "Har 4K-forespørsel", + "DenyReason": "Avslå årsak", + "DeniedReason": "Årsak for avslag", "Season": "Sesong", "GridTitle": "Tittel", "AirDate": "Sendedato", @@ -200,64 +203,65 @@ "NextMinutes": "En ny foresøprel vil bli lagt til om {{time}} minutter", "NextMinute": "En ny foresøprel vil bli lagt til om {{time}} minutt" }, - "AllRequests": "All Requests", - "PendingRequests": "Pending Requests", - "ProcessingRequests": "Processing Requests", - "AvailableRequests": "Available Requests", - "DeniedRequests": "Denied Requests", - "RequestsToDisplay": "Requests to display", + "AllRequests": "Alle Forespørsler", + "PendingRequests": "Ventende Forespørsler", + "ProcessingRequests": "Behandler Forespørsler", + "AvailableRequests": "Tilgjengelige Forespørsler", + "DeniedRequests": "Avviste Forespørsler", + "RequestsToDisplay": "Forespørsler å vise", "RequestsTitle": "Tittel", "Details": "Detaljer", - "Options": "Options", + "Options": "Alternativer", "RequestPanel": { - "Delete": "Delete Request", - "Approve": "Approve Request", - "Deny": "Deny Request", - "Approve4K": "Approve 4K Request", - "Deny4K": "Deny 4K Request", + "Delete": "Slett forespørsel", + "Approve": "Godkjenn forespørsel", + "Deny": "Avslå forespørsel", + "Approve4K": "Godkjenn 4K forespørsel", + "Deny4K": "Avslå 4K Forespørsel", "ChangeAvailability": "Merk tilgjengelig", - "Deleted": "Successfully deleted selected items", - "Approved": "Successfully approved selected items", - "Denied": "Successfully denied selected items" + "Deleted": "Valgte elementer ble slettet", + "Approved": "Valgte elementer ble godkjent", + "Denied": "Valgte elementer ble avvist" }, - "SuccessfullyApproved": "Successfully Approved", - "SuccessfullyDeleted": "Request successfully deleted", - "NowAvailable": "Request is now available", - "NowUnavailable": "Request is now unavailable", - "SuccessfullyReprocessed": "Successfully Re-processed the request", - "DeniedRequest": "Denied Request", - "RequestCollection": "Request Collection", - "CollectionSuccesfullyAdded": "The collection {{name}} has been successfully added!", - "NeedToSelectEpisodes": "You need to select some episodes!", + "SuccessfullyApproved": "Godkjenning vellykket", + "SuccessfullyDenied": "Successfully Denied", + "SuccessfullyDeleted": "Forespørselen ble slettet", + "NowAvailable": "Forespørselen er nå tilgjengelig", + "NowUnavailable": "Forespørselen er nå utilgjengelig", + "SuccessfullyReprocessed": "Forespørselen ble behandlet på nytt", + "DeniedRequest": "Avvist forespørsel", + "RequestCollection": "Be om samling", + "CollectionSuccesfullyAdded": "Samlingen {{name}} har blitt lagt til!", + "NeedToSelectEpisodes": "Du må velge noen episoder!", "RequestAddedSuccessfully": "Forespørsel om {{title}} er lagt til", "ErrorCodes": { - "AlreadyRequested": "This has already been requested", - "EpisodesAlreadyRequested": "We already have episodes requested from this series", - "NoPermissionsOnBehalf": "You do not have the correct permissions to request on behalf of users!", - "NoPermissions": "You do not have the correct permissions!", - "RequestDoesNotExist": "Request does not exist", - "ChildRequestDoesNotExist": "Child Request does not exist", - "NoPermissionsRequestMovie": "You do not have permissions to Request a Movie", - "NoPermissionsRequestTV": "You do not have permissions to Request a TV Show", - "NoPermissionsRequestAlbum": "You do not have permissions to Request an Album", - "MovieRequestQuotaExceeded": "You have exceeded your Movie request quota!", - "TvRequestQuotaExceeded": "You have exceeded your Episode request quota!", - "AlbumRequestQuotaExceeded": "You have exceeded your Album request quota!" + "AlreadyRequested": "Dette har allerede blitt forespurt", + "EpisodesAlreadyRequested": "Vi har allerede forespurte episoder fra denne serien", + "NoPermissionsOnBehalf": "Du har ikke rettigheter til å be om innhold på vegne av andre brukere!", + "NoPermissions": "Du har ikke riktige rettigheter!", + "RequestDoesNotExist": "Forespørselen eksisterer ikke", + "ChildRequestDoesNotExist": "Underforespørsel eksisterer ikke", + "NoPermissionsRequestMovie": "Du har ikke rettigheter til å be om en film", + "NoPermissionsRequestTV": "Du har ikke rettigheter til å be om en TV-serie", + "NoPermissionsRequestAlbum": "Du har ikke rettigheter til å be om et album", + "MovieRequestQuotaExceeded": "Du har overskredet din kvote for forespørsler av Filmer!", + "TvRequestQuotaExceeded": "Du har overskredet din kvote for forespørsler av Episoder!", + "AlbumRequestQuotaExceeded": "Du har overskredet din kvote for forespørsler av Album!" }, - "Notify": "Notify", - "RemoveNotification": "Remove Notifications", - "SuccessfulNotify": "You will now be notified for title {{title}}", - "SuccessfulUnNotify": "You will no longer be notified for title {{title}}", - "CouldntNotify": "Couldn't notify title {{title}}" + "Notify": "Gi beskjed", + "RemoveNotification": "Fjern Varslinger", + "SuccessfulNotify": "Du vil nå bli varslet om tittelen {{title}}", + "SuccessfulUnNotify": "Du vil ikke lenger bli varslet om tittelen {{title}}", + "CouldntNotify": "Kunne ikke varsle for tittelen {{title}}" }, "Issues": { "Title": "Mangler", - "IssuesForTitle": "Issues for {{title}}", + "IssuesForTitle": "Problemer med {{title}}", "PendingTitle": "Ventende løsninger", "InProgressTitle": "Mangler under behandling", "ResolvedTitle": "Løste mangler", "ColumnTitle": "Tittel", - "Count": "Count", + "Count": "Antall", "Category": "Kategori", "Status": "Status", "Details": "Detaljer", @@ -271,23 +275,23 @@ "WriteMessagePlaceholder": "Skriv meldingen din her...", "ReportedBy": "Rapportert av", "IssueDialog": { - "Title": "Report an issue", - "DescriptionPlaceholder": "Please describe the issue", - "TitlePlaceholder": "Short title of your issue", - "SelectCategory": "Select Category", - "IssueCreated": "Issue has been created" + "Title": "Rapporter et problem", + "DescriptionPlaceholder": "Beskriv problemet", + "TitlePlaceholder": "Kort tittel på saken din", + "SelectCategory": "Velg Kategori", + "IssueCreated": "Saken er opprettet" }, - "Outstanding": "There are outstanding issues", - "ResolvedDate": "Resolved date", - "CreatedDate": "Raised on", - "MarkedAsResolved": "This issue has now been marked as resolved!", - "MarkedAsInProgress": "This issue has now been marked as in progress!", - "Delete": "Delete issue", - "DeletedIssue": "Issue has been deleted", - "Chat": "Chat", - "EnterYourMessage": "Enter Your Message", + "Outstanding": "Det finnes utestående saker", + "ResolvedDate": "Løst dato", + "CreatedDate": "Opprettet den", + "MarkedAsResolved": "Denne saken er nå markert som løst!", + "MarkedAsInProgress": "Saken har nå blitt merket som pågår!", + "Delete": "Slett sak", + "DeletedIssue": "Saken har blitt slettet", + "Chat": "Chatte", + "EnterYourMessage": "Skriv meldingen din", "Requested": "Forespurt", - "UserOnDate": "{{user}} on {{date}}" + "UserOnDate": "{{user}} den {{date}}" }, "Filter": { "ClearFilter": "Tøm filter", @@ -295,8 +299,8 @@ "FilterHeaderRequestStatus": "Status", "Approved": "Godkjent", "PendingApproval": "Venter på godkjenning", - "WatchProviders": "Watch Providers", - "Keywords": "Keywords" + "WatchProviders": "Se tilbydere", + "Keywords": "Nøkkelord" }, "UserManagment": { "TvRemaining": "TV: {{remaining}}/{{total}} gjenstående", @@ -312,148 +316,149 @@ }, "MediaDetails": { "Denied": "Avslått", - "Denied4K": "Denied 4K", - "Trailers": "Trailers", - "RecommendationsTitle": "Recommendations", + "Denied4K": "Avvist 4K", + "Trailers": "Trailere", + "RecommendationsTitle": "Anbefalinger", "SimilarTitle": "Lignende", - "VideosTitle": "Videos", - "AlbumsTitle": "Albums", - "RequestAllAlbums": "Request All Albums", - "ClearSelection": "Clear Selection", - "RequestSelectedAlbums": "Request Selected Albums", - "ViewCollection": "View Collection", - "NotEnoughInfo": "Unfortunately there is not enough information about this show yet!", - "AdvancedOptions": "Advanced Options", - "AutoApproveOptions": "You can configure the request here, once requested it will be sent to your DVR application and will be auto approved! Please note, this is optional, just press Request to skip!", - "AutoApproveOptionsTv": "You can configure the request here, once requested it will be sent to your DVR application and will be auto approved! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it! Please note, this is optional, just press Request to skip!", - "AutoApproveOptionsTvShort": "You can configure the request here, once requested it will be sent to your DVR application! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it! Please note, this is optional, just press Request to skip!", - "QualityProfilesSelect": "Select A Quality Profile", - "RootFolderSelect": "Select A Root Folder", - "LanguageProfileSelect": "Select A Language Profile", + "VideosTitle": "Videoer", + "AlbumsTitle": "Album", + "RequestAllAlbums": "Forespør alle album", + "ClearSelection": "Opphev valg", + "RequestSelectedAlbums": "Forespør valgte album", + "ViewCollection": "Vis samling", + "NotEnoughInfo": "Det er dessverre ikke nok informasjon om denne serien enda!", + "AdvancedOptions": "Avanserte alternativer", + "AutoApproveOptions": "Du kan konfigurere forespørselen her. Ved forespørsel blir den sendt til din DVR-applikasjon og godkjent automatisk! Merk: Dette er valgfritt. Trykk på Forespør for å hoppe over!", + "AutoApproveOptionsTv": "Du kan konfigurere forespørselen her. Når forespurt vil den bli sendt til DVR-programmet ditt og vil automatisk bli godkjent. Hvis forespørselen allerede eksisterer i Sonarr, vil vi ikke endre rotmappen eller kvalitetsprofilen hvis du har valgt det! Vær oppmerksom på at dette er valgfritt, bare trykk på Forespør for å hoppe over!", + "AutoApproveOptionsTvShort": "Du kan konfigurere forespørselen her. Når forespurt vil den bli sendt til DVR-applikasjonen din! Hvis forespørselen allerede eksisterer i Sonarr, vil vi ikke forandre rotmappen eller kvalitetsprofilen hvis du endrer denne. Merk: Dette er valgfritt, trykk på Forespør for å hoppe over!", + "QualityProfilesSelect": "Velg en kvalitetsprofil", + "RootFolderSelect": "Velg en rotmappe", + "LanguageProfileSelect": "Velg en språkprofil", "Status": "Status:", "StatusValues": { - "Rumored": "Rumored", - "Planned": "Planned", - "In Production": "In Production", - "Post Production": "Post Production", - "Released": "Released", - "Running": "Running", - "Returning Series": "Returning Series", - "Ended": "Ended", - "Canceled": "Canceled" + "Rumored": "Ryktede", + "Planned": "Planlagte", + "In Production": "I Produksjon", + "Post Production": "Post-produksjon", + "Released": "Utgitt", + "Running": "Løpende", + "Returning Series": "Serier som returnerer", + "Ended": "Avsluttet", + "Canceled": "Kansellert" }, - "Seasons": "Seasons:", - "Episodes": "Episodes:", + "Seasons": "Sesonger:", + "Episodes": "Episoder:", "Availability": "Tilgjengelighet:", - "RequestStatus": "Request Status:", - "Quality": "Quality:", + "RequestStatus": "Status for forespørsel:", + "Quality": "Kvalitet:", "RootFolderOverride": "Overstyring av rotmappe:", "QualityOverride": "Overstyr kvalitet:", - "Network": "Network:", - "GenresLabel": "Genres:", - "Genres": "Genres", - "FirstAired": "First Aired:", + "Network": "Nettverk:", + "GenresLabel": "Sjangere:", + "Genres": "Sjangere", + "FirstAired": "Først sendt:", "TheatricalRelease": "Kinopremiere:", - "DigitalRelease": "Digital Release:", - "Votes": "Votes:", - "Runtime": "Runtime:", - "Minutes": "{{runtime}} Minutes", - "Revenue": "Revenue:", - "Budget": "Budget:", - "Keywords": "Keywords/Tags:", + "DigitalRelease": "Digital utgivelse:", + "Votes": "Stemmer:", + "Runtime": "Spilletid:", + "Minutes": "{{runtime}} Minutter", + "Revenue": "Omsetning:", + "Budget": "Budsjett:", + "Keywords": "Nøkkelord/Etiketter:", "Casts": { - "CastTitle": "Cast" + "CastTitle": "Rollebesetning" }, "Crews": { "CrewTitle": "Crew" }, "EpisodeSelector": { - "AllSeasonsTooltip": "This will request every season for this show", - "FirstSeasonTooltip": "This will only request the First Season for this show", - "LatestSeasonTooltip": "This will only request the Latest Season for this show", - "NoEpisodes": "There unfortunately is no episode data for this show yet!", + "AllSeasonsTooltip": "Dette vil be om hver sesong for denne serien", + "FirstSeasonTooltip": "Dette vil kun be om første sesong for denne serien", + "LatestSeasonTooltip": "Dette vil kun be om siste sesong for denne serien", + "NoEpisodes": "Det finnes dessverre ingen episode-data for denne serien ennå!", "SeasonNumber": "Sesong {{number}}" }, - "SonarrConfiguration": "Sonarr Configuration", - "RadarrConfiguration": "Radarr Configuration", - "RequestOnBehalf": "Request on behalf of", - "PleaseSelectUser": "Please select a user", - "StreamingOn": "Streaming On:", + "SonarrConfiguration": "Sonarr Konfigurasjon", + "RadarrConfiguration": "Radarr Konfigurasjon", + "RequestOnBehalf": "Forespør på vegne av", + "PleaseSelectUser": "Vennligst velg en bruker", + "StreamingOn": "Strømmer på:", "RequestedBy": "Etterspurt av:", - "OnDate": "On:", - "RequestedByOn": "Requested By {{user}} on {{date}}", + "OnDate": "På:", + "RequestedByOn": "Forespurt av {{user}} den {{date}}", "RequestDate": "Dato for forespørsel:", - "DeniedReason": "Denied Reason:", - "ReProcessRequest": "Re-Process Request", - "ReProcessRequest4K": "Re-Process 4K Request", + "DeniedReason": "Årsak for avslag:", + "ReProcessRequest": "Re-Prosessér Forespørsel", + "ReProcessRequest4K": "Re-Prosessér 4K-forespørsel", "Music": { "Type": "Type:", - "Country": "Country:", - "StartDate": "Start Date:", - "EndDate": "EndDate:" + "Country": "Land:", + "StartDate": "Startdato:", + "EndDate": "Sluttdato:" }, - "RequestSource": "Source:" + "RequestSource": "Kilde:" }, "Discovery": { "PopularTab": "Populært", "TrendingTab": "På vei opp", - "UpcomingTab": "Upcoming", - "SeasonalTab": "Seasonal", - "RecentlyRequestedTab": "Recently Requested", + "UpcomingTab": "Kommende", + "SeasonalTab": "Årstid", + "RecentlyRequestedTab": "Nylig Forespurte", "Movies": "Filmer", - "Combined": "Combined", + "Combined": "Kombinert", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Tilgjengelighet", "Studio": "Studio", - "Network": "Network", - "UnknownNetwork": "Unknown", - "RequestStatus": "Request Status", - "Director": "Director", - "InCinemas": "In Cinemas", - "FirstAired": "First Aired", - "Writer": "Writer", - "ExecProducer": "Exec Producer" + "Network": "Nettverk", + "UnknownNetwork": "Ukjent", + "RequestStatus": "Status for Forespørsel", + "Director": "Regissør", + "InCinemas": "På Kino", + "FirstAired": "Først Sendt", + "Writer": "Forfatter", + "ExecProducer": "Eksekutiv Produsent" }, - "NoSearch": "Sorry, nothing matches your search!" + "NoSearch": "Beklager, ingenting samsvarer med søket!" }, "UserPreferences": { "Welcome": "Velkommen {{username}}!", - "OmbiLanguage": "Language", - "DarkMode": "Dark Mode", - "Updated": "Successfully Updated", - "StreamingCountry": "Streaming Country", - "StreamingCountryDescription": "This is the country code that we will display streaming information for. If you are in the US please select US and you will get US related streaming information.", - "LanguageDescription": "This is the language you would like the Ombi interface to be displayed in.", - "MobileQRCode": "Mobile QR Code", - "LegacyApp": "Launch Legacy App", - "NoQrCode": "Please contact your administrator to enable QR codes", - "UserType": "User Type:", - "ChangeDetails": "Change Details", - "NeedCurrentPassword": "You need your current password to make any changes here", - "CurrentPassword": "Current Password", + "OmbiLanguage": "Språk", + "DarkMode": "Mørkt Tema", + "Updated": "Oppdatering Vellykket", + "StreamingCountry": "Strømmeland", + "StreamingCountryDescription": "Dette er landskoden vi vil vise strømmeinformasjon for. Hvis du er i USA, kan du velge USA og du vil motta USAs relaterte strømmeinformasjon.", + "LanguageDescription": "Dette er språket du ønsker at Ombis grensesnitt skal vises i.", + "MobileQRCode": "QR-kode for mobil", + "LegacyApp": "Start tidligere app", + "NoQrCode": "Kontakt din administrator for å aktivere QR-koder", + "UserType": "Brukertype:", + "ChangeDetails": "Endre Detaljer", + "NeedCurrentPassword": "Du trenger ditt nåværende passord for å gjøre endringer her", + "CurrentPassword": "Nåværende Passord", "EmailAddress": "E-postadresse", - "NewPassword": "New Password", - "NewPasswordConfirm": "New Password Confirm", - "Security": "Security", - "Profile": "Profile", - "UpdatedYourInformation": "Updated your information", - "Unsubscribed": "Unsubscribed!" + "NewPassword": "Nytt passord", + "NewPasswordConfirm": "Bekreft nytt passord", + "Security": "Sikkerhet", + "Profile": "Profil", + "UpdatedYourInformation": "Oppdaterte informasjonen din", + "Unsubscribed": "Avsluttet abonnement!" }, "UserTypeLabel": { - "1": "Local User", - "2": "Plex User", - "3": "Emby User", - "4": "Emby Connect User", - "5": "Jellyfin User" + "1": "Lokal Bruker", + "2": "Plex Bruker", + "3": "Emby Bruker", + "4": "Emby koble til bruker", + "5": "Jellyfin Bruker" }, "Paginator": { - "itemsPerPageLabel": "Items per page:", - "nextPageLabel": "Next page", - "previousPageLabel": "Previous page", - "firstPageLabel": "First page", - "lastPageLabel": "Last page", - "rangePageLabel1": "0 of {{length}}", - "rangePageLabel2": "{{startIndex}} – {{endIndex}} of {{length}}" + "itemsPerPageLabel": "Elementer per side:", + "nextPageLabel": "Neste side", + "previousPageLabel": "Forrige side", + "firstPageLabel": "Første side", + "lastPageLabel": "Siste side", + "rangePageLabel1": "0 av {{length}}", + "rangePageLabel2": "{{startIndex}} – {{endIndex}} av {{length}}" } } diff --git a/src/Ombi/wwwroot/translations/pl.json b/src/Ombi/wwwroot/translations/pl.json index 2f5ddb8fe7..a84b55c691 100644 --- a/src/Ombi/wwwroot/translations/pl.json +++ b/src/Ombi/wwwroot/translations/pl.json @@ -159,6 +159,9 @@ "RequestedBy": "Zgłoszone przez", "Status": "Stan", "RequestStatus": "Status zgłoszenia", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": "Odrzucono:", "TheatricalRelease": "Premiera kinowa: {{date}}", "ReleaseDate": "Wydany: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Zatwierdzono pomyślnie", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Prośba pomyślnie usunięta", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Filmy", "Combined": "Połączone", "Tv": "Seriale", + "Genres": "Genres", "CardDetails": { "Availability": "Dostępność", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/pt-BR.json b/src/Ombi/wwwroot/translations/pt-BR.json index 3473343c65..97f3678966 100644 --- a/src/Ombi/wwwroot/translations/pt-BR.json +++ b/src/Ombi/wwwroot/translations/pt-BR.json @@ -159,6 +159,9 @@ "RequestedBy": "Solicitado por", "Status": "Status", "RequestStatus": "Status da solicitação", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Negados:", "TheatricalRelease": "Lançamento nos Cinemas: {{date}}", "ReleaseDate": "Lançado: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Itens selecionados negados com sucesso" }, "SuccessfullyApproved": "Aprovado com Sucesso", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Solicitação excluída com sucesso", "NowAvailable": "O pedido agora está disponível", "NowUnavailable": "A solicitação está indisponível", @@ -403,6 +407,7 @@ "Movies": "Filmes", "Combined": "Combinados", "Tv": "Serie", + "Genres": "Genres", "CardDetails": { "Availability": "Disponibilidade", "Studio": "Estúdio", diff --git a/src/Ombi/wwwroot/translations/pt.json b/src/Ombi/wwwroot/translations/pt.json index e0c0b2378e..22955c7ad4 100644 --- a/src/Ombi/wwwroot/translations/pt.json +++ b/src/Ombi/wwwroot/translations/pt.json @@ -159,6 +159,9 @@ "RequestedBy": "Requested By", "Status": "Status", "RequestStatus": "Request status", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Denied:", "TheatricalRelease": "Theatrical Release: {{date}}", "ReleaseDate": "Released: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Successfully Approved", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Request successfully deleted", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Movies", "Combined": "Combined", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Availability", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/ru.json b/src/Ombi/wwwroot/translations/ru.json index d7f49ae38b..d8f1cbbf86 100644 --- a/src/Ombi/wwwroot/translations/ru.json +++ b/src/Ombi/wwwroot/translations/ru.json @@ -159,6 +159,9 @@ "RequestedBy": "Автор запроса", "Status": "Статус", "RequestStatus": "Статус запроса", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Отказано:", "TheatricalRelease": "Релиз в кинотеатрах: {{date}}", "ReleaseDate": "Дата выхода: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Successfully Approved", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Request successfully deleted", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Фильмы", "Combined": "Combined", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Доступность", "Studio": "Studio", diff --git a/src/Ombi/wwwroot/translations/sk.json b/src/Ombi/wwwroot/translations/sk.json index ce39f13d37..0353927727 100644 --- a/src/Ombi/wwwroot/translations/sk.json +++ b/src/Ombi/wwwroot/translations/sk.json @@ -159,6 +159,9 @@ "RequestedBy": "Vyžiadané od", "Status": "Stav", "RequestStatus": "Stav požiadavky", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Zamietnuté:", "TheatricalRelease": "Kino vydanie: {{date}}", "ReleaseDate": "Vydané: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Úspešne odstránené vybrané položky" }, "SuccessfullyApproved": "Úspešne schválené", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Žiadosť bola úspešne vymazaná", "NowAvailable": "Žiadosť je teraz k dispozícii", "NowUnavailable": "Žiadosť je teraz nedostupná", @@ -403,6 +407,7 @@ "Movies": "Filmy", "Combined": "Kombinované", "Tv": "Seriály", + "Genres": "Genres", "CardDetails": { "Availability": "Dostupnosť", "Studio": "Štúdio", diff --git a/src/Ombi/wwwroot/translations/sv.json b/src/Ombi/wwwroot/translations/sv.json index 17473fb2fe..821a0804c0 100644 --- a/src/Ombi/wwwroot/translations/sv.json +++ b/src/Ombi/wwwroot/translations/sv.json @@ -159,6 +159,9 @@ "RequestedBy": "Efterfrågats av", "Status": "Status", "RequestStatus": "Status för begäran", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": " Nekad:", "TheatricalRelease": "Biopremiär: {{date}}", "ReleaseDate": "Releasedatum: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "Successfully Approved", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "Request successfully deleted", "NowAvailable": "Request is now available", "NowUnavailable": "Request is now unavailable", @@ -403,6 +407,7 @@ "Movies": "Filmer", "Combined": "Kombinerad", "Tv": "TV", + "Genres": "Genres", "CardDetails": { "Availability": "Tillgänglighet", "Studio": "Filmstudio", diff --git a/src/Ombi/wwwroot/translations/zh-TW.json b/src/Ombi/wwwroot/translations/zh-TW.json index 52de1f7dc5..de96cfd15d 100644 --- a/src/Ombi/wwwroot/translations/zh-TW.json +++ b/src/Ombi/wwwroot/translations/zh-TW.json @@ -159,6 +159,9 @@ "RequestedBy": "请求者", "Status": "发行状态", "RequestStatus": "申请状态", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": "已拒绝:", "TheatricalRelease": "剧场版发行:{{date}}", "ReleaseDate": "已发行: {{date}}", @@ -221,6 +224,7 @@ "Denied": "Successfully denied selected items" }, "SuccessfullyApproved": "批准成功", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "删除请求成功", "NowAvailable": "请求现在可观看", "NowUnavailable": "请求现在不可观看", @@ -403,6 +407,7 @@ "Movies": "电影", "Combined": "混合", "Tv": "电视节目", + "Genres": "Genres", "CardDetails": { "Availability": "可用性", "Studio": "工作室", diff --git a/src/Ombi/wwwroot/translations/zh.json b/src/Ombi/wwwroot/translations/zh.json index 54878b499d..c555d96ee3 100644 --- a/src/Ombi/wwwroot/translations/zh.json +++ b/src/Ombi/wwwroot/translations/zh.json @@ -159,6 +159,9 @@ "RequestedBy": "请求者", "Status": "发行状态", "RequestStatus": "申请状态", + "Watched": "Watched", + "WatchedTooltip": "The user who made the request has watched it", + "WatchedByUsersCount": "{{count}} users have watched this.", "Denied": "已拒绝:", "TheatricalRelease": "剧场版发行:{{date}}", "ReleaseDate": "已发行: {{date}}", @@ -221,6 +224,7 @@ "Denied": "所选项目已拒绝" }, "SuccessfullyApproved": "批准成功", + "SuccessfullyDenied": "Successfully Denied", "SuccessfullyDeleted": "删除请求成功", "NowAvailable": "请求现在可观看", "NowUnavailable": "请求现在不可观看", @@ -403,6 +407,7 @@ "Movies": "电影", "Combined": "混合", "Tv": "电视节目", + "Genres": "Genres", "CardDetails": { "Availability": "可用性", "Studio": "工作室", diff --git a/version.json b/version.json index 07c5780278..b5b543e531 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "4.35.11" + "version": "4.39.0" } \ No newline at end of file