Merge pull request #4595 from Ombi-app/develop

dev to master
This commit is contained in:
Jamie 2022-04-14 10:43:45 +01:00 committed by GitHub
commit ee46bdf76f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
402 changed files with 30597 additions and 7437 deletions

View file

@ -190,6 +190,7 @@ jobs:
if: contains(github.ref, 'develop') if: contains(github.ref, 'develop')
with: with:
prerelease: true prerelease: true
generate_release_notes: true
body: ${{ needs.versioning.outputs.changelog }} body: ${{ needs.versioning.outputs.changelog }}
name: ${{ needs.versioning.outputs.tag }} name: ${{ needs.versioning.outputs.tag }}
tag_name: ${{ needs.versioning.outputs.tag }} tag_name: ${{ needs.versioning.outputs.tag }}

View file

@ -8,9 +8,6 @@ jobs:
issueCheck: issueCheck:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Output version
run: |
echo "log: ${{ github.event.issue.body }}"
- if: startsWith(github.event.issue.body , '**Describe the bug**') == false - if: startsWith(github.event.issue.body , '**Describe the bug**') == false
name: Close Issue name: Close Issue

View file

@ -1,376 +1,309 @@
## [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.10.1](https://github.com/Ombi-app/Ombi/compare/v4.10.0...v4.10.1) (2022-01-22) ## [4.16.9](https://github.com/Ombi-app/Ombi/compare/v4.16.8...v4.16.9) (2022-04-13)
### Bug Fixes
* **plex-watchlist:** Only request the latest season when importing from the watchlist ([77a47ff](https://github.com/Ombi-app/Ombi/commit/77a47ff157c6c5feafe3f2a29a3fcba8df4fdfef))
## [4.3.3](https://github.com/Ombi-app/Ombi/compare/v4.3.2...v4.3.3) (2021-11-05) ## [4.16.8](https://github.com/Ombi-app/Ombi/compare/v4.16.7...v4.16.8) (2022-04-13)
### 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))
# [4.10.0](https://github.com/Ombi-app/Ombi/compare/v4.9.2...v4.10.0) (2022-01-14) ## [4.16.7](https://github.com/Ombi-app/Ombi/compare/v4.16.6...v4.16.7) (2022-04-12)
## [4.16.6](https://github.com/Ombi-app/Ombi/compare/v4.16.5...v4.16.6) (2022-04-11)
## [4.16.5](https://github.com/Ombi-app/Ombi/compare/v4.16.4...v4.16.5) (2022-04-08)
### Bug Fixes
* **watchlist:** actually fixed it this time... ([d962a32](https://github.com/Ombi-app/Ombi/commit/d962a3211eca29520662ddce962676e3aea17ec5))
## [4.16.4](https://github.com/Ombi-app/Ombi/compare/v4.16.3...v4.16.4) (2022-04-08)
## [4.16.3](https://github.com/Ombi-app/Ombi/compare/v4.16.2...v4.16.3) (2022-04-08)
### 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))
## [4.16.2](https://github.com/Ombi-app/Ombi/compare/v4.16.1...v4.16.2) (2022-04-07)
### Bug Fixes
* **wizard:** Fixed an issue when using Plex OAuth it could fail setting up ([b743cf4](https://github.com/Ombi-app/Ombi/commit/b743cf4fafa7341ad1b163276f006d7ab0e9dcff))
## [4.16.1](https://github.com/Ombi-app/Ombi/compare/v4.16.0...v4.16.1) (2022-04-07)
# [4.16.0](https://github.com/Ombi-app/Ombi/compare/v4.15.6...v4.16.0) (2022-04-07)
## [4.15.6](https://github.com/Ombi-app/Ombi/compare/v4.15.5...v4.15.6) (2022-04-07)
### 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))
## [4.15.5](https://github.com/Ombi-app/Ombi/compare/v4.15.4...v4.15.5) (2022-04-06)
## [4.15.4](https://github.com/Ombi-app/Ombi/compare/v4.15.3...v4.15.4) (2022-03-29)
## [4.15.3](https://github.com/Ombi-app/Ombi/compare/v4.15.2...v4.15.3) (2022-03-24)
## [4.15.2](https://github.com/Ombi-app/Ombi/compare/v4.15.1...v4.15.2) (2022-03-23)
### 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))
## [4.15.1](https://github.com/Ombi-app/Ombi/compare/v4.15.0...v4.15.1) (2022-03-18)
### 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))
# [4.15.0](https://github.com/Ombi-app/Ombi/compare/v4.14.4...v4.15.0) (2022-03-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)
## [4.14.4](https://github.com/Ombi-app/Ombi/compare/v4.14.3...v4.14.4) (2022-03-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))
## [4.14.3](https://github.com/Ombi-app/Ombi/compare/v4.14.2...v4.14.3) (2022-03-06)
### Bug Fixes
* **availability:** :bug: Fixed an issue where with 4k content, we could repeat notifications ([f9ebc1c](https://github.com/Ombi-app/Ombi/commit/f9ebc1cc2e13c7cd335121cd86295b10eda529ba))
## [4.14.2](https://github.com/Ombi-app/Ombi/compare/v4.14.1...v4.14.2) (2022-03-05)
### 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)
## [4.14.1](https://github.com/Ombi-app/Ombi/compare/v4.14.0...v4.14.1) (2022-03-03)
# [4.14.0](https://github.com/Ombi-app/Ombi/compare/v4.13.2...v4.14.0) (2022-03-02)
## [4.13.2](https://github.com/Ombi-app/Ombi/compare/v4.13.1...v4.13.2) (2022-03-01)
### 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))
## [4.13.1](https://github.com/Ombi-app/Ombi/compare/v4.13.0...v4.13.1) (2022-03-01)
### 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))
# [4.13.0](https://github.com/Ombi-app/Ombi/compare/v4.12.7...v4.13.0) (2022-02-25)
### 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))
### Features ### Features
* **notifications:** :sparkles: Send new request email notifications to power users ([#4462](https://github.com/Ombi-app/Ombi/issues/4462)) ([10cc0c0](https://github.com/Ombi-app/Ombi/commit/10cc0c0951f13221179516f8ff5c44dbecc9a0fd)) * **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))
## [4.9.2](https://github.com/Ombi-app/Ombi/compare/v4.9.1...v4.9.2) (2022-01-14) ## [4.12.7](https://github.com/Ombi-app/Ombi/compare/v4.12.6...v4.12.7) (2022-02-23)
## [4.12.6](https://github.com/Ombi-app/Ombi/compare/v4.12.5...v4.12.6) (2022-02-22)
### Bug Fixes ### Bug Fixes
* :bug: Add UI for Emby recently added cronjob settings ([#4469](https://github.com/Ombi-app/Ombi/issues/4469)) ([7d47bbe](https://github.com/Ombi-app/Ombi/commit/7d47bbe92204855bf75d70b8fa548f9c3f3612bc)) * **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))
* **sonarr:** :bug: Fixed an issue where we could attempt to add a series to sonarr before sonarr has got all the metadata [#4459](https://github.com/Ombi-app/Ombi/issues/4459) ([5c691dc](https://github.com/Ombi-app/Ombi/commit/5c691dc98437a4cd24560ff625414fe05dd22f89)) * **mediaserver:** fixed some more issues in the media server sync and availability checks ([f3ea979](https://github.com/Ombi-app/Ombi/commit/f3ea979b8bd77842780ce8e6928b16237dd779cf))
* **wizard:** :bug: Fixed the issue where the Application Url wasn't validated in the wizard ([33b8d11](https://github.com/Ombi-app/Ombi/commit/33b8d1111a1c6663d8c0bbd912be4660da7d013f)), closes [#4417](https://github.com/Ombi-app/Ombi/issues/4417)
## [4.9.1](https://github.com/Ombi-app/Ombi/compare/v4.9.0...v4.9.1) (2022-01-14) ## [4.12.5](https://github.com/Ombi-app/Ombi/compare/v4.12.4...v4.12.5) (2022-02-21)
### Bug Fixes ### Bug Fixes
* **discover:** 🌐 Localize episodes names in TV details ([#4467](https://github.com/Ombi-app/Ombi/issues/4467)) [skip ci] ([35806ea](https://github.com/Ombi-app/Ombi/commit/35806ea2d2c866d628cf08577026a02ab04e49d9)) * **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))
* **email-notifications:** :bug: Fixed the issue where legacy requests were showing broken poster images [#4452](https://github.com/Ombi-app/Ombi/issues/4452) ([0ece2fd](https://github.com/Ombi-app/Ombi/commit/0ece2fd6e0eb01e0b7d4d2a01e1a276c7a9c5a51)) * **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))
* **emby/jellyfin:** :bug: A more reliable Emby and Jellyfin sync [skip ci] ([ad677fa](https://github.com/Ombi-app/Ombi/commit/ad677fa02eb75633014e9c9791c21ed2d6a23229))
# [4.9.0](https://github.com/Ombi-app/Ombi/compare/v4.8.1...v4.9.0) (2022-01-05) ## [4.12.4](https://github.com/Ombi-app/Ombi/compare/v4.12.3...v4.12.4) (2022-02-17)
## [4.12.3](https://github.com/Ombi-app/Ombi/compare/v4.12.2...v4.12.3) (2022-02-16)
## [4.12.2](https://github.com/Ombi-app/Ombi/compare/v4.12.1...v4.12.2) (2022-02-16)
### 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))
## [4.12.1](https://github.com/Ombi-app/Ombi/compare/v4.12.0...v4.12.1) (2022-02-16)
### 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)
# [4.12.0](https://github.com/Ombi-app/Ombi/compare/v4.11.8...v4.12.0) (2022-02-14)
### Features ### Features
* **customization:** :sparkles: Added possibility for custom favicons ([40af659](https://github.com/Ombi-app/Ombi/commit/40af6593b668d4712327c18f92f5b7b5a0a65e26)) * **radarr:** 4K Requests and Radarr 4K support ([ba88848](https://github.com/Ombi-app/Ombi/commit/ba88848866b0a9dedb1e79b55c4d81a0fd453843))
## [4.8.1](https://github.com/Ombi-app/Ombi/compare/v4.8.0...v4.8.1) (2022-01-04) ## [4.11.8](https://github.com/Ombi-app/Ombi/compare/v4.11.7...v4.11.8) (2022-02-13)
# [4.8.0](https://github.com/Ombi-app/Ombi/compare/v4.7.11...v4.8.0) (2021-12-22)
### Bug Fixes ### Bug Fixes
* **auto-delete:** :bug: We now also auto delete music requests, this was previously missing ([9fe1f8e](https://github.com/Ombi-app/Ombi/commit/9fe1f8e988aa31d36e7a685ae19f72d9c8414dc0)) * **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))
### Features
* **details:** :sparkles: Added the notify button back into the details pages for requests ([8b33cdc](https://github.com/Ombi-app/Ombi/commit/8b33cdccef83db8794414b247438214b00860fac))
## [4.7.11](https://github.com/Ombi-app/Ombi/compare/v4.7.10...v4.7.11) (2021-12-17) ## [4.11.7](https://github.com/Ombi-app/Ombi/compare/v4.11.6...v4.11.7) (2022-02-12)
### Bug Fixes ### Bug Fixes
* **availability-rules:** :bug: Show the 'Requested' button when a show has all of the episodes marked as requested ([cb7ecf6](https://github.com/Ombi-app/Ombi/commit/cb7ecf684ac3ab204f329a28baecfd4f6cd408f7)) * **notifications:** :bug: This is a fix for some of the duplicate notification issues [#3825](https://github.com/Ombi-app/Ombi/issues/3825) ([22bb422](https://github.com/Ombi-app/Ombi/commit/22bb4226ead2d62e8c2c2c05be47d7da621402e2))
## [4.7.10](https://github.com/Ombi-app/Ombi/compare/v4.7.9...v4.7.10) (2021-12-16) ## [4.11.6](https://github.com/Ombi-app/Ombi/compare/v4.11.5...v4.11.6) (2022-02-10)
### Bug Fixes ### Bug Fixes
* **discover:** :bug: Fixed an issue where monitored movies in radarr were not correctly represented on the search results ([75b15bc](https://github.com/Ombi-app/Ombi/commit/75b15bc7cba21f0a14a18c8e64fd52482f5c6325)) * **plex:** Fixed an issue where in a rare case we couldn't sync the data [#4502](https://github.com/Ombi-app/Ombi/issues/4502) ([191318d](https://github.com/Ombi-app/Ombi/commit/191318ddad5a8148422955bf928f1c49b890e3eb))
## [4.7.9](https://github.com/Ombi-app/Ombi/compare/v4.7.8...v4.7.9) (2021-12-16) ## [4.11.5](https://github.com/Ombi-app/Ombi/compare/v4.11.4...v4.11.5) (2022-02-05)
### Bug Fixes ### Bug Fixes
* **sonarr:** :bug: Fixed an issue where we were sometimes incorrectly setting the state of episodes that are already monitored in sonarr ([fd1acb8](https://github.com/Ombi-app/Ombi/commit/fd1acb88cbc5e73f91b7f81e6e28ee06d66b277e)) * **sonarr:** Fixed where requesting all seasons would only mark the latest as monitored [#4496](https://github.com/Ombi-app/Ombi/issues/4496) ([cfb85c2](https://github.com/Ombi-app/Ombi/commit/cfb85c23d77626b9ec1d99a6cf76497c438d0338))
## [4.7.8](https://github.com/Ombi-app/Ombi/compare/v4.7.7...v4.7.8) (2021-12-11) ## [4.11.4](https://github.com/Ombi-app/Ombi/compare/v4.11.3...v4.11.4) (2022-02-05)
### Bug Fixes ### Bug Fixes
* **notifications:** :bug: Fixed the DenyReason sometimes not appearing in the notification message [#4409](https://github.com/Ombi-app/Ombi/issues/4409) ([209e311](https://github.com/Ombi-app/Ombi/commit/209e31175c95f6ee8909d878d45bf8269a9842d9)) * **media-sync:** Add sanity checks upon media server sync ([#4493](https://github.com/Ombi-app/Ombi/issues/4493)) ([9915234](https://github.com/Ombi-app/Ombi/commit/9915234d38d4701c527081ccc21b566980375331)), closes [#4472](https://github.com/Ombi-app/Ombi/issues/4472)
* **oauth:** :lock: Fixed the issue where some users running their browsers in a different language could not open the Plex OAuth window ([d5404ea](https://github.com/Ombi-app/Ombi/commit/d5404eaad7837010d6e4563cd8f7a1009231d362)), closes [#4408](https://github.com/Ombi-app/Ombi/issues/4408) * **newsletter:** Fix newsletter not publishing double episodes ([#4495](https://github.com/Ombi-app/Ombi/issues/4495)) ([ddf63fb](https://github.com/Ombi-app/Ombi/commit/ddf63fbed0b9cbe458aec37318758c76b99b2de9))
* **translations:** 🌐 New translations from Crowdin ([5cfb76c](https://github.com/Ombi-app/Ombi/commit/5cfb76cad7a25eed8b452bf9c01cef8c32804369))
## [4.11.3](https://github.com/Ombi-app/Ombi/compare/v4.11.2...v4.11.3) (2022-02-03)
## [4.7.7](https://github.com/Ombi-app/Ombi/compare/v4.7.6...v4.7.7) (2021-12-08)
### Bug Fixes ### Bug Fixes
* **notifications:** 🐛 Do not notify user upon auto approval of a TV show ([#4432](https://github.com/Ombi-app/Ombi/issues/4432)) ([3ad3bdd](https://github.com/Ombi-app/Ombi/commit/3ad3bddd8313d607ee2a39a51a92e61a3673082c)), closes [#4431](https://github.com/Ombi-app/Ombi/issues/4431) * **API:** Fixed an issue where the API key couldn't delete a request [#4489](https://github.com/Ombi-app/Ombi/issues/4489) ([8e42dbf](https://github.com/Ombi-app/Ombi/commit/8e42dbf8f78caa51ca891bf3d702c6b0ac401f9c))
* **translations:** 🌐 New translations from Crowdin ([8943a97](https://github.com/Ombi-app/Ombi/commit/8943a978bf459eaeb496d50c61c4d1506c727366))
## [4.7.6](https://github.com/Ombi-app/Ombi/compare/v4.7.5...v4.7.6) (2021-12-02)
### Bug Fixes
* **user-management:** :bug: Fixed an issue where you couldn't 'unset' a users custom quality and root folders ([bae96af](https://github.com/Ombi-app/Ombi/commit/bae96af17f50a80ae3ade235a5ef68d5d2dc12ba))
## [4.7.5](https://github.com/Ombi-app/Ombi/compare/v4.7.4...v4.7.5) (2021-11-28)
### Bug Fixes
* **notifications:** fixed an error that could happen when Ombi sends out a issue notification ([7442dcf](https://github.com/Ombi-app/Ombi/commit/7442dcf59da5d2190cc3087b10402e85bcfcf83b))
* **translations:** 🌐 Fix incorrect text translation reference RequestedByOn ([#4420](https://github.com/Ombi-app/Ombi/issues/4420)) ([202d155](https://github.com/Ombi-app/Ombi/commit/202d155493c29a6ddd4c5507186bf376a28f4c1d))
* **translations:** 🌐 New translations from Crowdin ([473c172](https://github.com/Ombi-app/Ombi/commit/473c1724922515fe376e0b2058ac391807c923f2))
## [4.7.4](https://github.com/Ombi-app/Ombi/compare/v4.7.3...v4.7.4) (2021-11-25)
### Bug Fixes
* **availability-rules:** :bug: Fixed a small issue where some shows would not appear as Available even know they had no future unaired episodes listed ([914b096](https://github.com/Ombi-app/Ombi/commit/914b096781c9b73292a533a010a5dd05ecfd0aac))
* **emby:** :bug: Fixed an issue where we were not properly syncing episodes ([75529dd](https://github.com/Ombi-app/Ombi/commit/75529dd972c5102f3c5234a2acf6fe664a1bcfad))
## [4.7.3](https://github.com/Ombi-app/Ombi/compare/v4.7.2...v4.7.3) (2021-11-23)
## [4.7.2](https://github.com/Ombi-app/Ombi/compare/v4.7.1...v4.7.2) (2021-11-22)
### Bug Fixes
* **request-list:** :bug: Fixed an issue where the bulk delete would not work for movie requests ([4b540fb](https://github.com/Ombi-app/Ombi/commit/4b540fb45bcc389664f0953159802288d005db9f))
## [4.7.1](https://github.com/Ombi-app/Ombi/compare/v4.7.0...v4.7.1) (2021-11-22)
### Bug Fixes
* **emby:** :bug: Fixed an issue where we slightly broke the full sync ([332d934](https://github.com/Ombi-app/Ombi/commit/332d9344d002a5ffd5aeac516c7441dcdec52248))
# [4.7.0](https://github.com/Ombi-app/Ombi/compare/v4.6.5...v4.7.0) (2021-11-19)
### Features
* **emby:** :sparkles: Added a emby recently added sync! ([a0e1406](https://github.com/Ombi-app/Ombi/commit/a0e14068f4bc457f8a4a565de71707a8f16c803c))
## [4.6.5](https://github.com/Ombi-app/Ombi/compare/v4.6.4...v4.6.5) (2021-11-15)
### Bug Fixes
* **issues:** :bug: Added the issue category to the issue 'cards' [#4403](https://github.com/Ombi-app/Ombi/issues/4403) ([a3739f3](https://github.com/Ombi-app/Ombi/commit/a3739f375c49f48e34da12f0a74e4e068f12ab40))
* **issues:** :bug: Added the issues back to the details page for TV Shows ([0225000](https://github.com/Ombi-app/Ombi/commit/02250000c08a253e57d8a0a855c2d30b8a1e5baa))
* **issues:** :bug: Fixed an issue where you couldn't navigate to the details page from TV issues ([1a2825b](https://github.com/Ombi-app/Ombi/commit/1a2825bf3839b891b16e1dde4030afe53efe090e))
* **issues:** :bug: Fixed where we did not show the poster when an issue is raised for media we do not have a request for [#4402](https://github.com/Ombi-app/Ombi/issues/4402) ([15e37b5](https://github.com/Ombi-app/Ombi/commit/15e37b532a83097dbdf1a9fea3eead7d0e211898))
## [4.6.4](https://github.com/Ombi-app/Ombi/compare/v4.6.3...v4.6.4) (2021-11-12)
## [4.6.3](https://github.com/Ombi-app/Ombi/compare/v4.6.2...v4.6.3) (2021-11-11)
### Bug Fixes
* **discover:** :bug: Display TV + movies on actor page in user language ([#4395](https://github.com/Ombi-app/Ombi/issues/4395)) ([fe635c7](https://github.com/Ombi-app/Ombi/commit/fe635c7106bc487ff879bdc8a73bab16cb389b97))
* **permissions:** :bug: Improved the security around the role "Manage Own Requests" ([#4397](https://github.com/Ombi-app/Ombi/issues/4397)) ([334a32b](https://github.com/Ombi-app/Ombi/commit/334a32bca42f90198d9b720d2bdb710a583be47f)), closes [#4391](https://github.com/Ombi-app/Ombi/issues/4391)
* **search:** Fixed some cases where search wouldn't work correctly ([#4398](https://github.com/Ombi-app/Ombi/issues/4398)) ([4410790](https://github.com/Ombi-app/Ombi/commit/4410790bc096826bc11554098f846e3acb59589a))
## [4.6.2](https://github.com/Ombi-app/Ombi/compare/v4.6.1...v4.6.2) (2021-11-10)
### Bug Fixes
* **discover:** TV shows now display on the Actor Pages ([#4388](https://github.com/Ombi-app/Ombi/issues/4388)) ([6b716e7](https://github.com/Ombi-app/Ombi/commit/6b716e722076e3d1e6bf2097c5263645d5ea9edf))
## [4.6.1](https://github.com/Ombi-app/Ombi/compare/v4.6.0...v4.6.1) (2021-11-10)
### Bug Fixes
* :bug: Fixed the MySQL issue after .net 6 upgrade [#4393](https://github.com/Ombi-app/Ombi/issues/4393) ([fea7ff0](https://github.com/Ombi-app/Ombi/commit/fea7ff05139e9ff50c8097fa5389b4ef9ad21a15))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([c6acb45](https://github.com/Ombi-app/Ombi/commit/c6acb45f8d3f371c0b4024c4272849d0d0cc867f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([18c220a](https://github.com/Ombi-app/Ombi/commit/18c220a0cd0d19e45a07d0c319da2b9512778a8a))
# [4.6.0](https://github.com/Ombi-app/Ombi/compare/v4.4.0...v4.6.0) (2021-11-09)
### Features
* :sparkles: Upgrade Ombi to .NET 6 ([#4390](https://github.com/Ombi-app/Ombi/issues/4390)) ([719eb7d](https://github.com/Ombi-app/Ombi/commit/719eb7dbe37b3a72d264e2f670067518eef70694)), closes [#4392](https://github.com/Ombi-app/Ombi/issues/4392)
# [4.4.0](https://github.com/Ombi-app/Ombi/compare/v4.3.3...v4.4.0) (2021-11-06)
### Bug Fixes
* **request-list:** :bug: Fixed an issue where the request options were not appearing for Music requests ([c0406a2](https://github.com/Ombi-app/Ombi/commit/c0406a2ddebafb03d98ed25cdf7d89dc9a600c7d))
### Features
* **mass-email:** :sparkles: Added the ability to configure the Mass Email, we can now send BCC and we are less likely to be rate limited when not using bcc [#4377](https://github.com/Ombi-app/Ombi/issues/4377) ([ca655ae](https://github.com/Ombi-app/Ombi/commit/ca655ae57042dec44106a2f2ef5ba2e6f1019ee4))
## [4.3.3](https://github.com/Ombi-app/Ombi/compare/v4.3.2...v4.3.3) (2021-11-05)
## [4.3.2](https://github.com/Ombi-app/Ombi/compare/v4.3.1...v4.3.2) (2021-11-02)
### Bug Fixes
* **translations:** 🌐 Localization - Ensuring all of the app including backend are localized [#4366](https://github.com/Ombi-app/Ombi/issues/4366) ([5e140ab](https://github.com/Ombi-app/Ombi/commit/5e140ab6183b887a7665f5e870eb0bd05d487ace))
## [4.3.1](https://github.com/Ombi-app/Ombi/compare/v4.3.0...v4.3.1) (2021-10-27)
### Bug Fixes
* :bug: Hides no results message during search. ([#4375](https://github.com/Ombi-app/Ombi/issues/4375)) ([b819b0e](https://github.com/Ombi-app/Ombi/commit/b819b0e007e578bf3d8425f19591f87029c64d06))
# [4.3.0](https://github.com/Ombi-app/Ombi/compare/v4.2.13...v4.3.0) (2021-10-20)
### Bug Fixes
* **translations:** 🌐 New translations from Crowdin [skip ci] ([b0f3abb](https://github.com/Ombi-app/Ombi/commit/b0f3abb9ceebdbe5d6c20af98b7355df2999eb58))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([77d017b](https://github.com/Ombi-app/Ombi/commit/77d017b3d8ffd1714a2f6efecc8c900d56d062e4))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([f6e9784](https://github.com/Ombi-app/Ombi/commit/f6e9784367d3678d899ed79bef6caa52005b6661))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([601a877](https://github.com/Ombi-app/Ombi/commit/601a87762a2ad393ee5fa2fe52052ceeeefb1bef))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([a4a80ba](https://github.com/Ombi-app/Ombi/commit/a4a80ba4da49733a65e691003646c0f349bd4c5f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([2961319](https://github.com/Ombi-app/Ombi/commit/2961319f61e95b2871480152b86ddca3375576a1))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([fc8d108](https://github.com/Ombi-app/Ombi/commit/fc8d108b660d53f499538328bfc271b05ac47d2b))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([1e03651](https://github.com/Ombi-app/Ombi/commit/1e03651c3b0eb77e45f9f6c55d31ee672eacd51e))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([c0dd327](https://github.com/Ombi-app/Ombi/commit/c0dd327426514e305a88750d7c3deb21c194108f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([2156129](https://github.com/Ombi-app/Ombi/commit/2156129f175335746f204bb123035c070f518e96))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([aef0368](https://github.com/Ombi-app/Ombi/commit/aef0368de3aec306245bd1b16bc0de596a20d451))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([a38090b](https://github.com/Ombi-app/Ombi/commit/a38090b8dde17d1d150af0bca2830ea45d013a0e))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([c5f1d33](https://github.com/Ombi-app/Ombi/commit/c5f1d3355758a5c3648479d44e50397c7f6c1a9d))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([3846d56](https://github.com/Ombi-app/Ombi/commit/3846d56a6e561a1b1dc65c385151d90fdd6217ee))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([dafe9c1](https://github.com/Ombi-app/Ombi/commit/dafe9c1a19d84f00c13f0a51ba90927c24282926))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([edb418a](https://github.com/Ombi-app/Ombi/commit/edb418a6f05887c68a0c24c48decc691996f97e4))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([dadabf9](https://github.com/Ombi-app/Ombi/commit/dadabf93e1582a0c39321fd9bf3de3fb11e3f406))
### Features
* **request-limits:** :sparkles: Added the new request limit options into the user importer ([01d4f4d](https://github.com/Ombi-app/Ombi/commit/01d4f4d718fe85ac181dae52565fb1b427965b4f))
* **request-limits:** :sparkles: Added the new request limit options to the bulk edit ([03bc23a](https://github.com/Ombi-app/Ombi/commit/03bc23a74e4308aa6b4c6b25636edcdeb65c1f0e))
## [4.2.13](https://github.com/Ombi-app/Ombi/compare/v4.2.12...v4.2.13) (2021-10-20)
### Bug Fixes
* **translations:** 🌐 New translations %two_letters_code% from Crowdin [skip ci] ([8fbd267](https://github.com/Ombi-app/Ombi/commit/8fbd267b516ddaa80fd16c091bae532b860fbf45))
## [4.2.12](https://github.com/Ombi-app/Ombi/compare/v4.2.11...v4.2.12) (2021-10-20)
### Bug Fixes
* **newsletter:** :bug: Fixed a few small bugs in the newsletter ([21dba4c](https://github.com/Ombi-app/Ombi/commit/21dba4c524b98b9f2b883d97e7e13329425a8762))
* **translations:** 🌐 New translations en.json from Crowdin [skip ci] ([52eda6a](https://github.com/Ombi-app/Ombi/commit/52eda6ab917a73842bc02b0d8e0c442e564ca8f0))
* **translations:** 🌐 New translations en.json from Crowdin [skip ci] ([1095d52](https://github.com/Ombi-app/Ombi/commit/1095d524962648a1e427f0bcd8105fa734dd5b60))
## [4.2.11](https://github.com/Ombi-app/Ombi/compare/v4.2.10...v4.2.11) (2021-10-18)
## [4.2.10](https://github.com/Ombi-app/Ombi/compare/v4.2.9...v4.2.10) (2021-10-15)
### Bug Fixes
* :bug: Really really fix it this time? ([543d36e](https://github.com/Ombi-app/Ombi/commit/543d36e5615341bc8378cac377b843a3dbc1ef99))
## [4.2.9](https://github.com/Ombi-app/Ombi/compare/v4.2.8...v4.2.9) (2021-10-15)
### Bug Fixes
* :fire: Really fix the base url issue this time ([9f36923](https://github.com/Ombi-app/Ombi/commit/9f36923c51bfabf9cb026f2da14f9947050af0d9))
## [4.2.8](https://github.com/Ombi-app/Ombi/compare/v4.2.7...v4.2.8) (2021-10-15)
### Bug Fixes
* :adhesive_bandage: See if this fixes the proxy issue ([74d1aca](https://github.com/Ombi-app/Ombi/commit/74d1acae499707a7e21401f53eb2bb90c5bb9cfa))
* :bug: Fixed Ombi not writing the baseUrl correctly ([e9cc8b6](https://github.com/Ombi-app/Ombi/commit/e9cc8b6fe71d3e10c1a901e70227989b3362afe3))
## [4.2.7](https://github.com/Ombi-app/Ombi/compare/v4.2.6...v4.2.7) (2021-10-14)
### Bug Fixes
* :bug: Fixed the issue parsing TheMovieDB dates. They have broken something... ([6e397e0](https://github.com/Ombi-app/Ombi/commit/6e397e02e95f894a92e8bf02428efdcac1275b31))
## [4.2.6](https://github.com/Ombi-app/Ombi/compare/v4.2.5...v4.2.6) (2021-10-14)
### Performance Improvements
* :zap: Use ngxs store for the whole customization section of the app ([97b493d](https://github.com/Ombi-app/Ombi/commit/97b493d869feee59d360b484a6c59388a2aead1f))
## [4.2.5](https://github.com/Ombi-app/Ombi/compare/v4.2.4...v4.2.5) (2021-10-14)

109
README.md
View file

@ -106,14 +106,21 @@ Here are some of the features Ombi has:
<sub><b>Anojh Thayaparan</b></sub> <sub><b>Anojh Thayaparan</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/sephrat">
<img src="https://avatars.githubusercontent.com/u/34862846?v=4" width="50;" alt="sephrat"/>
<br />
<sub><b>Sephrat</b></sub>
</a>
</td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Magikarplvl4"> <a href="https://github.com/Magikarplvl4">
<img src="https://avatars.githubusercontent.com/u/2944704?v=4" width="50;" alt="Magikarplvl4"/> <img src="https://avatars.githubusercontent.com/u/2944704?v=4" width="50;" alt="Magikarplvl4"/>
<br /> <br />
<sub><b>Magikarp Lvl 4</b></sub> <sub><b>Magikarp Lvl 4</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/MrTopCat"> <a href="https://github.com/MrTopCat">
<img src="https://avatars.githubusercontent.com/u/774415?v=4" width="50;" alt="MrTopCat"/> <img src="https://avatars.githubusercontent.com/u/774415?v=4" width="50;" alt="MrTopCat"/>
@ -135,13 +142,6 @@ Here are some of the features Ombi has:
<sub><b>Matt Jeanes</b></sub> <sub><b>Matt Jeanes</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/sephrat">
<img src="https://avatars.githubusercontent.com/u/34862846?v=4" width="50;" alt="sephrat"/>
<br />
<sub><b>Sephrat</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/bernarden"> <a href="https://github.com/bernarden">
<img src="https://avatars.githubusercontent.com/u/12289537?v=4" width="50;" alt="bernarden"/> <img src="https://avatars.githubusercontent.com/u/12289537?v=4" width="50;" alt="bernarden"/>
@ -243,6 +243,13 @@ Here are some of the features Ombi has:
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
<td align="center">
<a href="https://github.com/fservida">
<img src="https://avatars.githubusercontent.com/u/501958?v=4" width="50;" alt="fservida"/>
<br />
<sub><b>Francesco Servida</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/Patricol"> <a href="https://github.com/Patricol">
<img src="https://avatars.githubusercontent.com/u/13428020?v=4" width="50;" alt="Patricol"/> <img src="https://avatars.githubusercontent.com/u/13428020?v=4" width="50;" alt="Patricol"/>
@ -277,15 +284,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Aptalca</b></sub> <sub><b>Aptalca</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/mhann"> <a href="https://github.com/mhann">
<img src="https://avatars.githubusercontent.com/u/17162399?v=4" width="50;" alt="mhann"/> <img src="https://avatars.githubusercontent.com/u/17162399?v=4" width="50;" alt="mhann"/>
<br /> <br />
<sub><b>Mhann</b></sub> <sub><b>Mhann</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/ombi-bot"> <a href="https://github.com/ombi-bot">
<img src="https://avatars.githubusercontent.com/u/51722903?v=4" width="50;" alt="ombi-bot"/> <img src="https://avatars.githubusercontent.com/u/51722903?v=4" width="50;" alt="ombi-bot"/>
@ -320,15 +327,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>D34DC3N73R</b></sub> <sub><b>D34DC3N73R</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/pooley182"> <a href="https://github.com/pooley182">
<img src="https://avatars.githubusercontent.com/u/5040011?v=4" width="50;" alt="pooley182"/> <img src="https://avatars.githubusercontent.com/u/5040011?v=4" width="50;" alt="pooley182"/>
<br /> <br />
<sub><b>David Pooley</b></sub> <sub><b>David Pooley</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Fredrik81"> <a href="https://github.com/Fredrik81">
<img src="https://avatars.githubusercontent.com/u/21292774?v=4" width="50;" alt="Fredrik81"/> <img src="https://avatars.githubusercontent.com/u/21292774?v=4" width="50;" alt="Fredrik81"/>
@ -363,15 +370,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Marius Schiffer</b></sub> <sub><b>Marius Schiffer</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Qstick"> <a href="https://github.com/Qstick">
<img src="https://avatars.githubusercontent.com/u/376117?v=4" width="50;" alt="Qstick"/> <img src="https://avatars.githubusercontent.com/u/376117?v=4" width="50;" alt="Qstick"/>
<br /> <br />
<sub><b>Qstick</b></sub> <sub><b>Qstick</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Vbgf"> <a href="https://github.com/Vbgf">
<img src="https://avatars.githubusercontent.com/u/5571734?v=4" width="50;" alt="Vbgf"/> <img src="https://avatars.githubusercontent.com/u/5571734?v=4" width="50;" alt="Vbgf"/>
@ -406,15 +413,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Alexander Standke</b></sub> <sub><b>Alexander Standke</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Alasano"> <a href="https://github.com/Alasano">
<img src="https://avatars.githubusercontent.com/u/14372930?v=4" width="50;" alt="Alasano"/> <img src="https://avatars.githubusercontent.com/u/14372930?v=4" width="50;" alt="Alasano"/>
<br /> <br />
<sub><b>Aljosa Asanovic</b></sub> <sub><b>Aljosa Asanovic</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Ashyni"> <a href="https://github.com/Ashyni">
<img src="https://avatars.githubusercontent.com/u/18462848?v=4" width="50;" alt="Ashyni"/> <img src="https://avatars.githubusercontent.com/u/18462848?v=4" width="50;" alt="Ashyni"/>
@ -449,15 +456,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Christopher Demicoli</b></sub> <sub><b>Christopher Demicoli</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Codehhh"> <a href="https://github.com/Codehhh">
<img src="https://avatars.githubusercontent.com/u/12055335?v=4" width="50;" alt="Codehhh"/> <img src="https://avatars.githubusercontent.com/u/12055335?v=4" width="50;" alt="Codehhh"/>
<br /> <br />
<sub><b>Codehhh</b></sub> <sub><b>Codehhh</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/danopia"> <a href="https://github.com/danopia">
<img src="https://avatars.githubusercontent.com/u/40628?v=4" width="50;" alt="danopia"/> <img src="https://avatars.githubusercontent.com/u/40628?v=4" width="50;" alt="danopia"/>
@ -492,15 +499,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Eli</b></sub> <sub><b>Eli</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Fish2"> <a href="https://github.com/Fish2">
<img src="https://avatars.githubusercontent.com/u/2311734?v=4" width="50;" alt="Fish2"/> <img src="https://avatars.githubusercontent.com/u/2311734?v=4" width="50;" alt="Fish2"/>
<br /> <br />
<sub><b>Fish2</b></sub> <sub><b>Fish2</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/hariesramdhani"> <a href="https://github.com/hariesramdhani">
<img src="https://avatars.githubusercontent.com/u/24251244?v=4" width="50;" alt="hariesramdhani"/> <img src="https://avatars.githubusercontent.com/u/24251244?v=4" width="50;" alt="hariesramdhani"/>
@ -535,15 +542,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Joe Groocock</b></sub> <sub><b>Joe Groocock</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/errorhandler"> <a href="https://github.com/errorhandler">
<img src="https://avatars.githubusercontent.com/u/17112958?v=4" width="50;" alt="errorhandler"/> <img src="https://avatars.githubusercontent.com/u/17112958?v=4" width="50;" alt="errorhandler"/>
<br /> <br />
<sub><b>Joe Harvey</b></sub> <sub><b>Joe Harvey</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/jonbloom"> <a href="https://github.com/jonbloom">
<img src="https://avatars.githubusercontent.com/u/492819?v=4" width="50;" alt="jonbloom"/> <img src="https://avatars.githubusercontent.com/u/492819?v=4" width="50;" alt="jonbloom"/>
@ -578,15 +585,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Lightkeeper</b></sub> <sub><b>Lightkeeper</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/devbymadde"> <a href="https://github.com/devbymadde">
<img src="https://avatars.githubusercontent.com/u/6094593?v=4" width="50;" alt="devbymadde"/> <img src="https://avatars.githubusercontent.com/u/6094593?v=4" width="50;" alt="devbymadde"/>
<br /> <br />
<sub><b>Madeleine Schönemann</b></sub> <sub><b>Madeleine Schönemann</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/mattmattmatt"> <a href="https://github.com/mattmattmatt">
<img src="https://avatars.githubusercontent.com/u/927830?v=4" width="50;" alt="mattmattmatt"/> <img src="https://avatars.githubusercontent.com/u/927830?v=4" width="50;" alt="mattmattmatt"/>
@ -594,6 +601,13 @@ Here are some of the features Ombi has:
<sub><b>Matt</b></sub> <sub><b>Matt</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/LMaxence">
<img src="https://avatars.githubusercontent.com/u/29194680?v=4" width="50;" alt="LMaxence"/>
<br />
<sub><b>Maxence Lecanu</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/AliMickey"> <a href="https://github.com/AliMickey">
<img src="https://avatars.githubusercontent.com/u/60691199?v=4" width="50;" alt="AliMickey"/> <img src="https://avatars.githubusercontent.com/u/60691199?v=4" width="50;" alt="AliMickey"/>
@ -608,6 +622,14 @@ Here are some of the features Ombi has:
<sub><b>Nathan Miller</b></sub> <sub><b>Nathan Miller</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/cqxmzz">
<img src="https://avatars.githubusercontent.com/u/3071863?v=4" width="50;" alt="cqxmzz"/>
<br />
<sub><b>Qiming Chen</b></sub>
</a>
</td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/randallbruder"> <a href="https://github.com/randallbruder">
<img src="https://avatars.githubusercontent.com/u/6447487?v=4" width="50;" alt="randallbruder"/> <img src="https://avatars.githubusercontent.com/u/6447487?v=4" width="50;" alt="randallbruder"/>
@ -628,8 +650,7 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Samuel Bartík</b></sub> <sub><b>Samuel Bartík</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/seancallinan"> <a href="https://github.com/seancallinan">
<img src="https://avatars.githubusercontent.com/u/1139665?v=4" width="50;" alt="seancallinan"/> <img src="https://avatars.githubusercontent.com/u/1139665?v=4" width="50;" alt="seancallinan"/>
@ -650,7 +671,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Thomas Van Tilburg</b></sub> <sub><b>Thomas Van Tilburg</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/Tim-Trott"> <a href="https://github.com/Tim-Trott">
<img src="https://avatars.githubusercontent.com/u/8249434?v=4" width="50;" alt="Tim-Trott"/> <img src="https://avatars.githubusercontent.com/u/8249434?v=4" width="50;" alt="Tim-Trott"/>
@ -671,8 +693,7 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Torkil</b></sub> <sub><b>Torkil</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/bybeet"> <a href="https://github.com/bybeet">
<img src="https://avatars.githubusercontent.com/u/1662279?v=4" width="50;" alt="bybeet"/> <img src="https://avatars.githubusercontent.com/u/1662279?v=4" width="50;" alt="bybeet"/>
@ -693,7 +714,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Tim OBrien</b></sub> <sub><b>Tim OBrien</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/x-limitless-x"> <a href="https://github.com/x-limitless-x">
<img src="https://avatars.githubusercontent.com/u/17127926?v=4" width="50;" alt="x-limitless-x"/> <img src="https://avatars.githubusercontent.com/u/17127926?v=4" width="50;" alt="x-limitless-x"/>
@ -714,8 +736,7 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Michael DiStaula</b></sub> <sub><b>Michael DiStaula</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/baikunz"> <a href="https://github.com/baikunz">
<img src="https://avatars.githubusercontent.com/u/984911?v=4" width="50;" alt="baikunz"/> <img src="https://avatars.githubusercontent.com/u/984911?v=4" width="50;" alt="baikunz"/>
@ -736,7 +757,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Maartenheebink</b></sub> <sub><b>Maartenheebink</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/masterhuck"> <a href="https://github.com/masterhuck">
<img src="https://avatars.githubusercontent.com/u/4671442?v=4" width="50;" alt="masterhuck"/> <img src="https://avatars.githubusercontent.com/u/4671442?v=4" width="50;" alt="masterhuck"/>
@ -757,8 +779,7 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Tdorsey</b></sub> <sub><b>Tdorsey</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/thegame3202"> <a href="https://github.com/thegame3202">
<img src="https://avatars.githubusercontent.com/u/22148848?v=4" width="50;" alt="thegame3202"/> <img src="https://avatars.githubusercontent.com/u/22148848?v=4" width="50;" alt="thegame3202"/>

View file

@ -1,10 +1,10 @@
commit_message: "fix(translations): 🌐 New translations from Crowdin [skip ci]" commit_message: "fix(translations): 🌐 New translations from Crowdin [skip ci]"
append_commit_message: false append_commit_message: false
pull_request_title: "🌐 Translations Update" pull_request_title: "🌐 Translations Update"
pull_request_labels: pull_request_labels:
- translations - translations
files: files:
- source: /src/Ombi/wwwroot/translations/en.json - source: /src/Ombi/wwwroot/translations/en.json
translation: /src/Ombi/wwwroot/translations/%two_letters_code%.json translation: /src/Ombi/wwwroot/translations/%two_letters_code%.json
- source: /src/Ombi.I18n/Resources/Texts.resx
translation: /src/Ombi.I18n/Resources/Texts.%two_letters_code%.resx

View file

@ -929,7 +929,7 @@
<e p="EmbyConfiguration.cs" t="Include" /> <e p="EmbyConfiguration.cs" t="Include" />
<e p="EmbyConnectUser.cs" t="Include" /> <e p="EmbyConnectUser.cs" t="Include" />
<e p="EmbyItemContainer.cs" t="Include" /> <e p="EmbyItemContainer.cs" t="Include" />
<e p="EmbyMediaType.cs" t="Include" /> <e p="MediaType.cs" t="Include" />
<e p="EmbyPolicy.cs" t="Include" /> <e p="EmbyPolicy.cs" t="Include" />
<e p="EmbySystemInfo.cs" t="Include" /> <e p="EmbySystemInfo.cs" t="Include" />
<e p="EmbyUser.cs" t="Include" /> <e p="EmbyUser.cs" t="Include" />
@ -1876,7 +1876,7 @@
<e p="PlexAvailabilityChecker.cs" t="Include" /> <e p="PlexAvailabilityChecker.cs" t="Include" />
<e p="PlexContentSync.cs" t="Include" /> <e p="PlexContentSync.cs" t="Include" />
<e p="PlexEpisodeSync.cs" t="Include" /> <e p="PlexEpisodeSync.cs" t="Include" />
<e p="PlexMediaType.cs" t="Include" /> <e p="MediaType.cs" t="Include" />
<e p="PlexRecentlyAddedSync.cs" t="Include" /> <e p="PlexRecentlyAddedSync.cs" t="Include" />
<e p="PlexUserImporter.cs" t="Include" /> <e p="PlexUserImporter.cs" t="Include" />
</e> </e>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -170,7 +170,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("Recursive", true.ToString()); request.AddQueryString("Recursive", true.ToString());
request.AddQueryString("IncludeItemTypes", type); request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds"); request.AddQueryString("Fields", includeOverview ? "ProviderIds,MediaStreams,Overview" : "ProviderIds,MediaStreams ");
request.AddQueryString("startIndex", startIndex.ToString()); request.AddQueryString("startIndex", startIndex.ToString());
request.AddQueryString("limit", count.ToString()); request.AddQueryString("limit", count.ToString());
request.AddQueryString("sortBy", "DateCreated"); request.AddQueryString("sortBy", "DateCreated");
@ -221,7 +221,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("Recursive", true.ToString()); request.AddQueryString("Recursive", true.ToString());
request.AddQueryString("IncludeItemTypes", type); request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds"); request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview,MediaStreams" : "ProviderIds,MediaStreams");
request.AddQueryString("startIndex", startIndex.ToString()); request.AddQueryString("startIndex", startIndex.ToString());
request.AddQueryString("limit", count.ToString()); request.AddQueryString("limit", count.ToString());
if (!string.IsNullOrEmpty(parentIdFilder)) if (!string.IsNullOrEmpty(parentIdFilder))

View file

@ -1,10 +0,0 @@
namespace Ombi.Api.Emby.Models
{
public enum EmbyMediaType
{
Movie = 0,
Series = 1,
Music = 2,
Episode = 3
}
}

View file

@ -2,35 +2,6 @@ namespace Ombi.Api.Emby.Models.Movie
{ {
public class EmbyMediastream public class EmbyMediastream
{ {
public string Codec { get; set; }
public string Language { get; set; }
public string TimeBase { get; set; }
public string CodecTimeBase { get; set; }
public string NalLengthSize { get; set; }
public bool IsInterlaced { get; set; }
public bool IsAVC { get; set; }
public int BitRate { get; set; }
public int BitDepth { get; set; }
public int RefFrames { get; set; }
public bool IsDefault { get; set; }
public bool IsForced { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public float AverageFrameRate { get; set; }
public float RealFrameRate { get; set; }
public string Profile { get; set; }
public string Type { get; set; }
public string AspectRatio { get; set; }
public int Index { get; set; }
public bool IsExternal { get; set; }
public bool IsTextSubtitleStream { get; set; }
public bool SupportsExternalStream { get; set; }
public string PixelFormat { get; set; }
public int Level { get; set; }
public bool IsAnamorphic { get; set; }
public string DisplayTitle { get; set; } public string DisplayTitle { get; set; }
public string ChannelLayout { get; set; }
public int Channels { get; set; }
public int SampleRate { get; set; }
} }
} }

View file

@ -1,12 +1,10 @@
namespace Ombi.Api.Emby.Models.Movie using Ombi.Api.MediaServer.Models;
{
public class EmbyProviderids
{
public string Tmdb { get; set; }
public string Imdb { get; set; }
public string TmdbCollection { get; set; }
public string Tvdb { get; set; } namespace Ombi.Api.Emby.Models.Movie
{
public class EmbyProviderids: BaseProviderids
{
public string TmdbCollection { get; set; }
public string Zap2It { get; set; } public string Zap2It { get; set; }
public string TvRage { get; set; } public string TvRage { get; set; }
} }

View file

@ -30,5 +30,6 @@ namespace Ombi.Api.Emby.Models.Movie
public int CriticRating { get; set; } public int CriticRating { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public EmbyProviderids ProviderIds { get; set; } public EmbyProviderids ProviderIds { get; set; }
public EmbyMediastream[] MediaStreams { get; set; }
} }
} }

View file

@ -6,12 +6,13 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" /> <ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
<ProjectReference Include="..\Ombi.Api.MediaServer\Ombi.Api.MediaServer.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" /> <ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
</ItemGroup> </ItemGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -157,7 +157,7 @@ namespace Ombi.Api.Jellyfin
request.AddQueryString("Recursive", true.ToString()); request.AddQueryString("Recursive", true.ToString());
request.AddQueryString("IncludeItemTypes", type); request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview,ParentId" : "ProviderIds,ParentId"); request.AddQueryString("Fields", includeOverview ? "ProviderIds,MediaStreams Overview,ParentId" : "ProviderIds,ParentId,MediaStreams");
request.AddQueryString("startIndex", startIndex.ToString()); request.AddQueryString("startIndex", startIndex.ToString());
request.AddQueryString("limit", count.ToString()); request.AddQueryString("limit", count.ToString());
if(!string.IsNullOrEmpty(parentIdFilder)) if(!string.IsNullOrEmpty(parentIdFilder))

View file

@ -1,10 +0,0 @@
namespace Ombi.Api.Jellyfin.Models
{
public enum JellyfinMediaType
{
Movie = 0,
Series = 1,
Music = 2,
Episode = 3
}
}

View file

@ -2,35 +2,6 @@ namespace Ombi.Api.Jellyfin.Models.Movie
{ {
public class JellyfinMediastream public class JellyfinMediastream
{ {
public string Codec { get; set; }
public string Language { get; set; }
public string TimeBase { get; set; }
public string CodecTimeBase { get; set; }
public string NalLengthSize { get; set; }
public bool IsInterlaced { get; set; }
public bool IsAVC { get; set; }
public int BitRate { get; set; }
public int BitDepth { get; set; }
public int RefFrames { get; set; }
public bool IsDefault { get; set; }
public bool IsForced { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public float AverageFrameRate { get; set; }
public float RealFrameRate { get; set; }
public string Profile { get; set; }
public string Type { get; set; }
public string AspectRatio { get; set; }
public int Index { get; set; }
public bool IsExternal { get; set; }
public bool IsTextSubtitleStream { get; set; }
public bool SupportsExternalStream { get; set; }
public string PixelFormat { get; set; }
public int Level { get; set; }
public bool IsAnamorphic { get; set; }
public string DisplayTitle { get; set; } public string DisplayTitle { get; set; }
public string ChannelLayout { get; set; }
public int Channels { get; set; }
public int SampleRate { get; set; }
} }
} }

View file

@ -1,12 +1,10 @@
namespace Ombi.Api.Jellyfin.Models.Movie using Ombi.Api.MediaServer.Models;
{
public class JellyfinProviderids
{
public string Tmdb { get; set; }
public string Imdb { get; set; }
public string TmdbCollection { get; set; }
public string Tvdb { get; set; } namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinProviderids: BaseProviderids
{
public string TmdbCollection { get; set; }
public string Zap2It { get; set; } public string Zap2It { get; set; }
public string TvRage { get; set; } public string TvRage { get; set; }
} }

View file

@ -30,5 +30,6 @@ namespace Ombi.Api.Jellyfin.Models.Movie
public int CriticRating { get; set; } public int CriticRating { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public JellyfinProviderids ProviderIds { get; set; } public JellyfinProviderids ProviderIds { get; set; }
public JellyfinMediastream[] MediaStreams { get; set; }
} }
} }

View file

@ -6,13 +6,14 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" /> <ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" /> <ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
<ProjectReference Include="..\Ombi.Api.MediaServer\Ombi.Api.MediaServer.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -0,0 +1,11 @@
namespace Ombi.Api.MediaServer.Models
{
public class BaseProviderids
{
public string Tmdb { get; set; }
public string Imdb { get; set; }
public string Tvdb { get; set; }
public bool Any() =>
!string.IsNullOrEmpty(Imdb) || !string.IsNullOrEmpty(Tmdb) || !string.IsNullOrEmpty(Tvdb);
}
}

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
<PackageVersion></PackageVersion>
<LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
</ItemGroup>
</Project>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.Plex.Models; using Ombi.Api.Plex.Models;
using Ombi.Api.Plex.Models.Friends; using Ombi.Api.Plex.Models.Friends;
@ -16,9 +17,9 @@ namespace Ombi.Api.Plex
Task<PlexServer> GetServer(string authToken); Task<PlexServer> GetServer(string authToken);
Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost); Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost);
Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId); Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId);
Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, int ratingKey); Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, string ratingKey);
Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId); Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId);
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey); Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey);
Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount); Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount);
Task<PlexFriends> GetUsers(string authToken); Task<PlexFriends> GetUsers(string authToken);
Task<PlexAccount> GetAccount(string authToken); Task<PlexAccount> GetAccount(string authToken);
@ -26,5 +27,7 @@ namespace Ombi.Api.Plex
Task<OAuthContainer> GetPin(int pinId); Task<OAuthContainer> GetPin(int pinId);
Task<Uri> GetOAuthUrl(string code, string applicationUrl); Task<Uri> GetOAuthUrl(string code, string applicationUrl);
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs); Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken);
Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken);
} }
} }

View file

@ -4,7 +4,7 @@ namespace Ombi.Api.Plex.Models
{ {
public class Metadata public class Metadata
{ {
public int ratingKey { get; set; } public string ratingKey { get; set; }
public string key { get; set; } public string key { get; set; }
public string studio { get; set; } public string studio { get; set; }
public string type { get; set; } public string type { get; set; }
@ -12,26 +12,18 @@ namespace Ombi.Api.Plex.Models
public string contentRating { get; set; } public string contentRating { get; set; }
public string summary { get; set; } public string summary { get; set; }
public int index { get; set; } public int index { get; set; }
public float rating { get; set; }
//public int viewCount { get; set; }
//public int lastViewedAt { get; set; }
public int year { get; set; } public int year { get; set; }
public string thumb { get; set; } public string thumb { get; set; }
public string art { get; set; } public string art { get; set; }
public string banner { get; set; } public string banner { get; set; }
public string theme { get; set; } public string theme { get; set; }
//public string duration { get; set; }
//public string originallyAvailableAt { get; set; }
public int leafCount { get; set; } public int leafCount { get; set; }
public int viewedLeafCount { get; set; } public int viewedLeafCount { get; set; }
public int childCount { get; set; } public int childCount { get; set; }
//public long addedAt { get; set; }
//public int updatedAt { get; set; }
public Genre[] Genre { get; set; } public Genre[] Genre { get; set; }
//public Role[] Role { get; set; }
public string primaryExtraKey { get; set; } public string primaryExtraKey { get; set; }
public int parentRatingKey { get; set; } public string parentRatingKey { get; set; }
public int grandparentRatingKey { get; set; } public string grandparentRatingKey { get; set; }
public string guid { get; set; } public string guid { get; set; }
public int librarySectionID { get; set; } public int librarySectionID { get; set; }
public string librarySectionKey { get; set; } public string librarySectionKey { get; set; }
@ -47,12 +39,10 @@ namespace Ombi.Api.Plex.Models
public string chapterSource { get; set; } public string chapterSource { get; set; }
public Medium[] Media { get; set; } public Medium[] Media { get; set; }
public List<PlexGuids> Guid { get; set; } = new List<PlexGuids>(); public List<PlexGuids> Guid { get; set; } = new List<PlexGuids>();
// public Director[] Director { get; set; }
// public Writer[] Writer { get; set; }
} }
public class PlexGuids public class PlexGuids
{ {
public string Id { get; set; } public string Id { get; set; }
} }
} }

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlist
{
public string librarySectionID { get; set; }
public string librarySectionTitle { get; set; }
public int offset { get; set; }
public int totalSize { get; set; }
public int size { get; set; }
public List<Metadata> Metadata { get; set; } = new List<Metadata>();
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlistContainer
{
public PlexWatchlist MediaContainer { get; set; }
}
}

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlistMetadataContainer
{
public PlexWatchlistMetadata MediaContainer { get; set; }
}
public class PlexWatchlistMetadata
{
public int offset { get; set; }
public int totalSize { get; set; }
public string identifier { get; set; }
public int size { get; set; }
public WatchlistMetadata[] Metadata { get; set; }
}
public class WatchlistMetadata
{
public string guid { get; set; }
public string key { get; set; }
public string primaryExtraKey { get; set; }
public string ratingKey { get; set; }
public string type { get; set; }
public string slug { get; set; }
public string title { get; set; }
public List<PlexGuids> Guid { get; set; } = new List<PlexGuids>();
}
}

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ombi.Api.Plex.Models; using Ombi.Api.Plex.Models;
@ -66,6 +67,7 @@ namespace Ombi.Api.Plex
private const string FriendsUri = "https://plex.tv/pms/friends/all"; private const string FriendsUri = "https://plex.tv/pms/friends/all";
private const string GetAccountUri = "https://plex.tv/users/account.json"; private const string GetAccountUri = "https://plex.tv/users/account.json";
private const string ServerUri = "https://plex.tv/pms/servers.xml"; private const string ServerUri = "https://plex.tv/pms/servers.xml";
private const string WatchlistUri = "https://metadata.provider.plex.tv/";
/// <summary> /// <summary>
/// Sign into the Plex API /// Sign into the Plex API
@ -145,21 +147,21 @@ namespace Ombi.Api.Plex
/// <param name="authToken"></param> /// <param name="authToken"></param>
/// <param name="plexFullHost"></param> /// <param name="plexFullHost"></param>
/// <param name="ratingKey"></param> /// <param name="ratingKey"></param>
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, int ratingKey) public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, string ratingKey)
{ {
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get); var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
return await Api.Request<PlexMetadata>(request); return await Api.Request<PlexMetadata>(request);
} }
public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId) public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId)
{ {
var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get); var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
return await Api.Request<PlexMetadata>(request); return await Api.Request<PlexMetadata>(request);
} }
public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey) public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey)
{ {
var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get); var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
@ -288,6 +290,26 @@ namespace Ombi.Api.Plex
} }
} }
public async Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken)
{
var request = new Request("library/sections/watchlist/all", WatchlistUri, HttpMethod.Get);
await AddHeaders(request, plexToken);
var result = await Api.Request<PlexWatchlistContainer>(request, cancellationToken);
return result;
}
public async Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken)
{
var request = new Request($"library/metadata/{ratingKey}", WatchlistUri, HttpMethod.Get);
await AddHeaders(request, plexToken);
var result = await Api.Request<PlexWatchlistMetadataContainer>(request, cancellationToken);
return result;
}
/// <summary> /// <summary>
/// Adds the required headers and also the authorization header /// Adds the required headers and also the authorization header

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -44,7 +44,10 @@ namespace Ombi.Api.Radarr.Models
public int id { get; set; } public int id { get; set; }
} }
public class MovieQuality
{
public V3.Quality quality { get; set; }
}
public class Moviefile public class Moviefile
{ {
public int movieId { get; set; } public int movieId { get; set; }
@ -54,7 +57,7 @@ namespace Ombi.Api.Radarr.Models
public DateTime dateAdded { get; set; } public DateTime dateAdded { get; set; }
public string sceneName { get; set; } public string sceneName { get; set; }
public int indexerFlags { get; set; } public int indexerFlags { get; set; }
public V3.Quality quality { get; set; } public MovieQuality quality { get; set; }
public Mediainfo mediaInfo { get; set; } public Mediainfo mediaInfo { get; set; }
public string originalFilePath { get; set; } public string originalFilePath { get; set; }
public bool qualityCutoffNotMet { get; set; } public bool qualityCutoffNotMet { get; set; }
@ -74,13 +77,10 @@ namespace Ombi.Api.Radarr.Models
public class Mediainfo public class Mediainfo
{ {
public string audioAdditionalFeatures { get; set; } public string audioAdditionalFeatures { get; set; }
public int audioBitrate { get; set; }
public float audioChannels { get; set; } public float audioChannels { get; set; }
public string audioCodec { get; set; } public string audioCodec { get; set; }
public string audioLanguages { get; set; } public string audioLanguages { get; set; }
public int audioStreamCount { get; set; } public int audioStreamCount { get; set; }
public int videoBitDepth { get; set; }
public int videoBitrate { get; set; }
public string videoCodec { get; set; } public string videoCodec { get; set; }
public float videoFps { get; set; } public float videoFps { get; set; }
public string resolution { get; set; } public string resolution { get; set; }
@ -119,4 +119,4 @@ namespace Ombi.Api.Radarr.Models
public int id { get; set; } public int id { get; set; }
public string name { get; set; } public string name { get; set; }
} }
} }

View file

@ -25,5 +25,4 @@
public int resolution { get; set; } public int resolution { get; set; }
public string modifier { get; set; } public string modifier { get; set; }
} }
} }

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -8,7 +8,7 @@
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<AssemblyName>Ombi.Api.Service</AssemblyName> <AssemblyName>Ombi.Api.Service</AssemblyName>
<RootNamespace>Ombi.Api.Service</RootNamespace> <RootNamespace>Ombi.Api.Service</RootNamespace>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -8,10 +8,8 @@ namespace Ombi.Api.TvMaze
public interface ITvMazeApi public interface ITvMazeApi
{ {
Task<IEnumerable<TvMazeEpisodes>> EpisodeLookup(int showId); Task<IEnumerable<TvMazeEpisodes>> EpisodeLookup(int showId);
Task<List<TvMazeSeasons>> GetSeasons(int id);
Task<List<TvMazeSearch>> Search(string searchTerm); Task<List<TvMazeSearch>> Search(string searchTerm);
Task<TvMazeShow> ShowLookup(int showId); Task<TvMazeShow> ShowLookup(int showId);
Task<TvMazeShow> ShowLookupByTheTvDbId(int theTvDbId); Task<TvMazeShow> ShowLookupByTheTvDbId(int theTvDbId);
Task<FullSearch> GetTvFullInformation(int id);
} }
} }

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -64,27 +64,5 @@ namespace Ombi.Api.TvMaze
return null; return null;
} }
} }
public async Task<List<TvMazeSeasons>> GetSeasons(int id)
{
var request = new Request($"shows/{id}/seasons", Uri, HttpMethod.Get);
request.AddContentHeader("Content-Type", "application/json");
return await Api.Request<List<TvMazeSeasons>>(request);
}
public async Task<FullSearch> GetTvFullInformation(int id)
{
var request = new Request($"shows/{id}", Uri, HttpMethod.Get);
request.AddQueryString("embed[]", "cast");
request.AddQueryString("embed[]", "crew");
request.AddQueryString("embed[]", "episodes");
request.AddContentHeader("Content-Type", "application/json");
return await Api.Request<FullSearch>(request);
}
} }
} }

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -10,6 +10,7 @@ using Ombi.Core.Authentication;
using Ombi.Core.Engine.V2; using Ombi.Core.Engine.V2;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Engine namespace Ombi.Core.Tests.Engine
{ {
@ -25,7 +26,7 @@ namespace Ombi.Core.Tests.Engine
{ {
MovieRepo = new Mock<IMovieRequestRepository>(); MovieRepo = new Mock<IMovieRequestRepository>();
TvRepo = new Mock<ITvRequestRepository>(); TvRepo = new Mock<ITvRequestRepository>();
var principle = new Mock<IPrincipal>(); var principle = new Mock<ICurrentUser>();
var identity = new Mock<IIdentity>(); var identity = new Mock<IIdentity>();
identity.Setup(x => x.Name).Returns("UnitTest"); identity.Setup(x => x.Name).Returns("UnitTest");
principle.Setup(x => x.Identity).Returns(identity.Object); principle.Setup(x => x.Identity).Returns(identity.Object);

View file

@ -1,135 +1,520 @@
//using System.Collections.Generic; using MockQueryable.Moq;
//using System.Linq; using Moq;
//using System.Threading.Tasks; using Moq.AutoMock;
//using Moq; using NUnit.Framework;
//using NUnit.Framework; using Ombi.Core.Authentication;
//using Ombi.Core.Engine; using Ombi.Core.Engine;
//using Ombi.Core.Models.Requests; using Ombi.Core.Helpers;
//using Ombi.Store.Entities.Requests; using Ombi.Core.Models.Requests;
//using Ombi.Store.Repository; using Ombi.Store.Entities;
//using Assert = Xunit.Assert; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests;
using Ombi.Test.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
//namespace Ombi.Core.Tests.Engine namespace Ombi.Core.Tests.Engine
//{ {
// [TestFixture] [TestFixture]
// public class MovieRequestEngineTests public class MovieRequestEngineTests
// { {
// public MovieRequestEngineTests() private MovieRequestEngine _subject;
// { private Mock<IMovieRequestRepository> _repoMock;
// RequestService = new Mock<IMovieRequestRepository>(); private AutoMocker _mocker;
// var requestService = new RequestService(null, RequestService.Object);
// Engine = new MovieRequestEngine(null, requestService, null, null, null, null, null, null);
// }
// private MovieRequestEngine Engine { get; } [SetUp]
// private Mock<IMovieRequestRepository> RequestService { get; } public void Setup()
{
_mocker = new AutoMocker();
var userManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { NormalizedUserName = "TEST", Id = "a" } });
userManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).ReturnsAsync(true);
var principle = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
identity.Setup(x => x.Name).Returns("Test");
principle.Setup(x => x.Identity).Returns(identity.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identity.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { NormalizedUserName = "TEST", Id = "a" });
// [Test] _repoMock = new Mock<IMovieRequestRepository>();
// public async Task GetNewRequests_Should_ReturnEmpty_WhenThereAreNoNewRequests() var requestServiceMock = new Mock<IRequestServiceMain>();
// { requestServiceMock.Setup(x => x.MovieRequestService).Returns(_repoMock.Object);
// var requests = new List<MovieRequests>
// {
// new MovieRequests { Available = true },
// new MovieRequests { Approved = true },
// };
// var r = DbHelper.GetQueryable(requests[0], requests[1]); _mocker.Use(principle.Object);
// RequestService.Setup(x => x.Get()).Returns(r); _mocker.Use(currentUser.Object);
_mocker.Use(userManager.Object);
_mocker.Use(requestServiceMock);
// var result = await Engine.GetNewRequests(); _subject = _mocker.CreateInstance<MovieRequestEngine>();
var list = DbHelper.GetQueryableMockDbSet(new RequestSubscription());
_mocker.Setup<IRepository<RequestSubscription>, IQueryable<RequestSubscription>>(x => x.GetAll()).Returns(new List<RequestSubscription>().AsQueryable().BuildMock().Object);
}
// Assert.False(result.Any()); [Test]
// } public async Task GetRequestByStatus_PendingRequests_Non4K()
{
var movies = RegularRequestData();
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
// [Test] var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", Models.Requests.RequestStatus.PendingApproval);
// public async Task GetNewRequests_Should_ReturnOnlyNewRequests_WhenThereAreMultipleRequests()
// {
// var requests = new List<MovieRequests>
// {
// new MovieRequests { Available = true },
// new MovieRequests { Approved = true },
// new MovieRequests(),
// };
// RequestService.Setup(x => x.Get()).Returns(requests.AsQueryable);
// var result = await Engine.GetNewRequests(); Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(4));
}
// Assert.Single(result); [Test]
// Assert.All(result, x => public async Task GetRequestByStatus_PendingRequests_4K()
// { {
// Assert.False(x.Available); var movies = new List<MovieRequests>
// Assert.False(x.Approved); {
// }); new MovieRequests
// } {
Id= 1,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.MinValue
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
// [Test] var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.PendingApproval);
// public async Task GetApprovedRequests_Should_ReturnEmpty_WhenThereAreNoApprovedRequests()
// {
// var requests = new List<MovieRequests>
// {
// new MovieRequests { Available = true },
// };
// RequestService.Setup(x => x.Get()).Returns(requests.AsQueryable);
// var result = await Engine.GetApprovedRequests(); Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(4));
}
// Assert.False(result.Any());
// }
// [Test] [Test]
// public async Task GetApprovedRequests_Should_ReturnOnlyApprovedRequests_WhenThereAreMultipleRequests() public async Task GetRequestByStatus_PendingRequests_Both4K_And_Regular()
// { {
// var requests = new List<MovieRequests> var movies = new List<MovieRequests>
// { {
// new MovieRequests { Available = true }, new MovieRequests
// new MovieRequests { Approved = true }, {
// new MovieRequests(), Id= 1,
// }; Approved = false,
// RequestService.Setup(x => x.Get()).Returns(requests.AsQueryable); Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.MinValue
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
// var result = await Engine.GetApprovedRequests(); var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.PendingApproval);
// Assert.Single(result); Assert.That(result.Total, Is.EqualTo(2));
// Assert.All(result, x => Assert.That(result.Collection.First().Id, Is.EqualTo(1));
// { Assert.That(result.Collection.ToArray()[1].Id, Is.EqualTo(4));
// Assert.False(x.Available); }
// Assert.True(x.Approved);
// });
// }
// [Test]
// public async Task GetAvailableRequests_Should_ReturnEmpty_WhenThereAreNoAvailableRequests()
// {
// var requests = new List<MovieRequests>
// {
// new MovieRequests { Approved = true },
// };
// RequestService.Setup(x => x.Get()).Returns(requests.AsQueryable);
// var result = await Engine.GetAvailableRequests(); [Test]
public async Task GetRequestByStatus_ProcessingRequests_Non4K()
{
var movies = RegularRequestData();
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
// Assert.False(result.Any()); var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", Models.Requests.RequestStatus.ProcessingRequest);
// }
// [Test] Assert.That(result.Total, Is.EqualTo(1));
// public async Task GetAvailableRequests_Should_ReturnOnlyAvailableRequests_WhenThereAreMultipleRequests() Assert.That(result.Collection.First().Id, Is.EqualTo(1));
// { }
// var requests = new List<MovieRequests>
// {
// new MovieRequests { Available = true },
// new MovieRequests { Approved = true },
// new MovieRequests(),
// };
// RequestService.Setup(x => x.Get()).Returns(requests.AsQueryable);
// var result = await Engine.GetAvailableRequests(); [Test]
public async Task GetRequestByStatus_ProcessingRequests_4K()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.MinValue
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
// Assert.Single(result); var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.ProcessingRequest);
// Assert.All(result, x =>
// { Assert.That(result.Total, Is.EqualTo(1));
// Assert.True(x.Available); Assert.That(result.Collection.First().Id, Is.EqualTo(1));
// Assert.False(x.Approved); }
// });
// }
// } [Test]
//} public async Task GetRequestByStatus_ProcessingRequests_Both4K_And_Regular()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Approved = false,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Approved = true,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.Now
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.ProcessingRequest);
Assert.That(result.Total, Is.EqualTo(2));
Assert.That(result.Collection.First().Id, Is.EqualTo(1));
Assert.That(result.Collection.ToArray()[1].Id, Is.EqualTo(4));
}
[Test]
public async Task GetRequestByStatus_AvailableRequests_Non4K()
{
List<MovieRequests> movies = RegularRequestData();
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", Models.Requests.RequestStatus.Available);
Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(2));
}
[Test]
public async Task GetRequestByStatus_AvailableRequests_4K()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.MinValue
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.Available);
Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(2));
}
[Test]
public async Task GetRequestByStatus_AvailableRequests_Both4K_And_Regular()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Available = true,
Approved = false,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Approved = true,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.Now
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.Available);
Assert.That(result.Total, Is.EqualTo(2));
Assert.That(result.Collection.First().Id, Is.EqualTo(1));
Assert.That(result.Collection.ToArray()[1].Id, Is.EqualTo(2));
}
[Test]
public async Task GetRequestByStatus_DeniedRequests_Non4K()
{
List<MovieRequests> movies = RegularRequestData();
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", Models.Requests.RequestStatus.Denied);
Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(3));
}
[Test]
public async Task GetRequestByStatus_DeniedRequests_4K()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.MinValue
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.Denied);
Assert.That(result.Total, Is.EqualTo(1));
Assert.That(result.Collection.First().Id, Is.EqualTo(3));
}
[Test]
public async Task GetRequestByStatus_DeniedRequests_Both4K_And_Regular()
{
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Available = true,
Approved = false,
Approved4K = true,
Has4KRequest = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 2,
Approved4K = false,
Available4K = true,
Denied = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 3,
Denied4K = true,
Has4KRequest = true,
RequestedDate = DateTime.MinValue
},
new MovieRequests
{
Id = 4,
Has4KRequest = true,
Approved4K = false,
Approved = true,
Available4K = false,
Denied4K = false,
RequestedDate = DateTime.Now
}
};
_repoMock.Setup(x => x.GetWithUser()).Returns(movies.AsQueryable());
var result = await _subject.GetRequestsByStatus(10, 0, "id", "asc", RequestStatus.Denied);
Assert.That(result.Total, Is.EqualTo(2));
Assert.That(result.Collection.First().Id, Is.EqualTo(2));
Assert.That(result.Collection.ToArray()[1].Id, Is.EqualTo(3));
}
private static List<MovieRequests> RegularRequestData()
{
return new List<MovieRequests>
{
new MovieRequests
{
Id= 1,
Approved = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 2,
Approved = false,
Available = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 3,
Denied = true,
RequestedDate = DateTime.Now
},
new MovieRequests
{
Id = 4,
Approved = false,
RequestedDate = DateTime.Now
}
};
}
}
}

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -36,6 +37,13 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(currentUser.Object);
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();
@ -429,6 +437,7 @@ namespace Ombi.Core.Tests.Engine
Id = "id1" Id = "id1"
}; };
var lastWeek = new DateTime(2020, 09, 05).AddMonths(-1).AddDays(-1); var lastWeek = new DateTime(2020, 09, 05).AddMonths(-1).AddDays(-1);
var today = new DateTime(2020, 09, 15, 13, 0, 0);
var log = new List<RequestLog> var log = new List<RequestLog>
{ {
new RequestLog new RequestLog
@ -441,7 +450,7 @@ namespace Ombi.Core.Tests.Engine
var repoMock = _mocker.GetMock<IRepository<RequestLog>>(); var repoMock = _mocker.GetMock<IRepository<RequestLog>>();
repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object);
var result = await _subject.GetRemainingMovieRequests(user); var result = await _subject.GetRemainingMovieRequests(user, today);
Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>() Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>()
.With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true)
@ -474,7 +483,7 @@ namespace Ombi.Core.Tests.Engine
var repoMock = _mocker.GetMock<IRepository<RequestLog>>(); var repoMock = _mocker.GetMock<IRepository<RequestLog>>();
repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object);
var result = await _subject.GetRemainingMovieRequests(user); var result = await _subject.GetRemainingMovieRequests(user, today);
Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>() Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>()
.With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true)
@ -494,7 +503,7 @@ namespace Ombi.Core.Tests.Engine
MovieRequestLimitType = RequestLimitType.Month, MovieRequestLimitType = RequestLimitType.Month,
Id = "id1" Id = "id1"
}; };
var today = DateTime.UtcNow; var today = new DateTime(2022,2,2,13,0,0);
var firstDayOfMonth = new DateTime(today.Year, today.Month, 1); var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
var log = new List<RequestLog> var log = new List<RequestLog>
{ {
@ -514,7 +523,7 @@ namespace Ombi.Core.Tests.Engine
var repoMock = _mocker.GetMock<IRepository<RequestLog>>(); var repoMock = _mocker.GetMock<IRepository<RequestLog>>();
repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object);
var result = await _subject.GetRemainingMovieRequests(user); var result = await _subject.GetRemainingMovieRequests(user, today);
Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>() Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>()
.With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true)

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -36,7 +37,12 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_mocker.Use(currentUser.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();
} }
@ -494,7 +500,7 @@ namespace Ombi.Core.Tests.Engine
MusicRequestLimitType = RequestLimitType.Month, MusicRequestLimitType = RequestLimitType.Month,
Id = "id1" Id = "id1"
}; };
var today = DateTime.UtcNow; var today = new DateTime(2022, 2, 2, 13, 0, 0);
var firstDayOfMonth = new DateTime(today.Year, today.Month, 1); var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
var log = new List<RequestLog> var log = new List<RequestLog>
{ {
@ -514,7 +520,7 @@ namespace Ombi.Core.Tests.Engine
var repoMock = _mocker.GetMock<IRepository<RequestLog>>(); var repoMock = _mocker.GetMock<IRepository<RequestLog>>();
repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object);
var result = await _subject.GetRemainingMusicRequests(user); var result = await _subject.GetRemainingMusicRequests(user, today);
Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>() Assert.That(result, Is.InstanceOf<RequestQuotaCountModel>()
.With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true)

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -33,7 +34,12 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_mocker.Use(currentUser.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();
} }

View file

@ -7,8 +7,10 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Services;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models;
@ -32,7 +34,7 @@ namespace Ombi.Core.Tests.Engine.V2
var requestService = new Mock<IRequestServiceMain>(); var requestService = new Mock<IRequestServiceMain>();
_movieRequestRepository = new Mock<IMovieRequestRepository>(); _movieRequestRepository = new Mock<IMovieRequestRepository>();
requestService.Setup(x => x.MovieRequestService).Returns(_movieRequestRepository.Object); requestService.Setup(x => x.MovieRequestService).Returns(_movieRequestRepository.Object);
var user = new Mock<IPrincipal>(); var user = new Mock<ICurrentUser>();
var notificationHelper = new Mock<INotificationHelper>(); var notificationHelper = new Mock<INotificationHelper>();
var rules = new Mock<IRuleEvaluator>(); var rules = new Mock<IRuleEvaluator>();
var movieSender = new Mock<IMovieSender>(); var movieSender = new Mock<IMovieSender>();
@ -43,8 +45,9 @@ namespace Ombi.Core.Tests.Engine.V2
var ombiSettings = new Mock<ISettingsService<OmbiSettings>>(); var ombiSettings = new Mock<ISettingsService<OmbiSettings>>();
var requestSubs = new Mock<IRepository<RequestSubscription>>(); var requestSubs = new Mock<IRepository<RequestSubscription>>();
var mediaCache = new Mock<IMediaCacheService>(); var mediaCache = new Mock<IMediaCacheService>();
var featureService = new Mock<IFeatureService>();
_engine = new MovieRequestEngine(movieApi.Object, requestService.Object, user.Object, notificationHelper.Object, rules.Object, movieSender.Object, _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); logger.Object, userManager.Object, requestLogRepo.Object, cache.Object, ombiSettings.Object, requestSubs.Object, mediaCache.Object, featureService.Object);
} }
[Test] [Test]

View file

@ -23,6 +23,7 @@ using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.Test.Common; using Ombi.Test.Common;
using Artist = Hqub.MusicBrainz.API.Entities.Artist; using Artist = Hqub.MusicBrainz.API.Entities.Artist;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Engine.V2 namespace Ombi.Core.Tests.Engine.V2
{ {
@ -45,7 +46,7 @@ namespace Ombi.Core.Tests.Engine.V2
.ForEach(b => F.Behaviors.Remove(b)); .ForEach(b => F.Behaviors.Remove(b));
F.Behaviors.Add(new OmitOnRecursionBehavior()); F.Behaviors.Add(new OmitOnRecursionBehavior());
var principle = new Mock<IPrincipal>(); var principle = new Mock<ICurrentUser>();
var requestService = new Mock<IRequestServiceMain>(); var requestService = new Mock<IRequestServiceMain>();
var ruleEval = new Mock<IRuleEvaluator>(); var ruleEval = new Mock<IRuleEvaluator>();
var um = MockHelper.MockUserManager(new List<OmbiUser>()); var um = MockHelper.MockUserManager(new List<OmbiUser>());

View file

@ -9,6 +9,7 @@ using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Settings; using Ombi.Core.Settings;
@ -32,8 +33,9 @@ namespace Ombi.Core.Tests.Engine
TvRequestEngine = new Mock<ITvRequestEngine>(); TvRequestEngine = new Mock<ITvRequestEngine>();
MovieRequestEngine = new Mock<IMovieRequestEngine>(); MovieRequestEngine = new Mock<IMovieRequestEngine>();
MovieRequestEngine = new Mock<IMovieRequestEngine>(); MovieRequestEngine = new Mock<IMovieRequestEngine>();
User = new Mock<IPrincipal>(); User = new Mock<ICurrentUser>();
User.Setup(x => x.Identity.Name).Returns("abc"); User.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "abc" });
UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc", NormalizedUserName = "ABC" } }); UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc", NormalizedUserName = "ABC" } });
Rule = new Mock<IRuleEvaluator>(); Rule = new Mock<IRuleEvaluator>();
Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object, Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object,
@ -48,7 +50,7 @@ namespace Ombi.Core.Tests.Engine
public Fixture F { get; set; } public Fixture F { get; set; }
public VoteEngine Engine { get; set; } public VoteEngine Engine { get; set; }
public Mock<IPrincipal> User { get; set; } public Mock<ICurrentUser> User { get; set; }
public Mock<OmbiUserManager> UserManager { get; set; } public Mock<OmbiUserManager> UserManager { get; set; }
public Mock<IRuleEvaluator> Rule { get; set; } public Mock<IRuleEvaluator> Rule { get; set; }
public Mock<IRepository<Votes>> VoteRepository { get; set; } public Mock<IRepository<Votes>> VoteRepository { get; set; }
@ -83,7 +85,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.True); Assert.That(result.Result, Is.True);
VoteRepository.Verify(x => x.Add(It.Is<Votes>(c => c.UserId == "abc" && c.VoteType == type)), Times.Once); VoteRepository.Verify(x => x.Add(It.Is<Votes>(c => c.UserId == "abc" && c.VoteType == type)), Times.Once);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never); VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never); MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
} }
public static IEnumerable<TestCaseData> VoteData public static IEnumerable<TestCaseData> VoteData
{ {
@ -129,7 +131,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.False); Assert.That(result.Result, Is.False);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never); VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never); MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
} }
public static IEnumerable<TestCaseData> AttemptedTwiceData public static IEnumerable<TestCaseData> AttemptedTwiceData
{ {
@ -175,7 +177,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.True); Assert.That(result.Result, Is.True);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once); VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
VoteRepository.Verify(x => x.Add(It.Is<Votes>(v => v.VoteType == type)), Times.Once); VoteRepository.Verify(x => x.Add(It.Is<Votes>(v => v.VoteType == type)), Times.Once);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never); MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
} }
public static IEnumerable<TestCaseData> VoteConvertData public static IEnumerable<TestCaseData> VoteConvertData
{ {

View file

@ -10,6 +10,8 @@ using Ombi.Test.Common;
using System.Collections.Generic; using System.Collections.Generic;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using System; using System;
using Ombi.Core.Services;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Rule.Request namespace Ombi.Core.Tests.Rule.Request
{ {
@ -26,23 +28,26 @@ namespace Ombi.Core.Tests.Rule.Request
public void Setup() public void Setup()
{ {
PrincipalMock = new Mock<IPrincipal>(); FeatureService = new Mock<IFeatureService>();
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
PrincipalMock = new Mock<ICurrentUser>();
PrincipalMock.Setup(x => x.Username).Returns("abc");
PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "a" });
UserManager = MockHelper.MockUserManager(_users); UserManager = MockHelper.MockUserManager(_users);
Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object); Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object, FeatureService.Object);
} }
private AutoApproveRule Rule { get; set; } private AutoApproveRule Rule { get; set; }
private Mock<IPrincipal> PrincipalMock { get; set; } private Mock<ICurrentUser> PrincipalMock { get; set; }
private Mock<OmbiUserManager> UserManager { get; set; } private Mock<OmbiUserManager> UserManager { get; set; }
private Mock<IFeatureService> FeatureService { get; set; }
[Test] [Test]
public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie() public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie()
{ {
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie }; var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);
Assert.True(result.Success); Assert.True(result.Success);
@ -64,7 +69,7 @@ namespace Ombi.Core.Tests.Rule.Request
public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie() public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
{ {
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie }; var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);
Assert.True(result.Success); Assert.True(result.Success);
@ -96,7 +101,8 @@ namespace Ombi.Core.Tests.Rule.Request
[Test] [Test]
public async Task Should_ReturnSuccess_WhenSystemUserAndRequestTV() public async Task Should_ReturnSuccess_WhenSystemUserAndRequestTV()
{ {
PrincipalMock.Setup(x => x.Identity.Name).Returns("sys"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "sys", NormalizedUserName = "SYS", Id = "a" });
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(false); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(false);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow }; var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);
@ -137,5 +143,17 @@ namespace Ombi.Core.Tests.Rule.Request
Assert.True(result.Success); Assert.True(result.Success);
Assert.False(request.Approved); Assert.False(request.Approved);
} }
[Test]
public async Task Should_ReturnFail_When4kRequestAndFeatureNotEnabled()
{
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).ReturnsAsync(false);
var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie, Is4kRequest = true };
var result = await Rule.Execute(request);
Assert.True(result.Success);
Assert.False(request.Approved);
Assert.False(request.Approved4K);
}
} }
} }

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Rule.Rules; using Ombi.Core.Rule.Rules;
using Ombi.Core.Rule.Rules.Request; using Ombi.Core.Rule.Rules.Request;
using Ombi.Helpers; using Ombi.Helpers;
@ -26,8 +27,9 @@ namespace Ombi.Core.Tests.Rule.Request
public void Setup() public void Setup()
{ {
PrincipalMock = new Mock<IPrincipal>(); PrincipalMock = new Mock<ICurrentUser>();
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "a" });
UserManager = MockHelper.MockUserManager(_users); UserManager = MockHelper.MockUserManager(_users);
Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object); Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object);
@ -35,14 +37,49 @@ namespace Ombi.Core.Tests.Rule.Request
private CanRequestRule Rule { get; set; } private CanRequestRule Rule { get; set; }
private Mock<IPrincipal> PrincipalMock { get; set; } private Mock<ICurrentUser> PrincipalMock { get; set; }
private Mock<OmbiUserManager> UserManager { get; set; } private Mock<OmbiUserManager> UserManager { get; set; }
[Test] [Test]
public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole() public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
{ {
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie }; var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request);
Assert.True(result.Success);
}
[Test]
public async Task Should_ReturnSuccess_WhenRequestingMovie4KWithMovieRole()
{
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true);
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Request4KMovie)).ReturnsAsync(true);
var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie, Has4KRequest = true };
var result = await Rule.Execute(request);
Assert.True(result.Success);
}
[Test]
public async Task Should_ReturnFailure_WhenRequestingMovie4KWithMovieRole()
{
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true);
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Request4KMovie)).ReturnsAsync(false);
var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie, Is4kRequest = true };
var result = await Rule.Execute(request);
Assert.False(result.Success);
Assert.False(string.IsNullOrEmpty(result.Message));
}
[Test]
public async Task Should_ReturnSuccess_WhenRequestingMovie4KWithAutoApprove()
{
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true);
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true);
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Request4KMovie)).ReturnsAsync(false);
var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie, Has4KRequest = true };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);
Assert.True(result.Success); Assert.True(result.Success);
@ -52,7 +89,7 @@ namespace Ombi.Core.Tests.Rule.Request
public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole() public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
{ {
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(false); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(false);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie }; var request = new MovieRequests() { RequestType = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);
Assert.False(result.Success); Assert.False(result.Success);
@ -72,7 +109,8 @@ namespace Ombi.Core.Tests.Rule.Request
[Test] [Test]
public async Task Should_ReturnSuccess_WhenRequestingMovieWithSystemRole() public async Task Should_ReturnSuccess_WhenRequestingMovieWithSystemRole()
{ {
PrincipalMock.Setup(x => x.Identity.Name).Returns("sys"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "sys", NormalizedUserName = "SYS", Id = "a" });
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(false); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(false);
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie }; var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); var result = await Rule.Execute(request);

View file

@ -9,7 +9,9 @@ using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Rule.Rules; using Ombi.Core.Rule.Rules;
using Ombi.Core.Rule.Rules.Request; using Ombi.Core.Rule.Rules.Request;
using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
@ -24,12 +26,14 @@ namespace Ombi.Core.Tests.Rule.Request
public void Setup() public void Setup()
{ {
ContextMock = new Mock<IMovieRequestRepository>(); ContextMock = new Mock<IMovieRequestRepository>();
Rule = new ExistingMovieRequestRule(ContextMock.Object); FeatureService = new Mock<IFeatureService>();
Rule = new ExistingMovieRequestRule(ContextMock.Object, FeatureService.Object);
} }
private ExistingMovieRequestRule Rule { get; set; } private ExistingMovieRequestRule Rule { get; set; }
private Mock<IMovieRequestRepository> ContextMock { get; set; } private Mock<IMovieRequestRepository> ContextMock { get; set; }
private Mock<IFeatureService> FeatureService { get; set; }
[Test] [Test]
public async Task ExistingRequestRule_Movie_Has_Been_Requested_With_TheMovieDBId() public async Task ExistingRequestRule_Movie_Has_Been_Requested_With_TheMovieDBId()
@ -96,5 +100,82 @@ namespace Ombi.Core.Tests.Rule.Request
Assert.That(result.Success, Is.True); Assert.That(result.Success, Is.True);
Assert.That(result.Message, Is.Null.Or.Empty); Assert.That(result.Message, Is.Null.Or.Empty);
} }
[Test]
public async Task ExistingRequestRule_Movie_HasAlready4K_Request()
{
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
{
new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "2",
RequestType = RequestType.Movie,
Is4kRequest = true
}
}.AsQueryable().BuildMock().Object);
var o = new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "1",
Has4KRequest = true
};
var result = await Rule.Execute(o);
Assert.That(result.Success, Is.False);
Assert.That(result.Message, Is.Not.Empty);
}
[Test]
public async Task ExistingRequestRule_Movie_4K_Request()
{
FeatureService.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(true);
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
{
new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "2",
RequestType = RequestType.Movie,
Is4kRequest = false
}
}.AsQueryable().BuildMock().Object);
var o = new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "1",
Is4kRequest = true
};
var result = await Rule.Execute(o);
Assert.That(result.Success, Is.True);
Assert.That(result.Message, Is.Null.Or.Empty);
}
[Test]
public async Task ExistingRequestRule_Movie_4K_Request_FeatureNotEnabled()
{
FeatureService.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(false);
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
{
new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "2",
RequestType = RequestType.Movie,
Is4kRequest = false
}
}.AsQueryable().BuildMock().Object);
var o = new MovieRequests
{
TheMovieDbId = 2,
ImdbId = "1",
Is4kRequest = true
};
var result = await Rule.Execute(o);
Assert.That(result.Success, Is.False);
Assert.That(result.Message, Is.Not.Null);
}
} }
} }

View file

@ -1,6 +1,7 @@
using MockQueryable.Moq; using MockQueryable.Moq;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Engine;
using Ombi.Core.Rule.Rules.Request; using Ombi.Core.Rule.Rules.Request;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
@ -176,17 +177,58 @@ namespace Ombi.Core.Tests.Rule.Request
Assert.That(result.Success, Is.True); Assert.That(result.Success, Is.True);
} }
[Test]
public async Task RequestMovie_IsSuccessful()
{
SetupMockData();
var req = new MovieRequests
{
RequestType = RequestType.Movie,
TheMovieDbId = 123,
Id = 1,
};
var result = await Rule.Execute(req);
Assert.That(result.Success, Is.True);
}
[Test]
public async Task RequestMovie_IsAlreadyAvailable()
{
var content = new List<PlexServerContent> {
new PlexServerContent
{
TheMovieDbId = 123.ToString(),
}
};
PlexContentRepo.Setup(x => x.GetAll()).Returns(content.AsQueryable().BuildMock().Object);
var req = new MovieRequests
{
RequestType = RequestType.Movie,
TheMovieDbId = 123,
Id = 1,
};
var result = await Rule.Execute(req);
Assert.That(result.Success, Is.False);
Assert.That(result.ErrorCode, Is.EqualTo(ErrorCode.AlreadyRequested));
}
private void SetupMockData() private void SetupMockData()
{ {
var childRequests = new List<PlexServerContent> var childRequests = new List<PlexServerContent>
{ {
new PlexServerContent new PlexServerContent
{ {
Type = PlexMediaTypeEntity.Show, Type = MediaType.Series,
TheMovieDbId = "1", TheMovieDbId = "1",
Title = "Test", Title = "Test",
ReleaseYear = "2001", ReleaseYear = "2001",
Episodes = new List<PlexEpisode> Episodes = new List<IMediaServerEpisode>
{ {
new PlexEpisode new PlexEpisode
{ {

View file

@ -1,11 +1,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Rules.Search; using Ombi.Core.Rule.Rules.Search;
using Ombi.Core.Services;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
@ -18,21 +21,23 @@ namespace Ombi.Core.Tests.Rule.Search
public void Setup() public void Setup()
{ {
ContextMock = new Mock<IEmbyContentRepository>(); ContextMock = new Mock<IEmbyContentRepository>();
SettingsMock = new Mock<ISettingsService<EmbySettings>>(); LoggerMock = new Mock<ILogger<EmbyAvailabilityRule>>();
Rule = new EmbyAvailabilityRule(ContextMock.Object, SettingsMock.Object); FeatureMock = new Mock<IFeatureService>();
Rule = new EmbyAvailabilityRule(ContextMock.Object, LoggerMock.Object, FeatureMock.Object);
} }
private EmbyAvailabilityRule Rule { get; set; } private EmbyAvailabilityRule Rule { get; set; }
private Mock<IEmbyContentRepository> ContextMock { get; set; } private Mock<IEmbyContentRepository> ContextMock { get; set; }
private Mock<ISettingsService<EmbySettings>> SettingsMock { get; set; } private Mock<ILogger<EmbyAvailabilityRule>> LoggerMock { get; set; }
private Mock<IFeatureService> FeatureMock { get; set; }
[Test] [Test]
public async Task Movie_ShouldBe_Available_WhenFoundInEmby() public async Task Movie_ShouldBe_Available_WhenFoundInEmby()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings());
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
{ {
ProviderId = "123" TheMovieDbId = "123",
Quality = "1"
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()
{ {
@ -45,24 +50,13 @@ namespace Ombi.Core.Tests.Rule.Search
} }
[Test] [Test]
public async Task Movie_Has_Custom_Url_When_Specified_In_Settings() public async Task Movie_ShouldBe_Available_WhenFoundInEmby_4K()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings FeatureMock.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(true);
{
Enable = true,
Servers = new List<EmbyServers>
{
new EmbyServers
{
ServerHostname = "http://test.com/",
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
{ {
ProviderId = "123", TheMovieDbId = "123",
EmbyId = 1.ToString(), Has4K = true
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()
{ {
@ -71,28 +65,19 @@ namespace Ombi.Core.Tests.Rule.Search
var result = await Rule.Execute(search); var result = await Rule.Execute(search);
Assert.True(result.Success); Assert.True(result.Success);
Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/web/index.html#!/item?id=1&serverId=8")); Assert.True(search.Available4K);
Assert.False(search.Available);
} }
[Test] [Test]
public async Task Movie_Uses_Default_Url_When() public async Task Movie_ShouldBe_Available_WhenFoundInEmby_Both()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings FeatureMock.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(true);
{
Enable = true,
Servers = new List<EmbyServers>
{
new EmbyServers
{
ServerHostname = string.Empty,
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
{ {
ProviderId = "123", TheMovieDbId = "123",
EmbyId = 1.ToString() Has4K = true,
Quality = "1"
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()
{ {
@ -101,7 +86,8 @@ namespace Ombi.Core.Tests.Rule.Search
var result = await Rule.Execute(search); var result = await Rule.Execute(search);
Assert.True(result.Success); Assert.True(result.Success);
Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/web/index.html#!/item?id=1&serverId=8")); Assert.True(search.Available4K);
Assert.True(search.Available);
} }
[Test] [Test]

View file

@ -30,13 +30,14 @@ namespace Ombi.Core.Tests.Rule.Search
[Test] [Test]
public async Task ShouldBe_Requested_WhenExisitngMovie() public async Task ShouldBe_Requested_WhenExistingMovie()
{ {
var list = new MovieRequests var list = new MovieRequests
{ {
TheMovieDbId = 123, TheMovieDbId = 123,
Approved = true, Approved = true,
RequestType = RequestType.Movie RequestType = RequestType.Movie,
RequestedDate = System.DateTime.Now,
}; };
MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list); MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list);

View file

@ -1,11 +1,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Rules.Search; using Ombi.Core.Rule.Rules.Search;
using Ombi.Core.Services;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
@ -18,21 +21,23 @@ namespace Ombi.Core.Tests.Rule.Search
public void Setup() public void Setup()
{ {
ContextMock = new Mock<IJellyfinContentRepository>(); ContextMock = new Mock<IJellyfinContentRepository>();
SettingsMock = new Mock<ISettingsService<JellyfinSettings>>(); LoggerMock = new Mock<ILogger<JellyfinAvailabilityRule>>();
Rule = new JellyfinAvailabilityRule(ContextMock.Object, SettingsMock.Object); FeatureMock = new Mock<IFeatureService>();
Rule = new JellyfinAvailabilityRule(ContextMock.Object, LoggerMock.Object, FeatureMock.Object);
} }
private JellyfinAvailabilityRule Rule { get; set; } private JellyfinAvailabilityRule Rule { get; set; }
private Mock<IJellyfinContentRepository> ContextMock { get; set; } private Mock<IJellyfinContentRepository> ContextMock { get; set; }
private Mock<ISettingsService<JellyfinSettings>> SettingsMock { get; set; } private Mock<ILogger<JellyfinAvailabilityRule>> LoggerMock { get; set; }
private Mock<IFeatureService> FeatureMock { get; set; }
[Test] [Test]
public async Task Movie_ShouldBe_Available_WhenFoundInJellyfin() public async Task Movie_ShouldBe_Available_WhenFoundInJellyfin()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings());
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{ {
ProviderId = "123" TheMovieDbId = "123",
Quality = "1080"
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()
{ {
@ -45,24 +50,13 @@ namespace Ombi.Core.Tests.Rule.Search
} }
[Test] [Test]
public async Task Movie_Has_Custom_Url_When_Specified_In_Settings() public async Task Movie_ShouldBe_Available_WhenFoundInJellyfin_4K()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings FeatureMock.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(true);
{
Enable = true,
Servers = new List<JellyfinServers>
{
new JellyfinServers
{
ServerHostname = "http://test.com/",
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{ {
ProviderId = "123", TheMovieDbId = "123",
JellyfinId = 1.ToString(), Has4K = true
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()
{ {
@ -71,29 +65,37 @@ namespace Ombi.Core.Tests.Rule.Search
var result = await Rule.Execute(search); var result = await Rule.Execute(search);
Assert.True(result.Success); Assert.True(result.Success);
Assert.That(search.JellyfinUrl, Is.EqualTo("http://test.com/web/index.html#!/details?id=1&serverId=8")); Assert.False(search.Available);
Assert.True(search.Available4K);
}
[Test]
public async Task Movie_ShouldBe_Available_WhenFoundInJellyfin_Both()
{
FeatureMock.Setup(x => x.FeatureEnabled(FeatureNames.Movie4KRequests)).ReturnsAsync(true);
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{
TheMovieDbId = "123",
Has4K = true,
Quality = "1"
});
var search = new SearchMovieViewModel()
{
TheMovieDbId = "123",
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.True(search.Available);
Assert.True(search.Available4K);
} }
[Test] [Test]
public async Task Movie_Uses_Default_Url_When() public async Task Movie_Uses_Default_Url_When()
{ {
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings
{
Enable = true,
Servers = new List<JellyfinServers>
{
new JellyfinServers
{
Ip = "8080",
Port = 9090,
ServerHostname = string.Empty,
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{ {
ProviderId = "123", TheMovieDbId = "123",
JellyfinId = 1.ToString() JellyfinId = 1.ToString()
}); });
var search = new SearchMovieViewModel() var search = new SearchMovieViewModel()

View file

@ -28,25 +28,67 @@ namespace Ombi.Core.Tests.Rule.Search
{ {
var list = new List<RadarrCache>(){new RadarrCache var list = new List<RadarrCache>(){new RadarrCache
{ {
TheMovieDbId = 123 TheMovieDbId = 123,
HasRegular = true
}}.AsQueryable(); }}.AsQueryable();
ContextMock.Setup(x => x.GetAll()).Returns(list); ContextMock.Setup(x => x.GetAll()).Returns(list);
var request = new SearchMovieViewModel { Id = 123 }; var request = new SearchMovieViewModel { Id = 123 };
var result =await Rule.Execute(request); var result = await Rule.Execute(request);
Assert.True(result.Success); Assert.True(result.Success);
Assert.True(request.Approved); Assert.True(request.Approved);
} }
[Test]
public async Task Should_ReturnAvailabl_WhenMovieIsInRadarr_4K()
{
var list = new List<RadarrCache>(){new RadarrCache
{
TheMovieDbId = 123,
Has4K = true,
HasFile = true
}}.AsQueryable();
ContextMock.Setup(x => x.GetAll()).Returns(list);
var request = new SearchMovieViewModel { Id = 123 };
var result = await Rule.Execute(request);
Assert.True(result.Success);
Assert.False(request.Available);
Assert.True(request.Available4K);
}
[Test]
public async Task Should_ReturnAvailable_WhenMovieIsInRadarr_Both()
{
var list = new List<RadarrCache>(){new RadarrCache
{
TheMovieDbId = 123,
Has4K = true,
HasRegular = true,
HasFile = true
}}.AsQueryable();
ContextMock.Setup(x => x.GetAll()).Returns(list);
var request = new SearchMovieViewModel { Id = 123 };
var result = await Rule.Execute(request);
Assert.True(result.Success);
Assert.True(request.Available);
Assert.True(request.Available4K);
}
[Test] [Test]
public async Task Should_ReturnNotApproved_WhenMovieIsNotInRadarr() public async Task Should_ReturnNotApproved_WhenMovieIsNotInRadarr()
{ {
var list = DbHelper.GetQueryableMockDbSet(new RadarrCache var list = DbHelper.GetQueryableMockDbSet(new RadarrCache
{ {
TheMovieDbId = 000012 TheMovieDbId = 000012,
}); });
ContextMock.Setup(x => x.GetAll()).Returns(list); ContextMock.Setup(x => x.GetAll()).Returns(list);

View file

@ -116,16 +116,25 @@ namespace Ombi.Core.Authentication
public async Task<OmbiUser> GetOmbiUserFromPlexToken(string plexToken) public async Task<OmbiUser> GetOmbiUserFromPlexToken(string plexToken)
{ {
var plexAccount = await _plexApi.GetAccount(plexToken); var plexAccount = await _plexApi.GetAccount(plexToken);
// Check for a ombi user // Check for a ombi user
if (plexAccount?.user != null) if (plexAccount?.user == null)
{ {
var potentialOmbiUser = await Users.FirstOrDefaultAsync(x => return null;
x.ProviderUserId == plexAccount.user.id);
return potentialOmbiUser;
} }
return null; var potentialOmbiUser = await Users.FirstOrDefaultAsync(x =>
x.ProviderUserId == plexAccount.user.id);
// Update ombi user with the token
if (potentialOmbiUser != null)
{
potentialOmbiUser.MediaServerToken = plexAccount.user.authentication_token;
await UpdateAsync(potentialOmbiUser);
}
return potentialOmbiUser;
} }
@ -142,6 +151,10 @@ namespace Ombi.Core.Authentication
var result = await _plexApi.SignIn(new UserRequest { password = password, login = login }); var result = await _plexApi.SignIn(new UserRequest { password = password, login = login });
if (result.user?.authentication_token != null) if (result.user?.authentication_token != null)
{ {
// Update ombi user with the token
user.MediaServerToken = result.user?.authentication_token;
await UpdateAsync(user);
return true; return true;
} }
return false; return false;

View file

@ -26,7 +26,7 @@ namespace Ombi.Core.Engine
private Dictionary<int, MovieRequests> _dbMovies; private Dictionary<int, MovieRequests> _dbMovies;
private Dictionary<int, TvRequests> _dbTv; private Dictionary<int, TvRequests> _dbTv;
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService, protected BaseMediaEngine(ICurrentUser identity, IRequestServiceMain requestService,
IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub) : base(identity, um, rules) IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub) : base(identity, um, rules)
{ {
RequestService = requestService; RequestService = requestService;

View file

@ -11,6 +11,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Config; using Ombi.Config;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine.Demo
{ {
public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine
{ {
public DemoMovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public DemoMovieSearchEngine(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s,
IRepository<RequestSubscription> sub, IOptions<DemoLists> lists) IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
: base(identity, service, movApi, mapper, logger, r, um, mem, s, sub) : base(identity, service, movApi, mapper, logger, r, um, mem, s, sub)

View file

@ -4,6 +4,7 @@ using Ombi.Api.Trakt;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Config; using Ombi.Config;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine.Demo
public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine
{ {
public DemoTvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public DemoTvSearchEngine(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache,
ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists, IImageService imageService, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists, IImageService imageService,
ISettingsService<CustomizationSettings> custom) ISettingsService<CustomizationSettings> custom)

View file

@ -1,42 +1,35 @@
using System; using System;
using Ombi.Core.Rule; using Ombi.Core.Rule;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Helpers; using Ombi.Core.Helpers;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
public abstract class BaseEngine public abstract class BaseEngine
{ {
protected BaseEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules) protected BaseEngine(ICurrentUser user, OmbiUserManager um, IRuleEvaluator rules)
{ {
UserPrinciple = user; CurrentUser = user;
Rules = rules; Rules = rules;
UserManager = um; UserManager = um;
} }
protected IPrincipal UserPrinciple { get; } protected ICurrentUser CurrentUser { get; }
protected IRuleEvaluator Rules { get; } protected IRuleEvaluator Rules { get; }
protected OmbiUserManager UserManager { get; } protected OmbiUserManager UserManager { get; }
protected string Username => UserPrinciple.Identity.Name; protected string Username => CurrentUser.Username;
protected Task<OmbiUser> GetUser() => CurrentUser.GetUser();
private OmbiUser _user; /// <summary>
protected async Task<OmbiUser> GetUser() /// Only used for background tasks
{ /// </summary>
if(!Username.HasValue()) public void SetUser(OmbiUser user) => CurrentUser.SetUser(user);
{
return null;
}
var username = Username.ToUpper();
return _user ??= await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
}
protected async Task<string> UserAlias() protected async Task<string> UserAlias()
{ {
@ -45,9 +38,14 @@ namespace Ombi.Core.Engine.Interfaces
protected async Task<bool> IsInRole(string roleName) protected async Task<bool> IsInRole(string roleName)
{ {
return await UserManager.IsInRoleAsync(await GetUser(), roleName); if (Username.Equals("API", StringComparison.CurrentCultureIgnoreCase))
{
return true;
}
var user = await GetUser();
return await UserManager.IsInRoleAsync(user, roleName);
} }
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model) public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
{ {
var ruleResults = await Rules.StartRequestRules(model); var ruleResults = await Rules.StartRequestRules(model);

View file

@ -18,9 +18,9 @@ namespace Ombi.Core.Engine.Interfaces
Task RemoveAllMovieRequests(); Task RemoveAllMovieRequests();
Task<MovieRequests> GetRequest(int requestId); Task<MovieRequests> GetRequest(int requestId);
Task<MovieRequests> UpdateMovieRequest(MovieRequests request); Task<MovieRequests> UpdateMovieRequest(MovieRequests request);
Task<RequestEngineResult> ApproveMovie(MovieRequests request); Task<RequestEngineResult> ApproveMovie(MovieRequests request, bool is4K);
Task<RequestEngineResult> ApproveMovieById(int requestId); Task<RequestEngineResult> ApproveMovieById(int requestId, bool is4K);
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason); Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason, bool is4K);
Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder); Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
Task<RequestsViewModel<MovieRequests>> GetUnavailableRequests(int count, int position, string sortProperty, Task<RequestsViewModel<MovieRequests>> GetUnavailableRequests(int count, int position, string sortProperty,

View file

@ -19,11 +19,12 @@ namespace Ombi.Core.Engine.Interfaces
Task<IEnumerable<T>> GetRequests(); Task<IEnumerable<T>> GetRequests();
Task<bool> UserHasRequest(string userId); Task<bool> UserHasRequest(string userId);
Task<RequestEngineResult> MarkUnavailable(int modelId); Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K);
Task<RequestEngineResult> MarkAvailable(int modelId); Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K);
Task<int> GetTotal(); Task<int> GetTotal();
Task UnSubscribeRequest(int requestId, RequestType type); Task UnSubscribeRequest(int requestId, RequestType type);
Task SubscribeToRequest(int requestId, RequestType type); Task SubscribeToRequest(int requestId, RequestType type);
Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken); Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken);
void SetUser(OmbiUser user);
} }
} }

View file

@ -22,15 +22,18 @@ using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.Core.Models; using Ombi.Core.Models;
using System.Threading; using System.Threading;
using Ombi.Core.Services;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MovieRequestEngine : BaseMediaEngine, IMovieRequestEngine public class MovieRequestEngine : BaseMediaEngine, IMovieRequestEngine
{ {
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log, INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService,
IFeatureService featureService)
: base(user, requestService, r, manager, cache, ombiSettings, sub) : base(user, requestService, r, manager, cache, ombiSettings, sub)
{ {
MovieApi = movieApi; MovieApi = movieApi;
@ -39,6 +42,7 @@ namespace Ombi.Core.Engine
Logger = log; Logger = log;
_requestLog = rl; _requestLog = rl;
_mediaCacheService = mediaCacheService; _mediaCacheService = mediaCacheService;
_featureService = featureService;
} }
private IMovieDbApi MovieApi { get; } private IMovieDbApi MovieApi { get; }
@ -47,6 +51,7 @@ namespace Ombi.Core.Engine
private ILogger<MovieRequestEngine> Logger { get; } private ILogger<MovieRequestEngine> Logger { get; }
private readonly IRepository<RequestLog> _requestLog; private readonly IRepository<RequestLog> _requestLog;
private readonly IMediaCacheService _mediaCacheService; private readonly IMediaCacheService _mediaCacheService;
private readonly IFeatureService _featureService;
/// <summary> /// <summary>
/// Requests the movie. /// Requests the movie.
@ -72,7 +77,8 @@ namespace Ombi.Core.Engine
var userDetails = await GetUser(); var userDetails = await GetUser();
var canRequestOnBehalf = model.RequestOnBehalf.HasValue(); var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin); var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser)
|| await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
if (canRequestOnBehalf && !isAdmin) if (canRequestOnBehalf && !isAdmin)
{ {
return new RequestEngineResult return new RequestEngineResult
@ -93,27 +99,54 @@ namespace Ombi.Core.Engine
}; };
} }
var requestModel = new MovieRequests var is4kFeatureEnabled = await _featureService.FeatureEnabled(FeatureNames.Movie4KRequests);
var is4kRequest = is4kFeatureEnabled && model.Is4kRequest;
MovieRequests requestModel;
bool isExisting = false;
// Do we already have a request? 4k or non 4k
var existingRequest = await MovieRepository.GetRequestAsync(movieInfo.Id);
if (existingRequest != null && is4kFeatureEnabled)
{ {
TheMovieDbId = movieInfo.Id, if (model.Is4kRequest)
RequestType = RequestType.Movie, {
Overview = movieInfo.Overview, existingRequest.Is4kRequest = true;
ImdbId = movieInfo.ImdbId, existingRequest.RequestedDate4k = DateTime.Now;
PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath), }
Title = movieInfo.Title, else
ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate) {
? DateTime.Parse(movieInfo.ReleaseDate) existingRequest.RequestedDate = DateTime.Now;
: DateTime.MinValue, }
Status = movieInfo.Status, isExisting = true;
RequestedDate = DateTime.UtcNow, requestModel = existingRequest;
Approved = false, }
RequestedUserId = canRequestOnBehalf ? model.RequestOnBehalf : userDetails.Id, else
Background = movieInfo.BackdropPath, {
LangCode = model.LanguageCode, requestModel = new MovieRequests
RequestedByAlias = model.RequestedByAlias, {
RootPathOverride = model.RootFolderOverride.GetValueOrDefault(), TheMovieDbId = movieInfo.Id,
QualityOverride = model.QualityPathOverride.GetValueOrDefault() RequestType = RequestType.Movie,
}; Overview = movieInfo.Overview,
ImdbId = movieInfo.ImdbId,
PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath),
Title = movieInfo.Title,
ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate)
? DateTime.Parse(movieInfo.ReleaseDate)
: DateTime.MinValue,
Status = movieInfo.Status,
RequestedDate = model.Is4kRequest ? DateTime.MinValue : DateTime.Now,
Approved = false,
RequestedUserId = canRequestOnBehalf ? model.RequestOnBehalf : userDetails.Id,
Background = movieInfo.BackdropPath,
LangCode = model.LanguageCode,
RequestedByAlias = model.RequestedByAlias,
RootPathOverride = model.RootFolderOverride.GetValueOrDefault(),
QualityOverride = model.QualityPathOverride.GetValueOrDefault(),
RequestedDate4k = model.Is4kRequest ? DateTime.Now : DateTime.MinValue,
Is4kRequest = model.Is4kRequest,
Source = model.Source
};
}
var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
requestModel.DigitalReleaseDate = usDates?.ReleaseDate requestModel.DigitalReleaseDate = usDates?.ReleaseDate
@ -132,10 +165,10 @@ namespace Ombi.Core.Engine
if (requestModel.Approved) // The rules have auto approved this if (requestModel.Approved) // The rules have auto approved this
{ {
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf); var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf, isExisting, is4kRequest);
if (requestEngineResult.Result) if (requestEngineResult.Result)
{ {
var result = await ApproveMovie(requestModel); var result = await ApproveMovie(requestModel, model.Is4kRequest);
if (result.IsError) if (result.IsError)
{ {
Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message);
@ -153,7 +186,7 @@ namespace Ombi.Core.Engine
// If there are no providers then it's successful but movie has not been sent // If there are no providers then it's successful but movie has not been sent
} }
return await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf); return await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf, isExisting, is4kRequest);
} }
@ -218,7 +251,7 @@ namespace Ombi.Core.Engine
var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count)
.ToListAsync(); .ToListAsync();
await CheckForSubscription(shouldHide, requests); await CheckForSubscription(shouldHide.UserId, requests);
return new RequestsViewModel<MovieRequests> return new RequestsViewModel<MovieRequests>
{ {
Collection = requests, Collection = requests,
@ -262,7 +295,7 @@ namespace Ombi.Core.Engine
var total = requests.Count(); var total = requests.Count();
requests = requests.Skip(position).Take(count).ToList(); requests = requests.Skip(position).Take(count).ToList();
await CheckForSubscription(shouldHide, requests); await CheckForSubscription(shouldHide.UserId, requests);
return new RequestsViewModel<MovieRequests> return new RequestsViewModel<MovieRequests>
{ {
Collection = requests, Collection = requests,
@ -290,21 +323,44 @@ namespace Ombi.Core.Engine
switch (status) switch (status)
{ {
case RequestStatus.PendingApproval: case RequestStatus.PendingApproval:
allRequests = allRequests.Where(x => !x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value)); allRequests = allRequests.Where(x =>
(x.RequestedDate != DateTime.MinValue && !x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value))
||
(x.Has4KRequest && !x.Approved4K && !x.Available4K && (!x.Denied4K.HasValue || !x.Denied4K.Value))
);
break; break;
case RequestStatus.ProcessingRequest: case RequestStatus.ProcessingRequest:
allRequests = allRequests.Where(x => x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value)); allRequests = allRequests.Where(x =>
(x.RequestedDate != DateTime.MinValue && x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value))
||
(x.Has4KRequest && x.Approved4K && !x.Available && (!x.Denied.HasValue || !x.Denied.Value))
);
break; break;
case RequestStatus.Available: case RequestStatus.Available:
allRequests = allRequests.Where(x => x.Available); allRequests = allRequests.Where(x => x.Available || x.Available4K);
break; break;
case RequestStatus.Denied: case RequestStatus.Denied:
allRequests = allRequests.Where(x => x.Denied.HasValue && x.Denied.Value && !x.Available); allRequests = allRequests.Where(x =>
(x.Denied.HasValue && x.Denied.Value && !x.Available)
||
(x.Has4KRequest && x.Denied4K.HasValue && x.Denied4K.Value && !x.Available4K)
);
break; break;
default: default:
break; break;
} }
var requests = allRequests.ToList();
var total = requests.Count;
if (total == 0)
{
return new RequestsViewModel<MovieRequests>
{
Collection = Enumerable.Empty<MovieRequests>(),
Total = total
};
}
var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true); var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true);
if (sortProperty.Contains('.')) if (sortProperty.Contains('.'))
@ -317,14 +373,14 @@ namespace Ombi.Core.Engine
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true); //var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
} }
// TODO fix this so we execute this on the server requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
? allRequests.ToList().OrderBy(x => prop.GetValue(x)).ToList() ? allRequests.ToList().OrderBy(x => prop.GetValue(x)).ToList()
: allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList(); : allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList();
var total = requests.Count();
// TODO fix this so we execute this on the server
requests = requests.Skip(position).Take(count).ToList(); requests = requests.Skip(position).Take(count).ToList();
await CheckForSubscription(shouldHide, requests); await CheckForSubscription(shouldHide.UserId, requests);
return new RequestsViewModel<MovieRequests> return new RequestsViewModel<MovieRequests>
{ {
Collection = requests, Collection = requests,
@ -367,7 +423,7 @@ namespace Ombi.Core.Engine
var total = requests.Count(); var total = requests.Count();
requests = requests.Skip(position).Take(count).ToList(); requests = requests.Skip(position).Take(count).ToList();
await CheckForSubscription(shouldHide, requests); await CheckForSubscription(shouldHide.UserId, requests);
return new RequestsViewModel<MovieRequests> return new RequestsViewModel<MovieRequests>
{ {
Collection = requests, Collection = requests,
@ -449,7 +505,7 @@ namespace Ombi.Core.Engine
allRequests = await MovieRepository.GetWithUser().ToListAsync(); allRequests = await MovieRepository.GetWithUser().ToListAsync();
} }
await CheckForSubscription(shouldHide, allRequests); await CheckForSubscription(shouldHide.UserId, allRequests);
return allRequests; return allRequests;
} }
@ -457,21 +513,21 @@ namespace Ombi.Core.Engine
public async Task<MovieRequests> GetRequest(int requestId) public async Task<MovieRequests> GetRequest(int requestId)
{ {
var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync(); var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync();
await CheckForSubscription(new HideResult(), new List<MovieRequests> { request }); await CheckForSubscription((await GetUser()).Id, new List<MovieRequests> { request });
return request; return request;
} }
private async Task CheckForSubscription(HideResult shouldHide, List<MovieRequests> movieRequests) private async Task CheckForSubscription(string UserId, List<MovieRequests> movieRequests)
{ {
var requestIds = movieRequests.Select(x => x.Id); var requestIds = movieRequests.Select(x => x.Id);
var sub = await _subscriptionRepository.GetAll().Where(s => var sub = await _subscriptionRepository.GetAll().Where(s =>
s.UserId == shouldHide.UserId && requestIds.Contains(s.RequestId) && s.RequestType == RequestType.Movie) s.UserId == UserId && requestIds.Contains(s.RequestId) && s.RequestType == RequestType.Movie)
.ToListAsync(); .ToListAsync();
foreach (var x in movieRequests) foreach (var x in movieRequests)
{ {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
if (shouldHide.UserId == x.RequestedUserId) if (UserId == x.RequestedUserId)
{ {
x.ShowSubscribe = false; x.ShowSubscribe = false;
} }
@ -503,18 +559,18 @@ namespace Ombi.Core.Engine
} }
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
await CheckForSubscription(shouldHide, results); await CheckForSubscription(shouldHide.UserId, results);
return results; return results;
} }
public async Task<RequestEngineResult> ApproveMovieById(int requestId) public async Task<RequestEngineResult> ApproveMovieById(int requestId, bool is4K)
{ {
var request = await MovieRepository.Find(requestId); var request = await MovieRepository.Find(requestId);
return await ApproveMovie(request); return await ApproveMovie(request, is4K);
} }
public async Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason) public async Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason, bool is4K)
{ {
var request = await MovieRepository.Find(modelId); var request = await MovieRepository.Find(modelId);
if (request == null) if (request == null)
@ -525,8 +581,16 @@ namespace Ombi.Core.Engine
}; };
} }
request.Denied = true; if (is4K)
request.DeniedReason = denyReason; {
request.Denied4K = true;
request.DeniedReason4K = denyReason;
}
else
{
request.Denied = true;
request.DeniedReason = denyReason;
}
await MovieRepository.Update(request); await MovieRepository.Update(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
@ -540,7 +604,7 @@ namespace Ombi.Core.Engine
}; };
} }
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request) public async Task<RequestEngineResult> ApproveMovie(MovieRequests request, bool is4K)
{ {
if (request == null) if (request == null)
{ {
@ -550,9 +614,18 @@ namespace Ombi.Core.Engine
}; };
} }
request.MarkedAsApproved = DateTime.Now; if (is4K)
request.Approved = true; {
request.Denied = false; request.MarkedAsApproved4K = DateTime.Now;
request.Approved4K = true;
request.Denied4K = false;
}
else
{
request.MarkedAsApproved = DateTime.Now;
request.Approved = true;
request.Denied = false;
}
await MovieRepository.Update(request); await MovieRepository.Update(request);
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty); var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
@ -562,7 +635,7 @@ namespace Ombi.Core.Engine
} }
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
return await ProcessSendingMovie(request); return await ProcessSendingMovie(request, is4K);
} }
public async Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken) public async Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken)
@ -590,11 +663,11 @@ namespace Ombi.Core.Engine
return new RequestEngineResult { Result = true, Message = $"The collection {collections.name} has been successfully added!", RequestId = results.FirstOrDefault().RequestId }; return new RequestEngineResult { Result = true, Message = $"The collection {collections.name} has been successfully added!", RequestId = results.FirstOrDefault().RequestId };
} }
private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request) private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request, bool is4K)
{ {
if (request.Approved) if (is4K ? request.Approved4K : request.Approved)
{ {
var result = await Sender.Send(request); var result = await Sender.Send(request, is4K);
if (result.Success && result.Sent) if (result.Success && result.Sent)
{ {
return new RequestEngineResult return new RequestEngineResult
@ -662,7 +735,7 @@ namespace Ombi.Core.Engine
var result = await CheckCanManageRequest(request); var result = await CheckCanManageRequest(request);
if (result.IsError) if (result.IsError)
return result; return result;
await MovieRepository.Delete(request); await MovieRepository.Delete(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
return new RequestEngineResult return new RequestEngineResult
@ -683,7 +756,7 @@ namespace Ombi.Core.Engine
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId); return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
} }
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken) public async Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken)
{ {
var request = await MovieRepository.Find(requestId); var request = await MovieRepository.Find(requestId);
if (request == null) if (request == null)
@ -695,10 +768,10 @@ namespace Ombi.Core.Engine
}; };
} }
return await ProcessSendingMovie(request); return await ProcessSendingMovie(request, is4K);
} }
public async Task<RequestEngineResult> MarkUnavailable(int modelId) public async Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K)
{ {
var request = await MovieRepository.Find(modelId); var request = await MovieRepository.Find(modelId);
if (request == null) if (request == null)
@ -709,7 +782,14 @@ namespace Ombi.Core.Engine
}; };
} }
request.Available = false; if (is4K)
{
request.Available4K = false;
}
else
{
request.Available = false;
}
await MovieRepository.Update(request); await MovieRepository.Update(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
@ -720,7 +800,7 @@ namespace Ombi.Core.Engine
}; };
} }
public async Task<RequestEngineResult> MarkAvailable(int modelId) public async Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K)
{ {
var request = await MovieRepository.Find(modelId); var request = await MovieRepository.Find(modelId);
if (request == null) if (request == null)
@ -730,9 +810,16 @@ namespace Ombi.Core.Engine
ErrorMessage = "Request does not exist" ErrorMessage = "Request does not exist"
}; };
} }
if (!is4K)
request.Available = true; {
request.MarkedAsAvailable = DateTime.Now; request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
}
else
{
request.Available4K = true;
request.MarkedAsAvailable4K = DateTime.Now;
}
await NotificationHelper.Notify(request, NotificationType.RequestAvailable); await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MovieRepository.Update(request); await MovieRepository.Update(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
@ -744,9 +831,20 @@ namespace Ombi.Core.Engine
}; };
} }
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName, string requestOnBehalf) private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName, string requestOnBehalf, bool isExisting, bool is4k)
{ {
await MovieRepository.Add(model); if (is4k)
{
model.Has4KRequest = true;
}
if (!isExisting)
{
await MovieRepository.Add(model);
}
else
{
await MovieRepository.Update(model);
}
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf); var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
if (result.Success) if (result.Success)

View file

@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -22,7 +23,7 @@ namespace Ombi.Core.Engine
{ {
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
{ {
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public MovieSearchEngine(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub) ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)
{ {
@ -46,7 +47,7 @@ namespace Ombi.Core.Engine
{ {
langCode = await DefaultLanguageCode(langCode); langCode = await DefaultLanguageCode(langCode);
var movieInfo = await Cache.GetOrAddAsync(nameof(LookupImdbInformation) + langCode + theMovieDbId, var movieInfo = await Cache.GetOrAddAsync(nameof(LookupImdbInformation) + langCode + theMovieDbId,
() => MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId, langCode), () => MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId, langCode),
DateTimeOffset.Now.AddHours(12)); DateTimeOffset.Now.AddHours(12));
var viewMovie = Mapper.Map<SearchMovieViewModel>(movieInfo); var viewMovie = Mapper.Map<SearchMovieViewModel>(movieInfo);
@ -81,11 +82,11 @@ namespace Ombi.Core.Engine
{ {
return resultSet; return resultSet;
} }
// Get this person movie credits // Get this person movie credits
var credits = await MovieApi.GetActorMovieCredits(person.id, langaugeCode); var credits = await MovieApi.GetActorMovieCredits(person.id, langaugeCode);
// Grab results from both cast and crew, prefer items in cast. we can handle directors like this. // Grab results from both cast and crew, prefer items in cast. we can handle directors like this.
var movieResults = (from role in credits.cast select new { Id = role.id, Title = role.title, ReleaseDate = role.release_date }).ToList(); var movieResults = (from role in credits.cast select new { Id = role.id, Title = role.title, ReleaseDate = role.release_date }).ToList();
movieResults.AddRange((from job in credits.crew select new { Id = job.id, Title = job.title, ReleaseDate = job.release_date }).ToList()); movieResults.AddRange((from job in credits.crew select new { Id = job.id, Title = job.title, ReleaseDate = job.release_date }).ToList());
movieResults = movieResults.Take(10).ToList(); movieResults = movieResults.Take(10).ToList();
@ -120,7 +121,7 @@ namespace Ombi.Core.Engine
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies() public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
{ {
var result = await Cache.GetOrAddAsync(CacheKeys.PopularMovies, async () => var result = await Cache.GetOrAddAsync(CacheKeys.PopularMovies, async () =>
{ {
var langCode = await DefaultLanguageCode(null); var langCode = await DefaultLanguageCode(null);
@ -201,7 +202,7 @@ namespace Ombi.Core.Engine
protected async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, bool lookupExtraInfo = false) protected async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, bool lookupExtraInfo = false)
{ {
if (lookupExtraInfo && viewMovie.ImdbId.IsNullOrEmpty()) if (lookupExtraInfo && viewMovie.ImdbId.IsNullOrEmpty() && viewMovie.Id > 0)
{ {
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id); var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
viewMovie.Id = showInfo.Id; // TheMovieDbId viewMovie.Id = showInfo.Id; // TheMovieDbId
@ -217,7 +218,7 @@ namespace Ombi.Core.Engine
// This requires the rules to be run first to populate the RequestId property // This requires the rules to be run first to populate the RequestId property
await CheckForSubscription(viewMovie); await CheckForSubscription(viewMovie);
return viewMovie; return viewMovie;
} }

View file

@ -24,12 +24,13 @@ using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using System.ComponentModel; using System.ComponentModel;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine
{ {
public MusicRequestEngine(IRequestServiceMain requestService, IPrincipal user, public MusicRequestEngine(IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log, INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,

View file

@ -27,7 +27,7 @@ namespace Ombi.Core.Engine
{ {
public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine
{ {
public MusicSearchEngine(IPrincipal identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper, public MusicSearchEngine(ICurrentUser identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper,
ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
ISettingsService<LidarrSettings> lidarrSettings) ISettingsService<LidarrSettings> lidarrSettings)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)

View file

@ -30,26 +30,26 @@ namespace Ombi.Core.Engine
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(DateTime from, DateTime to) public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(DateTime from, DateTime to)
{ {
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie && x.AddedAt > from && x.AddedAt < to); var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie && x.AddedAt > from && x.AddedAt < to); var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie && x.AddedAt > from && x.AddedAt < to); var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies).Take(30); return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies).Take(30);
} }
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies() public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies()
{ {
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie); var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie); var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie); var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies); return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies);
} }
public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(DateTime from, DateTime to, bool groupBySeason) public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(DateTime from, DateTime to, bool groupBySeason)
{ {
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show && x.AddedAt > from && x.AddedAt < to); var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series && x.AddedAt > from && x.AddedAt < to); var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series && x.AddedAt > from && x.AddedAt < to); var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason).Take(30); return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason).Take(30);
} }
@ -57,9 +57,9 @@ namespace Ombi.Core.Engine
public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(bool groupBySeason) public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(bool groupBySeason)
{ {
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show); var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series); var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series); var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason); return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason);
} }
@ -76,7 +76,7 @@ namespace Ombi.Core.Engine
{ {
continue; continue;
} }
if (p.Type == PlexMediaTypeEntity.Movie) if (p.Type == MediaType.Movie)
{ {
recentlyAddedLog.Add(new RecentlyAddedLog recentlyAddedLog.Add(new RecentlyAddedLog
{ {
@ -114,7 +114,7 @@ namespace Ombi.Core.Engine
{ {
continue; continue;
} }
if (e.Type == EmbyMediaType.Movie) if (e.Type == MediaType.Movie)
{ {
recentlyAddedLog.Add(new RecentlyAddedLog recentlyAddedLog.Add(new RecentlyAddedLog
{ {
@ -152,7 +152,7 @@ namespace Ombi.Core.Engine
{ {
continue; continue;
} }
if (e.Type == JellyfinMediaType.Movie) if (e.Type == MediaType.Movie)
{ {
recentlyAddedLog.Add(new RecentlyAddedLog recentlyAddedLog.Add(new RecentlyAddedLog
{ {

View file

@ -32,7 +32,7 @@ namespace Ombi.Core.Engine
{ {
public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine
{ {
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user, public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, ILogger<TvRequestEngine> logger, INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, ILogger<TvRequestEngine> logger,
ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache, ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) : base(user, requestService, rule, manager, cache, settings, sub) IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) : base(user, requestService, rule, manager, cache, settings, sub)
@ -188,7 +188,7 @@ namespace Ombi.Core.Engine
(await tvBuilder (await tvBuilder
.GetShowInfo(tv.TheMovieDbId, tv.languageCode)) .GetShowInfo(tv.TheMovieDbId, tv.languageCode))
.CreateTvList(tv) .CreateTvList(tv)
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id); .CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id, tv.Source);
await tvBuilder.BuildEpisodes(tv); await tvBuilder.BuildEpisodes(tv);
@ -793,7 +793,7 @@ namespace Ombi.Core.Engine
return await TvRepository.GetChild().AnyAsync(x => x.RequestedUserId == userId); return await TvRepository.GetChild().AnyAsync(x => x.RequestedUserId == userId);
} }
public async Task<RequestEngineResult> MarkUnavailable(int modelId) public async Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K)
{ {
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId); var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId);
if (request == null) if (request == null)
@ -821,7 +821,7 @@ namespace Ombi.Core.Engine
}; };
} }
public async Task<RequestEngineResult> MarkAvailable(int modelId) public async Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K)
{ {
ChildRequests request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId); ChildRequests request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId);
if (request == null) if (request == null)
@ -918,7 +918,7 @@ namespace Ombi.Core.Engine
return await AfterRequest(model.ChildRequests.FirstOrDefault(), requestOnBehalf); return await AfterRequest(model.ChildRequests.FirstOrDefault(), requestOnBehalf);
} }
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken) public async Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken)
{ {
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId, cancellationToken); var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId, cancellationToken);
if (request == null) if (request == null)

View file

@ -23,6 +23,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using System.Threading; using System.Threading;
using TraktSharp.Entities; using TraktSharp.Entities;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -32,7 +33,7 @@ namespace Ombi.Core.Engine
private readonly IImageService _imageService; private readonly IImageService _imageService;
private readonly IMovieDbApi _theMovieDbApi; private readonly IMovieDbApi _theMovieDbApi;
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public TvSearchEngine(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ISettingsService<CustomizationSettings> customizationSettings, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ISettingsService<CustomizationSettings> customizationSettings,
ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IImageService imageService, ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IImageService imageService,
IMovieDbApi theMovieDbApi) IMovieDbApi theMovieDbApi)

View file

@ -5,6 +5,7 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -17,7 +18,7 @@ namespace Ombi.Core.Engine.V2
{ {
public DateTime DaysAgo => DateTime.Now.AddDays(-90); public DateTime DaysAgo => DateTime.Now.AddDays(-90);
public DateTime DaysAhead => DateTime.Now.AddDays(90); public DateTime DaysAhead => DateTime.Now.AddDays(90);
public CalendarEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo, public CalendarEngine(ICurrentUser user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo,
ITvRequestRepository tvRequestRepo) : base(user, um, rules) ITvRequestRepository tvRequestRepo) : base(user, um, rules)
{ {
_movieRepo = movieRepo; _movieRepo = movieRepo;

View file

@ -4,10 +4,15 @@ using System.Threading.Tasks;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
// Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
using Genre = Ombi.TheMovieDbApi.Models.Genre;
namespace Ombi.Core.Engine.V2 namespace Ombi.Core.Engine.V2
{ {
public interface IMultiSearchEngine public interface IMultiSearchEngine
{ {
Task<List<MultiSearchResult>> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken); Task<List<MultiSearchResult>> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken);
Task<IEnumerable<Genre>> GetGenres(string media, CancellationToken requestAborted);
} }
} }

View file

@ -33,7 +33,7 @@ namespace Ombi.Core.Engine.V2
public async Task<IEnumerable<IssuesSummaryModel>> GetIssues(int position, int take, IssueStatus status, CancellationToken token) public async Task<IEnumerable<IssuesSummaryModel>> GetIssues(int position, int take, IssueStatus status, CancellationToken token)
{ {
var issues = await _issues.GetAll().Where(x => x.Status == status && x.ProviderId != null).Skip(position).Take(take).OrderBy(x => x.Title).ToListAsync(token); var issues = await _issues.GetAll().Where(x => x.Status == status && x.ProviderId != null).Skip(position).Take(take).OrderBy(x => x.Title).ToListAsync(token);
var grouped = issues.GroupBy(x => x.Title, (key, g) => new { Title = key, Issues = g }); var grouped = issues.GroupBy(x => new { x.Title, x.ProviderId }, (key, g) => new { key = key, Issues = g });
var model = new List<IssuesSummaryModel>(); var model = new List<IssuesSummaryModel>();
@ -42,8 +42,8 @@ namespace Ombi.Core.Engine.V2
model.Add(new IssuesSummaryModel model.Add(new IssuesSummaryModel
{ {
Count = group.Issues.Count(), Count = group.Issues.Count(),
Title = group.Title, Title = group.key.Title,
ProviderId = group.Issues.FirstOrDefault()?.ProviderId ProviderId = group.key.ProviderId
}); });
} }

View file

@ -5,6 +5,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
@ -28,7 +29,7 @@ namespace Ombi.Core.Engine.V2
{ {
public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2 public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2
{ {
public MovieSearchEngineV2(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public MovieSearchEngineV2(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngineV2> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, ILogger<MovieSearchEngineV2> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine, IHttpClientFactory httpClientFactory) ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine, IHttpClientFactory httpClientFactory)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)
@ -398,6 +399,8 @@ namespace Ombi.Core.Engine.V2
mapped.Available = viewMovie.Available; mapped.Available = viewMovie.Available;
mapped.Approved = viewMovie.Approved; mapped.Approved = viewMovie.Approved;
mapped.Denied = viewMovie.Denied;
mapped.DeniedReason = viewMovie.DeniedReason;
mapped.RequestId = viewMovie.RequestId; mapped.RequestId = viewMovie.RequestId;
mapped.Requested = viewMovie.Requested; mapped.Requested = viewMovie.Requested;
mapped.PlexUrl = viewMovie.PlexUrl; mapped.PlexUrl = viewMovie.PlexUrl;
@ -406,6 +409,13 @@ namespace Ombi.Core.Engine.V2
mapped.Subscribed = viewMovie.Subscribed; mapped.Subscribed = viewMovie.Subscribed;
mapped.ShowSubscribe = viewMovie.ShowSubscribe; mapped.ShowSubscribe = viewMovie.ShowSubscribe;
mapped.DigitalReleaseDate = viewMovie.DigitalReleaseDate; mapped.DigitalReleaseDate = viewMovie.DigitalReleaseDate;
mapped.RequestedDate4k = viewMovie.RequestedDate4k;
mapped.Approved4K = viewMovie.Approved4K;
mapped.Available4K = viewMovie.Available4K;
mapped.Denied4K = viewMovie.Denied4K;
mapped.DeniedReason4K = viewMovie.DeniedReason4K;
mapped.Has4KRequest = viewMovie.Has4KRequest;
return mapped; return mapped;
} }

View file

@ -7,6 +7,7 @@ using Ombi.Api.MusicBrainz;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -17,11 +18,15 @@ using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
// Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
using Genre = Ombi.TheMovieDbApi.Models.Genre;
namespace Ombi.Core.Engine.V2 namespace Ombi.Core.Engine.V2
{ {
public class MultiSearchEngine : BaseMediaEngine, IMultiSearchEngine public class MultiSearchEngine : BaseMediaEngine, IMultiSearchEngine
{ {
public MultiSearchEngine(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules, public MultiSearchEngine(ICurrentUser identity, IRequestServiceMain requestService, IRuleEvaluator rules,
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub,
IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, IMusicBrainzApi musicApi) IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, IMusicBrainzApi musicApi)
: base(identity, requestService, rules, um, cache, ombiSettings, sub) : base(identity, requestService, rules, um, cache, ombiSettings, sub)
@ -113,5 +118,11 @@ namespace Ombi.Core.Engine.V2
return model; return model;
} }
public async Task<IEnumerable<Genre>> GetGenres(string media, CancellationToken cancellationToken)
{
var lang = await DefaultLanguageCode(null);
return await _movieDbApi.GetGenres(media, cancellationToken, lang);
}
} }
} }

View file

@ -11,6 +11,7 @@ using Ombi.Api.Lidarr.Models;
using Ombi.Api.MusicBrainz; using Ombi.Api.MusicBrainz;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search.V2.Music; using Ombi.Core.Models.Search.V2.Music;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -31,7 +32,7 @@ namespace Ombi.Core.Engine.V2
private readonly ISettingsService<LidarrSettings> _lidarrSettings; private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi; private readonly ILidarrApi _lidarrApi;
public MusicSearchEngineV2(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules, public MusicSearchEngineV2(ICurrentUser identity, IRequestServiceMain requestService, IRuleEvaluator rules,
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings,
IRepository<RequestSubscription> sub, IMusicBrainzApi musicBrainzApi, ISettingsService<LidarrSettings> lidarrSettings, IRepository<RequestSubscription> sub, IMusicBrainzApi musicBrainzApi, ISettingsService<LidarrSettings> lidarrSettings,
ILidarrApi lidarrApi) ILidarrApi lidarrApi)

View file

@ -25,6 +25,7 @@ using Ombi.Api.TheMovieDb.Models;
using System.Diagnostics; using System.Diagnostics;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine.V2 namespace Ombi.Core.Engine.V2
{ {
@ -37,7 +38,7 @@ namespace Ombi.Core.Engine.V2
private readonly ISettingsService<CustomizationSettings> _customization; private readonly ISettingsService<CustomizationSettings> _customization;
private readonly ITvRequestEngine _requestEngine; private readonly ITvRequestEngine _requestEngine;
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public TvSearchEngineV2(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s,
IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization, ITvRequestEngine requestEngine) IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization, ITvRequestEngine requestEngine)
: base(identity, service, r, um, memCache, s, sub) : base(identity, service, r, um, memCache, s, sub)
@ -307,6 +308,8 @@ namespace Ombi.Core.Engine.V2
item.PartlyAvailable = oldModel.PartlyAvailable; item.PartlyAvailable = oldModel.PartlyAvailable;
item.Requested = oldModel.Requested; item.Requested = oldModel.Requested;
item.Available = oldModel.Available; item.Available = oldModel.Available;
item.Denied = oldModel.Denied;
item.DeniedReason = oldModel.DeniedReason;
item.Approved = oldModel.Approved; item.Approved = oldModel.Approved;
item.SeasonRequests = oldModel.SeasonRequests; item.SeasonRequests = oldModel.SeasonRequests;
item.RequestId = oldModel.RequestId; item.RequestId = oldModel.RequestId;

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -20,7 +21,7 @@ namespace Ombi.Core.Engine
{ {
public class VoteEngine : BaseEngine, IVoteEngine public class VoteEngine : BaseEngine, IVoteEngine
{ {
public VoteEngine(IRepository<Votes> votes, IPrincipal user, OmbiUserManager um, IRuleEvaluator r, ISettingsService<VoteSettings> voteSettings, public VoteEngine(IRepository<Votes> votes, ICurrentUser user, OmbiUserManager um, IRuleEvaluator r, ISettingsService<VoteSettings> voteSettings,
IMusicRequestEngine musicRequestEngine, ITvRequestEngine tvRequestEngine, IMovieRequestEngine movieRequestEngine) : base(user, um, r) IMusicRequestEngine musicRequestEngine, ITvRequestEngine tvRequestEngine, IMovieRequestEngine movieRequestEngine) : base(user, um, r)
{ {
_voteRepository = votes; _voteRepository = votes;
@ -193,7 +194,7 @@ namespace Ombi.Core.Engine
case RequestType.Movie: case RequestType.Movie:
if (totalVotes >= voteSettings.MovieVoteMax) if (totalVotes >= voteSettings.MovieVoteMax)
{ {
result = await _movieRequestEngine.ApproveMovieById(requestId); result = await _movieRequestEngine.ApproveMovieById(requestId, false);
} }
break; break;
case RequestType.Album: case RequestType.Album:

View file

@ -0,0 +1,47 @@
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
using Ombi.Helpers;
using Ombi.Store.Entities;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Ombi.Core.Helpers
{
public class CurrentUser : ICurrentUser
{
private readonly IPrincipal _principle;
private readonly OmbiUserManager _userManager;
private OmbiUser _user;
public IIdentity Identity { get; set; }
public CurrentUser(IPrincipal principle, OmbiUserManager userManager)
{
_principle = principle;
_userManager = userManager;
Identity = _principle?.Identity ?? null;
}
public void SetUser(OmbiUser user)
{
_user = user;
}
public string Username => Identity?.Name ?? _user?.UserName;
public async Task<OmbiUser> GetUser()
{
if (!Username.HasValue() && _user == null)
{
return null;
}
if (_user != null)
{
return _user;
}
var username = Username.ToUpper();
return _user ??= await _userManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
}
}
}

View file

@ -0,0 +1,15 @@
using Ombi.Store.Entities;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Ombi.Core.Helpers
{
public interface ICurrentUser
{
string Username { get; }
Task<OmbiUser> GetUser();
void SetUser(OmbiUser user);
IIdentity Identity { get; set; }
}
}

View file

@ -53,7 +53,7 @@ namespace Ombi.Core.Helpers
return this; return this;
} }
public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId) public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId, RequestSource source)
{ {
var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false; var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false;
var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false; var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false;
@ -68,7 +68,8 @@ namespace Ombi.Core.Helpers
Title = TheMovieDbRecord.name, Title = TheMovieDbRecord.name,
ReleaseYear = FirstAir, ReleaseYear = FirstAir,
RequestedByAlias = model.RequestedByAlias, RequestedByAlias = model.RequestedByAlias,
SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard,
Source = source
}; };
return this; return this;

View file

@ -1,31 +1,5 @@
#region Copyright using Newtonsoft.Json;
// /************************************************************************ using Ombi.Store.Entities.Requests;
// Copyright (c) 2018 Jamie Rees
// File: MovieRequestViewModel.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using Newtonsoft.Json;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
@ -34,10 +8,18 @@ namespace Ombi.Core.Models.Requests
public int TheMovieDbId { get; set; } public int TheMovieDbId { get; set; }
public string LanguageCode { get; set; } = "en"; public string LanguageCode { get; set; } = "en";
public bool Is4kRequest { get; set; }
/// <summary> /// <summary>
/// This is only set from a HTTP Header /// This is only set from a HTTP Header
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public string RequestedByAlias { get; set; } public string RequestedByAlias { get; set; }
/// <summary>
/// Only set via list imports
/// </summary>
[JsonIgnore]
public RequestSource Source { get; set; } = RequestSource.Ombi;
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
@ -7,5 +8,6 @@ namespace Ombi.Core.Models.Requests
{ {
public int TheMovieDbId { get; set; } public int TheMovieDbId { get; set; }
public string languageCode { get; set; } = "en"; public string languageCode { get; set; } = "en";
public RequestSource Source { get; set; } = RequestSource.Ombi;
} }
} }

View file

@ -28,5 +28,14 @@ namespace Ombi.Core.Models.Search
public override RequestType Type => RequestType.Movie; public override RequestType Type => RequestType.Movie;
public ReleaseDatesDto ReleaseDates { get; set; } public ReleaseDatesDto ReleaseDates { get; set; }
public DateTime? DigitalReleaseDate { get; set; } public DateTime? DigitalReleaseDate { get; set; }
public bool Has4KRequest { get; set; }
public bool Approved4K { get; set; }
public DateTime MarkedAsApproved4K { get; set; }
public DateTime RequestedDate4k { get; set; }
public bool Available4K { get; set; }
public DateTime? MarkedAsAvailable4K { get; set; }
public bool? Denied4K { get; set; }
public DateTime MarkedAsDenied4K { get; set; }
public string DeniedReason4K { get; set; }
} }
} }

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations.Schema; using System;
using System.ComponentModel.DataAnnotations.Schema;
using Ombi.Store.Entities; using Ombi.Store.Entities;
namespace Ombi.Core.Models.Search namespace Ombi.Core.Models.Search
@ -32,6 +33,7 @@ namespace Ombi.Core.Models.Search
public string TheMovieDbId { get; set; } public string TheMovieDbId { get; set; }
[NotMapped] [NotMapped]
[Obsolete("Use request service instead")]
public bool Subscribed { get; set; } public bool Subscribed { get; set; }
[NotMapped] [NotMapped]
public bool ShowSubscribe { get; set; } public bool ShowSubscribe { get; set; }

View file

@ -41,6 +41,15 @@ namespace Ombi.Core.Models.Search.V2
public Recommendations Recommendations { get; set; } public Recommendations Recommendations { get; set; }
public ExternalIds ExternalIds { get; set; } public ExternalIds ExternalIds { get; set; }
public Keywords Keywords { get; set; } public Keywords Keywords { get; set; }
public bool Has4KRequest { get; set; }
public bool Approved4K { get; set; }
public DateTime MarkedAsApproved4K { get; set; }
public DateTime RequestedDate4k { get; set; }
public bool Available4K { get; set; }
public DateTime? MarkedAsAvailable4K { get; set; }
public bool? Denied4K { get; set; }
public DateTime MarkedAsDenied4K { get; set; }
public string DeniedReason4K { get; set; }
} }
public class Keywords public class Keywords
{ {

Some files were not shown because too many files have changed in this diff Show more