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 a04f84d86..863e0ccbc 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 c42059e78..ec40a056f 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 e9e5f0fca..d8691d984 100644 --- a/src/Ombi.Api.Emby/EmbyApi.cs +++ b/src/Ombi.Api.Emby/EmbyApi.cs @@ -248,5 +248,37 @@ namespace Ombi.Api.Emby 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 248c0a88f..582eac0c9 100644 --- a/src/Ombi.Api.Emby/IBaseEmbyApi.cs +++ b/src/Ombi.Api.Emby/IBaseEmbyApi.cs @@ -32,5 +32,7 @@ namespace Ombi.Api.Emby 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 e127f75f6..3e8f5407e 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 a83e1f087..7368c194e 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 778570a4c..a78429328 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 8418cddbc..c55d76e8f 100644 --- a/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs +++ b/src/Ombi.Core.Tests/Engine/MovieRequestEngineTests.cs @@ -52,6 +52,7 @@ namespace Ombi.Core.Tests.Engine _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 16b7cb811..c483d81ba 100644 --- a/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs +++ b/src/Ombi.Core.Tests/Engine/V2/MovieRequestEngineTests.cs @@ -46,8 +46,9 @@ namespace Ombi.Core.Tests.Engine.V2 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 7e1046ca5..dc748e0d9 100644 --- a/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs +++ b/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs @@ -173,6 +173,7 @@ namespace Ombi.Core.Tests.Services [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 109460ff9..4d3cd2cf9 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -33,7 +33,8 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine _requestLog = rl; _mediaCacheService = mediaCacheService; _featureService = featureService; + _userPlayedMovieRepository = userPlayedMovieRepository; } private IMovieDbApi MovieApi { get; } @@ -52,6 +54,7 @@ namespace Ombi.Core.Engine private readonly IRepository _requestLog; private readonly IMediaCacheService _mediaCacheService; private readonly IFeatureService _featureService; + protected readonly IUserPlayedMovieRepository _userPlayedMovieRepository; /// /// Requests the movie. @@ -77,7 +80,8 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine // 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine } } } + + 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 @@ namespace Ombi.Core.Engine } 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 8ccc6d17e..5ebce9586 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -161,7 +161,7 @@ namespace Ombi.Core.Engine 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 4296c2cc1..daab65e71 100644 --- a/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs +++ b/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs @@ -16,6 +16,7 @@ namespace Ombi.Core.Models.Requests 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 563fa5cb2..945e0e261 100644 --- a/src/Ombi.Core/Models/TesterResultModel.cs +++ b/src/Ombi.Core/Models/TesterResultModel.cs @@ -5,5 +5,6 @@ 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 260b008fe..57bf4ab68 100644 --- a/src/Ombi.Core/Senders/MusicSender.cs +++ b/src/Ombi.Core/Senders/MusicSender.cs @@ -100,7 +100,7 @@ namespace Ombi.Core.Senders addOptions = new Addoptions { monitored = true, - monitor = MonitorTypes.None, + monitor = MonitorTypes.Existing, searchForMissingAlbums = false, AlbumsToMonitor = new[] {model.ForeignAlbumId} }, @@ -199,4 +199,4 @@ namespace Ombi.Core.Senders 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 6628dd8b8..26d873c4d 100644 --- a/src/Ombi.Core/Services/RecentlyRequestedService.cs +++ b/src/Ombi.Core/Services/RecentlyRequestedService.cs @@ -88,6 +88,7 @@ namespace Ombi.Core.Services 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 @@ namespace Ombi.Core.Services 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 @@ namespace Ombi.Core.Services 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 09d99d4b7..c9bcc13d3 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -197,6 +197,7 @@ namespace Ombi.DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -244,6 +245,7 @@ namespace Ombi.DependencyInjection 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 726d02078..000000000 --- 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 f89c71a52..000000000 --- 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 182c1b2f8..bc90c4756 100644 --- a/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs +++ b/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs @@ -27,7 +27,7 @@ namespace Ombi.HealthChecks.Checks 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 2f80378ff..21b9d5dde 100644 --- a/src/Ombi.HealthChecks/HealthCheckExtensions.cs +++ b/src/Ombi.HealthChecks/HealthCheckExtensions.cs @@ -18,39 +18,8 @@ namespace Ombi.HealthChecks 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 4e7cebcfd..bd9f1a19e 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 e785eb494..873d68ac2 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 bf0daa456..b3fd2fe8e 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 f079c03a3..c1fecb00c 100644 --- a/src/Ombi.Notifications/NotificationMessageCurlys.cs +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -153,6 +153,7 @@ namespace Ombi.Notifications RequestedUser = req?.RequestedUser?.UserName; RequestedDate = req?.RequestedDate.ToString("D"); DetailsUrl = GetDetailsUrl(s, req); + RequestedByAlias = req?.RequestedByAlias; if (Type.IsNullOrEmpty()) { @@ -276,6 +277,7 @@ namespace Ombi.Notifications // 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 @@ namespace Ombi.Notifications { 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 35cc66be4..7b301d4ed 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; 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 @@ using MediaType = Ombi.Store.Entities.MediaType; 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 @@ namespace Ombi.Schedule.Jobs.Emby 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 @@ namespace Ombi.Schedule.Jobs.Emby // 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 @@ namespace Ombi.Schedule.Jobs.Emby 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 000000000..095364037 --- /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 000000000..5af5a9756 --- /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 000000000..80434bddb --- /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 58dacaed5..3eab17a35 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -228,7 +228,12 @@ namespace Ombi.Schedule.Jobs.Jellyfin // Check if it exists var existingMovie = await _repo.GetByJellyfinId(movieInfo.Id); var alreadyGoingToAdd = content.Any(x => 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 46f3a7e56..e3573e6c8 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 @@ namespace Ombi.Schedule.Jobs.Ombi private readonly IPlexContentRepository _plexRepo; private readonly IEmbyContentRepository _embyRepo; private readonly IJellyfinContentRepository _jellyfinRepo; + private readonly IUserPlayedMovieRepository _userPlayedRepo; private readonly ISettingsService _embySettings; private readonly ISettingsService _jellyfinSettings; @@ -41,6 +49,7 @@ namespace Ombi.Schedule.Jobs.Ombi { try { + await RemovePlayedData(); await RemovePlexData(); await RemoveEmbyData(); await RemoveJellyfinData(); @@ -52,6 +61,20 @@ namespace Ombi.Schedule.Jobs.Ombi } + 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 ef2975057..3eaf0154a 100644 --- a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs @@ -46,8 +46,8 @@ namespace Ombi.Schedule.Jobs.Radarr 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 41602f641..3b4f6316f 100644 --- a/src/Ombi.Schedule/OmbiScheduler.cs +++ b/src/Ombi.Schedule/OmbiScheduler.cs @@ -99,6 +99,7 @@ namespace Ombi.Schedule 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 9d0149e5d..f541d1e0d 100644 --- a/src/Ombi.Settings/Settings/Models/FeatureSettings.cs +++ b/src/Ombi.Settings/Settings/Models/FeatureSettings.cs @@ -21,5 +21,6 @@ namespace Ombi.Settings.Settings.Models { 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 b80943cc5..fb51ae147 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 @@ namespace Ombi.Settings.Settings.Models 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 f13c1e74f..c54c39beb 100644 --- a/src/Ombi.Store/Context/ExternalContext.cs +++ b/src/Ombi.Store/Context/ExternalContext.cs @@ -41,6 +41,7 @@ namespace Ombi.Store.Context 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 415efded2..3c3c75893 100644 --- a/src/Ombi.Store/Entities/Requests/MovieRequests.cs +++ b/src/Ombi.Store/Entities/Requests/MovieRequests.cs @@ -84,5 +84,10 @@ namespace Ombi.Store.Entities.Requests [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 000000000..7f28e9d99 --- /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 000000000..0e2e290b7 --- /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 000000000..48336a03d --- /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 1e86ddf7b..0121a99ba 100644 --- a/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/ExternalMySql/ExternalMySqlContextModelSnapshot.cs @@ -16,7 +16,7 @@ namespace Ombi.Store.Migrations.ExternalMySql { #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 @@ namespace Ombi.Store.Migrations.ExternalMySql 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 000000000..f1162e20f --- /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 000000000..23345e7a1 --- /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 2f5de3382..857259ab1 100644 --- a/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/ExternalSqlite/ExternalSqliteContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace Ombi.Store.Migrations.ExternalSqlite 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 @@ namespace Ombi.Store.Migrations.ExternalSqlite 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 000000000..966171b3a --- /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 000000000..aaff5f2b1 --- /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 3186f3f07..e55ce3b3c 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 5d2f1886d..701d58f80 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 454874490..29ac3699e 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 @@
- +
+ + +
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 3580331a3..7dd442aa4 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 0892bc9b2..270a6eb2f 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 da0b1af41..81ecb21dd 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 000000000..688634dc7 --- /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 000000000..65dcc4d98 --- /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 000000000..4dbf7233c --- /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 3b3993d39..4ae524f7b 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 f73b74752..93d66de36 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 e869abc13..d30b4b66d 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 97ff038a0..dcaec3f55 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 728ff23c5..0c617ca8c 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 9cd5dc76e..67da55783 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 36b75adb6..6031e9796 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 b5615aae7..6bca107f2 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 29d2c6beb..db6a78b5a 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 ade256a82..4838dff51 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 9780f5b5d..7b0500f77 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 26da47524..0e91ce5e3 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 ca36a5d62..4b0b0ebb4 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 7eb4b5634..d7045665a 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 573463cf0..749be6ff6 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 10e229eba..9b5091cba 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 143dfb875..bbea921e5 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 b59faa624..20bf3fe9c 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 4f08896f8..218dd912c 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 276f78996..8fc0a3a7e 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 1d63c6013..0bcd39c55 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 @@ namespace Ombi.Controllers.V1.External [PowerUser] public async Task> GetProfiles() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -75,6 +77,7 @@ namespace Ombi.Controllers.V1.External [PowerUser] public async Task> GetRootFolders() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -92,6 +95,7 @@ namespace Ombi.Controllers.V1.External [PowerUser] public async Task> GetLanguageProfiles() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { @@ -147,6 +151,7 @@ namespace Ombi.Controllers.V1.External [PowerUser] public async Task Enabled() { + SonarrSettings.ClearCache(); var settings = await SonarrSettings.GetSettingsAsync(); return settings.Enabled; } @@ -155,13 +160,21 @@ namespace Ombi.Controllers.V1.External [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 79a008322..a244fd0fb 100644 --- a/src/Ombi/Controllers/V1/External/TesterController.cs +++ b/src/Ombi/Controllers/V1/External/TesterController.cs @@ -410,6 +410,30 @@ namespace Ombi.Controllers.V1.External { 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 0892b1dda..c77913e48 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -652,7 +652,9 @@ namespace Ombi.Controllers.V1 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 6b76d053d..b2aed3f44 100644 --- a/src/Ombi/Controllers/V2/SystemController.cs +++ b/src/Ombi/Controllers/V2/SystemController.cs @@ -44,25 +44,33 @@ namespace Ombi.Controllers.V2 } [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 1a9618e47..9f66f52f5 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 57fcc6b49..39aba51f8 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 4b9910539..db4d7e435 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 8777affb9..9c72bdc32 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 a9e78199e..f140f4634 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 f3e2813a9..ed09c1b64 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 97bd73cb8..aacf225cd 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 e70ca1e23..0359a0411 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 96b702d50..de0d004e4 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 af7b22104..c5d8bd051 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 097292cf1..c0ac0930b 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 edf0df0fa..6bf644c15 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 2f5ddb8fe..a84b55c69 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 3473343c6..97f367896 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 e0c0b2378..22955c7ad 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 d7f49ae38..d8f1cbbf8 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 ce39f13d3..035392772 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 17473fb2f..821a0804c 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 52de1f7dc..de96cfd15 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 54878b499..c555d96ee 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 07c578027..b5b543e53 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