Merge branch 'develop' into recently-requested

This commit is contained in:
tidusjar 2022-07-30 20:32:03 +01:00
commit 32cbff19b0
595 changed files with 43308 additions and 10538 deletions

View file

@ -3,6 +3,7 @@ name: CI Build
on: on:
push: push:
branches: [ develop, master ] branches: [ develop, master ]
workflow_dispatch:
jobs: jobs:
build-ui: build-ui:
@ -38,7 +39,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v1
with: with:
dotnet-version: '5.0.x' dotnet-version: '6.0.x'
- name: Nuget Cache - name: Nuget Cache
uses: actions/cache@v2 uses: actions/cache@v2
@ -67,7 +68,7 @@ jobs:
uses: TriPSs/conventional-changelog-action@v3 uses: TriPSs/conventional-changelog-action@v3
with: with:
version-file: 'version.json' version-file: 'version.json'
release-count: 20 release-count: 40
skip-on-empty: 'false' skip-on-empty: 'false'
git-message: 'chore(release): :rocket: {version}' git-message: 'chore(release): :rocket: {version}'
@ -103,6 +104,12 @@ jobs:
format: tar.gz format: tar.gz
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Nuget Cache - name: Nuget Cache
uses: actions/cache@v2 uses: actions/cache@v2
@ -183,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 }}

47
.github/workflows/chromatic.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: 'Chromatic'
# Event for the workflow
on:
push:
workflow_dispatch:
# List of jobs
jobs:
storybook-build:
# Operating System
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: NodeModules Cache
uses: actions/cache@v2
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
working-directory: ./src/Ombi/ClientApp
run: yarn
- name: Publish to Chromatic
if: github.ref != 'refs/heads/master'
uses: chromaui/action@v1
with:
projectToken: 7c47e1a1a4bd
exitZeroOnChanges: true
workingDir: ./src/Ombi/ClientApp
buildScriptName: storybookbuild
exitOnceUploaded: true
- name: Publish to Chromatic and auto accept changes
if: github.ref == 'refs/heads/master'
uses: chromaui/action@v1
with:
projectToken: 7c47e1a1a4bd
autoAcceptChanges: true # 👈 Option to accept all changes
workingDir: ./src/Ombi/ClientApp
buildScriptName: storybookbuild
exitOnceUploaded: true

View file

@ -7,6 +7,7 @@ on:
branches: [ develop ] branches: [ develop ]
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
workflow_dispatch:
jobs: jobs:
automation-tests: automation-tests:
@ -18,7 +19,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 5.0.x dotnet-version: 6.0.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '14' node-version: '14'
@ -33,15 +34,17 @@ jobs:
- name: Install Frontend Deps - name: Install Frontend Deps
run: yarn --cwd ./src/Ombi/ClientApp install run: yarn --cwd ./src/Ombi/ClientApp install
- name: Start Frontend
run: |
nohup yarn --cwd ./src/Ombi/ClientApp start &
- name: Install Automation Deps - name: Install Automation Deps
run: yarn --cwd ./tests install run: yarn --cwd ./tests install
- name: Start Backend - name: Start Backend
run: | run: |
nohup dotnet run -p ./src/Ombi -- --host http://*:3577 & nohup dotnet run --project ./src/Ombi -- --host http://*:3577 &
- name: Start Frontend
run: |
nohup yarn --cwd ./src/Ombi/ClientApp start &
- name: Cypress Tests - name: Cypress Tests
uses: cypress-io/github-action@v2.8.2 uses: cypress-io/github-action@v2.8.2
with: with:
@ -50,8 +53,8 @@ jobs:
headless: true headless: true
working-directory: tests working-directory: tests
wait-on: http://localhost:3577/ wait-on: http://localhost:3577/
# 7 minutes # 10 minutes
wait-on-timeout: 420 wait-on-timeout: 600
env: env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

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

@ -8,6 +8,8 @@
name: Labeler name: Labeler
on: [pull_request] on: [pull_request]
permissions: write-all
jobs: jobs:
label: label:

View file

@ -3,6 +3,12 @@ name: PR Build
on: on:
pull_request: pull_request:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
workflow_dispatch:
permissions:
pull-requests: write
issues: write
repository-projects: write
jobs: jobs:
build-ui: build-ui:
@ -27,11 +33,12 @@ jobs:
unit-test: unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v1
with: with:
dotnet-version: '5.0.x' dotnet-version: '6.0.x'
- name: Nuget Cache - name: Nuget Cache
uses: actions/cache@v2 uses: actions/cache@v2
@ -44,7 +51,7 @@ jobs:
- name: Run Unit Tests - name: Run Unit Tests
run: | run: |
cd src cd src
dotnet test --logger trx --results-directory "TestResults" dotnet test --configuration "Release" --logger "trx;LogFileName=test-results.trx"
analysis: analysis:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -89,6 +96,9 @@ jobs:
format: tar.gz format: tar.gz
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
- name: Nuget Cache - name: Nuget Cache
uses: actions/cache@v2 uses: actions/cache@v2

1
.gitignore vendored
View file

@ -251,3 +251,4 @@ _Pvt_Extensions
/src/Ombi/databases.json /src/Ombi/databases.json
/src/Ombi/healthchecksdb /src/Ombi/healthchecksdb
/src/Ombi/ClientApp/package-lock.json /src/Ombi/ClientApp/package-lock.json
/src/Ombi.Core/Properties/launchSettings.json

7
.mergify.yml Normal file
View file

@ -0,0 +1,7 @@
pull_request_rules:
- name: Automatic merge on approval
conditions:
- "#approved-reviews-by>=1"
actions:
merge:
method: merge

View file

@ -1,62 +1,361 @@
## [4.3.3](https://github.com/Ombi-app/Ombi/compare/v4.3.2...v4.3.3) (2021-11-05) ## [4.22.3](https://github.com/Ombi-app/Ombi/compare/v4.22.2...v4.22.3) (2022-07-28)
## [4.3.2](https://github.com/Ombi-app/Ombi/compare/v4.3.1...v4.3.2) (2021-11-02)
### Bug Fixes ### 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)) * Override Sonarr V3 Profiles endpoint ([#4678](https://github.com/Ombi-app/Ombi/issues/4678)) ([875da95](https://github.com/Ombi-app/Ombi/commit/875da959f353119b05138d68ee6d32a49e14b91e))
## [4.3.1](https://github.com/Ombi-app/Ombi/compare/v4.3.0...v4.3.1) (2021-10-27) ## [4.22.2](https://github.com/Ombi-app/Ombi/compare/v4.22.1...v4.22.2) (2022-07-25)
### Bug Fixes ### 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)) * fixed an issue where I broke images for some users ([81ddc85](https://github.com/Ombi-app/Ombi/commit/81ddc8553b9094c3f6843b036daebb2eb9262e00))
# [4.3.0](https://github.com/Ombi-app/Ombi/compare/v4.2.13...v4.3.0) (2021-10-20) ## [4.22.1](https://github.com/Ombi-app/Ombi/compare/v4.22.0...v4.22.1) (2022-07-25)
### Bug Fixes ### Bug Fixes
* **translations:** 🌐 New translations from Crowdin [skip ci] ([b0f3abb](https://github.com/Ombi-app/Ombi/commit/b0f3abb9ceebdbe5d6c20af98b7355df2999eb58)) * **discover:** :bug: Created new Image component to handle 429's from TMDB ([#4698](https://github.com/Ombi-app/Ombi/issues/4698)) and fixed [#4635](https://github.com/Ombi-app/Ombi/issues/4635) ([#4699](https://github.com/Ombi-app/Ombi/issues/4699)) ([f22d3da](https://github.com/Ombi-app/Ombi/commit/f22d3da765799365455b919027f7563e52b347c3))
* **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)) # [4.22.0](https://github.com/Ombi-app/Ombi/compare/v4.21.2...v4.22.0) (2022-07-22)
* **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 ### Features
* **request-limits:** :sparkles: Added the new request limit options into the user importer ([01d4f4d](https://github.com/Ombi-app/Ombi/commit/01d4f4d718fe85ac181dae52565fb1b427965b4f)) * **discover:** ✨ Added infinite scroll on advanced search results ([898bc89](https://github.com/Ombi-app/Ombi/commit/898bc89fa78245c1f3de9481f6c724f087a16e39))
* **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) ## [4.21.2](https://github.com/Ombi-app/Ombi/compare/v4.21.1...v4.21.2) (2022-07-22)
### Bug Fixes ### Bug Fixes
* **translations:** 🌐 New translations %two_letters_code% from Crowdin [skip ci] ([8fbd267](https://github.com/Ombi-app/Ombi/commit/8fbd267b516ddaa80fd16c091bae532b860fbf45)) * Landing and Login page improvements ([#4690](https://github.com/Ombi-app/Ombi/issues/4690)) ([6d423b5](https://github.com/Ombi-app/Ombi/commit/6d423b5447c52c5e59d8d2bd92a23b47468eb736))
## [4.21.1](https://github.com/Ombi-app/Ombi/compare/v4.21.0...v4.21.1) (2022-07-11)
### Bug Fixes
* **images:** Retry images with a backoff when we get a Too Many requests from TheMovieDb [#4685](https://github.com/Ombi-app/Ombi/issues/4685) ([3f1f35d](https://github.com/Ombi-app/Ombi/commit/3f1f35df3164db6739691cdda8f925c296239791))
# [4.21.0](https://github.com/Ombi-app/Ombi/compare/v4.20.4...v4.21.0) (2022-06-22)
### Features
* Upgrade to Angular14 ([#4668](https://github.com/Ombi-app/Ombi/issues/4668)) ([b9d55a4](https://github.com/Ombi-app/Ombi/commit/b9d55a469b412558cbf67c1e25db7fdda5964cd8))
### Performance Improvements
* stop populating obsolete subscribe fields ([#4625](https://github.com/Ombi-app/Ombi/issues/4625)) ([9a73463](https://github.com/Ombi-app/Ombi/commit/9a734637665f671b17c2bb440d93b35a891c142b))
## [4.20.4](https://github.com/Ombi-app/Ombi/compare/v4.20.3...v4.20.4) (2022-06-15)
### Bug Fixes
* fixed build ([f877921](https://github.com/Ombi-app/Ombi/commit/f8779219146051ea74f8b6408658ff7975afb88b))
## [4.20.3](https://github.com/Ombi-app/Ombi/compare/v4.20.2...v4.20.3) (2022-06-05)
### Bug Fixes
* **plex:** 🐛 Fixed an issue with the Plex Sync ([ab1a11a](https://github.com/Ombi-app/Ombi/commit/ab1a11af78efbe9d37bd55aa80a640796c138a98))
## [4.20.2](https://github.com/Ombi-app/Ombi/compare/v4.20.1...v4.20.2) (2022-06-03)
### Bug Fixes
* :bug: Fixed the Request on Behalf of having blanks ([#4667](https://github.com/Ombi-app/Ombi/issues/4667)) ([7dd9b1c](https://github.com/Ombi-app/Ombi/commit/7dd9b1cac07f571dd35b362544e4fe0226c4b817))
## [4.20.1](https://github.com/Ombi-app/Ombi/compare/v4.20.0...v4.20.1) (2022-05-27)
### Bug Fixes
* added media type tag to media type text ([#4638](https://github.com/Ombi-app/Ombi/issues/4638)) ([fe501d3](https://github.com/Ombi-app/Ombi/commit/fe501d34a0c36ac9f000b107eca49dbc6694d006))
* **API:** Fix pagination in some edge cases ([#4649](https://github.com/Ombi-app/Ombi/issues/4649)) ([a70bf8f](https://github.com/Ombi-app/Ombi/commit/a70bf8f46c76d74c9dfdf908c53bd9955ca0a35d))
* **discover:** Carousel touch not working when scrolling page and recommendations and similar movie navigation ([#4633](https://github.com/Ombi-app/Ombi/issues/4633)) ([d5ef1d5](https://github.com/Ombi-app/Ombi/commit/d5ef1d53e5f77d19dba8b8059c80b538a3e14f2a))
* Improve Swagger documentation ([#4652](https://github.com/Ombi-app/Ombi/issues/4652)) ([181892b](https://github.com/Ombi-app/Ombi/commit/181892bcfe88e6d76febf49ef57745d04552d08e))
* Missing Poster broken link fix ([#4637](https://github.com/Ombi-app/Ombi/issues/4637)) ([4070f0d](https://github.com/Ombi-app/Ombi/commit/4070f0d093b1c92487a1c80cabad8283a9650f51))
* **sickrage:** Fixed issue with incorrect handling of SiCKRAGE episode results returned during episode status changes, now expects array of objects from data path if present ([#4648](https://github.com/Ombi-app/Ombi/issues/4648)) ([6d16442](https://github.com/Ombi-app/Ombi/commit/6d16442d4d714920367df065a3ced42b729f4233))
* **sync:** Emby+Jellyfin - sync multi-episode files of 3+ episodes ([bd8fd89](https://github.com/Ombi-app/Ombi/commit/bd8fd890554c9d85d6da4d2cee813e82ce698e52))
# [4.20.0](https://github.com/Ombi-app/Ombi/compare/v4.19.1...v4.20.0) (2022-04-28)
### Features
* **discover:** Show more relevant shows in upcoming TV ([8357819](https://github.com/Ombi-app/Ombi/commit/8357819b53b8c675c0b246d7006b5a778bdba33f))
## [4.19.1](https://github.com/Ombi-app/Ombi/compare/v4.19.0...v4.19.1) (2022-04-27)
# [4.19.0](https://github.com/Ombi-app/Ombi/compare/v4.18.0...v4.19.0) (2022-04-27)
### Features
* **sync:** Detect reidentified movies in Emby and Jellyfin ([5938077](https://github.com/Ombi-app/Ombi/commit/5938077d82a5357f79c07b218b3986557a5816e8))
* **sync:** Detect reidentified series in Emby and Jellyfin ([9096e91](https://github.com/Ombi-app/Ombi/commit/9096e91d55d268819bce22831f8a8b27f2a1776b))
# [4.18.0](https://github.com/Ombi-app/Ombi/compare/v4.17.0...v4.18.0) (2022-04-26)
### Bug Fixes
* **discover:** Fix cache mix up ([03d9422](https://github.com/Ombi-app/Ombi/commit/03d94220c7eaafb50c6c80a6ed1150794b873ac3))
* **discover:** Fix new trending feature detection ([6794b88](https://github.com/Ombi-app/Ombi/commit/6794b887f6544fb41528bdd9728b7824b65e47ee))
* **settings:** Allow toggling features when there are more than one ([a373359](https://github.com/Ombi-app/Ombi/commit/a373359ae8e6bad42b558a6e01a8ff2840d3bbaa))
### Features
* **discover:** Add new trending source experimental feature ([1a0823c](https://github.com/Ombi-app/Ombi/commit/1a0823ca80559417c67323aaeaa1ef5243e98031))
* **discover:** Default trending source to new logic ([4f12939](https://github.com/Ombi-app/Ombi/commit/4f12939e22020a67a5ee75e2907923faea136e8d))
# [4.17.0](https://github.com/Ombi-app/Ombi/compare/v4.16.17...v4.17.0) (2022-04-25)
### Features
* **discover:** Add original language filter ([ef7ec86](https://github.com/Ombi-app/Ombi/commit/ef7ec861d8aede2a4817752c990617f583805391))
## [4.16.17](https://github.com/Ombi-app/Ombi/compare/v4.16.16...v4.16.17) (2022-04-25)
## [4.16.16](https://github.com/Ombi-app/Ombi/compare/v4.16.15...v4.16.16) (2022-04-25)
### Bug Fixes
* **4616:** :bug: fixed mandatory fields ([d8f2260](https://github.com/Ombi-app/Ombi/commit/d8f2260c7ae3ed48386743b7adbd06e284487034))
## [4.16.15](https://github.com/Ombi-app/Ombi/compare/v4.16.14...v4.16.15) (2022-04-24)
## [4.16.14](https://github.com/Ombi-app/Ombi/compare/v4.16.13...v4.16.14) (2022-04-19)
## [4.16.13](https://github.com/Ombi-app/Ombi/compare/v4.16.12...v4.16.13) (2022-04-19)
## [4.16.12](https://github.com/Ombi-app/Ombi/compare/v4.16.11...v4.16.12) (2022-04-19)
## [4.16.11](https://github.com/Ombi-app/Ombi/compare/v4.16.10...v4.16.11) (2022-04-14)
### Bug Fixes
* Set the default job for the watchlist import to hourly instead of daily ([75906af](https://github.com/Ombi-app/Ombi/commit/75906af0adee3e3c68d825c3aaa8f7b918461b1f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([0e8a64b](https://github.com/Ombi-app/Ombi/commit/0e8a64b8ca00d210fbe843ac2c3f6af218d80cbc))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([7b0ad61](https://github.com/Ombi-app/Ombi/commit/7b0ad61bfcff3986b33180dc64022cba7ea8eefb))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([4fc2c1f](https://github.com/Ombi-app/Ombi/commit/4fc2c1f24534085a783a3d5791f5533b68272153))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([76ab733](https://github.com/Ombi-app/Ombi/commit/76ab733b91791e4d93d184f3c7d0779c6a388695))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([06e4cef](https://github.com/Ombi-app/Ombi/commit/06e4cefa7b4e55b860da9a64f461f6ec8fa17367))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([c12d89d](https://github.com/Ombi-app/Ombi/commit/c12d89d6781a337520977ad285f8d08c93f434dd))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([bc0c2f6](https://github.com/Ombi-app/Ombi/commit/bc0c2f622e34fb5a2711039d9ed7aad34f982b15))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([e4b00e6](https://github.com/Ombi-app/Ombi/commit/e4b00e6b3468bd9389eeb02fc6ad7daf27abc3b3))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d1998d3](https://github.com/Ombi-app/Ombi/commit/d1998d326f999a38586d0a351a20c5448df95842))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([bee4ccb](https://github.com/Ombi-app/Ombi/commit/bee4ccb804594e7385b1fbdc9fe2ef5c42e0d21f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([80233ed](https://github.com/Ombi-app/Ombi/commit/80233ed560cc976e83570d0655c3472f20171fb3))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([8a78adc](https://github.com/Ombi-app/Ombi/commit/8a78adc9bb62f277f2b213dcb3847ed6d0089fcb))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d04c60a](https://github.com/Ombi-app/Ombi/commit/d04c60aa5909b47ba6bffa6f66b03079cbd43521))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([92a785e](https://github.com/Ombi-app/Ombi/commit/92a785e736fa4b72a45270da2d0f4661df433078))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([634982d](https://github.com/Ombi-app/Ombi/commit/634982df2661cefab5ea9f5163fe04a005cc0171))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([b404baa](https://github.com/Ombi-app/Ombi/commit/b404baad6d0aeaa1561701e0db8db4e78613a364))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d14f11e](https://github.com/Ombi-app/Ombi/commit/d14f11e0eb20ab0a68e765ee77968b3b3e54e995))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([7cf64f9](https://github.com/Ombi-app/Ombi/commit/7cf64f909d78908edaabeffb8a39a7d02e73fe7e))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([0c9e1ec](https://github.com/Ombi-app/Ombi/commit/0c9e1ec090827080cc8f7393e5e91456ff37d691))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([3b0b730](https://github.com/Ombi-app/Ombi/commit/3b0b730cb02efe24f6d4026e5fdb20d37e495119))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([6ed1a03](https://github.com/Ombi-app/Ombi/commit/6ed1a03b7ff4077f09ea9e13394b18b0d138f4c3))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([2941acd](https://github.com/Ombi-app/Ombi/commit/2941acd3b2ec74a5e6aeea275ab5a39d2653f37f))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([c075a1a](https://github.com/Ombi-app/Ombi/commit/c075a1a66784d975eaf60f2dfbbcbe048f2f63d7))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([76bd81c](https://github.com/Ombi-app/Ombi/commit/76bd81c3ca55a98c6ec944a838dc01294a6193a6))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([0d38275](https://github.com/Ombi-app/Ombi/commit/0d3827507e002bcf58f673e97ffcc3bd25dcf337))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([5c99601](https://github.com/Ombi-app/Ombi/commit/5c99601b07aec1a65d0186a4c4327440811e64c6))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([01546a0](https://github.com/Ombi-app/Ombi/commit/01546a0f7f86379528b486463246ef9bdfb9033e))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d7fea78](https://github.com/Ombi-app/Ombi/commit/d7fea7843aaaab7ddff8dc31ca6d2a9117471dcc))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([1a6b95d](https://github.com/Ombi-app/Ombi/commit/1a6b95d45c220310213b8d811272a63f0f6ff42b))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([fa10174](https://github.com/Ombi-app/Ombi/commit/fa1017422c4efd4b0897871bd3c671151774d7c3))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([0c31e62](https://github.com/Ombi-app/Ombi/commit/0c31e628df376aac6d56ae67c7c705a9a4a7c080))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([6399643](https://github.com/Ombi-app/Ombi/commit/63996437a02fe10ffae6822ffa15369bec0a6b36))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([5826e2d](https://github.com/Ombi-app/Ombi/commit/5826e2d9a1c3f1210a87fa270dc0c81bac32944a))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d434514](https://github.com/Ombi-app/Ombi/commit/d43451405be489254d7cdc7755d5f516a1e495a5))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([0b9596d](https://github.com/Ombi-app/Ombi/commit/0b9596d807178f5e071113ec0347868ec7f0960b))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([8c4c0b2](https://github.com/Ombi-app/Ombi/commit/8c4c0b262978c1303767af360d802c4b4c2b4d24))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([289ab77](https://github.com/Ombi-app/Ombi/commit/289ab77b0e04aae235b6f6cebc86e0a8d1f0cf2b))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([30e3417](https://github.com/Ombi-app/Ombi/commit/30e3417285a4eed18d429d7776f0e74096e834c0))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([6c0a5da](https://github.com/Ombi-app/Ombi/commit/6c0a5dadd4b8f37760252eb0fe7f88908f55506d))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d5bf969](https://github.com/Ombi-app/Ombi/commit/d5bf9692ce1fc0ccfe7beca6dd200c78be177bdc))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([8a9e7ea](https://github.com/Ombi-app/Ombi/commit/8a9e7ea588aefbcd73ed82625887e3614e1703ea))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([01047a3](https://github.com/Ombi-app/Ombi/commit/01047a3fd67153f3ff16f860d2c7b50213e8d9b2))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([698a23f](https://github.com/Ombi-app/Ombi/commit/698a23fb83f323cdd1dd57cb49803079d44214a7))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([24eb842](https://github.com/Ombi-app/Ombi/commit/24eb842fc4424f7bcc3ec2949d7f5472492e96f6))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([ac8b16a](https://github.com/Ombi-app/Ombi/commit/ac8b16a3051ad71dbd54a8973c7dd847b564a515))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([f428ce6](https://github.com/Ombi-app/Ombi/commit/f428ce6a700c081437703839bc84d2f2b1138bcc))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([94b16df](https://github.com/Ombi-app/Ombi/commit/94b16dfe09bf1d2cd6286777d74eb5d4496abbbb))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([4881775](https://github.com/Ombi-app/Ombi/commit/4881775eda69a8f136ce0d8fbbf970e3d0406dc9))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([8297db9](https://github.com/Ombi-app/Ombi/commit/8297db91e85da308bde6fb09ad78347dee063630))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([d1152ab](https://github.com/Ombi-app/Ombi/commit/d1152ab7674243daa528c524c0cdc87d81ad49c9))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([eb2788b](https://github.com/Ombi-app/Ombi/commit/eb2788b761b55c487a59a049427ca08f6c10e836))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([21a794c](https://github.com/Ombi-app/Ombi/commit/21a794cbc0a5fa735ca0347c8f7f1ac04a487fbc))
## [4.10.2](https://github.com/Ombi-app/Ombi/compare/v4.10.1...v4.10.2) (2022-01-22)
## [4.16.10](https://github.com/Ombi-app/Ombi/compare/v4.16.9...v4.16.10) (2022-04-13)
## [4.16.9](https://github.com/Ombi-app/Ombi/compare/v4.16.8...v4.16.9) (2022-04-13)
### Bug Fixes
* **plex-watchlist:** Only request the latest season when importing from the watchlist ([77a47ff](https://github.com/Ombi-app/Ombi/commit/77a47ff157c6c5feafe3f2a29a3fcba8df4fdfef))
## [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.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))

173
README.md
View file

@ -18,7 +18,7 @@ Don't worry, it's grandma friendly, and more importantly; has wife approval cert
| Service | Stable | Develop | Service | Stable | Develop
|----------|:---------------------------:|:----------------------------:| |----------|:---------------------------:|:----------------------------:|
| Build Status | [![CI Build](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml) | [![CI Build](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml/badge.svg)](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml) | [![Build Status](https://dev.azure.com/tidusjar/Ombi/_apis/build/status/Ombi%20CI?branchName=feature%2Fv4)](https://dev.azure.com/tidusjar/Ombi/_build/latest?definitionId=18&branchName=feature%2Fv4) | Build Status | [![CI Build](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml) | [![CI Build](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/Ombi-app/Ombi/actions/workflows/build.yml) | [![Build Status](https://dev.azure.com/tidusjar/Ombi/_apis/build/status/Ombi%20CI?branchName=feature%2Fv4)](https://dev.azure.com/tidusjar/Ombi/_build/latest?definitionId=18&branchName=feature%2Fv4)
| Download |[![Download](https://img.shields.io/badge/-Download-blue)](https://github.com/Ombi-app/Ombi/releases) | [![Download](https://img.shields.io/badge/-Download-blue)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/develop/artifacts) | [![Download](https://img.shields.io/badge/-Download-blue)](https://github.com/ombi-app/ombi/releases) | | Download |[![Download](https://img.shields.io/badge/-Download-blue)](https://github.com/Ombi-app/Ombi/releases) | [![Download](https://img.shields.io/badge/-Download-blue)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/develop/artifacts) | [![Download](https://img.shields.io/badge/-Download-blue)](https://github.com/ombi-app/ombi/releases) |
# Feature Requests # Feature Requests
@ -99,21 +99,28 @@ Here are some of the features Ombi has:
<sub><b>Drew</b></sub> <sub><b>Drew</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/anojht"> <a href="https://github.com/anojht">
<img src="https://avatars.githubusercontent.com/u/21053678?v=4" width="50;" alt="anojht"/> <img src="https://avatars.githubusercontent.com/u/21053678?v=4" width="50;" alt="anojht"/>
<br /> <br />
<sub><b>Anojh Thayaparan</b></sub> <sub><b>Anojh Thayaparan</b></sub>
</a> </a>
</td> </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"/>
@ -148,15 +155,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Dhruv Bhavsar</b></sub> <sub><b>Dhruv Bhavsar</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/joshuaboniface"> <a href="https://github.com/joshuaboniface">
<img src="https://avatars.githubusercontent.com/u/4031396?v=4" width="50;" alt="joshuaboniface"/> <img src="https://avatars.githubusercontent.com/u/4031396?v=4" width="50;" alt="joshuaboniface"/>
<br /> <br />
<sub><b>Joshua M. Boniface</b></sub> <sub><b>Joshua M. Boniface</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/bruvv"> <a href="https://github.com/bruvv">
<img src="https://avatars.githubusercontent.com/u/3063928?v=4" width="50;" alt="bruvv"/> <img src="https://avatars.githubusercontent.com/u/3063928?v=4" width="50;" alt="bruvv"/>
@ -164,13 +171,6 @@ Here are some of the features Ombi has:
<sub><b>Bruvv</b></sub> <sub><b>Bruvv</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/louis-lau"> <a href="https://github.com/louis-lau">
<img src="https://avatars.githubusercontent.com/u/1346804?v=4" width="50;" alt="louis-lau"/> <img src="https://avatars.githubusercontent.com/u/1346804?v=4" width="50;" alt="louis-lau"/>
@ -222,10 +222,10 @@ Here are some of the features Ombi has:
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/stefangross"> <a href="https://github.com/grimsan55">
<img src="https://avatars.githubusercontent.com/u/8499989?v=4" width="50;" alt="stefangross"/> <img src="https://avatars.githubusercontent.com/u/8499989?v=4" width="50;" alt="grimsan55"/>
<br /> <br />
<sub><b>Stefangross</b></sub> <sub><b>Stefan</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -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,6 +284,14 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Aptalca</b></sub> <sub><b>Aptalca</b></sub>
</a> </a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/dr3am37">
<img src="https://avatars.githubusercontent.com/u/91037083?v=4" width="50;" alt="dr3am37"/>
<br />
<sub><b>Dr3amer</b></sub>
</a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/mhann"> <a href="https://github.com/mhann">
@ -284,8 +299,7 @@ Here are some of the features Ombi has:
<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"/>
@ -313,7 +327,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Austin Jackson</b></sub> <sub><b>Austin Jackson</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/D34DC3N73R"> <a href="https://github.com/D34DC3N73R">
<img src="https://avatars.githubusercontent.com/u/9123670?v=4" width="50;" alt="D34DC3N73R"/> <img src="https://avatars.githubusercontent.com/u/9123670?v=4" width="50;" alt="D34DC3N73R"/>
@ -327,8 +342,7 @@ Here are some of the features Ombi has:
<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"/>
@ -356,7 +370,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Jeffrey Peters</b></sub> <sub><b>Jeffrey Peters</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/MariusSchiffer"> <a href="https://github.com/MariusSchiffer">
<img src="https://avatars.githubusercontent.com/u/183124?v=4" width="50;" alt="MariusSchiffer"/> <img src="https://avatars.githubusercontent.com/u/183124?v=4" width="50;" alt="MariusSchiffer"/>
@ -370,8 +385,7 @@ Here are some of the features Ombi has:
<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"/>
@ -399,7 +413,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Abe Kline</b></sub> <sub><b>Abe Kline</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/XanderStrike"> <a href="https://github.com/XanderStrike">
<img src="https://avatars.githubusercontent.com/u/1565303?v=4" width="50;" alt="XanderStrike"/> <img src="https://avatars.githubusercontent.com/u/1565303?v=4" width="50;" alt="XanderStrike"/>
@ -413,8 +428,7 @@ Here are some of the features Ombi has:
<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"/>
@ -442,7 +456,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Chris Lees</b></sub> <sub><b>Chris Lees</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/cdemi"> <a href="https://github.com/cdemi">
<img src="https://avatars.githubusercontent.com/u/8025435?v=4" width="50;" alt="cdemi"/> <img src="https://avatars.githubusercontent.com/u/8025435?v=4" width="50;" alt="cdemi"/>
@ -456,8 +471,7 @@ Here are some of the features Ombi has:
<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"/>
@ -485,7 +499,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Devin Buhl</b></sub> <sub><b>Devin Buhl</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/elisspace"> <a href="https://github.com/elisspace">
<img src="https://avatars.githubusercontent.com/u/18365129?v=4" width="50;" alt="elisspace"/> <img src="https://avatars.githubusercontent.com/u/18365129?v=4" width="50;" alt="elisspace"/>
@ -499,8 +514,7 @@ Here are some of the features Ombi has:
<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"/>
@ -508,6 +522,13 @@ Here are some of the features Ombi has:
<sub><b>Haries Ramdhani</b></sub> <sub><b>Haries Ramdhani</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/comigor">
<img src="https://avatars.githubusercontent.com/u/735858?v=4" width="50;" alt="comigor"/>
<br />
<sub><b>Igor Borges</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/ImgBotApp"> <a href="https://github.com/ImgBotApp">
<img src="https://avatars.githubusercontent.com/u/31427850?v=4" width="50;" alt="ImgBotApp"/> <img src="https://avatars.githubusercontent.com/u/31427850?v=4" width="50;" alt="ImgBotApp"/>
@ -521,7 +542,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Jacob Pyke</b></sub> <sub><b>Jacob Pyke</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/jamesmacwhite"> <a href="https://github.com/jamesmacwhite">
<img src="https://avatars.githubusercontent.com/u/8067792?v=4" width="50;" alt="jamesmacwhite"/> <img src="https://avatars.githubusercontent.com/u/8067792?v=4" width="50;" alt="jamesmacwhite"/>
@ -542,8 +564,7 @@ Here are some of the features Ombi has:
<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"/>
@ -564,7 +585,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Kris Klosterman</b></sub> <sub><b>Kris Klosterman</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/kmlucy"> <a href="https://github.com/kmlucy">
<img src="https://avatars.githubusercontent.com/u/13952475?v=4" width="50;" alt="kmlucy"/> <img src="https://avatars.githubusercontent.com/u/13952475?v=4" width="50;" alt="kmlucy"/>
@ -579,20 +601,41 @@ Here are some of the features Ombi has:
<sub><b>Lightkeeper</b></sub> <sub><b>Lightkeeper</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/Lucane">
<img src="https://avatars.githubusercontent.com/u/7999446?v=4" width="50;" alt="Lucane"/>
<br />
<sub><b>Lucane</b></sub>
</a>
</td>
<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">
<a href="https://github.com/marleypowell">
<img src="https://avatars.githubusercontent.com/u/55280588?v=4" width="50;" alt="marleypowell"/>
<br />
<sub><b>Marley</b></sub>
</a>
</td>
<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"/>
<br /> <br />
<sub><b>Matt</b></sub> <sub><b>Matt</b></sub>
</a> </a>
</td></tr>
<tr>
<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>
<td align="center"> <td align="center">
<a href="https://github.com/AliMickey"> <a href="https://github.com/AliMickey">
@ -608,6 +651,13 @@ 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>
<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"/>
@ -621,15 +671,15 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Rob Gökemeijer</b></sub> <sub><b>Rob Gökemeijer</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/sambartik"> <a href="https://github.com/sambartik">
<img src="https://avatars.githubusercontent.com/u/63553146?v=4" width="50;" alt="sambartik"/> <img src="https://avatars.githubusercontent.com/u/63553146?v=4" width="50;" alt="sambartik"/>
<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"/>
@ -644,6 +694,13 @@ Here are some of the features Ombi has:
<sub><b>Shoghi</b></sub> <sub><b>Shoghi</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/Teifun2">
<img src="https://avatars.githubusercontent.com/u/7461832?v=4" width="50;" alt="Teifun2"/>
<br />
<sub><b>Teifun2</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/thomasvt1"> <a href="https://github.com/thomasvt1">
<img src="https://avatars.githubusercontent.com/u/2271011?v=4" width="50;" alt="thomasvt1"/> <img src="https://avatars.githubusercontent.com/u/2271011?v=4" width="50;" alt="thomasvt1"/>
@ -657,7 +714,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Tim Trott</b></sub> <sub><b>Tim Trott</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/tombomb"> <a href="https://github.com/tombomb">
<img src="https://avatars.githubusercontent.com/u/544509?v=4" width="50;" alt="tombomb"/> <img src="https://avatars.githubusercontent.com/u/544509?v=4" width="50;" alt="tombomb"/>
@ -671,8 +729,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"/>
@ -700,7 +757,8 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Blake Drumm</b></sub> <sub><b>Blake Drumm</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/camjac251"> <a href="https://github.com/camjac251">
<img src="https://avatars.githubusercontent.com/u/6313132?v=4" width="50;" alt="camjac251"/> <img src="https://avatars.githubusercontent.com/u/6313132?v=4" width="50;" alt="camjac251"/>
@ -714,8 +772,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"/>
@ -723,6 +780,13 @@ Here are some of the features Ombi has:
<sub><b>Dorian ALKOUM</b></sub> <sub><b>Dorian ALKOUM</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/echel0n">
<img src="https://avatars.githubusercontent.com/u/1128022?v=4" width="50;" alt="echel0n"/>
<br />
<sub><b>Echel0n</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/m4tta"> <a href="https://github.com/m4tta">
<img src="https://avatars.githubusercontent.com/u/427218?v=4" width="50;" alt="m4tta"/> <img src="https://avatars.githubusercontent.com/u/427218?v=4" width="50;" alt="m4tta"/>
@ -730,6 +794,14 @@ Here are some of the features Ombi has:
<sub><b>M4tta</b></sub> <sub><b>M4tta</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/maartenheebink">
<img src="https://avatars.githubusercontent.com/u/28894544?v=4" width="50;" alt="maartenheebink"/>
<br />
<sub><b>Maartenheebink</b></sub>
</a>
</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 +829,7 @@ Here are some of the features Ombi has:
<br /> <br />
<sub><b>Mike</b></sub> <sub><b>Mike</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/zobe123"> <a href="https://github.com/zobe123">
<img src="https://avatars.githubusercontent.com/u/13840542?v=4" width="50;" alt="zobe123"/> <img src="https://avatars.githubusercontent.com/u/13840542?v=4" width="50;" alt="zobe123"/>

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

17
makefile Normal file
View file

@ -0,0 +1,17 @@
backend:
cd src/Ombi && dotnet watch run -- --host http://*:3577
frontend:
cd src/Ombi/ClientApp && yarn start
install-frontend:
cd src/Ombi/ClientApp && yarn
install-frontend-tests:
cd tests && yarn
frontend-tests:
cd tests && npx cypress run
backend-tests:
cd src/Ombi.Core.Tests && dotnet test

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,8 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Internal;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ombi.Api.Emby.Models; using Ombi.Api.Emby.Models;
using Ombi.Api.Emby.Models.Media;
using Ombi.Api.Emby.Models.Media.Tv; using Ombi.Api.Emby.Models.Media.Tv;
using Ombi.Api.Emby.Models.Movie; using Ombi.Api.Emby.Models.Movie;
using Ombi.Helpers; using Ombi.Helpers;
@ -110,7 +106,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("Fields", "ProviderIds,Overview"); request.AddQueryString("Fields", "ProviderIds,Overview");
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("IsMissing", "False");
return await Api.Request<EmbyItemContainer<EmbyMovie>>(request); return await Api.Request<EmbyItemContainer<EmbyMovie>>(request);
} }
@ -124,22 +120,36 @@ namespace Ombi.Api.Emby
return response; return response;
} }
public async Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri) public async Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{ {
return await GetAll<EmbyMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count, parentIdFilder); return await GetAll<EmbyMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count, parentIdFilder);
} }
public async Task<EmbyItemContainer<EmbyMovie>> RecentlyAddedMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{
return await RecentlyAdded<EmbyMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count, parentIdFilder);
}
public async Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri) public async Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{ {
return await GetAll<EmbyEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder); return await GetAll<EmbyEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder);
} }
public async Task<EmbyItemContainer<EmbyEpisodes>> RecentlyAddedEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{
return await RecentlyAdded<EmbyEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder);
}
public async Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri) public async Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{ {
return await GetAll<EmbySeries>("Series", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder); return await GetAll<EmbySeries>("Series", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder);
} }
public async Task<EmbyItemContainer<EmbySeries>> RecentlyAddedShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
{
return await RecentlyAdded<EmbySeries>("Series", apiKey, userId, baseUri, false, startIndex, count, parentIdFilder);
}
public async Task<SeriesInformation> GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl) public async Task<SeriesInformation> GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl)
{ {
return await GetInformation<SeriesInformation>(mediaId, apiKey, userId, baseUrl); return await GetInformation<SeriesInformation>(mediaId, apiKey, userId, baseUrl);
@ -154,6 +164,31 @@ namespace Ombi.Api.Emby
return await GetInformation<EpisodeInformation>(mediaId, apiKey, userId, baseUrl); return await GetInformation<EpisodeInformation>(mediaId, apiKey, userId, baseUrl);
} }
private async Task<EmbyItemContainer<T>> RecentlyAdded<T>(string type, string apiKey, string userId, string baseUri, bool includeOverview, int startIndex, int count, string parentIdFilder = default)
{
var request = new Request($"emby/users/{userId}/items", baseUri, HttpMethod.Get);
request.AddQueryString("Recursive", true.ToString());
request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,MediaStreams,Overview" : "ProviderIds,MediaStreams ");
request.AddQueryString("startIndex", startIndex.ToString());
request.AddQueryString("limit", count.ToString());
request.AddQueryString("sortBy", "DateCreated");
request.AddQueryString("SortOrder", "Descending");
if (!string.IsNullOrEmpty(parentIdFilder))
{
request.AddQueryString("ParentId", parentIdFilder);
}
request.AddQueryString("IsMissing", "False");
AddHeaders(request, apiKey);
var obj = await Api.Request<EmbyItemContainer<T>>(request);
return obj;
}
private async Task<T> GetInformation<T>(string mediaId, string apiKey, string userId, string baseUrl) private async Task<T> GetInformation<T>(string mediaId, string apiKey, string userId, string baseUrl)
{ {
var request = new Request($"emby/users/{userId}/items/{mediaId}", baseUrl, HttpMethod.Get); var request = new Request($"emby/users/{userId}/items/{mediaId}", baseUrl, HttpMethod.Get);
@ -172,7 +207,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("IncludeItemTypes", type); request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds"); request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds");
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("IsMissing", "False");
AddHeaders(request, apiKey); AddHeaders(request, apiKey);
@ -186,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))
@ -194,7 +229,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("ParentId", parentIdFilder); request.AddQueryString("ParentId", parentIdFilder);
} }
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("isMissing", "False");
AddHeaders(request, apiKey); AddHeaders(request, apiKey);

View file

@ -29,5 +29,8 @@ namespace Ombi.Api.Emby
Task<MovieInformation> GetMovieInformation(string mediaId, string apiKey, string userId, string baseUrl); Task<MovieInformation> GetMovieInformation(string mediaId, string apiKey, string userId, string baseUrl);
Task<EpisodeInformation> GetEpisodeInformation(string mediaId, string apiKey, string userId, string baseUrl); Task<EpisodeInformation> GetEpisodeInformation(string mediaId, string apiKey, string userId, string baseUrl);
Task<PublicInfo> GetPublicInformation(string baseUrl); Task<PublicInfo> GetPublicInformation(string baseUrl);
Task<EmbyItemContainer<EmbyMovie>> RecentlyAddedMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
Task<EmbyItemContainer<EmbyEpisodes>> RecentlyAddedEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
Task<EmbyItemContainer<EmbySeries>> RecentlyAddedShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
} }
} }

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

@ -1,17 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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

@ -82,7 +82,7 @@ namespace Ombi.Api.Jellyfin
request.AddQueryString("Fields", "ProviderIds,Overview"); request.AddQueryString("Fields", "ProviderIds,Overview");
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("isMissing", "False");
return await Api.Request<JellyfinItemContainer<JellyfinMovie>>(request); return await Api.Request<JellyfinItemContainer<JellyfinMovie>>(request);
} }
@ -143,7 +143,7 @@ namespace Ombi.Api.Jellyfin
request.AddQueryString("IncludeItemTypes", type); request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds"); request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds");
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("isMissing", "False");
AddHeaders(request, apiKey); AddHeaders(request, apiKey);
@ -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))
@ -165,7 +165,7 @@ namespace Ombi.Api.Jellyfin
request.AddQueryString("ParentId", parentIdFilder); request.AddQueryString("ParentId", parentIdFilder);
} }
request.AddQueryString("IsVirtualItem", "False"); request.AddQueryString("isMissing", "False");
AddHeaders(request, apiKey); AddHeaders(request, apiKey);

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

@ -1,18 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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

@ -1,10 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json;
namespace Ombi.Api.Plex.Models 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 +13,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,8 +40,6 @@ 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

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

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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; }

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

@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<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>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -9,7 +9,7 @@
public class SickRageEpisodeSetStatus public class SickRageEpisodeSetStatus
{ {
public Data data { get; set; } public Data[] data { get; set; }
public string message { get; set; } public string message { get; set; }
public string result { get; set; } public string result { get; set; }
} }

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -19,7 +19,7 @@ namespace Ombi.Api.Sonarr
protected IApi Api { get; } protected IApi Api { get; }
protected virtual string ApiBaseUrl => "/api/"; protected virtual string ApiBaseUrl => "/api/";
public async Task<IEnumerable<SonarrProfile>> GetProfiles(string apiKey, string baseUrl) public virtual async Task<IEnumerable<SonarrProfile>> GetProfiles(string apiKey, string baseUrl)
{ {
var request = new Request($"{ApiBaseUrl}profile", baseUrl, HttpMethod.Get); var request = new Request($"{ApiBaseUrl}profile", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey); request.AddHeader("X-Api-Key", apiKey);

View file

@ -1,6 +1,8 @@
using System.Net.Http; using System.Net.Http;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.Sonarr.Models;
using Ombi.Api.Sonarr.Models.V3; using Ombi.Api.Sonarr.Models.V3;
namespace Ombi.Api.Sonarr namespace Ombi.Api.Sonarr
@ -21,5 +23,12 @@ namespace Ombi.Api.Sonarr
return await Api.Request<List<LanguageProfiles>>(request); return await Api.Request<List<LanguageProfiles>>(request);
} }
public override async Task<IEnumerable<SonarrProfile>> GetProfiles(string apiKey, string baseUrl)
{
var request = new Request($"{ApiBaseUrl}qualityprofile", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request<List<SonarrProfile>>(request);
}
} }
} }

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.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,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>

View file

@ -66,6 +66,8 @@ namespace Ombi.Api
startingTag = builder.Query.Contains("?") ? "&" : "?"; startingTag = builder.Query.Contains("?") ? "&" : "?";
} }
value = Uri.EscapeDataString(value);
builder.Query = hasQuery builder.Query = hasQuery
? $"{builder.Query}{startingTag}{parameter}={value}" ? $"{builder.Query}{startingTag}{parameter}={value}"
: $"{startingTag}{parameter}={value}"; : $"{startingTag}{parameter}={value}";

View file

@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion> <AssemblyVersion>3.0.0.0</AssemblyVersion>
<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>
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Polly" Version="7.1.0" /> <PackageReference Include="Polly" Version="7.1.0" />
</ItemGroup> </ItemGroup>

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoFixture" Version="4.11.0" /> <PackageReference Include="AutoFixture" Version="4.11.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" /> <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
<PackageReference Include="Moq" Version="4.15.1" /> <PackageReference Include="Moq" Version="4.15.1" />
<PackageReference Include="Moq.AutoMock" Version="3.0.0" /> <PackageReference Include="Moq.AutoMock" Version="3.0.0" />
<PackageReference Include="Nunit" Version="3.12.0" /> <PackageReference Include="Nunit" Version="3.12.0" />

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);
@ -130,5 +131,76 @@ namespace Ombi.Core.Tests.Rule.Search
Assert.False(search.Approved); Assert.False(search.Approved);
Assert.False(search.Requested); Assert.False(search.Requested);
} }
[Test]
public async Task ShouldBeFullyAvailable_NoFutureAiredEpisodes_NoRequest()
{
var search = new SearchTvShowViewModel()
{
Id = 999,
SeasonRequests = new List<SeasonRequests>
{
new SeasonRequests
{
Episodes = new List<EpisodeRequests>
{
new EpisodeRequests
{
Available = true,
AirDate = new System.DateTime(2020,01,01)
},
new EpisodeRequests
{
Available = true,
AirDate = new System.DateTime(2020,01,02)
},
}
}
}
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.That(search.FullyAvailable, Is.True);
Assert.That(search.PartlyAvailable, Is.False);
}
[Test]
public async Task ShouldBeFullyAvailable_AndPartly_FutureAiredEpisodes_NoRequest()
{
var search = new SearchTvShowViewModel()
{
Id = 999,
SeasonRequests = new List<SeasonRequests>
{
new SeasonRequests
{
Episodes = new List<EpisodeRequests>
{
new EpisodeRequests
{
Available = true,
AirDate = new System.DateTime(2020,01,01)
},
new EpisodeRequests
{
Available = true,
AirDate = new System.DateTime(2020,01,02)
},
new EpisodeRequests
{
Available = true,
AirDate = new System.DateTime(2029,01,02)
},
}
}
}
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.That(search.FullyAvailable, Is.True);
Assert.That(search.PartlyAvailable, Is.True);
}
} }
} }

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

@ -0,0 +1,228 @@
using Microsoft.Extensions.Logging;
using MockQueryable.Moq;
using Moq;
using Moq.AutoMock;
using NUnit.Framework;
using Ombi.Core.Authentication;
using Ombi.Core.Models;
using Ombi.Core.Senders;
using Ombi.Notifications;
using Ombi.Notifications.Models;
using Ombi.Settings.Settings.Models.Notifications;
using Ombi.Store.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ombi.Core.Tests.Senders
{
[TestFixture]
public class MassEmailSenderTests
{
private MassEmailSender _subject;
private AutoMocker _mocker;
[SetUp]
public void Setup()
{
_mocker = new AutoMocker();
_subject = _mocker.CreateInstance<MassEmailSender>();
}
[Test]
public async Task SendMassEmail_SingleUser()
{
var model = new MassEmailModel
{
Body = "Test",
Subject = "Subject",
Users = new List<OmbiUser>
{
new OmbiUser
{
Id = "a"
}
}
};
_mocker.Setup<OmbiUserManager, IQueryable<OmbiUser>>(x => x.Users).Returns(new List<OmbiUser>
{
new OmbiUser
{
Id = "a",
Email = "Test@test.com"
}
}.AsQueryable().BuildMock().Object);
var result = await _subject.SendMassEmail(model);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.Is<NotificationMessage>(m => m.Subject == model.Subject
&& m.Message == model.Body
&& m.To == "Test@test.com"), It.IsAny<EmailNotificationSettings>()), Times.Once);
}
[Test]
public async Task SendMassEmail_MultipleUsers()
{
var model = new MassEmailModel
{
Body = "Test",
Subject = "Subject",
Users = new List<OmbiUser>
{
new OmbiUser
{
Id = "a"
},
new OmbiUser
{
Id = "b"
}
}
};
_mocker.Setup<OmbiUserManager, IQueryable<OmbiUser>>(x => x.Users).Returns(new List<OmbiUser>
{
new OmbiUser
{
Id = "a",
Email = "Test@test.com"
},
new OmbiUser
{
Id = "b",
Email = "b@test.com"
}
}.AsQueryable().BuildMock().Object);
var result = await _subject.SendMassEmail(model);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.Is<NotificationMessage>(m => m.Subject == model.Subject
&& m.Message == model.Body
&& m.To == "Test@test.com"), It.IsAny<EmailNotificationSettings>()), Times.Once);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.Is<NotificationMessage>(m => m.Subject == model.Subject
&& m.Message == model.Body
&& m.To == "b@test.com"), It.IsAny<EmailNotificationSettings>()), Times.Once);
}
[Test]
public async Task SendMassEmail_UserNoEmail()
{
var model = new MassEmailModel
{
Body = "Test",
Subject = "Subject",
Users = new List<OmbiUser>
{
new OmbiUser
{
Id = "a"
}
}
};
_mocker.Setup<OmbiUserManager, IQueryable<OmbiUser>>(x => x.Users).Returns(new List<OmbiUser>
{
new OmbiUser
{
Id = "a",
}
}.AsQueryable().BuildMock().Object);
var result = await _subject.SendMassEmail(model);
_mocker.Verify<ILogger<MassEmailSender>>(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
Times.Once);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.IsAny<NotificationMessage>(), It.IsAny<EmailNotificationSettings>()), Times.Never);
}
[Test]
public async Task SendMassEmail_Bcc()
{
var model = new MassEmailModel
{
Body = "Test",
Subject = "Subject",
Bcc = true,
Users = new List<OmbiUser>
{
new OmbiUser
{
Id = "a"
},
new OmbiUser
{
Id = "b"
}
}
};
_mocker.Setup<OmbiUserManager, IQueryable<OmbiUser>>(x => x.Users).Returns(new List<OmbiUser>
{
new OmbiUser
{
Id = "a",
Email = "Test@test.com"
},
new OmbiUser
{
Id = "b",
Email = "b@test.com"
}
}.AsQueryable().BuildMock().Object);
var result = await _subject.SendMassEmail(model);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.Is<NotificationMessage>(m => m.Subject == model.Subject
&& m.Message == model.Body
&& m.Other["bcc"] == "Test@test.com,b@test.com"), It.IsAny<EmailNotificationSettings>()), Times.Once);
}
[Test]
public async Task SendMassEmail_Bcc_NoEmails()
{
var model = new MassEmailModel
{
Body = "Test",
Subject = "Subject",
Bcc = true,
Users = new List<OmbiUser>
{
new OmbiUser
{
Id = "a"
},
new OmbiUser
{
Id = "b"
}
}
};
_mocker.Setup<OmbiUserManager, IQueryable<OmbiUser>>(x => x.Users).Returns(new List<OmbiUser>
{
new OmbiUser
{
Id = "a",
},
new OmbiUser
{
Id = "b",
}
}.AsQueryable().BuildMock().Object);
var result = await _subject.SendMassEmail(model);
_mocker.Verify<IEmailProvider>(x => x.SendAdHoc(It.IsAny<NotificationMessage>(), It.IsAny<EmailNotificationSettings>()), Times.Never);
}
}
}

View file

@ -118,14 +118,23 @@ namespace Ombi.Core.Authentication
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;
@ -78,6 +78,32 @@ namespace Ombi.Core.Engine
return _dbTv; return _dbTv;
} }
protected async Task<RequestEngineResult> CheckCanManageRequest(BaseRequest request) {
var errorResult = new RequestEngineResult {
Result = false,
ErrorCode = ErrorCode.NoPermissions
};
var successResult = new RequestEngineResult { Result = true };
// Admins can always manage requests
var isAdmin = await IsInRole(OmbiRoles.PowerUser) || await IsInRole(OmbiRoles.Admin);
if (isAdmin) {
return successResult;
}
// Users with 'ManageOwnRequests' can only manage their own requests
var canManageOwnRequests = await IsInRole(OmbiRoles.ManageOwnRequests);
if (!canManageOwnRequests) {
return errorResult;
}
var isRequestedBySameUser = ( await GetUser() ).Id == request.RequestedUser?.Id;
if (isRequestedBySameUser) {
return successResult;
}
return errorResult;
}
public RequestCountModel RequestCount() public RequestCountModel RequestCount()
{ {
var movieQuery = MovieRepository.GetAll(); var movieQuery = MovieRepository.GetAll();

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

@ -18,7 +18,7 @@ namespace Ombi.Core.Engine
Task<int> GetTotal(); Task<int> GetTotal();
Task<RequestEngineResult> MarkAvailable(int modelId); Task<RequestEngineResult> MarkAvailable(int modelId);
Task<RequestEngineResult> MarkUnavailable(int modelId); Task<RequestEngineResult> MarkUnavailable(int modelId);
Task RemoveAlbumRequest(int requestId); Task<RequestEngineResult> RemoveAlbumRequest(int requestId);
Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model); Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model);
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search); Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
Task<bool> UserHasRequest(string userId); Task<bool> UserHasRequest(string userId);

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,7 +38,12 @@ 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)

View file

@ -14,13 +14,13 @@ namespace Ombi.Core.Engine.Interfaces
Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search); Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken); Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken);
Task RemoveMovieRequest(int requestId); Task<RequestEngineResult> RemoveMovieRequest(int requestId);
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

@ -20,7 +20,7 @@ namespace Ombi.Core.Engine.Interfaces
Task<TvRequests> UpdateTvRequest(TvRequests request); Task<TvRequests> UpdateTvRequest(TvRequests request);
Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId); Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId);
Task<ChildRequests> UpdateChildRequest(ChildRequests request); Task<ChildRequests> UpdateChildRequest(ChildRequests request);
Task RemoveTvChild(int requestId); Task<RequestEngineResult> RemoveTvChild(int requestId);
Task<RequestEngineResult> ApproveChildRequest(int id); Task<RequestEngineResult> ApproveChildRequest(int id);
Task<IEnumerable<TvRequests>> GetRequestsLite(); Task<IEnumerable<TvRequests>> GetRequestsLite();
Task UpdateQualityProfile(int requestId, int profileId); Task UpdateQualityProfile(int requestId, int profileId);

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
@ -10,6 +11,7 @@ namespace Ombi.Core
{ {
Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token); Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token);
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token); Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token);
Task<ActorCredits> GetTvByActor(int actorId, string langCode);
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken); Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad, string langCustomCode = null); Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad, string langCustomCode = null);
Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad); Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad);

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,55 @@ 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,
Approved4K = 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
@ -130,12 +164,12 @@ namespace Ombi.Core.Engine
}; };
} }
if (requestModel.Approved) // The rules have auto approved this if (requestModel.Approved || requestModel.Approved4K) // 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 +187,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 +252,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 +296,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 +324,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.Available4K && (!x.Denied4K.HasValue || !x.Denied4K.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 +374,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 +424,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 +506,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,27 +514,30 @@ 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;
} }
else else
{ {
x.ShowSubscribe = true; if (!x.Available && !x.Available4K && (!x.Denied ?? true) && (!x.Denied4K ?? true))
{
x.ShowSubscribe = true;
}
var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id); var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id);
x.Subscribed = hasSub != null; x.Subscribed = hasSub != null;
} }
@ -503,18 +563,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,13 +585,22 @@ namespace Ombi.Core.Engine
}; };
} }
request.Denied = true; if (is4K)
request.DeniedReason = denyReason; {
// We are denying a request request.Denied4K = true;
await NotificationHelper.Notify(request, NotificationType.RequestDeclined); request.DeniedReason4K = denyReason;
}
else
{
request.Denied = true;
request.DeniedReason = denyReason;
}
await MovieRepository.Update(request); await MovieRepository.Update(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
// We are denying a request
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
return new RequestEngineResult return new RequestEngineResult
{ {
Result = true, Result = true,
@ -539,7 +608,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)
{ {
@ -549,9 +618,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);
@ -561,7 +639,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)
@ -589,11 +667,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
@ -654,11 +732,20 @@ namespace Ombi.Core.Engine
/// </summary> /// </summary>
/// <param name="requestId">The request identifier.</param> /// <param name="requestId">The request identifier.</param>
/// <returns></returns> /// <returns></returns>
public async Task RemoveMovieRequest(int requestId) public async Task<RequestEngineResult> RemoveMovieRequest(int requestId)
{ {
var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId); var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MovieRepository.Delete(request); await MovieRepository.Delete(request);
await _mediaCacheService.Purge(); await _mediaCacheService.Purge();
return new RequestEngineResult
{
Result = true,
};
} }
public async Task RemoveAllMovieRequests() public async Task RemoveAllMovieRequests()
@ -673,7 +760,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)
@ -685,10 +772,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)
@ -699,7 +786,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();
@ -710,7 +804,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)
@ -720,9 +814,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();
@ -734,9 +835,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;
@ -15,14 +16,13 @@ using Ombi.Store.Repository;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ombi.Core.Engine 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 +46,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);
@ -85,7 +85,7 @@ namespace Ombi.Core.Engine
// 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();
@ -160,7 +160,7 @@ namespace Ombi.Core.Engine
var result = await Cache.GetOrAddAsync(CacheKeys.UpcomingMovies, async () => var result = await Cache.GetOrAddAsync(CacheKeys.UpcomingMovies, async () =>
{ {
var langCode = await DefaultLanguageCode(null); var langCode = await DefaultLanguageCode(null);
return await MovieApi.Upcoming(langCode); return await MovieApi.UpcomingMovies(langCode);
}, DateTimeOffset.Now.AddHours(12)); }, DateTimeOffset.Now.AddHours(12));
if (result != null) if (result != null)
{ {
@ -201,7 +201,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
@ -215,34 +215,9 @@ namespace Ombi.Core.Engine
await RunSearchRules(viewMovie); await RunSearchRules(viewMovie);
// This requires the rules to be run first to populate the RequestId property
await CheckForSubscription(viewMovie);
return viewMovie; return viewMovie;
} }
private async Task CheckForSubscription(SearchMovieViewModel viewModel)
{
// Check if this user requested it
var user = await GetUser();
if (user == null)
{
return;
}
var request = await RequestService.MovieRequestService.GetAll()
.AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id);
if (request || viewModel.Available)
{
viewModel.ShowSubscribe = false;
}
else
{
viewModel.ShowSubscribe = true;
var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => s.UserId == user.Id
&& s.RequestId == viewModel.RequestId && s.RequestType == RequestType.Movie);
viewModel.Subscribed = sub != null;
}
}
private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieDbSearchResult movie) private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieDbSearchResult movie)
{ {

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,
@ -269,7 +270,10 @@ namespace Ombi.Core.Engine
} }
else else
{ {
x.ShowSubscribe = true; if (!x.Available && (!x.Denied ?? false))
{
x.ShowSubscribe = true;
}
var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id); var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id);
x.Subscribed = hasSub != null; x.Subscribed = hasSub != null;
} }
@ -404,10 +408,20 @@ namespace Ombi.Core.Engine
/// </summary> /// </summary>
/// <param name="requestId">The request identifier.</param> /// <param name="requestId">The request identifier.</param>
/// <returns></returns> /// <returns></returns>
public async Task RemoveAlbumRequest(int requestId) public async Task<RequestEngineResult> RemoveAlbumRequest(int requestId)
{ {
var request = await MusicRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId); var request = await MusicRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MusicRepository.Delete(request); await MusicRepository.Delete(request);
return new RequestEngineResult
{
Result = true,
};
} }
public async Task<bool> UserHasRequest(string userId) public async Task<bool> UserHasRequest(string userId)

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