mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
Merge
This commit is contained in:
commit
f16b33c437
367 changed files with 12069 additions and 3073 deletions
48
.github/ISSUE_TEMPLATE.md
vendored
48
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,48 +0,0 @@
|
||||||
<!---
|
|
||||||
|
|
||||||
!! Please use the Support / bug report template, otherwise we will close the Github issue !!
|
|
||||||
|
|
||||||
Version 2.X is not supported anymore. Please don't open a issue for the 2.x version.
|
|
||||||
See https://github.com/tidusjar/Ombi/issues/1455 for more information.
|
|
||||||
|
|
||||||
(Pleas submit a feature request over here: http://feathub.com/tidusjar/Ombi)
|
|
||||||
|
|
||||||
|
|
||||||
--->
|
|
||||||
|
|
||||||
#### Ombi build Version:
|
|
||||||
|
|
||||||
V 3.0.XX
|
|
||||||
|
|
||||||
#### Update Branch:
|
|
||||||
|
|
||||||
Open Beta
|
|
||||||
|
|
||||||
#### Media Sever:
|
|
||||||
|
|
||||||
Plex/Emby
|
|
||||||
|
|
||||||
#### Media Server Version:
|
|
||||||
|
|
||||||
<!-- If appropriate --->
|
|
||||||
|
|
||||||
#### Operating System:
|
|
||||||
|
|
||||||
(Place text here)
|
|
||||||
|
|
||||||
|
|
||||||
#### Ombi Applicable Logs (from `/logs/` directory or the Admin page):
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
(Logs go here. Don't remove the ' tags for showing your logs correctly. Please make sure you remove any personal information from the logs)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Problem Description:
|
|
||||||
|
|
||||||
(Place text here)
|
|
||||||
|
|
||||||
#### Reproduction Steps:
|
|
||||||
|
|
||||||
Please include any steps to reproduce the issue, this the request that is causing the problem etc.
|
|
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Logs (Logs directory where Ombi is located)**
|
||||||
|
If applicable, a snippet of the logs that seems relevant to the bug if present.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
|
||||||
|
**Ombi Version (please complete the following information):**
|
||||||
|
- Version [e.g. 3.0.1158]
|
||||||
|
- Media Server [e.g. Plex]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
96
CHANGELOG.md
96
CHANGELOG.md
|
@ -1,11 +1,105 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## (unreleased)
|
## v3.0.4256 (2019-02-18)
|
||||||
|
|
||||||
### **New Features**
|
### **New Features**
|
||||||
|
|
||||||
|
- Update discord link to follow the scheme of other links. [Tom McClellan]
|
||||||
|
|
||||||
|
- Update issue templates. [Jamie]
|
||||||
|
|
||||||
|
- Update README.md. [Jamie]
|
||||||
|
|
||||||
|
- Update CHANGELOG.md. [Jamie]
|
||||||
|
|
||||||
|
- Added the functionality to remove a user from getting notifications to their mobile device #2780. [tidusjar]
|
||||||
|
|
||||||
|
- Added a demo mode, this will only show movies and shows that are in the public domain. Dam that stupid fruit company. [tidusjar]
|
||||||
|
|
||||||
|
- Added Actor Searching for Movies! [TidusJar]
|
||||||
|
|
||||||
|
- Added the ability to change where the View on Emby link goes to #2730. [TidusJar]
|
||||||
|
|
||||||
|
- Added the request queue to the notifications UI so you can turn it off per notification agent #2747. [TidusJar]
|
||||||
|
|
||||||
- Added new classes to the posters #2732. [TidusJar]
|
- Added new classes to the posters #2732. [TidusJar]
|
||||||
|
|
||||||
|
### **Fixes**
|
||||||
|
|
||||||
|
- Fix: src/Ombi/package.json to reduce vulnerabilities. [snyk-bot]
|
||||||
|
|
||||||
|
- Fixed #2801 this is when a season is not correctly monitored in sonarr when approved by an admin. [tidusjar]
|
||||||
|
|
||||||
|
- Small improvements to try and mitigate #2750. [tidusjar]
|
||||||
|
|
||||||
|
- Removed some areas where we clear out the cache. This should help with DB locking #2750. [tidusjar]
|
||||||
|
|
||||||
|
- Fixed #2810. [tidusjar]
|
||||||
|
|
||||||
|
- Cannot create an issue comment with the API #2811. [tidusjar]
|
||||||
|
|
||||||
|
- Set the local domain if the Application URL is set for the HELO or EHLO commands. #2636. [tidusjar]
|
||||||
|
|
||||||
|
- New translations en.json (Spanish) [Jamie]
|
||||||
|
|
||||||
|
- Delete ISSUE_TEMPLATE.md. [Jamie]
|
||||||
|
|
||||||
|
- More minor grammatical edits. [Andrew Metzger]
|
||||||
|
|
||||||
|
- Minor grammatical edits. [Andrew Metzger]
|
||||||
|
|
||||||
|
- Fixed #2802 the issue where "Issues" were not being deleted correctly. [tidusjar]
|
||||||
|
|
||||||
|
- Fixed #2797. [tidusjar]
|
||||||
|
|
||||||
|
- New translations en.json (Dutch) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Spanish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||||
|
|
||||||
|
- Fixed #2786. [tidusjar]
|
||||||
|
|
||||||
|
- Fixed #2756. [tidusjar]
|
||||||
|
|
||||||
|
- Ignore the UserName header as part of the Api is the value is an empty string. [tidusjar]
|
||||||
|
|
||||||
|
- Fixed #2759. [tidusjar]
|
||||||
|
|
||||||
|
- Did #2756. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed the exception that sometimes makes ombi fallover. [TidusJar]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- Log the error to the ui to figure out what's going on with #2755. [tidusjar]
|
||||||
|
|
||||||
|
- Small fix when denying a request with a reason, we wasn't updating the ui. [TidusJar]
|
||||||
|
|
||||||
|
- Make sure we can only set the ApiAlias when using the API Key. [tidusjar]
|
||||||
|
|
||||||
|
- #2363 Added the ability to pass any username into the API using the ApiAlias header. [tidusjar]
|
||||||
|
|
||||||
|
- Removed the Add user to Plex from Ombi. [tidusjar]
|
||||||
|
|
||||||
|
|
||||||
## v3.0.4119 (2019-01-09)
|
## v3.0.4119 (2019-01-09)
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ We integrate with the following applications:
|
||||||
Supported notifications:
|
Supported notifications:
|
||||||
* SMTP Notifications (Email)
|
* SMTP Notifications (Email)
|
||||||
* Discord
|
* Discord
|
||||||
|
* Gotify
|
||||||
* Slack
|
* Slack
|
||||||
* Pushbullet
|
* Pushbullet
|
||||||
* Pushover
|
* Pushover
|
||||||
|
@ -117,13 +118,12 @@ Please feel free to submit a pull request!
|
||||||
# Donation
|
# Donation
|
||||||
If you feel like donating you can donate with the below buttons!
|
If you feel like donating you can donate with the below buttons!
|
||||||
|
|
||||||
[](https://patreon.com/tidusjar/Ombi)
|
|
||||||
[](https://paypal.me/PlexRequestsNet)
|
[](https://patreon.com/tidusjar/Ombi)
|
||||||
|
[](https://paypal.me/PlexRequestsNet)
|
||||||
|
|
||||||
### A massive thanks to everyone for all their help!
|
### A massive thanks to everyone for all their help!
|
||||||
|
|
||||||
## Stats
|
|
||||||
[](https://waffle.io/tidusjar/PlexRequests.Net/metrics/throughput)
|
|
||||||
|
|
||||||
### Sponsors ###
|
### Sponsors ###
|
||||||
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
|
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
|
||||||
|
|
72
appveyor.yml
72
appveyor.yml
|
@ -1,13 +1,17 @@
|
||||||
version: 3.0.{build}
|
version: 4.0.{build}
|
||||||
configuration: Release
|
configuration: Release
|
||||||
os: Visual Studio 2017
|
os: Visual Studio 2017
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
nodejs_version: "9.8.0"
|
nodejs_version: "11.5.0"
|
||||||
typescript_version: "3.0.1"
|
typescript_version: "3.0.1"
|
||||||
github_auth_token:
|
github_auth_token:
|
||||||
secure: H/7uCrjmWHGJxgN3l9fbhhdVjvvWI8VVF4ZzQqeXuJwAf+PgSNBdxv4SS+rMQ+RH
|
secure: H/7uCrjmWHGJxgN3l9fbhhdVjvvWI8VVF4ZzQqeXuJwAf+PgSNBdxv4SS+rMQ+RH
|
||||||
sonarrcloudtoken:
|
|
||||||
secure: WGkIog4wuMSx1q5vmSOgIBXMtI/leMpLbZhi9MJnJdBBuDfcv12zwXg3LQwY0WbE
|
|
||||||
|
|
||||||
|
# Do not build on tags (GitHub and BitBucket)
|
||||||
|
skip_tags: true
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# Get the latest stable version of Node.js or io.js
|
# Get the latest stable version of Node.js or io.js
|
||||||
|
@ -16,35 +20,45 @@ install:
|
||||||
- cmd: set path=%programfiles(x86)%\\Microsoft SDKs\TypeScript\3.0;%path%
|
- cmd: set path=%programfiles(x86)%\\Microsoft SDKs\TypeScript\3.0;%path%
|
||||||
- cmd: tsc -v
|
- cmd: tsc -v
|
||||||
build_script:
|
build_script:
|
||||||
# - dotnet tool install --global dotnet-sonarscanner
|
- ps: |
|
||||||
#- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { dotnet sonarscanner begin /k:"tidusjar_Ombi" /d:sonar.organization="tidusjar-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$env.sonarrcloud_token" /d:sonar.analysis.mode="preview" /d:sonar.github.pullRequest="$env:APPVEYOR_PULL_REQUEST_NUMBER" /d:sonar.github.repository="https://github.com/tidusjar/ombi" /d:sonar.github.oauth="$env.github_auth_token" }
|
$deployBranches =
|
||||||
# - ps: if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) { dotnet sonarscanner begin /k:"tidusjar_Ombi" /d:sonar.organization="tidusjar-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$env.SONARRCLOUDTOKEN" }
|
"feature/v4",
|
||||||
- ps: ./build.ps1 --settings_skipverification=true
|
"develop",
|
||||||
# - dotnet sonarscanner end /d:sonar.login="%sonarrcloudtoken%"
|
"master";
|
||||||
|
|
||||||
test: off
|
If(($env:APPVEYOR_REPO_BRANCH -in $deployBranches -Or $env:APPVEYOR_REPO_COMMIT_MESSAGE -Match '!deploy') -And $env:APPVEYOR_REPO_COMMIT_MESSAGE -NotMatch '!build') {
|
||||||
|
Write-Output "This is a deployment build"
|
||||||
|
$env:Deploy = 'true'
|
||||||
|
./build.ps1
|
||||||
|
}
|
||||||
|
Else
|
||||||
|
{
|
||||||
|
$env:Deploy = 'false'
|
||||||
|
Write-Output "This is a not a deployment build"
|
||||||
|
./build.ps1 --target=build
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_commits:
|
||||||
|
files:
|
||||||
|
- '**/*.md'
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
- cmd: >-
|
- ps: |
|
||||||
|
$deployBranches =
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\windows.zip"
|
"feature/v4",
|
||||||
|
"develop",
|
||||||
|
"master";
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\osx.tar.gz"
|
|
||||||
|
|
||||||
|
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux.tar.gz"
|
|
||||||
|
|
||||||
|
If(($env:APPVEYOR_REPO_BRANCH -in $deployBranches -Or $env:APPVEYOR_REPO_COMMIT_MESSAGE -Match '!deploy') -And $env:APPVEYOR_REPO_COMMIT_MESSAGE -NotMatch '!build')
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux-arm.tar.gz"
|
{
|
||||||
|
Write-Output "Deploying!"
|
||||||
|
Get-ChildItem -Recurse .\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\windows-32bit.zip"
|
Get-ChildItem -Recurse .\*.gz | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||||
|
}
|
||||||
|
Else
|
||||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux-arm64.tar.gz"
|
{
|
||||||
|
Write-Output "No Deployment"
|
||||||
|
}
|
||||||
|
|
||||||
#cache:
|
#cache:
|
||||||
#- '%USERPROFILE%\.nuget\packages'
|
#- '%USERPROFILE%\.nuget\packages'
|
||||||
|
|
63
build.cake
63
build.cake
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
#tool "nuget:?package=GitVersion.CommandLine"
|
#tool "nuget:?package=GitVersion.CommandLine&version=4.0.0"
|
||||||
#addin "Cake.Gulp"
|
#addin nuget:?package=SharpZipLib&version=1.1.0
|
||||||
#addin "SharpZipLib"
|
#addin nuget:?package=Cake.Compression&version=0.2.2
|
||||||
#addin nuget:?package=Cake.Compression&version=0.1.4
|
#addin "Cake.Incubator&version=3.1.0"
|
||||||
#addin "Cake.Incubator"
|
#addin nuget:?package=Cake.Yarn&version=0.4.5
|
||||||
#addin "Cake.Yarn"
|
#addin "Cake.Powershell"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// ARGUMENTS
|
// ARGUMENTS
|
||||||
|
@ -82,9 +82,9 @@ Task("SetVersionInfo")
|
||||||
|
|
||||||
versionInfo = GitVersion(settings);
|
versionInfo = GitVersion(settings);
|
||||||
|
|
||||||
Information("GitResults -> {0}", versionInfo.Dump());
|
// Information("GitResults -> {0}", versionInfo.Dump());
|
||||||
|
|
||||||
Information(@"Build:{0}",AppVeyor.Environment.Build.Dump());
|
//Information(@"Build:{0}",AppVeyor.Environment.Build.Dump());
|
||||||
|
|
||||||
var buildVersion = string.Empty;
|
var buildVersion = string.Empty;
|
||||||
if(string.IsNullOrEmpty(AppVeyor.Environment.Build.Version))
|
if(string.IsNullOrEmpty(AppVeyor.Environment.Build.Version))
|
||||||
|
@ -135,7 +135,7 @@ Task("Gulp Publish")
|
||||||
Task("TSLint")
|
Task("TSLint")
|
||||||
.Does(() =>
|
.Does(() =>
|
||||||
{
|
{
|
||||||
// Yarn.FromPath(uiProjectDir).RunScript("lint");
|
//Yarn.FromPath(uiProjectDir).RunScript("lint");
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("PrePublish")
|
Task("PrePublish")
|
||||||
|
@ -156,6 +156,7 @@ Task("Package")
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("Publish")
|
Task("Publish")
|
||||||
|
.IsDependentOn("Run-Unit-Tests")
|
||||||
.IsDependentOn("PrePublish")
|
.IsDependentOn("PrePublish")
|
||||||
.IsDependentOn("Publish-Windows")
|
.IsDependentOn("Publish-Windows")
|
||||||
.IsDependentOn("Publish-Windows-32bit")
|
.IsDependentOn("Publish-Windows-32bit")
|
||||||
|
@ -250,9 +251,43 @@ Task("Publish-Linux-ARM-64Bit")
|
||||||
|
|
||||||
Task("Run-Unit-Tests")
|
Task("Run-Unit-Tests")
|
||||||
.Does(() =>
|
.Does(() =>
|
||||||
{
|
{
|
||||||
DotNetCoreBuild(csProj, buildSettings);
|
var settings = new DotNetCoreTestSettings
|
||||||
|
{
|
||||||
|
ArgumentCustomization = args => args.Append("--logger \"trx;LogFileName=Test.trx\""),
|
||||||
|
Configuration = "Release"
|
||||||
|
};
|
||||||
|
var projectFiles = GetFiles("./**/*Tests.csproj");
|
||||||
|
foreach(var file in projectFiles)
|
||||||
|
{
|
||||||
|
DotNetCoreTest(file.FullPath, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
var script = @"
|
||||||
|
$wc = New-Object 'System.Net.WebClient'
|
||||||
|
foreach ($name in Resolve-Path .\src\**\TestResults\Test*.trx)
|
||||||
|
{
|
||||||
|
$wc.UploadFile(""https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)\"", $name)
|
||||||
|
}
|
||||||
|
";
|
||||||
|
// Upload the results
|
||||||
|
StartPowershellScript(script);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task("Run-Server-Build")
|
||||||
|
.Does(() =>
|
||||||
|
{
|
||||||
|
var settings = new DotNetCoreBuildSettings
|
||||||
|
{
|
||||||
|
Framework = frameworkVer,
|
||||||
|
Configuration = "Release",
|
||||||
|
OutputDirectory = Directory(buildDir)
|
||||||
|
};
|
||||||
|
DotNetCoreBuild(csProj, settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
Task("Run-UI-Build")
|
||||||
|
.IsDependentOn("PrePublish");
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// TASK TARGETS
|
// TASK TARGETS
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -260,6 +295,12 @@ Task("Run-Unit-Tests")
|
||||||
Task("Default")
|
Task("Default")
|
||||||
.IsDependentOn("Publish");
|
.IsDependentOn("Publish");
|
||||||
|
|
||||||
|
Task("Build")
|
||||||
|
.IsDependentOn("SetVersionInfo")
|
||||||
|
.IsDependentOn("Run-Unit-Tests")
|
||||||
|
.IsDependentOn("Run-Server-Build");
|
||||||
|
// .IsDependentOn("Run-UI-Build");
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// EXECUTION
|
// EXECUTION
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
135
build.ps1
135
build.ps1
|
@ -21,40 +21,49 @@ The build script target to run.
|
||||||
The build configuration to use.
|
The build configuration to use.
|
||||||
.PARAMETER Verbosity
|
.PARAMETER Verbosity
|
||||||
Specifies the amount of information to be displayed.
|
Specifies the amount of information to be displayed.
|
||||||
.PARAMETER Experimental
|
.PARAMETER ShowDescription
|
||||||
Tells Cake to use the latest Roslyn release.
|
Shows description about tasks.
|
||||||
.PARAMETER WhatIf
|
.PARAMETER DryRun
|
||||||
Performs a dry run of the build script.
|
Performs a dry run.
|
||||||
No tasks will be executed.
|
|
||||||
.PARAMETER Mono
|
|
||||||
Tells Cake to use the Mono scripting engine.
|
|
||||||
.PARAMETER SkipToolPackageRestore
|
.PARAMETER SkipToolPackageRestore
|
||||||
Skips restoring of packages.
|
Skips restoring of packages.
|
||||||
.PARAMETER ScriptArgs
|
.PARAMETER ScriptArgs
|
||||||
Remaining arguments are added here.
|
Remaining arguments are added here.
|
||||||
|
|
||||||
.LINK
|
.LINK
|
||||||
http://cakebuild.net
|
https://cakebuild.net
|
||||||
|
|
||||||
#>
|
#>
|
||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
Param(
|
Param(
|
||||||
[string]$Script = "build.cake",
|
[string]$Script = "build.cake",
|
||||||
[string]$Target = "Default",
|
[string]$Target,
|
||||||
[ValidateSet("Release", "Debug")]
|
[string]$Configuration,
|
||||||
[string]$Configuration = "Release",
|
|
||||||
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
|
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
|
||||||
[string]$Verbosity = "Verbose",
|
[string]$Verbosity,
|
||||||
[switch]$Experimental,
|
[switch]$ShowDescription,
|
||||||
[Alias("DryRun","Noop")]
|
[Alias("WhatIf", "Noop")]
|
||||||
[switch]$WhatIf,
|
[switch]$DryRun,
|
||||||
[switch]$Mono,
|
|
||||||
[switch]$SkipToolPackageRestore,
|
[switch]$SkipToolPackageRestore,
|
||||||
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
|
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
|
||||||
[string[]]$ScriptArgs
|
[string[]]$ScriptArgs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Attempt to set highest encryption available for SecurityProtocol.
|
||||||
|
# PowerShell will not set this by default (until maybe .NET 4.6.x). This
|
||||||
|
# will typically produce a message for PowerShell v2 (just an info
|
||||||
|
# message though)
|
||||||
|
try {
|
||||||
|
# Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48)
|
||||||
|
# Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't
|
||||||
|
# exist in .NET 4.0, even though they are addressable if .NET 4.5+ is
|
||||||
|
# installed (.NET 4.5 is an in-place upgrade).
|
||||||
|
[System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48
|
||||||
|
} catch {
|
||||||
|
Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3'
|
||||||
|
}
|
||||||
|
|
||||||
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
|
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
|
||||||
function MD5HashFile([string] $filePath)
|
function MD5HashFile([string] $filePath)
|
||||||
{
|
{
|
||||||
|
@ -80,6 +89,15 @@ function MD5HashFile([string] $filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetProxyEnabledWebClient
|
||||||
|
{
|
||||||
|
$wc = New-Object System.Net.WebClient
|
||||||
|
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
|
||||||
|
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
|
||||||
|
$wc.Proxy = $proxy
|
||||||
|
return $wc
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Preparing to run build script..."
|
Write-Host "Preparing to run build script..."
|
||||||
|
|
||||||
if(!$PSScriptRoot){
|
if(!$PSScriptRoot){
|
||||||
|
@ -87,31 +105,15 @@ if(!$PSScriptRoot){
|
||||||
}
|
}
|
||||||
|
|
||||||
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
|
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
|
||||||
|
$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
|
||||||
|
$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
|
||||||
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
|
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
|
||||||
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
|
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
|
||||||
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
|
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
|
||||||
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
|
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
|
||||||
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
|
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
|
||||||
|
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
|
||||||
# Should we use mono?
|
$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
|
||||||
$UseMono = "";
|
|
||||||
if($Mono.IsPresent) {
|
|
||||||
Write-Verbose -Message "Using the Mono based scripting engine."
|
|
||||||
$UseMono = "-mono"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Should we use the new Roslyn?
|
|
||||||
$UseExperimental = "";
|
|
||||||
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
|
|
||||||
Write-Verbose -Message "Using experimental version of Roslyn."
|
|
||||||
$UseExperimental = "-experimental"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Is this a dry run?
|
|
||||||
$UseDryRun = "";
|
|
||||||
if($WhatIf.IsPresent) {
|
|
||||||
$UseDryRun = "-dryrun"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make sure tools folder exists
|
# Make sure tools folder exists
|
||||||
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
|
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
|
||||||
|
@ -122,7 +124,10 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
|
||||||
# Make sure that packages.config exist.
|
# Make sure that packages.config exist.
|
||||||
if (!(Test-Path $PACKAGES_CONFIG)) {
|
if (!(Test-Path $PACKAGES_CONFIG)) {
|
||||||
Write-Verbose -Message "Downloading packages.config..."
|
Write-Verbose -Message "Downloading packages.config..."
|
||||||
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
|
try {
|
||||||
|
$wc = GetProxyEnabledWebClient
|
||||||
|
$wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG)
|
||||||
|
} catch {
|
||||||
Throw "Could not download packages.config."
|
Throw "Could not download packages.config."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +147,8 @@ if (!(Test-Path $NUGET_EXE)) {
|
||||||
if (!(Test-Path $NUGET_EXE)) {
|
if (!(Test-Path $NUGET_EXE)) {
|
||||||
Write-Verbose -Message "Downloading NuGet.exe..."
|
Write-Verbose -Message "Downloading NuGet.exe..."
|
||||||
try {
|
try {
|
||||||
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
|
$wc = GetProxyEnabledWebClient
|
||||||
|
$wc.DownloadFile($NUGET_URL, $NUGET_EXE)
|
||||||
} catch {
|
} catch {
|
||||||
Throw "Could not download NuGet.exe."
|
Throw "Could not download NuGet.exe."
|
||||||
}
|
}
|
||||||
|
@ -161,20 +167,56 @@ if(-Not $SkipToolPackageRestore.IsPresent) {
|
||||||
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
|
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
|
||||||
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
|
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
|
||||||
Write-Verbose -Message "Missing or changed package.config hash..."
|
Write-Verbose -Message "Missing or changed package.config hash..."
|
||||||
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
|
Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery |
|
||||||
|
Remove-Item -Recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Verbose -Message "Restoring tools from NuGet..."
|
Write-Verbose -Message "Restoring tools from NuGet..."
|
||||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Throw "An error occured while restoring NuGet tools."
|
Throw "An error occurred while restoring NuGet tools."
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
|
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
|
||||||
}
|
}
|
||||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||||
|
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restore addins from NuGet
|
||||||
|
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
|
||||||
|
Push-Location
|
||||||
|
Set-Location $ADDINS_DIR
|
||||||
|
|
||||||
|
Write-Verbose -Message "Restoring addins from NuGet..."
|
||||||
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Throw "An error occurred while restoring NuGet addins."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||||
|
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restore modules from NuGet
|
||||||
|
if (Test-Path $MODULES_PACKAGES_CONFIG) {
|
||||||
|
Push-Location
|
||||||
|
Set-Location $MODULES_DIR
|
||||||
|
|
||||||
|
Write-Verbose -Message "Restoring modules from NuGet..."
|
||||||
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Throw "An error occurred while restoring NuGet modules."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||||
|
|
||||||
Pop-Location
|
Pop-Location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +225,18 @@ if (!(Test-Path $CAKE_EXE)) {
|
||||||
Throw "Could not find Cake.exe at $CAKE_EXE"
|
Throw "Could not find Cake.exe at $CAKE_EXE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Build Cake arguments
|
||||||
|
$cakeArguments = @("$Script");
|
||||||
|
if ($Target) { $cakeArguments += "-target=$Target" }
|
||||||
|
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
|
||||||
|
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
|
||||||
|
if ($ShowDescription) { $cakeArguments += "-showdescription" }
|
||||||
|
if ($DryRun) { $cakeArguments += "-dryrun" }
|
||||||
|
$cakeArguments += $ScriptArgs
|
||||||
|
|
||||||
# Start Cake
|
# Start Cake
|
||||||
Write-Host "Running build script..."
|
Write-Host "Running build script..."
|
||||||
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
|
&$CAKE_EXE $cakeArguments
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
36
src/Ombi.Api.Gotify/GotifyApi.cs
Normal file
36
src/Ombi.Api.Gotify/GotifyApi.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Gotify
|
||||||
|
{
|
||||||
|
public class GotifyApi : IGotifyApi
|
||||||
|
{
|
||||||
|
public GotifyApi(IApi api)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IApi _api;
|
||||||
|
|
||||||
|
public async Task PushAsync(string baseUrl, string accessToken, string subject, string body, sbyte priority)
|
||||||
|
{
|
||||||
|
var request = new Request("/message", baseUrl, HttpMethod.Post);
|
||||||
|
request.AddQueryString("token", accessToken);
|
||||||
|
|
||||||
|
request.AddHeader("Access-Token", accessToken);
|
||||||
|
request.ApplicationJsonContentType();
|
||||||
|
|
||||||
|
|
||||||
|
var jsonBody = new
|
||||||
|
{
|
||||||
|
message = body,
|
||||||
|
title = subject,
|
||||||
|
priority = priority
|
||||||
|
};
|
||||||
|
|
||||||
|
request.AddJsonBody(jsonBody);
|
||||||
|
|
||||||
|
await _api.Request(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/Ombi.Api.Gotify/IGotifyApi.cs
Normal file
9
src/Ombi.Api.Gotify/IGotifyApi.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Gotify
|
||||||
|
{
|
||||||
|
public interface IGotifyApi
|
||||||
|
{
|
||||||
|
Task PushAsync(string endpoint, string accessToken, string subject, string body, sbyte priority);
|
||||||
|
}
|
||||||
|
}
|
15
src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
Normal file
15
src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
||||||
|
<FileVersion>3.0.0.0</FileVersion>
|
||||||
|
<Version></Version>
|
||||||
|
<PackageVersion></PackageVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -12,5 +12,6 @@ namespace Ombi.Api.Trakt
|
||||||
Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
|
Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
|
Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
|
Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<TraktShow> GetTvExtendedInfo(string imdbId);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@ namespace Ombi.Api.Trakt
|
||||||
|
|
||||||
public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
|
public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
|
||||||
{
|
{
|
||||||
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true, Images = true}, null, page ?? 1, limitPerPage ?? 10);
|
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true, Images = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
return popular.Value;
|
return popular.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@ namespace Ombi.Api.Trakt
|
||||||
var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true, Images = true }, null, page ?? 1, limitPerPage ?? 10);
|
var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true, Images = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
return anticipatedShows.Value;
|
return anticipatedShows.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<TraktShow> GetTvExtendedInfo(string imdbId)
|
||||||
|
{
|
||||||
|
return await Client.Shows.GetShowAsync(imdbId, new TraktExtendedInfo { Full = true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ombi.Api.TvMaze.Models;
|
using Ombi.Api.TvMaze.Models;
|
||||||
|
using Ombi.Api.TvMaze.Models.V2;
|
||||||
|
|
||||||
namespace Ombi.Api.TvMaze
|
namespace Ombi.Api.TvMaze
|
||||||
{
|
{
|
||||||
|
@ -11,5 +12,6 @@ namespace Ombi.Api.TvMaze
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
144
src/Ombi.Api.TvMaze/Models/V2/FullSearch.cs
Normal file
144
src/Ombi.Api.TvMaze/Models/V2/FullSearch.cs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.TvMaze.Models.V2
|
||||||
|
{
|
||||||
|
public class FullSearch
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string language { get; set; }
|
||||||
|
public string[] genres { get; set; }
|
||||||
|
public string status { get; set; }
|
||||||
|
public int runtime { get; set; }
|
||||||
|
public string premiered { get; set; }
|
||||||
|
public string officialSite { get; set; }
|
||||||
|
public Schedule schedule { get; set; }
|
||||||
|
public Rating rating { get; set; }
|
||||||
|
public int weight { get; set; }
|
||||||
|
public Network network { get; set; }
|
||||||
|
public object webChannel { get; set; }
|
||||||
|
public Externals externals { get; set; }
|
||||||
|
public Image image { get; set; }
|
||||||
|
public string summary { get; set; }
|
||||||
|
public int updated { get; set; }
|
||||||
|
public _Links _links { get; set; }
|
||||||
|
public _Embedded _embedded { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Schedule
|
||||||
|
{
|
||||||
|
public string time { get; set; }
|
||||||
|
public string[] days { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Rating
|
||||||
|
{
|
||||||
|
public float average { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Network
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public Country country { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Country
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public string code { get; set; }
|
||||||
|
public string timezone { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Externals
|
||||||
|
{
|
||||||
|
public int tvrage { get; set; }
|
||||||
|
public int thetvdb { get; set; }
|
||||||
|
public string imdb { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Image
|
||||||
|
{
|
||||||
|
public string medium { get; set; }
|
||||||
|
public string original { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class _Links
|
||||||
|
{
|
||||||
|
public Self self { get; set; }
|
||||||
|
public Previousepisode previousepisode { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Self
|
||||||
|
{
|
||||||
|
public string href { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Previousepisode
|
||||||
|
{
|
||||||
|
public string href { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class _Embedded
|
||||||
|
{
|
||||||
|
public Cast[] cast { get; set; }
|
||||||
|
public Crew[] crew { get; set; }
|
||||||
|
public Episode[] episodes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Cast
|
||||||
|
{
|
||||||
|
public Person person { get; set; }
|
||||||
|
public Character character { get; set; }
|
||||||
|
public bool self { get; set; }
|
||||||
|
public bool voice { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public Country country { get; set; }
|
||||||
|
public string birthday { get; set; }
|
||||||
|
public object deathday { get; set; }
|
||||||
|
public string gender { get; set; }
|
||||||
|
public Image image { get; set; }
|
||||||
|
public _Links _links { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Character
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public Image image { get; set; }
|
||||||
|
public _Links _links { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Crew
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public Person person { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Episode
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public int season { get; set; }
|
||||||
|
public int number { get; set; }
|
||||||
|
public string airdate { get; set; }
|
||||||
|
public string airtime { get; set; }
|
||||||
|
public DateTime airstamp { get; set; }
|
||||||
|
public int runtime { get; set; }
|
||||||
|
public Image image { get; set; }
|
||||||
|
public string summary { get; set; }
|
||||||
|
public _Links _links { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
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.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.TvMaze.Models;
|
using Ombi.Api.TvMaze.Models;
|
||||||
|
using Ombi.Api.TvMaze.Models.V2;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
|
||||||
namespace Ombi.Api.TvMaze
|
namespace Ombi.Api.TvMaze
|
||||||
|
@ -15,7 +15,6 @@ namespace Ombi.Api.TvMaze
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
//Mapper = mapper;
|
|
||||||
}
|
}
|
||||||
private string Uri = "http://api.tvmaze.com";
|
private string Uri = "http://api.tvmaze.com";
|
||||||
private IApi Api { get; }
|
private IApi Api { get; }
|
||||||
|
@ -75,5 +74,17 @@ namespace Ombi.Api.TvMaze
|
||||||
return await Api.Request<List<TvMazeSeasons>>(request);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
src/Ombi.Core.Tests/Authentication/OmbiUserManagerTests.cs
Normal file
106
src/Ombi.Core.Tests/Authentication/OmbiUserManagerTests.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Api.Plex;
|
||||||
|
using Ombi.Api.Plex.Models;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Test.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Authentication
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class OmbiUserManagerTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
UserStore = new Mock<IUserStore<OmbiUser>>();
|
||||||
|
PlexApi = new Mock<IPlexApi>();
|
||||||
|
AuthenticationSettings = new Mock<ISettingsService<AuthenticationSettings>>();
|
||||||
|
|
||||||
|
AuthenticationSettings.Setup(x => x.GetSettingsAsync())
|
||||||
|
.ReturnsAsync(new AuthenticationSettings());
|
||||||
|
_um = new OmbiUserManager(UserStore.Object, null, null, null, null, null, null, null, null,
|
||||||
|
PlexApi.Object, null, null, AuthenticationSettings.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OmbiUserManager _um { get; set; }
|
||||||
|
private Mock<IUserStore<OmbiUser>> UserStore { get; set; }
|
||||||
|
private Mock<IPlexApi> PlexApi { get; set; }
|
||||||
|
private Mock<ISettingsService<AuthenticationSettings>> AuthenticationSettings { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CheckPassword_PlexUser_EmailLogin_ValidPassword()
|
||||||
|
{
|
||||||
|
var user = new OmbiUser
|
||||||
|
{
|
||||||
|
UserType = UserType.PlexUser,
|
||||||
|
EmailLogin = true,
|
||||||
|
Email = "MyEmail@email.com"
|
||||||
|
};
|
||||||
|
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||||
|
.ReturnsAsync(new PlexAuthentication
|
||||||
|
{
|
||||||
|
user = new User
|
||||||
|
{
|
||||||
|
authentication_token = "abc"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||||
|
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "MyEmail@email.com")), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CheckPassword_PlexUser_UserNameLogin_ValidPassword()
|
||||||
|
{
|
||||||
|
var user = new OmbiUser
|
||||||
|
{
|
||||||
|
UserType = UserType.PlexUser,
|
||||||
|
EmailLogin = false,
|
||||||
|
Email = "MyEmail@email.com",
|
||||||
|
UserName = "heyhey"
|
||||||
|
};
|
||||||
|
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||||
|
.ReturnsAsync(new PlexAuthentication
|
||||||
|
{
|
||||||
|
user = new User
|
||||||
|
{
|
||||||
|
authentication_token = "abc"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||||
|
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "heyhey")), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CheckPassword_PlexUser_UserNameLogin_InvalidPassword()
|
||||||
|
{
|
||||||
|
var user = new OmbiUser
|
||||||
|
{
|
||||||
|
UserType = UserType.PlexUser,
|
||||||
|
EmailLogin = false,
|
||||||
|
Email = "MyEmail@email.com",
|
||||||
|
UserName = "heyhey"
|
||||||
|
};
|
||||||
|
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||||
|
.ReturnsAsync(new PlexAuthentication());
|
||||||
|
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||||
|
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "heyhey")), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
195
src/Ombi.Core.Tests/Engine/CalendarEngineTests.cs
Normal file
195
src/Ombi.Core.Tests/Engine/CalendarEngineTests.cs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Engine.V2;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Engine
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CalendarEngineTests
|
||||||
|
{
|
||||||
|
public Mock<IMovieRequestRepository> MovieRepo { get; set; }
|
||||||
|
public Mock<ITvRequestRepository> TvRepo { get; set; }
|
||||||
|
public CalendarEngine CalendarEngine { get; set; }
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
MovieRepo = new Mock<IMovieRequestRepository>();
|
||||||
|
TvRepo = new Mock<ITvRequestRepository>();
|
||||||
|
var principle = new Mock<IPrincipal>();
|
||||||
|
var identity = new Mock<IIdentity>();
|
||||||
|
identity.Setup(x => x.Name).Returns("UnitTest");
|
||||||
|
principle.Setup(x => x.Identity).Returns(identity.Object);
|
||||||
|
CalendarEngine = new CalendarEngine(principle.Object, null, null, MovieRepo.Object, TvRepo.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Calendar_Movies_OnlyGet_PreviousAndFuture_90_Days()
|
||||||
|
{
|
||||||
|
var movies = new List<MovieRequests>
|
||||||
|
{
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
Title="Invalid",
|
||||||
|
ReleaseDate = new DateTime(2018,10,01)
|
||||||
|
},
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
Title="Invalid",
|
||||||
|
ReleaseDate = DateTime.Now.AddDays(91)
|
||||||
|
},
|
||||||
|
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
Title="Valid",
|
||||||
|
ReleaseDate = DateTime.Now
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MovieRepo.Setup(x => x.GetAll()).Returns(movies.AsQueryable());
|
||||||
|
var data = await CalendarEngine.GetCalendarData();
|
||||||
|
|
||||||
|
Assert.That(data.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(data[0].Title, Is.EqualTo("Valid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Calendar_Episodes_OnlyGet_PreviousAndFuture_90_Days()
|
||||||
|
{
|
||||||
|
var tv = new List<ChildRequests>
|
||||||
|
{
|
||||||
|
new ChildRequests
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests>
|
||||||
|
{
|
||||||
|
new SeasonRequests
|
||||||
|
{
|
||||||
|
Episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
Title = "Invalid",
|
||||||
|
AirDate = new DateTime(2018,01,01)
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
Title = "Invalid",
|
||||||
|
AirDate = DateTime.Now.AddDays(91)
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
Title = "Valid",
|
||||||
|
AirDate = DateTime.Now
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
TvRepo.Setup(x => x.GetChild()).Returns(tv.AsQueryable());
|
||||||
|
var data = await CalendarEngine.GetCalendarData();
|
||||||
|
|
||||||
|
Assert.That(data.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(data[0].Title, Is.EqualTo("Valid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(StatusTvColorData))]
|
||||||
|
public async Task<string> Calendar_Tv_StatusColor(AvailabilityTestModel model)
|
||||||
|
{
|
||||||
|
var tv = new List<ChildRequests>
|
||||||
|
{
|
||||||
|
new ChildRequests
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests>
|
||||||
|
{
|
||||||
|
new SeasonRequests
|
||||||
|
{
|
||||||
|
Episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
Title = "Valid",
|
||||||
|
AirDate = DateTime.Now,
|
||||||
|
Approved = model.Approved,
|
||||||
|
Available = model.Available
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
TvRepo.Setup(x => x.GetChild()).Returns(tv.AsQueryable());
|
||||||
|
var data = await CalendarEngine.GetCalendarData();
|
||||||
|
|
||||||
|
return data[0].BackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(StatusColorData))]
|
||||||
|
public async Task<string> Calendar_Movie_StatusColor(AvailabilityTestModel model)
|
||||||
|
{
|
||||||
|
var movies = new List<MovieRequests>
|
||||||
|
{
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
Title="Valid",
|
||||||
|
ReleaseDate = DateTime.Now,
|
||||||
|
Denied = model.Denied,
|
||||||
|
Approved = model.Approved,
|
||||||
|
Available = model.Available
|
||||||
|
},
|
||||||
|
};
|
||||||
|
MovieRepo.Setup(x => x.GetAll()).Returns(movies.AsQueryable());
|
||||||
|
var data = await CalendarEngine.GetCalendarData();
|
||||||
|
|
||||||
|
return data[0].BackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> StatusColorData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(new AvailabilityTestModel
|
||||||
|
{
|
||||||
|
Approved = true,
|
||||||
|
Denied = true
|
||||||
|
}).Returns("red").SetName("Calendar_DeniedRequest");
|
||||||
|
foreach (var testCaseData in StatusTvColorData)
|
||||||
|
{
|
||||||
|
yield return testCaseData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> StatusTvColorData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(new AvailabilityTestModel
|
||||||
|
{
|
||||||
|
Available = true,
|
||||||
|
Approved = true
|
||||||
|
}).Returns("#469c83").SetName("Calendar_AvailableRequest");
|
||||||
|
yield return new TestCaseData(new AvailabilityTestModel
|
||||||
|
{
|
||||||
|
Approved = true
|
||||||
|
}).Returns("blue").SetName("Calendar_ApprovedRequest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AvailabilityTestModel
|
||||||
|
{
|
||||||
|
public bool Available { get; set; }
|
||||||
|
public bool Denied { get; set; }
|
||||||
|
public bool Approved { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,16 +3,19 @@ using System.Linq;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AutoFixture;
|
using AutoFixture;
|
||||||
|
using MockQueryable.Moq;
|
||||||
using Moq;
|
using Moq;
|
||||||
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.Engine.Interfaces;
|
using Ombi.Core.Engine.Interfaces;
|
||||||
|
using Ombi.Core.Models;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Test.Common;
|
||||||
|
|
||||||
namespace Ombi.Core.Tests.Engine
|
namespace Ombi.Core.Tests.Engine
|
||||||
{
|
{
|
||||||
|
@ -30,12 +33,17 @@ namespace Ombi.Core.Tests.Engine
|
||||||
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
||||||
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
||||||
User = new Mock<IPrincipal>();
|
User = new Mock<IPrincipal>();
|
||||||
UserManager = new Mock<OmbiUserManager>();
|
User.Setup(x => x.Identity.Name).Returns("abc");
|
||||||
UserManager.Setup(x => x.Users)
|
UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc" } });
|
||||||
.Returns(new EnumerableQuery<OmbiUser>(new List<OmbiUser> {new OmbiUser {Id = "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,
|
||||||
TvRequestEngine.Object, MovieRequestEngine.Object);
|
TvRequestEngine.Object, MovieRequestEngine.Object);
|
||||||
|
|
||||||
|
F.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
|
||||||
|
.ForEach(b => F.Behaviors.Remove(b));
|
||||||
|
F.Behaviors.Add(new OmitOnRecursionBehavior());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fixture F { get; set; }
|
public Fixture F { get; set; }
|
||||||
|
@ -49,25 +57,160 @@ namespace Ombi.Core.Tests.Engine
|
||||||
public Mock<ITvRequestEngine> TvRequestEngine { get; set; }
|
public Mock<ITvRequestEngine> TvRequestEngine { get; set; }
|
||||||
public Mock<IMovieRequestEngine> MovieRequestEngine { get; set; }
|
public Mock<IMovieRequestEngine> MovieRequestEngine { get; set; }
|
||||||
|
|
||||||
[Test]
|
[TestCaseSource(nameof(VoteData))]
|
||||||
[Ignore("Need to mock the user manager")]
|
public async Task Vote(VoteType type, RequestType request)
|
||||||
public async Task New_Upvote()
|
|
||||||
{
|
{
|
||||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings());
|
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||||
|
{
|
||||||
|
Enabled = true,
|
||||||
|
MovieVoteMax = 10
|
||||||
|
});
|
||||||
|
var votes = F.CreateMany<Votes>().ToList();
|
||||||
|
|
||||||
|
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||||
|
.AsQueryable()
|
||||||
|
.BuildMock().Object);
|
||||||
|
var result = new VoteEngineResult();
|
||||||
|
if (type == VoteType.Downvote)
|
||||||
|
{
|
||||||
|
result = await Engine.DownVote(1, request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await Engine.UpVote(1, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Delete(It.IsAny<Votes>()), Times.Never);
|
||||||
|
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> VoteData
|
||||||
|
{
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Movie_Upvote");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("Movie_Downvote");
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Tv_Upvote");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("Tv_Downvote");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(AttemptedTwiceData))]
|
||||||
|
public async Task Attempted_Twice(VoteType type, RequestType request)
|
||||||
|
{
|
||||||
|
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||||
|
{
|
||||||
|
Enabled = true,
|
||||||
|
MovieVoteMax = 10
|
||||||
|
});
|
||||||
var votes = F.CreateMany<Votes>().ToList();
|
var votes = F.CreateMany<Votes>().ToList();
|
||||||
votes.Add(new Votes
|
votes.Add(new Votes
|
||||||
{
|
{
|
||||||
RequestId = 1,
|
RequestId = 1,
|
||||||
RequestType = RequestType.Movie,
|
RequestType = RequestType.Movie,
|
||||||
UserId = "abc"
|
UserId = "abc",
|
||||||
|
VoteType = type
|
||||||
});
|
});
|
||||||
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes));
|
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||||
var result = await Engine.UpVote(1, RequestType.Movie);
|
.AsQueryable()
|
||||||
|
.BuildMock().Object);
|
||||||
|
var result = new VoteEngineResult();
|
||||||
|
if (type == VoteType.Downvote)
|
||||||
|
{
|
||||||
|
result = await Engine.DownVote(1, request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await Engine.UpVote(1, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(result.Result, Is.False);
|
||||||
|
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
|
||||||
|
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> AttemptedTwiceData
|
||||||
|
{
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Upvote_Attemped_Twice_Movie");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("Downvote_Attempted_Twice_Movie");
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Upvote_Attemped_Twice_Tv");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("Downvote_Attempted_Twice_Tv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(VoteConvertData))]
|
||||||
|
public async Task Downvote_Converted_To_Upvote(VoteType type, RequestType request)
|
||||||
|
{
|
||||||
|
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||||
|
{
|
||||||
|
Enabled = true,
|
||||||
|
MovieVoteMax = 10
|
||||||
|
});
|
||||||
|
var votes = F.CreateMany<Votes>().ToList();
|
||||||
|
votes.Add(new Votes
|
||||||
|
{
|
||||||
|
RequestId = 1,
|
||||||
|
RequestType = request,
|
||||||
|
UserId = "abc",
|
||||||
|
VoteType = type == VoteType.Upvote ? VoteType.Downvote : VoteType.Upvote
|
||||||
|
});
|
||||||
|
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||||
|
.AsQueryable()
|
||||||
|
.BuildMock().Object);
|
||||||
|
|
||||||
|
var result = new VoteEngineResult();
|
||||||
|
if (type == VoteType.Downvote)
|
||||||
|
{
|
||||||
|
result = await Engine.DownVote(1, request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await Engine.UpVote(1, request);
|
||||||
|
}
|
||||||
|
Assert.That(result.Result, Is.True);
|
||||||
|
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
|
||||||
|
VoteRepository.Verify(x => x.Add(It.Is<Votes>(v => v.VoteType == type)), Times.Once);
|
||||||
|
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> VoteConvertData
|
||||||
|
{
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Downvote_Converted_To_UpVote_Movie");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("UpVote_Converted_To_DownVote_Movie");
|
||||||
|
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Downvote_Converted_To_UpVote_TvShow");
|
||||||
|
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("UpVote_Converted_To_DownVote_TvShow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(VotingDisabledData))]
|
||||||
|
public async Task Voting_Disabled(RequestType type)
|
||||||
|
{
|
||||||
|
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||||
|
{
|
||||||
|
Enabled = false,
|
||||||
|
MovieVoteMax = 10
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = await Engine.UpVote(1, type);
|
||||||
|
|
||||||
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 == VoteType.Upvote)), Times.Once);
|
VoteRepository.Verify(x => x.Add(It.IsAny<Votes>()), Times.Never);
|
||||||
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
|
}
|
||||||
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
public static IEnumerable<TestCaseData> VotingDisabledData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(RequestType.Movie).SetName("Voting_Disabled_Movie");
|
||||||
|
yield return new TestCaseData(RequestType.TvShow).SetName("Voting_Disabled_TV");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,14 +7,16 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoFixture" Version="4.5.0" />
|
<PackageReference Include="AutoFixture" Version="4.5.0" />
|
||||||
<PackageReference Include="Moq" Version="4.10.0" />
|
<PackageReference Include="Moq" Version="4.10.0" />
|
||||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||||
|
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Test.Common\Ombi.Test.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -4,29 +4,43 @@ using Moq;
|
||||||
using Ombi.Core.Rule.Rules.Request;
|
using Ombi.Core.Rule.Rules.Request;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Test.Common;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ombi.Core.Tests.Rule.Request
|
namespace Ombi.Core.Tests.Rule.Request
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AutoApproveRuleTests
|
public class AutoApproveRuleTests
|
||||||
{
|
{
|
||||||
|
private List<OmbiUser> _users = new List<OmbiUser>
|
||||||
|
{
|
||||||
|
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="abc" }
|
||||||
|
};
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
PrincipalMock = new Mock<IPrincipal>();
|
PrincipalMock = new Mock<IPrincipal>();
|
||||||
Rule = new AutoApproveRule(PrincipalMock.Object);
|
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
|
||||||
|
|
||||||
|
UserManager = MockHelper.MockUserManager(_users);
|
||||||
|
Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AutoApproveRule Rule { get; set; }
|
private AutoApproveRule Rule { get; set; }
|
||||||
private Mock<IPrincipal> PrincipalMock { get; set; }
|
private Mock<IPrincipal> PrincipalMock { get; set; }
|
||||||
|
private Mock<OmbiUserManager> UserManager { get; set; }
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie()
|
public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(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 BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
@ -37,7 +51,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenAdminAndRequestTV()
|
public async Task Should_ReturnSuccess_WhenAdminAndRequestTV()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -48,7 +62,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
|
public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.AutoApproveMovie)).Returns(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 BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
@ -56,10 +70,21 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
Assert.True(request.Approved);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_ReturnFail_WhenAutoApproveMovie_And_RequestTV()
|
||||||
|
{
|
||||||
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true);
|
||||||
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV()
|
public async Task Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.AutoApproveTv)).Returns(true);
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(true);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -67,9 +92,21 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
Assert.True(request.Approved);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_ReturnFail_WhenAutoApproveTV_And_RequestMovie()
|
||||||
|
{
|
||||||
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(true);
|
||||||
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnFail_WhenNoClaimsAndRequestMovie()
|
public async Task Should_ReturnFail_WhenNoClaimsAndRequestMovie()
|
||||||
{
|
{
|
||||||
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).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);
|
||||||
|
|
||||||
|
@ -80,6 +117,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnFail_WhenNoClaimsAndRequestTV()
|
public async Task Should_ReturnFail_WhenNoClaimsAndRequestTV()
|
||||||
{
|
{
|
||||||
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).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);
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Rule.Rules;
|
using Ombi.Core.Rule.Rules;
|
||||||
|
using Ombi.Core.Rule.Rules.Request;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Test.Common;
|
||||||
|
|
||||||
namespace Ombi.Core.Tests.Rule.Request
|
namespace Ombi.Core.Tests.Rule.Request
|
||||||
{
|
{
|
||||||
public class CanRequestRuleTests
|
public class CanRequestRuleTests
|
||||||
{
|
{
|
||||||
|
private List<OmbiUser> _users = new List<OmbiUser>
|
||||||
|
{
|
||||||
|
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="abc" }
|
||||||
|
};
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
PrincipalMock = new Mock<IPrincipal>();
|
PrincipalMock = new Mock<IPrincipal>();
|
||||||
Rule = new CanRequestRule(PrincipalMock.Object);
|
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
|
||||||
|
|
||||||
|
UserManager = MockHelper.MockUserManager(_users);
|
||||||
|
Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private CanRequestRule Rule { get; set; }
|
private CanRequestRule Rule { get; set; }
|
||||||
private Mock<IPrincipal> PrincipalMock { get; set; }
|
private Mock<IPrincipal> PrincipalMock { get; set; }
|
||||||
|
private Mock<OmbiUserManager> UserManager { get; set; }
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
|
public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestMovie)).Returns(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 BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
@ -35,7 +50,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
|
public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestMovie)).Returns(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 BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
@ -46,7 +61,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenRequestingMovieWithAdminRole()
|
public async Task Should_ReturnSuccess_WhenRequestingMovieWithAdminRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(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 BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
@ -56,7 +71,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenRequestingTVWithAdminRole()
|
public async Task Should_ReturnSuccess_WhenRequestingTVWithAdminRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -66,7 +81,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnSuccess_WhenRequestingTVWithTVRole()
|
public async Task Should_ReturnSuccess_WhenRequestingTVWithTVRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestTv)).Returns(true);
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestTv)).ReturnsAsync(true);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -76,7 +91,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Should_ReturnFail_WhenRequestingTVWithoutTVRole()
|
public async Task Should_ReturnFail_WhenRequestingTVWithoutTVRole()
|
||||||
{
|
{
|
||||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestTv)).Returns(false);
|
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestTv)).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);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MockQueryable.Moq;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Rule.Rules;
|
||||||
|
using Ombi.Core.Rule.Rules.Request;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
using Ombi.Test.Common;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Rule.Request
|
||||||
|
{
|
||||||
|
public class ExistingMovieRequestRuleTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
ContextMock = new Mock<IMovieRequestRepository>();
|
||||||
|
Rule = new ExistingMovieRequestRule(ContextMock.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ExistingMovieRequestRule Rule { get; set; }
|
||||||
|
private Mock<IMovieRequestRepository> ContextMock { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ExistingRequestRule_Movie_Has_Been_Requested_With_TheMovieDBId()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||||
|
{
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
TheMovieDbId = 1,
|
||||||
|
RequestType = RequestType.Movie
|
||||||
|
}
|
||||||
|
}.AsQueryable().BuildMock().Object);
|
||||||
|
var o = new MovieRequests
|
||||||
|
{
|
||||||
|
TheMovieDbId = 1,
|
||||||
|
};
|
||||||
|
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_Has_Been_Requested_With_ImdbId()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||||
|
{
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
TheMovieDbId = 11111,
|
||||||
|
ImdbId = 1.ToString(),
|
||||||
|
RequestType = RequestType.Movie
|
||||||
|
}
|
||||||
|
}.AsQueryable().BuildMock().Object);
|
||||||
|
var o = new MovieRequests
|
||||||
|
{
|
||||||
|
ImdbId = 1.ToString(),
|
||||||
|
};
|
||||||
|
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_HasNot_Been_Requested()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||||
|
{
|
||||||
|
new MovieRequests
|
||||||
|
{
|
||||||
|
TheMovieDbId = 2,
|
||||||
|
ImdbId = "2",
|
||||||
|
RequestType = RequestType.Movie
|
||||||
|
}
|
||||||
|
}.AsQueryable().BuildMock().Object);
|
||||||
|
var o = new MovieRequests
|
||||||
|
{
|
||||||
|
TheMovieDbId = 1,
|
||||||
|
ImdbId = "1"
|
||||||
|
};
|
||||||
|
var result = await Rule.Execute(o);
|
||||||
|
|
||||||
|
Assert.That(result.Success, Is.True);
|
||||||
|
Assert.That(result.Message, Is.Null.Or.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
201
src/Ombi.Core.Tests/Rule/Search/AvailabilityRuleHelperTests.cs
Normal file
201
src/Ombi.Core.Tests/Rule/Search/AvailabilityRuleHelperTests.cs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Rules.Search;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Rule.Search
|
||||||
|
{
|
||||||
|
public class AvailabilityRuleHelperTests
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Is_Available_When_All_We_Have_All_Aired_Episodes()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = true
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(1), // Tomorrow!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Is_Available_When_All_We_Have_All_Aired_Episodes_With_Unknown_Dates()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = true
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue, // Unknown date!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Is_PartlyAvailable_When_All_We_Have_Some_Aired_Episodes()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = true
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-14), // Yesterday
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue, // Unknown date!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.False);
|
||||||
|
Assert.That(model.PartlyAvailable, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Is_SeasonAvailable_When_All_We_Have_All_Aired_Episodes_In_A_Season()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = true
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-14), // Yesterday
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue, // Unknown date!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var availableEpisodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = true
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests>
|
||||||
|
{
|
||||||
|
new SeasonRequests { Episodes = episodes },
|
||||||
|
new SeasonRequests { Episodes = availableEpisodes },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.False);
|
||||||
|
Assert.That(model.PartlyAvailable, Is.True);
|
||||||
|
Assert.That(model.SeasonRequests[1].SeasonAvailable, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Is_NotAvailable_When_All_We_Have_No_Aired_Episodes()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.Now.AddDays(-14),
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue, // Unknown date!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.False);
|
||||||
|
Assert.That(model.PartlyAvailable, Is.False);
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void Is_NotAvailable_When_All_Episodes_Are_Unknown()
|
||||||
|
{
|
||||||
|
var episodes = new List<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue,
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue,
|
||||||
|
Available = false
|
||||||
|
},
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
AirDate = DateTime.MinValue, // Unknown date!
|
||||||
|
Available = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||||
|
};
|
||||||
|
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||||
|
Assert.That(model.FullyAvailable, Is.False);
|
||||||
|
Assert.That(model.PartlyAvailable, Is.False);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ 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.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
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;
|
||||||
|
@ -16,15 +18,18 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
ContextMock = new Mock<IEmbyContentRepository>();
|
ContextMock = new Mock<IEmbyContentRepository>();
|
||||||
Rule = new EmbyAvailabilityRule(ContextMock.Object);
|
SettingsMock = new Mock<ISettingsService<EmbySettings>>();
|
||||||
|
Rule = new EmbyAvailabilityRule(ContextMock.Object, SettingsMock.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; }
|
||||||
|
|
||||||
[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"
|
ProviderId = "123"
|
||||||
|
@ -39,6 +44,64 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
Assert.True(search.Available);
|
Assert.True(search.Available);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Movie_Has_Custom_Url_When_Specified_In_Settings()
|
||||||
|
{
|
||||||
|
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings
|
||||||
|
{
|
||||||
|
Enable = true,
|
||||||
|
Servers = new List<EmbyServers>
|
||||||
|
{
|
||||||
|
new EmbyServers
|
||||||
|
{
|
||||||
|
ServerHostname = "http://test.com/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||||
|
{
|
||||||
|
ProviderId = "123",
|
||||||
|
EmbyId = 1.ToString()
|
||||||
|
});
|
||||||
|
var search = new SearchMovieViewModel()
|
||||||
|
{
|
||||||
|
TheMovieDbId = "123",
|
||||||
|
};
|
||||||
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/#!/itemdetails.html?id=1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Movie_Uses_Default_Url_When()
|
||||||
|
{
|
||||||
|
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings
|
||||||
|
{
|
||||||
|
Enable = true,
|
||||||
|
Servers = new List<EmbyServers>
|
||||||
|
{
|
||||||
|
new EmbyServers
|
||||||
|
{
|
||||||
|
ServerHostname = string.Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||||
|
{
|
||||||
|
ProviderId = "123",
|
||||||
|
EmbyId = 1.ToString()
|
||||||
|
});
|
||||||
|
var search = new SearchMovieViewModel()
|
||||||
|
{
|
||||||
|
TheMovieDbId = "123",
|
||||||
|
};
|
||||||
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/#!/itemdetails.html?id=1"));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInEmby()
|
public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInEmby()
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,7 @@ using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
namespace Ombi.Core.Tests.Rule.Search
|
namespace Ombi.Core.Tests.Rule.Search
|
||||||
{
|
{
|
||||||
public class ExistignRequestRuleTests
|
public class ExistingRequestRuleTests
|
||||||
{
|
{
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
@ -39,18 +39,16 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
RequestType = RequestType.Movie
|
RequestType = RequestType.Movie
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list);
|
||||||
var search = new SearchMovieViewModel
|
var search = new SearchMovieViewModel
|
||||||
{
|
{
|
||||||
Id = 123,
|
Id = 123,
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
var result = await Rule.Execute(search);
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
Assert.True(result.Success);
|
Assert.That(result.Success, Is.True);
|
||||||
Assert.True(search.Approved);
|
Assert.That(search.Approved, Is.True);
|
||||||
Assert.True(search.Requested);
|
Assert.That(search.Requested, Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -62,7 +60,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
Approved = true
|
Approved = true
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list);
|
||||||
var search = new SearchMovieViewModel
|
var search = new SearchMovieViewModel
|
||||||
{
|
{
|
||||||
Id = 999,
|
Id = 999,
|
||||||
|
|
126
src/Ombi.Core.Tests/Rule/Search/LidarrAlbumCacheRuleTests.cs
Normal file
126
src/Ombi.Core.Tests/Rule/Search/LidarrAlbumCacheRuleTests.cs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Rules.Search;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Rule.Search
|
||||||
|
{
|
||||||
|
public class LidarrAlbumCacheRuleTests
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
ContextMock = new Mock<IExternalRepository<LidarrAlbumCache>>();
|
||||||
|
Rule = new LidarrAlbumCacheRule(ContextMock.Object);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private LidarrAlbumCacheRule Rule { get; set; }
|
||||||
|
private Mock<IExternalRepository<LidarrAlbumCache>> ContextMock { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Not_Be_Monitored_Or_Available()
|
||||||
|
{
|
||||||
|
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
Assert.False(request.Monitored);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored_But_Not_Available()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||||
|
{
|
||||||
|
new LidarrAlbumCache
|
||||||
|
{
|
||||||
|
ForeignAlbumId = "abc",
|
||||||
|
PercentOfTracks = 0
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||||
|
Assert.That(request.Available, Is.EqualTo(false));
|
||||||
|
Assert.That(request.FullyAvailable, Is.EqualTo(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored_And_Partly_Available()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||||
|
{
|
||||||
|
new LidarrAlbumCache
|
||||||
|
{
|
||||||
|
ForeignAlbumId = "abc",
|
||||||
|
PercentOfTracks = 1
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
Assert.That(request.PartiallyAvailable, Is.EqualTo(true));
|
||||||
|
Assert.That(request.Available, Is.EqualTo(false));
|
||||||
|
Assert.That(request.FullyAvailable, Is.EqualTo(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored_And_Fully_Available()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||||
|
{
|
||||||
|
new LidarrAlbumCache
|
||||||
|
{
|
||||||
|
ForeignAlbumId = "abc",
|
||||||
|
PercentOfTracks = 100
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||||
|
Assert.That(request.FullyAvailable, Is.EqualTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored_And_Fully_Available_Casing()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||||
|
{
|
||||||
|
new LidarrAlbumCache
|
||||||
|
{
|
||||||
|
ForeignAlbumId = "abc",
|
||||||
|
PercentOfTracks = 100
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchAlbumViewModel { ForeignAlbumId = "ABC" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Approved);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||||
|
Assert.That(request.FullyAvailable, Is.EqualTo(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Rules.Search;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests.Rule.Search
|
||||||
|
{
|
||||||
|
public class LidarrArtistCacheRuleTests
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
ContextMock = new Mock<IExternalRepository<LidarrArtistCache>>();
|
||||||
|
Rule = new LidarrArtistCacheRule(ContextMock.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LidarrArtistCacheRule Rule { get; set; }
|
||||||
|
private Mock<IExternalRepository<LidarrArtistCache>> ContextMock { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Not_Be_Monitored()
|
||||||
|
{
|
||||||
|
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.False(request.Monitored);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrArtistCache>
|
||||||
|
{
|
||||||
|
new LidarrArtistCache
|
||||||
|
{
|
||||||
|
ForeignArtistId = "abc",
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Should_Be_Monitored_Casing()
|
||||||
|
{
|
||||||
|
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrArtistCache>
|
||||||
|
{
|
||||||
|
new LidarrArtistCache
|
||||||
|
{
|
||||||
|
ForeignArtistId = "abc",
|
||||||
|
}
|
||||||
|
}.AsQueryable());
|
||||||
|
var request = new SearchArtistViewModel { ForignArtistId = "ABC" };
|
||||||
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
|
Assert.True(result.Success);
|
||||||
|
Assert.True(request.Monitored);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using Ombi.Core.Models.Search;
|
|
||||||
using Ombi.Core.Rule.Rules.Search;
|
|
||||||
using Ombi.Store.Entities;
|
|
||||||
using Ombi.Store.Repository;
|
|
||||||
|
|
||||||
namespace Ombi.Core.Tests.Rule.Search
|
|
||||||
{
|
|
||||||
public class PlexAvailabilityRuleTests
|
|
||||||
{
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
ContextMock = new Mock<IPlexContentRepository>();
|
|
||||||
Rule = new PlexAvailabilityRule(ContextMock.Object);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlexAvailabilityRule Rule { get; set; }
|
|
||||||
private Mock<IPlexContentRepository> ContextMock { get; set; }
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task ShouldBe_Available_WhenFoundInPlex()
|
|
||||||
{
|
|
||||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).ReturnsAsync(new PlexServerContent
|
|
||||||
{
|
|
||||||
Url = "TestUrl",
|
|
||||||
ImdbId = "132"
|
|
||||||
});
|
|
||||||
|
|
||||||
var search = new SearchMovieViewModel
|
|
||||||
{
|
|
||||||
ImdbId = "123",
|
|
||||||
};
|
|
||||||
var result = await Rule.Execute(search);
|
|
||||||
|
|
||||||
Assert.True(result.Success);
|
|
||||||
Assert.AreEqual("TestUrl", search.PlexUrl);
|
|
||||||
Assert.True(search.Available);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task ShouldBe_NotAvailable_WhenNotFoundInPlex()
|
|
||||||
{
|
|
||||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).Returns(Task.FromResult(default(PlexServerContent)));
|
|
||||||
var search = new SearchMovieViewModel();
|
|
||||||
var result = await Rule.Execute(search);
|
|
||||||
|
|
||||||
Assert.True(result.Success);
|
|
||||||
Assert.Null(search.PlexUrl);
|
|
||||||
Assert.False(search.Available);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,7 @@ namespace Ombi.Core.Tests
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multipe Chars");
|
yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multiple Chars");
|
||||||
yield return new TestCaseData("What is this madness'",new []{'\'','^','*'}).Returns("What is this madness").SetName("Basic Strip Multipe Chars");
|
yield return new TestCaseData("What is this madness'",new []{'\'','^','*'}).Returns("What is this madness").SetName("Basic Strip Multipe Chars");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
Normal file
106
src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Ombi.Api.TheMovieDb;
|
||||||
|
using Ombi.Api.TheMovieDb.Models;
|
||||||
|
using Ombi.Config;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine.Demo
|
||||||
|
{
|
||||||
|
public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine
|
||||||
|
{
|
||||||
|
public DemoMovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
||||||
|
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s,
|
||||||
|
IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
|
||||||
|
: base(identity, service, movApi, mapper, logger, r, um, mem, s, sub)
|
||||||
|
{
|
||||||
|
_demoLists = lists.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly DemoLists _demoLists;
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> Search(string search)
|
||||||
|
{
|
||||||
|
var result = await MovieApi.SearchMovie(search, null, "en");
|
||||||
|
|
||||||
|
for (var i = 0; i < result.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_demoLists.Movies.Contains(result[i].Id))
|
||||||
|
{
|
||||||
|
result.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(result.Count > 0)
|
||||||
|
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||||
|
{
|
||||||
|
var rand = new Random();
|
||||||
|
var responses = new List<SearchMovieViewModel>();
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
var item = rand.Next(_demoLists.Movies.Length);
|
||||||
|
var movie = _demoLists.Movies[item];
|
||||||
|
if (responses.Any(x => x.Id == movie))
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var movieResult = await MovieApi.GetMovieInformationWithExtraInfo(movie);
|
||||||
|
var viewMovie = Mapper.Map<SearchMovieViewModel>(movieResult);
|
||||||
|
|
||||||
|
responses.Add(await ProcessSingleMovie(viewMovie));
|
||||||
|
}
|
||||||
|
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||||
|
{
|
||||||
|
return await NowPlayingMovies();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||||
|
{
|
||||||
|
return await NowPlayingMovies();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||||
|
{
|
||||||
|
|
||||||
|
return await NowPlayingMovies();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDemoMovieSearchEngine
|
||||||
|
{
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies();
|
||||||
|
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||||
|
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> Search(string search);
|
||||||
|
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||||
|
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
96
src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
Normal file
96
src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Ombi.Api.Trakt;
|
||||||
|
using Ombi.Api.TvMaze;
|
||||||
|
using Ombi.Config;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine.Demo
|
||||||
|
{
|
||||||
|
public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine
|
||||||
|
{
|
||||||
|
|
||||||
|
public DemoTvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
|
||||||
|
ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo,
|
||||||
|
IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache,
|
||||||
|
ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
|
||||||
|
: base(identity, service, tvMaze, mapper, plexSettings, embySettings, repo, embyRepo, trakt, r, um, memCache, s, sub)
|
||||||
|
{
|
||||||
|
_demoLists = lists.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly DemoLists _demoLists;
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string search)
|
||||||
|
{
|
||||||
|
var searchResult = await TvMazeApi.Search(search);
|
||||||
|
|
||||||
|
for (var i = 0; i < searchResult.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_demoLists.TvShows.Contains(searchResult[i].show?.externals?.thetvdb ?? 0))
|
||||||
|
{
|
||||||
|
searchResult.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchResult != null)
|
||||||
|
{
|
||||||
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
|
foreach (var tvMazeSearch in searchResult)
|
||||||
|
{
|
||||||
|
if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
retVal.Add(ProcessResult(tvMazeSearch));
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchTvShowViewModel>> NowPlayingMovies()
|
||||||
|
{
|
||||||
|
var rand = new Random();
|
||||||
|
var responses = new List<SearchTvShowViewModel>();
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
var item = rand.Next(_demoLists.TvShows.Length);
|
||||||
|
var tv = _demoLists.TvShows[item];
|
||||||
|
if (responses.Any(x => x.Id == tv))
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var movieResult = await TvMazeApi.ShowLookup(tv);
|
||||||
|
responses.Add(ProcessResult(movieResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDemoTvSearchEngine
|
||||||
|
{
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> Search(string search);
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> NowPlayingMovies();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,24 @@
|
||||||
using Ombi.Core.Models.Search;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
using Ombi.Core.Models.Search.V2;
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
|
||||||
namespace Ombi.Core
|
namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
public interface IMovieEngineV2
|
public interface IMovieEngineV2
|
||||||
{
|
{
|
||||||
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, string langCode = null);
|
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, string langCode = null);
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode);
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies();
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies();
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad);
|
||||||
|
Task<MovieCollectionsViewModel> GetCollection(int collectionId, string langCode = null);
|
||||||
|
Task<int> GetTvDbId(int theMovieDbId);
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad);
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies(int currentlyLoaded, int toLoad);
|
||||||
|
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentlyLoaded, int toLoad);
|
||||||
|
int ResultLimit { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.UI;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.Interfaces
|
namespace Ombi.Core.Engine.Interfaces
|
||||||
|
@ -13,10 +14,11 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
|
|
||||||
Task RemoveMovieRequest(int requestId);
|
Task RemoveMovieRequest(int requestId);
|
||||||
Task RemoveAllMovieRequests();
|
Task RemoveAllMovieRequests();
|
||||||
|
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);
|
||||||
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
||||||
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason);
|
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason);
|
||||||
|
Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,5 +23,6 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<IEnumerable<TvRequests>> GetRequestsLite();
|
Task<IEnumerable<TvRequests>> GetRequestsLite();
|
||||||
Task UpdateQualityProfile(int requestId, int profileId);
|
Task UpdateQualityProfile(int requestId, int profileId);
|
||||||
Task UpdateRootPath(int requestId, int rootPath);
|
Task UpdateRootPath(int requestId, int rootPath);
|
||||||
|
Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,9 +9,13 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
|
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
|
||||||
Task<SearchTvShowViewModel> GetShowInformation(int tvdbid);
|
Task<SearchTvShowViewModel> GetShowInformation(int tvdbid);
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> Popular();
|
Task<IEnumerable<SearchTvShowViewModel>> Popular();
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad);
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
|
Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad);
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
|
Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> Trending();
|
Task<IEnumerable<SearchTvShowViewModel>> Trending();
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> MostWatches(int currentlyLoaded, int amountToLoad);
|
||||||
|
Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad);
|
||||||
int ResultLimit { get; set; }
|
int ResultLimit { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
10
src/Ombi.Core/Engine/Interfaces/ITvSearchEngineV2.cs
Normal file
10
src/Ombi.Core/Engine/Interfaces/ITvSearchEngineV2.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
|
||||||
|
namespace Ombi.Core
|
||||||
|
{
|
||||||
|
public interface ITVSearchEngineV2
|
||||||
|
{
|
||||||
|
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
|
@ -200,6 +201,54 @@ namespace Ombi.Core.Engine
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<MovieRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MovieRepository.GetWithUser(shouldHide
|
||||||
|
.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MovieRepository
|
||||||
|
.GetWithUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true);
|
||||||
|
|
||||||
|
if (sortProperty.Contains('.'))
|
||||||
|
{
|
||||||
|
// This is a navigation property currently not supported
|
||||||
|
prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find("RequestedDate", true);
|
||||||
|
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||||
|
//var propType = firstProp.PropertyType;
|
||||||
|
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
? allRequests.OrderBy(x => prop.GetValue(x))
|
||||||
|
: allRequests.OrderByDescending(x => prop.GetValue(x));
|
||||||
|
var total = await allRequests.CountAsync();
|
||||||
|
var requests = await allRequests.Skip(position).Take(count)
|
||||||
|
.ToListAsync();
|
||||||
|
requests.ForEach(async x =>
|
||||||
|
{
|
||||||
|
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
|
||||||
|
await CheckForSubscription(shouldHide, x);
|
||||||
|
});
|
||||||
|
return new RequestsViewModel<MovieRequests>
|
||||||
|
{
|
||||||
|
Collection = requests,
|
||||||
|
Total = total
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> allRequests, OrderType type)
|
private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> allRequests, OrderType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -259,6 +308,15 @@ namespace Ombi.Core.Engine
|
||||||
return allRequests;
|
return allRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<MovieRequests> GetRequest(int requestId)
|
||||||
|
{
|
||||||
|
var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync();
|
||||||
|
request.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath);
|
||||||
|
await CheckForSubscription(new HideResult(), request);
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x)
|
private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x)
|
||||||
{
|
{
|
||||||
if (shouldHide.UserId == x.RequestedUserId)
|
if (shouldHide.UserId == x.RequestedUserId)
|
||||||
|
@ -493,7 +551,7 @@ namespace Ombi.Core.Engine
|
||||||
RequestType = RequestType.Movie,
|
RequestType = RequestType.Movie,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!", RequestId = model.Id};
|
return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!", RequestId = model.Id };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||||
|
@ -533,7 +591,7 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
return new RequestQuotaCountModel()
|
return new RequestQuotaCountModel()
|
||||||
{
|
{
|
||||||
HasLimit = true,
|
HasLimit = true,
|
||||||
Limit = limit,
|
Limit = limit,
|
||||||
Remaining = count,
|
Remaining = count,
|
||||||
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||||
|
|
|
@ -31,10 +31,11 @@ namespace Ombi.Core.Engine
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMovieDbApi MovieApi { get; }
|
protected IMovieDbApi MovieApi { get; }
|
||||||
private IMapper Mapper { get; }
|
protected IMapper Mapper { get; }
|
||||||
private ILogger<MovieSearchEngine> Logger { get; }
|
private ILogger<MovieSearchEngine> Logger { get; }
|
||||||
|
|
||||||
|
protected const int MovieLimit = 10;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lookups the imdb information.
|
/// Lookups the imdb information.
|
||||||
|
@ -185,7 +186,7 @@ namespace Ombi.Core.Engine
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||||
IEnumerable<MovieSearchResult> movies)
|
IEnumerable<MovieSearchResult> movies)
|
||||||
{
|
{
|
||||||
var viewMovies = new List<SearchMovieViewModel>();
|
var viewMovies = new List<SearchMovieViewModel>();
|
||||||
|
@ -196,7 +197,7 @@ namespace Ombi.Core.Engine
|
||||||
return viewMovies;
|
return viewMovies;
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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())
|
||||||
{
|
{
|
||||||
|
@ -214,7 +215,7 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
// This requires the rules to be run first to populate the RequestId property
|
// This requires the rules to be run first to populate the RequestId property
|
||||||
await CheckForSubscription(viewMovie);
|
await CheckForSubscription(viewMovie);
|
||||||
|
|
||||||
return viewMovie;
|
return viewMovie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +229,7 @@ namespace Ombi.Core.Engine
|
||||||
}
|
}
|
||||||
var request = await RequestService.MovieRequestService.GetAll()
|
var request = await RequestService.MovieRequestService.GetAll()
|
||||||
.AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id);
|
.AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id);
|
||||||
if (request)
|
if (request || viewModel.Available)
|
||||||
{
|
{
|
||||||
viewModel.ShowSubscribe = false;
|
viewModel.ShowSubscribe = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,12 @@ namespace Ombi.Core.Engine
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(album?.artist == null)
|
||||||
|
{
|
||||||
|
// Lookup the artist
|
||||||
|
//album.artist = await _lidarrApi.ArtistLookup(album.artist, s.ApiKey, s.FullUri);
|
||||||
|
}
|
||||||
|
|
||||||
var userDetails = await GetUser();
|
var userDetails = await GetUser();
|
||||||
|
|
||||||
var requestModel = new AlbumRequest
|
var requestModel = new AlbumRequest
|
||||||
|
@ -83,7 +89,7 @@ namespace Ombi.Core.Engine
|
||||||
Title = album.title,
|
Title = album.title,
|
||||||
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
||||||
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
|
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
|
||||||
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty,
|
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty, // This needs to be populated to send to Lidarr for new requests
|
||||||
RequestedByAlias = model.RequestedByAlias
|
RequestedByAlias = model.RequestedByAlias
|
||||||
};
|
};
|
||||||
if (requestModel.Cover.IsNullOrEmpty())
|
if (requestModel.Cover.IsNullOrEmpty())
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Ombi.Core.Models.Search;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
|
@ -31,14 +32,13 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
|
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
|
||||||
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
||||||
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
|
ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
|
||||||
IRepository<RequestSubscription> sub) : base(user, requestService, rule, manager, cache, settings, sub)
|
IRepository<RequestSubscription> sub) : base(user, requestService, rule, manager, cache, settings, sub)
|
||||||
{
|
{
|
||||||
TvApi = tvApi;
|
TvApi = tvApi;
|
||||||
MovieDbApi = movApi;
|
MovieDbApi = movApi;
|
||||||
NotificationHelper = helper;
|
NotificationHelper = helper;
|
||||||
TvSender = sender;
|
TvSender = sender;
|
||||||
Audit = audit;
|
|
||||||
_requestLog = rl;
|
_requestLog = rl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ namespace Ombi.Core.Engine
|
||||||
private ITvMazeApi TvApi { get; }
|
private ITvMazeApi TvApi { get; }
|
||||||
private IMovieDbApi MovieDbApi { get; }
|
private IMovieDbApi MovieDbApi { get; }
|
||||||
private ITvSender TvSender { get; }
|
private ITvSender TvSender { get; }
|
||||||
private IAuditRepository Audit { get; }
|
|
||||||
private readonly IRepository<RequestLog> _requestLog;
|
private readonly IRepository<RequestLog> _requestLog;
|
||||||
|
|
||||||
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
|
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
|
||||||
|
@ -84,8 +83,6 @@ namespace Ombi.Core.Engine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tvBuilder.ChildRequest.Title}", Username);
|
|
||||||
|
|
||||||
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId);
|
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId);
|
||||||
if (existingRequest != null)
|
if (existingRequest != null)
|
||||||
{
|
{
|
||||||
|
@ -160,7 +157,7 @@ namespace Ombi.Core.Engine
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault())
|
.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault())
|
||||||
.Skip(position).Take(count).ToListAsync();
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||||
|
@ -225,6 +222,59 @@ namespace Ombi.Core.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<ChildRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.GetChild(shouldHide.UserId).ToListAsync();
|
||||||
|
|
||||||
|
// Filter out children
|
||||||
|
|
||||||
|
FilterChildren(allRequests, shouldHide);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.GetChild().ToListAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allRequests == null)
|
||||||
|
{
|
||||||
|
return new RequestsViewModel<ChildRequests>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var total = allRequests.Count;
|
||||||
|
|
||||||
|
|
||||||
|
var prop = TypeDescriptor.GetProperties(typeof(ChildRequests)).Find(sortProperty, true);
|
||||||
|
|
||||||
|
if (sortProperty.Contains('.'))
|
||||||
|
{
|
||||||
|
// This is a navigation property currently not supported
|
||||||
|
prop = TypeDescriptor.GetProperties(typeof(ChildRequests)).Find("Title", true);
|
||||||
|
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||||
|
//var propType = firstProp.PropertyType;
|
||||||
|
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||||
|
}
|
||||||
|
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
? allRequests.OrderBy(x => prop.GetValue(x)).ToList()
|
||||||
|
: allRequests.OrderByDescending(x => prop.GetValue(x)).ToList();
|
||||||
|
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||||
|
|
||||||
|
// Make sure we do not show duplicate child requests
|
||||||
|
allRequests = allRequests.DistinctBy(x => x.ParentRequest.Title).ToList();
|
||||||
|
|
||||||
|
return new RequestsViewModel<ChildRequests>
|
||||||
|
{
|
||||||
|
Collection = allRequests,
|
||||||
|
Total = total,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TvRequests>> GetRequestsLite()
|
public async Task<IEnumerable<TvRequests>> GetRequestsLite()
|
||||||
{
|
{
|
||||||
var shouldHide = await HideFromOtherUsers();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
@ -282,17 +332,22 @@ namespace Ombi.Core.Engine
|
||||||
private static void FilterChildren(TvRequests t, HideResult shouldHide)
|
private static void FilterChildren(TvRequests t, HideResult shouldHide)
|
||||||
{
|
{
|
||||||
// Filter out children
|
// Filter out children
|
||||||
|
FilterChildren(t.ChildRequests, shouldHide);
|
||||||
|
}
|
||||||
|
|
||||||
for (var j = 0; j < t.ChildRequests.Count; j++)
|
private static void FilterChildren(List<ChildRequests> t, HideResult shouldHide)
|
||||||
|
{
|
||||||
|
// Filter out children
|
||||||
|
|
||||||
|
for (var j = 0; j < t.Count; j++)
|
||||||
{
|
{
|
||||||
var child = t.ChildRequests[j];
|
var child = t[j];
|
||||||
if (child.RequestedUserId != shouldHide.UserId)
|
if (child.RequestedUserId != shouldHide.UserId)
|
||||||
{
|
{
|
||||||
t.ChildRequests.RemoveAt(j);
|
t.RemoveAt(j);
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId)
|
public async Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId)
|
||||||
|
@ -351,7 +406,6 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
public async Task<TvRequests> UpdateTvRequest(TvRequests request)
|
public async Task<TvRequests> UpdateTvRequest(TvRequests request)
|
||||||
{
|
{
|
||||||
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
|
||||||
var allRequests = TvRepository.Get();
|
var allRequests = TvRepository.Get();
|
||||||
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id);
|
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id);
|
||||||
|
|
||||||
|
@ -385,6 +439,7 @@ namespace Ombi.Core.Engine
|
||||||
foreach (var ep in s.Episodes)
|
foreach (var ep in s.Episodes)
|
||||||
{
|
{
|
||||||
ep.Approved = true;
|
ep.Approved = true;
|
||||||
|
ep.Requested = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +448,6 @@ namespace Ombi.Core.Engine
|
||||||
if (request.Approved)
|
if (request.Approved)
|
||||||
{
|
{
|
||||||
NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||||
await Audit.Record(AuditType.Approved, AuditArea.TvRequest, $"Approved Request {request.Title}", Username);
|
|
||||||
// Autosend
|
// Autosend
|
||||||
await TvSender.Send(request);
|
await TvSender.Send(request);
|
||||||
}
|
}
|
||||||
|
@ -425,9 +479,7 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
||||||
{
|
{
|
||||||
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
await TvRepository.UpdateChild(request);
|
||||||
|
|
||||||
await TvRepository.UpdateChild(request);
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,16 +497,14 @@ namespace Ombi.Core.Engine
|
||||||
// Delete the parent
|
// Delete the parent
|
||||||
TvRepository.Db.TvRequests.Remove(parent);
|
TvRepository.Db.TvRequests.Remove(parent);
|
||||||
}
|
}
|
||||||
await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username);
|
|
||||||
|
|
||||||
await TvRepository.Db.SaveChangesAsync();
|
await TvRepository.Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveTvRequest(int requestId)
|
public async Task RemoveTvRequest(int requestId)
|
||||||
{
|
{
|
||||||
var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username);
|
await TvRepository.Delete(request);
|
||||||
await TvRepository.Delete(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UserHasRequest(string userId)
|
public async Task<bool> UserHasRequest(string userId)
|
||||||
|
@ -569,7 +619,7 @@ namespace Ombi.Core.Engine
|
||||||
return await AfterRequest(model.ChildRequests.FirstOrDefault());
|
return await AfterRequest(model.ChildRequests.FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||||
{
|
{
|
||||||
foreach (var value in items)
|
foreach (var value in items)
|
||||||
{
|
{
|
||||||
|
@ -606,7 +656,7 @@ namespace Ombi.Core.Engine
|
||||||
var result = await TvSender.Send(model);
|
var result = await TvSender.Send(model);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
return new RequestEngineResult { Result = true, RequestId = model.Id};
|
return new RequestEngineResult { Result = true, RequestId = model.Id };
|
||||||
}
|
}
|
||||||
return new RequestEngineResult
|
return new RequestEngineResult
|
||||||
{
|
{
|
||||||
|
@ -659,10 +709,10 @@ namespace Ombi.Core.Engine
|
||||||
DateTime oldestRequestedAt = await log.OrderBy(x => x.RequestDate)
|
DateTime oldestRequestedAt = await log.OrderBy(x => x.RequestDate)
|
||||||
.Select(x => x.RequestDate)
|
.Select(x => x.RequestDate)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
return new RequestQuotaCountModel()
|
return new RequestQuotaCountModel()
|
||||||
{
|
{
|
||||||
HasLimit = true,
|
HasLimit = true,
|
||||||
Limit = limit,
|
Limit = limit,
|
||||||
Remaining = count,
|
Remaining = count,
|
||||||
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||||
|
|
|
@ -21,6 +21,8 @@ using Ombi.Core.Authentication;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -40,8 +42,8 @@ namespace Ombi.Core.Engine
|
||||||
EmbyContentRepo = embyRepo;
|
EmbyContentRepo = embyRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ITvMazeApi TvMazeApi { get; }
|
protected ITvMazeApi TvMazeApi { get; }
|
||||||
private IMapper Mapper { get; }
|
protected IMapper Mapper { get; }
|
||||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||||
private IPlexContentRepository PlexContentRepo { get; }
|
private IPlexContentRepository PlexContentRepo { get; }
|
||||||
|
@ -99,7 +101,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
Url = e.url,
|
Url = e.url,
|
||||||
Title = e.name,
|
Title = e.name,
|
||||||
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
|
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
|
||||||
EpisodeNumber = e.number,
|
EpisodeNumber = e.number,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -112,7 +114,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
Url = e.url,
|
Url = e.url,
|
||||||
Title = e.name,
|
Title = e.name,
|
||||||
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
|
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
|
||||||
EpisodeNumber = e.number,
|
EpisodeNumber = e.number,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -127,6 +129,19 @@ namespace Ombi.Core.Engine
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad)
|
||||||
|
{
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||||
|
var results = new List<TraktShow>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await TraktApi.GetPopularShows(pagesToLoad.Page, ResultLimit);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
var processed = ProcessResults(results);
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -135,6 +150,19 @@ namespace Ombi.Core.Engine
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad)
|
||||||
|
{
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||||
|
var results = new List<TraktMostAnticipatedShow>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await TraktApi.GetAnticipatedShows(pagesToLoad.Page, ResultLimit);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
var processed = ProcessResults(results);
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
||||||
{
|
{
|
||||||
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
||||||
|
@ -149,7 +177,33 @@ namespace Ombi.Core.Engine
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches(int currentlyLoaded, int amountToLoad)
|
||||||
|
{
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||||
|
var results = new List<TraktMostWatchedShow>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await TraktApi.GetMostWatchesShows(null, pagesToLoad.Page, ResultLimit);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
var processed = ProcessResults(results);
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad)
|
||||||
|
{
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||||
|
var results = new List<TraktTrendingShow>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await TraktApi.GetTrendingShows(pagesToLoad.Page, ResultLimit);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
var processed = ProcessResults(results);
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||||
{
|
{
|
||||||
var retVal = new List<SearchTvShowViewModel>();
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
foreach (var tvMazeSearch in items)
|
foreach (var tvMazeSearch in items)
|
||||||
|
@ -159,7 +213,7 @@ namespace Ombi.Core.Engine
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
protected SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
||||||
{
|
{
|
||||||
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||||
}
|
}
|
||||||
|
|
127
src/Ombi.Core/Engine/V2/CalendarEngine.cs
Normal file
127
src/Ombi.Core/Engine/V2/CalendarEngine.cs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Sonarr.Models;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Engine.Interfaces;
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine.V2
|
||||||
|
{
|
||||||
|
public class CalendarEngine : BaseEngine, ICalendarEngine
|
||||||
|
{
|
||||||
|
public DateTime DaysAgo => DateTime.Now.AddDays(-90);
|
||||||
|
public DateTime DaysAhead => DateTime.Now.AddDays(90);
|
||||||
|
public CalendarEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo,
|
||||||
|
ITvRequestRepository tvRequestRepo) : base(user, um, rules)
|
||||||
|
{
|
||||||
|
_movieRepo = movieRepo;
|
||||||
|
_tvRepo = tvRequestRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IMovieRequestRepository _movieRepo;
|
||||||
|
private readonly ITvRequestRepository _tvRepo;
|
||||||
|
|
||||||
|
public async Task<List<CalendarViewModel>> GetCalendarData()
|
||||||
|
{
|
||||||
|
var viewModel = new List<CalendarViewModel>();
|
||||||
|
var movies = _movieRepo.GetAll().Where(x =>
|
||||||
|
x.ReleaseDate > DaysAgo && x.ReleaseDate < DaysAhead);
|
||||||
|
var episodes = _tvRepo.GetChild().SelectMany(x => x.SeasonRequests.SelectMany(e => e.Episodes
|
||||||
|
.Where(w => w.AirDate > DaysAgo && w.AirDate < DaysAhead)));
|
||||||
|
foreach (var e in episodes)
|
||||||
|
{
|
||||||
|
viewModel.Add(new CalendarViewModel
|
||||||
|
{
|
||||||
|
Title = e.Title,
|
||||||
|
Start = e.AirDate.Date,
|
||||||
|
Type = RequestType.TvShow,
|
||||||
|
BackgroundColor = GetBackgroundColor(e),
|
||||||
|
ExtraParams = new List<ExtraParams>
|
||||||
|
{
|
||||||
|
new ExtraParams { Overview = e.Season?.ChildRequest?.ParentRequest?.Overview ?? string.Empty, ProviderId = e.Season?.ChildRequest?.ParentRequest?.TvDbId ?? 0}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var m in movies)
|
||||||
|
{
|
||||||
|
viewModel.Add(new CalendarViewModel
|
||||||
|
{
|
||||||
|
Title = m.Title,
|
||||||
|
Start = m.ReleaseDate.Date,
|
||||||
|
BackgroundColor = GetBackgroundColor(m),
|
||||||
|
Type = RequestType.Movie,
|
||||||
|
ExtraParams = new List<ExtraParams>
|
||||||
|
{
|
||||||
|
new ExtraParams { Overview = m.Overview, ProviderId = m.TheMovieDbId}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetBackgroundColor(BaseRequest req)
|
||||||
|
{
|
||||||
|
if (req.Available)
|
||||||
|
{
|
||||||
|
return "#469c83";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.Available)
|
||||||
|
{
|
||||||
|
if (req.Denied ?? false)
|
||||||
|
{
|
||||||
|
return "red";
|
||||||
|
}
|
||||||
|
if (req.Approved)
|
||||||
|
{
|
||||||
|
// We are approved state
|
||||||
|
return "blue";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.Approved)
|
||||||
|
{
|
||||||
|
// Processing
|
||||||
|
return "teal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "gray";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetBackgroundColor(EpisodeRequests req)
|
||||||
|
{
|
||||||
|
if (req.Available)
|
||||||
|
{
|
||||||
|
return "#469c83";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.Available)
|
||||||
|
{
|
||||||
|
if (req.Approved)
|
||||||
|
{
|
||||||
|
// We are approved state
|
||||||
|
return "blue";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.Approved)
|
||||||
|
{
|
||||||
|
// Processing
|
||||||
|
return "teal";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return "gray";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/Ombi.Core/Engine/V2/ICalendarEngine.cs
Normal file
11
src/Ombi.Core/Engine/V2/ICalendarEngine.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine.V2
|
||||||
|
{
|
||||||
|
public interface ICalendarEngine
|
||||||
|
{
|
||||||
|
Task<List<CalendarViewModel>> GetCalendarData();
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,10 @@ 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.Engine.Interfaces;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
@ -17,9 +19,8 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ombi.Core.Models.Search.V2;
|
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine.V2
|
||||||
{
|
{
|
||||||
public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2
|
public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2
|
||||||
{
|
{
|
||||||
|
@ -45,6 +46,198 @@ namespace Ombi.Core.Engine
|
||||||
return await ProcessSingleMovie(movieInfo);
|
return await ProcessSingleMovie(movieInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, string langCode = null)
|
||||||
|
{
|
||||||
|
langCode = await DefaultLanguageCode(langCode);
|
||||||
|
var collections = await MovieApi.GetCollection(langCode, collectionId);
|
||||||
|
|
||||||
|
var c = await ProcessCollection(collections);
|
||||||
|
c.Collection = c.Collection.OrderBy(x => x.ReleaseDate).ToList();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetTvDbId(int theMovieDbId)
|
||||||
|
{
|
||||||
|
var result = await MovieApi.GetTvExternals(theMovieDbId);
|
||||||
|
return result.tvdb_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get similar movies to the id passed in
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="theMovieDbId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode)
|
||||||
|
{
|
||||||
|
langCode = await DefaultLanguageCode(langCode);
|
||||||
|
var result = await MovieApi.SimilarMovies(theMovieDbId, langCode);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets popular movies.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||||
|
{
|
||||||
|
|
||||||
|
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () =>
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
return await MovieApi.PopularMovies(langCode);
|
||||||
|
}, DateTime.Now.AddHours(12));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private const int _theMovieDbMaxPageItems = 20;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets popular movies by paging
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad)
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, _theMovieDbMaxPageItems);
|
||||||
|
|
||||||
|
var results = new List<MovieSearchResult>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await MovieApi.PopularMovies(langCode, pagesToLoad.Page);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
return await TransformMovieResultsToResponse(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets top rated movies.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||||
|
{
|
||||||
|
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () =>
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
return await MovieApi.TopRated(langCode);
|
||||||
|
}, DateTime.Now.AddHours(12));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies(int currentPosition, int amountToLoad)
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||||
|
|
||||||
|
var results = new List<MovieSearchResult>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await MovieApi.TopRated(langCode, pagesToLoad.Page);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
return await TransformMovieResultsToResponse(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad)
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||||
|
|
||||||
|
var results = new List<MovieSearchResult>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await MovieApi.NowPlaying(langCode, pagesToLoad.Page);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
return await TransformMovieResultsToResponse(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets upcoming movies.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||||
|
{
|
||||||
|
var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () =>
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
return await MovieApi.Upcoming(langCode);
|
||||||
|
}, DateTime.Now.AddHours(12));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentPosition, int amountToLoad)
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
|
||||||
|
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||||
|
|
||||||
|
var results = new List<MovieSearchResult>();
|
||||||
|
foreach (var pagesToLoad in pages)
|
||||||
|
{
|
||||||
|
var apiResult = await MovieApi.Upcoming(langCode, pagesToLoad.Page);
|
||||||
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
|
}
|
||||||
|
return await TransformMovieResultsToResponse(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets now playing movies.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||||
|
{
|
||||||
|
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () =>
|
||||||
|
{
|
||||||
|
var langCode = await DefaultLanguageCode(null);
|
||||||
|
return await MovieApi.NowPlaying(langCode);
|
||||||
|
}, DateTime.Now.AddHours(12));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||||
|
IEnumerable<MovieSearchResult> movies)
|
||||||
|
{
|
||||||
|
var viewMovies = new List<SearchMovieViewModel>();
|
||||||
|
foreach (var movie in movies)
|
||||||
|
{
|
||||||
|
viewMovies.Add(await ProcessSingleMovie(movie));
|
||||||
|
}
|
||||||
|
return viewMovies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieSearchResult movie)
|
||||||
|
{
|
||||||
|
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||||
|
return await ProcessSingleMovie(viewMovie);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<MovieFullInfoViewModel> ProcessSingleMovie(FullMovieInfo movie)
|
private async Task<MovieFullInfoViewModel> ProcessSingleMovie(FullMovieInfo movie)
|
||||||
{
|
{
|
||||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||||
|
@ -65,6 +258,50 @@ namespace Ombi.Core.Engine
|
||||||
return mapped;
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<MovieCollectionsViewModel> ProcessCollection(Collections collection)
|
||||||
|
{
|
||||||
|
var viewMovie = Mapper.Map<MovieCollectionsViewModel>(collection);
|
||||||
|
foreach (var movie in viewMovie.Collection)
|
||||||
|
{
|
||||||
|
var mappedMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||||
|
await RunSearchRules(mappedMovie);
|
||||||
|
|
||||||
|
// This requires the rules to be run first to populate the RequestId property
|
||||||
|
await CheckForSubscription(mappedMovie);
|
||||||
|
var mapped = Mapper.Map<MovieCollection>(movie);
|
||||||
|
|
||||||
|
mapped.Available = movie.Available;
|
||||||
|
mapped.RequestId = movie.RequestId;
|
||||||
|
mapped.Requested = movie.Requested;
|
||||||
|
mapped.PlexUrl = movie.PlexUrl;
|
||||||
|
mapped.EmbyUrl = movie.EmbyUrl;
|
||||||
|
mapped.Subscribed = movie.Subscribed;
|
||||||
|
mapped.ShowSubscribe = movie.ShowSubscribe;
|
||||||
|
mapped.ReleaseDate = movie.ReleaseDate;
|
||||||
|
}
|
||||||
|
return viewMovie;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie)
|
||||||
|
{
|
||||||
|
if (viewMovie.ImdbId.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
|
||||||
|
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
||||||
|
viewMovie.ImdbId = showInfo.ImdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewMovie.TheMovieDbId = viewMovie.Id.ToString();
|
||||||
|
|
||||||
|
await RunSearchRules(viewMovie);
|
||||||
|
|
||||||
|
// This requires the rules to be run first to populate the RequestId property
|
||||||
|
await CheckForSubscription(viewMovie);
|
||||||
|
|
||||||
|
return viewMovie;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CheckForSubscription(SearchViewModel viewModel)
|
private async Task CheckForSubscription(SearchViewModel viewModel)
|
||||||
{
|
{
|
||||||
// Check if this user requested it
|
// Check if this user requested it
|
||||||
|
|
154
src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs
Normal file
154
src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Api.Trakt;
|
||||||
|
using Ombi.Api.TvMaze;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine.V2
|
||||||
|
{
|
||||||
|
public class TvSearchEngineV2 : BaseMediaEngine, ITVSearchEngineV2
|
||||||
|
{
|
||||||
|
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
|
||||||
|
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um,
|
||||||
|
ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
|
||||||
|
: base(identity, service, r, um, memCache, s, sub)
|
||||||
|
{
|
||||||
|
TvMazeApi = tvMaze;
|
||||||
|
Mapper = mapper;
|
||||||
|
PlexSettings = plexSettings;
|
||||||
|
EmbySettings = embySettings;
|
||||||
|
PlexContentRepo = repo;
|
||||||
|
TraktApi = trakt;
|
||||||
|
EmbyContentRepo = embyRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ITvMazeApi TvMazeApi { get; }
|
||||||
|
private IMapper Mapper { get; }
|
||||||
|
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||||
|
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||||
|
private IPlexContentRepository PlexContentRepo { get; }
|
||||||
|
private IEmbyContentRepository EmbyContentRepo { get; }
|
||||||
|
private ITraktApi TraktApi { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid)
|
||||||
|
{
|
||||||
|
var tvdbshow = await TvMazeApi.ShowLookupByTheTvDbId(tvdbid);
|
||||||
|
var show = await TvMazeApi.GetTvFullInformation(tvdbshow.id);
|
||||||
|
if (show == null)
|
||||||
|
{
|
||||||
|
// We don't have enough information
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the task so we can get the data later on if we have a IMDBID
|
||||||
|
Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null);
|
||||||
|
if (show.externals?.imdb.HasValue() ?? false)
|
||||||
|
{
|
||||||
|
traktInfoTask = TraktApi.GetTvExtendedInfo(show.externals?.imdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapped = Mapper.Map<SearchFullInfoTvShowViewModel>(show);
|
||||||
|
|
||||||
|
foreach (var e in show._embedded.episodes)
|
||||||
|
{
|
||||||
|
var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
|
||||||
|
if (season == null)
|
||||||
|
{
|
||||||
|
var newSeason = new SeasonRequests
|
||||||
|
{
|
||||||
|
SeasonNumber = e.season,
|
||||||
|
Episodes = new List<EpisodeRequests>()
|
||||||
|
};
|
||||||
|
newSeason.Episodes.Add(new EpisodeRequests
|
||||||
|
{
|
||||||
|
Url = e.url,
|
||||||
|
Title = e.name,
|
||||||
|
AirDate = e.airstamp,
|
||||||
|
EpisodeNumber = e.number,
|
||||||
|
|
||||||
|
});
|
||||||
|
mapped.SeasonRequests.Add(newSeason);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We already have the season, so just add the episode
|
||||||
|
season.Episodes.Add(new EpisodeRequests
|
||||||
|
{
|
||||||
|
Url = e.url,
|
||||||
|
Title = e.name,
|
||||||
|
AirDate = e.airstamp,
|
||||||
|
EpisodeNumber = e.number,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await ProcessResult(mapped, traktInfoTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||||
|
{
|
||||||
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
|
foreach (var tvMazeSearch in items)
|
||||||
|
{
|
||||||
|
retVal.Add(ProcessResult(tvMazeSearch));
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
||||||
|
{
|
||||||
|
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchFullInfoTvShowViewModel> ProcessResult(SearchFullInfoTvShowViewModel item, Task<TraktShow> showInfoTask)
|
||||||
|
{
|
||||||
|
item.TheTvDbId = item.Id.ToString();
|
||||||
|
|
||||||
|
var oldModel = Mapper.Map<SearchTvShowViewModel>(item);
|
||||||
|
await RunSearchRules(oldModel);
|
||||||
|
|
||||||
|
item.Available = oldModel.Available;
|
||||||
|
item.FullyAvailable = oldModel.FullyAvailable;
|
||||||
|
item.PartlyAvailable = oldModel.PartlyAvailable;
|
||||||
|
item.Requested = oldModel.Requested;
|
||||||
|
item.Available = oldModel.Available;
|
||||||
|
item.Approved = oldModel.Approved;
|
||||||
|
item.SeasonRequests = oldModel.SeasonRequests;
|
||||||
|
item.RequestId = oldModel.RequestId;
|
||||||
|
|
||||||
|
return await GetExtraInfo(showInfoTask, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model)
|
||||||
|
{
|
||||||
|
var result = await showInfoTask;
|
||||||
|
if(result == null)
|
||||||
|
{
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.Trailer = result.Trailer;
|
||||||
|
model.Certification = result.Certification;
|
||||||
|
model.Homepage = result.Homepage;
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/Ombi.Core/Models/Search/V2/CalendarViewModel.cs
Normal file
39
src/Ombi.Core/Models/Search/V2/CalendarViewModel.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search.V2
|
||||||
|
{
|
||||||
|
public class CalendarViewModel
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime Start { get; set; }
|
||||||
|
public string BackgroundColor { get; set; }
|
||||||
|
public RequestType Type { get; set; }
|
||||||
|
public List<ExtraParams> ExtraParams { get; set; }
|
||||||
|
|
||||||
|
public string BorderColor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case RequestType.TvShow:
|
||||||
|
return "#ff0000";
|
||||||
|
case RequestType.Movie:
|
||||||
|
return "#0d5a3e";
|
||||||
|
case RequestType.Album:
|
||||||
|
return "#797979";
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExtraParams
|
||||||
|
{
|
||||||
|
public int ProviderId { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
}
|
||||||
|
}
|
25
src/Ombi.Core/Models/Search/V2/MovieCollectionsViewModel.cs
Normal file
25
src/Ombi.Core/Models/Search/V2/MovieCollectionsViewModel.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search.V2
|
||||||
|
{
|
||||||
|
public class MovieCollectionsViewModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public List<MovieCollection> Collection { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MovieCollection : SearchViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public string PosterPath { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public override RequestType Type => RequestType.Movie;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ namespace Ombi.Core.Models.Search.V2
|
||||||
public class MovieFullInfoViewModel : SearchViewModel
|
public class MovieFullInfoViewModel : SearchViewModel
|
||||||
{
|
{
|
||||||
public bool Adult { get; set; }
|
public bool Adult { get; set; }
|
||||||
|
public CollectionsViewModel BelongsToCollection { get; set; }
|
||||||
public string BackdropPath { get; set; }
|
public string BackdropPath { get; set; }
|
||||||
public string OriginalLanguage { get; set; }
|
public string OriginalLanguage { get; set; }
|
||||||
public int Budget { get; set; }
|
public int Budget { get; set; }
|
||||||
|
@ -39,8 +40,26 @@ namespace Ombi.Core.Models.Search.V2
|
||||||
public Similar Similar { get; set; }
|
public Similar Similar { get; set; }
|
||||||
public Recommendations Recommendations { get; set; }
|
public Recommendations Recommendations { get; set; }
|
||||||
public ExternalIds ExternalIds { get; set; }
|
public ExternalIds ExternalIds { get; set; }
|
||||||
|
public Keywords Keywords { get; set; }
|
||||||
|
}
|
||||||
|
public class Keywords
|
||||||
|
{
|
||||||
|
public List<KeywordsValue> KeywordsValue { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class KeywordsValue
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CollectionsViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string PosterPath { get; set; }
|
||||||
|
public string BackdropPath { get; set; }
|
||||||
|
}
|
||||||
public class ExternalIds
|
public class ExternalIds
|
||||||
{
|
{
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
|
|
114
src/Ombi.Core/Models/Search/V2/SearchFullInfoTvShowViewModel.cs
Normal file
114
src/Ombi.Core/Models/Search/V2/SearchFullInfoTvShowViewModel.cs
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search.V2
|
||||||
|
{
|
||||||
|
public class SearchFullInfoTvShowViewModel : SearchViewModel
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public List<string> Aliases { get; set; }
|
||||||
|
public string Banner { get; set; }
|
||||||
|
public int SeriesId { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public string FirstAired { get; set; }
|
||||||
|
public string NetworkId { get; set; }
|
||||||
|
public string Runtime { get; set; }
|
||||||
|
public List<string> Genre { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public int LastUpdated { get; set; }
|
||||||
|
public string AirsDayOfWeek { get; set; }
|
||||||
|
public string AirsTime { get; set; }
|
||||||
|
public string Rating { get; set; }
|
||||||
|
public int SiteRating { get; set; }
|
||||||
|
public NetworkViewModel Network { get; set; }
|
||||||
|
public Images Images { get; set; }
|
||||||
|
public List<CastViewModel> Cast { get; set; }
|
||||||
|
public List<CrewViewModel> Crew { get; set; }
|
||||||
|
public string Certification { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Trailer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Homepage { get; set; }
|
||||||
|
|
||||||
|
public List<SeasonRequests> SeasonRequests { get; set; } = new List<SeasonRequests>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If we are requesting the entire series
|
||||||
|
/// </summary>
|
||||||
|
public bool RequestAll { get; set; }
|
||||||
|
|
||||||
|
public bool FirstSeason { get; set; }
|
||||||
|
public bool LatestSeason { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is where we have EVERY Episode for that series
|
||||||
|
/// </summary>
|
||||||
|
public bool FullyAvailable { get; set; }
|
||||||
|
// We only have some episodes
|
||||||
|
public bool PartlyAvailable { get; set; }
|
||||||
|
public override RequestType Type => RequestType.TvShow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetworkViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public Country Country { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Country
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
public string Timezone { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Images
|
||||||
|
{
|
||||||
|
public string Medium { get; set; }
|
||||||
|
public string Original { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CastViewModel
|
||||||
|
{
|
||||||
|
public PersonViewModel Person { get; set; }
|
||||||
|
public CharacterViewModel Character { get; set; }
|
||||||
|
public bool Self { get; set; }
|
||||||
|
public bool Voice { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PersonViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public Images Image { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CharacterViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public Images Image { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CrewViewModel
|
||||||
|
{
|
||||||
|
public string Type { get; set; }
|
||||||
|
public PersonViewModel Person { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs
Normal file
23
src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The view model for the notification settings page
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="GotifyNotificationSettings" />
|
||||||
|
public class GotifyNotificationViewModel : GotifySettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification templates.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The notification templates.
|
||||||
|
/// </value>
|
||||||
|
public List<NotificationTemplates> NotificationTemplates { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
||||||
<PackageReference Include="Hangfire" Version="1.6.21" />
|
<PackageReference Include="Hangfire" Version="1.7.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.3" />
|
||||||
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
@ -10,28 +12,31 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
{
|
{
|
||||||
public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest>
|
public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest>
|
||||||
{
|
{
|
||||||
public AutoApproveRule(IPrincipal principal)
|
public AutoApproveRule(IPrincipal principal, OmbiUserManager um)
|
||||||
{
|
{
|
||||||
User = principal;
|
User = principal;
|
||||||
|
_manager = um;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPrincipal User { get; }
|
private IPrincipal User { get; }
|
||||||
|
private readonly OmbiUserManager _manager;
|
||||||
|
|
||||||
public Task<RuleResult> Execute(BaseRequest obj)
|
public async Task<RuleResult> Execute(BaseRequest obj)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.Admin))
|
var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name);
|
||||||
|
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin))
|
||||||
{
|
{
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.RequestType == RequestType.Movie && User.IsInRole(OmbiRoles.AutoApproveMovie))
|
if (obj.RequestType == RequestType.Movie && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiRoles.AutoApproveTv))
|
if (obj.RequestType == RequestType.TvShow && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
if (obj.RequestType == RequestType.Album && User.IsInRole(OmbiRoles.AutoApproveMusic))
|
if (obj.RequestType == RequestType.Album && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve
|
return Success(); // We don't really care, we just don't set the obj to approve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,46 +1,52 @@
|
||||||
using Ombi.Store.Entities;
|
using System.Security.Claims;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
namespace Ombi.Core.Rule.Rules
|
namespace Ombi.Core.Rule.Rules.Request
|
||||||
{
|
{
|
||||||
public class CanRequestRule : BaseRequestRule, IRules<BaseRequest>
|
public class CanRequestRule : BaseRequestRule, IRules<BaseRequest>
|
||||||
{
|
{
|
||||||
public CanRequestRule(IPrincipal principal)
|
public CanRequestRule(IPrincipal principal, OmbiUserManager manager)
|
||||||
{
|
{
|
||||||
User = principal;
|
User = principal;
|
||||||
|
_manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPrincipal User { get; }
|
private IPrincipal User { get; }
|
||||||
|
private readonly OmbiUserManager _manager;
|
||||||
|
|
||||||
public Task<RuleResult> Execute(BaseRequest obj)
|
public async Task<RuleResult> Execute(BaseRequest obj)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.Admin))
|
var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name);
|
||||||
return Task.FromResult(Success());
|
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin))
|
||||||
|
return Success();
|
||||||
|
|
||||||
if (obj.RequestType == RequestType.Movie)
|
if (obj.RequestType == RequestType.Movie)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.RequestMovie) || User.IsInRole(OmbiRoles.AutoApproveMovie))
|
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
return Task.FromResult(Fail("You do not have permissions to Request a Movie"));
|
return Fail("You do not have permissions to Request a Movie");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.RequestType == RequestType.TvShow)
|
if (obj.RequestType == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.RequestTv) || User.IsInRole(OmbiRoles.AutoApproveTv))
|
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.RequestType == RequestType.Album)
|
if (obj.RequestType == RequestType.Album)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.RequestMusic) || User.IsInRole(OmbiRoles.AutoApproveMusic))
|
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMusic) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(Fail("You do not have permissions to Request a TV Show"));
|
return Fail("You do not have permissions to Request a TV Show");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Threading.Tasks;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
@ -28,8 +30,24 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
{
|
{
|
||||||
var movie = (MovieRequests) obj;
|
var movie = (MovieRequests) obj;
|
||||||
var movieRequests = Movie.GetAll();
|
var movieRequests = Movie.GetAll();
|
||||||
|
var found = false;
|
||||||
var existing = await movieRequests.FirstOrDefaultAsync(x => x.TheMovieDbId == movie.TheMovieDbId);
|
var existing = await movieRequests.FirstOrDefaultAsync(x => x.TheMovieDbId == movie.TheMovieDbId);
|
||||||
if (existing != null) // Do we already have a request for this?
|
if (existing != null) // Do we already have a request for this?
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found && movie.ImdbId.HasValue())
|
||||||
|
{
|
||||||
|
// Let's check imdbid
|
||||||
|
existing = await movieRequests.FirstOrDefaultAsync(x =>
|
||||||
|
x.ImdbId.Equals(movie.ImdbId, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found)
|
||||||
{
|
{
|
||||||
return Fail($"\"{obj.Title}\" has already been requested");
|
return Fail($"\"{obj.Title}\" has already been requested");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
|
|
||||||
var tvContent = _plexContent.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Show);
|
var tvContent = _plexContent.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Show);
|
||||||
// We need to do a check on the TVDBId
|
// We need to do a check on the TVDBId
|
||||||
var anyTvDbMatches = await tvContent.Include(x => x.Episodes).FirstOrDefaultAsync(x => x.HasTvDb && x.TvDbId.Equals(tvRequest.Id.ToString())); // the Id on the child is the tvdbid at this point
|
var anyTvDbMatches = await tvContent.Include(x => x.Episodes).FirstOrDefaultAsync(x => x.HasTvDb && x.TvDbId.Equals(tvRequest.Id.ToString(), StringComparison.InvariantCultureIgnoreCase)); // the Id on the child is the tvdbid at this point
|
||||||
if (anyTvDbMatches == null)
|
if (anyTvDbMatches == null)
|
||||||
{
|
{
|
||||||
// So we do not have a TVDB Id, that really sucks.
|
// So we do not have a TVDB Id, that really sucks.
|
||||||
|
@ -42,7 +42,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
&& x.ReleaseYear == tvRequest.ReleaseYear.Year.ToString());
|
&& x.ReleaseYear == tvRequest.ReleaseYear.Year.ToString());
|
||||||
if (titleAndYearMatch != null)
|
if (titleAndYearMatch != null)
|
||||||
{
|
{
|
||||||
// We have a match! Suprise Motherfucker
|
// We have a match! Surprise Motherfucker
|
||||||
return CheckExistingContent(tvRequest, titleAndYearMatch);
|
return CheckExistingContent(tvRequest, titleAndYearMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository.Requests;
|
using Ombi.Store.Repository.Requests;
|
||||||
|
@ -13,6 +13,18 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public static void CheckForUnairedEpisodes(SearchTvShowViewModel search)
|
public static void CheckForUnairedEpisodes(SearchTvShowViewModel search)
|
||||||
{
|
{
|
||||||
|
foreach (var season in search.SeasonRequests)
|
||||||
|
{
|
||||||
|
// If we have all the episodes for this season, then this season is available
|
||||||
|
if (season.Episodes.All(x => x.Available))
|
||||||
|
{
|
||||||
|
season.SeasonAvailable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(search.SeasonRequests.Any(x => x.Episodes.Any(e => e.Available)))
|
||||||
|
{
|
||||||
|
search.PartlyAvailable = true;
|
||||||
|
}
|
||||||
if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
||||||
{
|
{
|
||||||
search.FullyAvailable = true;
|
search.FullyAvailable = true;
|
||||||
|
@ -24,7 +36,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
if (!airedButNotAvailable)
|
if (!airedButNotAvailable)
|
||||||
{
|
{
|
||||||
var unairedEpisodes = search.SeasonRequests.Any(x =>
|
var unairedEpisodes = search.SeasonRequests.Any(x =>
|
||||||
x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date));
|
x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date || c.AirDate != DateTime.MinValue));
|
||||||
if (unairedEpisodes)
|
if (unairedEpisodes)
|
||||||
{
|
{
|
||||||
search.FullyAvailable = true;
|
search.FullyAvailable = true;
|
||||||
|
@ -34,28 +46,36 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<PlexEpisode> allEpisodes, EpisodeRequests episode,
|
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<PlexEpisode> allEpisodes, EpisodeRequests episode,
|
||||||
SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb)
|
SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log)
|
||||||
{
|
{
|
||||||
PlexEpisode epExists = null;
|
PlexEpisode epExists = null;
|
||||||
if (useImdb)
|
try
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
|
||||||
x.Series.ImdbId == item.ImdbId.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useTheMovieDb)
|
if (useImdb)
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
|
x.Series.ImdbId == item.ImdbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useTvDb)
|
if (useTheMovieDb)
|
||||||
|
{
|
||||||
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
|
x.Series.TheMovieDbId == item.TheMovieDbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useTvDb)
|
||||||
|
{
|
||||||
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
|
x.Series.TvDbId == item.TvDbId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
log.LogError(e, "Exception thrown when attempting to check if something is available");
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
|
||||||
x.Series.TvDbId == item.TvDbId.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (epExists != null)
|
if (epExists != null)
|
||||||
|
@ -71,21 +91,21 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
x.Series.ImdbId == item.ImdbId.ToString());
|
x.Series.ImdbId == item.ImdbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useTheMovieDb)
|
if (useTheMovieDb)
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
|
x.Series.TheMovieDbId == item.TheMovieDbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useTvDb)
|
if (useTvDb)
|
||||||
{
|
{
|
||||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||||
x.Series.TvDbId == item.TvDbId.ToString());
|
x.Series.TvDbId == item.TvDbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (epExists != null)
|
if (epExists != null)
|
||||||
|
|
|
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
@ -11,12 +13,14 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public class EmbyAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
public class EmbyAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
||||||
{
|
{
|
||||||
public EmbyAvailabilityRule(IEmbyContentRepository repo)
|
public EmbyAvailabilityRule(IEmbyContentRepository repo, ISettingsService<EmbySettings> s)
|
||||||
{
|
{
|
||||||
EmbyContentRepository = repo;
|
EmbyContentRepository = repo;
|
||||||
|
EmbySettings = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEmbyContentRepository EmbyContentRepository { get; }
|
private IEmbyContentRepository EmbyContentRepository { get; }
|
||||||
|
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||||
|
|
||||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +64,19 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
obj.Available = true;
|
obj.Available = true;
|
||||||
obj.EmbyUrl = item.Url;
|
var s = await EmbySettings.GetSettingsAsync();
|
||||||
|
if (s.Enable)
|
||||||
|
{
|
||||||
|
var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null);
|
||||||
|
if ((server?.ServerHostname ?? string.Empty).HasValue())
|
||||||
|
{
|
||||||
|
obj.EmbyUrl = $"{server.ServerHostname}#!/itemdetails.html?id={item.EmbyId}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj.EmbyUrl = $"https://app.emby.media/#!/itemdetails.html?id={item.EmbyId}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (obj.Type == RequestType.TvShow)
|
if (obj.Type == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
|
@ -29,7 +30,6 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
var movieRequests = await Movie.GetRequestAsync(obj.Id);
|
var movieRequests = await Movie.GetRequestAsync(obj.Id);
|
||||||
if (movieRequests != null) // Do we already have a request for this?
|
if (movieRequests != null) // Do we already have a request for this?
|
||||||
{
|
{
|
||||||
|
|
||||||
obj.Requested = true;
|
obj.Requested = true;
|
||||||
obj.RequestId = movieRequests.Id;
|
obj.RequestId = movieRequests.Id;
|
||||||
obj.Approved = movieRequests.Approved;
|
obj.Approved = movieRequests.Approved;
|
||||||
|
@ -41,22 +41,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
}
|
}
|
||||||
if (obj.Type == RequestType.TvShow)
|
if (obj.Type == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
//var tvRequests = Tv.GetRequest(obj.Id);
|
|
||||||
//if (tvRequests != null) // Do we already have a request for this?
|
|
||||||
//{
|
|
||||||
|
|
||||||
// obj.Requested = true;
|
|
||||||
// obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
|
||||||
// obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
|
|
||||||
|
|
||||||
// return Task.FromResult(Success());
|
|
||||||
//}
|
|
||||||
|
|
||||||
var request = (SearchTvShowViewModel)obj;
|
var request = (SearchTvShowViewModel)obj;
|
||||||
var tvRequests = Tv.GetRequest(obj.Id);
|
var tvRequests = Tv.GetRequest(obj.Id);
|
||||||
if (tvRequests != null) // Do we already have a request for this?
|
if (tvRequests != null) // Do we already have a request for this?
|
||||||
{
|
{
|
||||||
|
request.RequestId = tvRequests.Id;
|
||||||
request.Requested = true;
|
request.Requested = true;
|
||||||
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||||
|
|
||||||
|
@ -87,11 +76,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available && e.AirDate > DateTime.MinValue)))
|
||||||
{
|
{
|
||||||
request.FullyAvailable = true;
|
request.FullyAvailable = true;
|
||||||
}
|
}
|
||||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available)))
|
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available && e.AirDate > DateTime.MinValue)))
|
||||||
{
|
{
|
||||||
request.PartlyAvailable = true;
|
request.PartlyAvailable = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
@ -10,12 +11,14 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public class PlexAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
public class PlexAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
||||||
{
|
{
|
||||||
public PlexAvailabilityRule(IPlexContentRepository repo)
|
public PlexAvailabilityRule(IPlexContentRepository repo, ILogger<PlexAvailabilityRule> log)
|
||||||
{
|
{
|
||||||
PlexContentRepository = repo;
|
PlexContentRepository = repo;
|
||||||
|
Log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPlexContentRepository PlexContentRepository { get; }
|
private IPlexContentRepository PlexContentRepository { get; }
|
||||||
|
private ILogger Log { get; }
|
||||||
|
|
||||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
|
@ -72,7 +75,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
foreach (var episode in season.Episodes)
|
foreach (var episode in season.Episodes)
|
||||||
{
|
{
|
||||||
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb);
|
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
|
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
|
||||||
//var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
//var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
||||||
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
||||||
|
@ -76,7 +75,7 @@ namespace Ombi.Core.Senders
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.LogError(e, "Error when seing movie to DVR app, added to the request queue");
|
Log.LogError(e, "Error when sending movie to DVR app, added to the request queue");
|
||||||
|
|
||||||
// Check if already in request quee
|
// Check if already in request quee
|
||||||
var existingQueue = await _requestQueuRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
var existingQueue = await _requestQueuRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
||||||
|
|
|
@ -16,6 +16,7 @@ using Ombi.Settings.Settings.Models.External;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Remotion.Linq.Parsing.Structure.IntermediateModel;
|
||||||
|
|
||||||
namespace Ombi.Core.Senders
|
namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
|
@ -57,7 +58,7 @@ namespace Ombi.Core.Senders
|
||||||
var sonarr = await SonarrSettings.GetSettingsAsync();
|
var sonarr = await SonarrSettings.GetSettingsAsync();
|
||||||
if (sonarr.Enabled)
|
if (sonarr.Enabled)
|
||||||
{
|
{
|
||||||
var result = await SendToSonarr(model);
|
var result = await SendToSonarr(model, sonarr);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
return new SenderResult
|
return new SenderResult
|
||||||
|
@ -109,7 +110,7 @@ namespace Ombi.Core.Senders
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError(e, "Exception thrown when sending a movie to DVR app, added to the request queue");
|
Logger.LogError(e, "Exception thrown when sending a movie to DVR app, added to the request queue");
|
||||||
// Check if already in request quee
|
// Check if already in request queue
|
||||||
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
||||||
if (existingQueue != null)
|
if (existingQueue != null)
|
||||||
{
|
{
|
||||||
|
@ -134,7 +135,7 @@ namespace Ombi.Core.Senders
|
||||||
return new SenderResult
|
return new SenderResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
Message = "Something wen't wrong!"
|
Message = "Something went wrong!"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,13 +151,8 @@ namespace Ombi.Core.Senders
|
||||||
/// <param name="s"></param>
|
/// <param name="s"></param>
|
||||||
/// <param name="model"></param>
|
/// <param name="model"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<NewSeries> SendToSonarr(ChildRequests model)
|
public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
|
||||||
{
|
{
|
||||||
var s = await SonarrSettings.GetSettingsAsync();
|
|
||||||
if (!s.Enabled)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(s.ApiKey))
|
if (string.IsNullOrEmpty(s.ApiKey))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -319,10 +315,19 @@ namespace Ombi.Core.Senders
|
||||||
|
|
||||||
foreach (var season in model.SeasonRequests)
|
foreach (var season in model.SeasonRequests)
|
||||||
{
|
{
|
||||||
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber);
|
var sonarrEpisodeList = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber).ToList();
|
||||||
var sonarrEpCount = sonarrSeason.Count();
|
var sonarrEpCount = sonarrEpisodeList.Count;
|
||||||
var ourRequestCount = season.Episodes.Count;
|
var ourRequestCount = season.Episodes.Count;
|
||||||
|
|
||||||
|
var ourEpisodes = season.Episodes.Select(x => x.EpisodeNumber).ToList();
|
||||||
|
var unairedEpisodes = sonarrEpisodeList.Where(x => x.airDateUtc > DateTime.UtcNow).Select(x => x.episodeNumber).ToList();
|
||||||
|
|
||||||
|
//// Check if we have requested all the latest episodes, if we have then monitor
|
||||||
|
//// NOTE, not sure if needed since ombi ui displays future episodes anyway...
|
||||||
|
//ourEpisodes.AddRange(unairedEpisodes);
|
||||||
|
//var distinctEpisodes = ourEpisodes.Distinct().ToList();
|
||||||
|
//var missingEpisodes = Enumerable.Range(distinctEpisodes.Min(), distinctEpisodes.Count).Except(distinctEpisodes);
|
||||||
|
|
||||||
var existingSeason =
|
var existingSeason =
|
||||||
result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
||||||
if (existingSeason == null)
|
if (existingSeason == null)
|
||||||
|
@ -332,7 +337,7 @@ namespace Ombi.Core.Senders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sonarrEpCount == ourRequestCount)
|
if (sonarrEpCount == ourRequestCount /*|| !missingEpisodes.Any()*/)
|
||||||
{
|
{
|
||||||
// We have the same amount of requests as all of the episodes in the season.
|
// We have the same amount of requests as all of the episodes in the season.
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ using Ombi.Api.CouchPotato;
|
||||||
using Ombi.Api.DogNzb;
|
using Ombi.Api.DogNzb;
|
||||||
using Ombi.Api.FanartTv;
|
using Ombi.Api.FanartTv;
|
||||||
using Ombi.Api.Github;
|
using Ombi.Api.Github;
|
||||||
|
using Ombi.Api.Gotify;
|
||||||
using Ombi.Api.Lidarr;
|
using Ombi.Api.Lidarr;
|
||||||
using Ombi.Api.Mattermost;
|
using Ombi.Api.Mattermost;
|
||||||
using Ombi.Api.Notifications;
|
using Ombi.Api.Notifications;
|
||||||
|
@ -51,16 +52,15 @@ using Ombi.Schedule.Jobs.Plex;
|
||||||
using Ombi.Schedule.Jobs.Sonarr;
|
using Ombi.Schedule.Jobs.Sonarr;
|
||||||
using Ombi.Store.Repository.Requests;
|
using Ombi.Store.Repository.Requests;
|
||||||
using Ombi.Updater;
|
using Ombi.Updater;
|
||||||
using PlexContentCacher = Ombi.Schedule.Jobs.Plex;
|
|
||||||
using Ombi.Api.Telegram;
|
using Ombi.Api.Telegram;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Engine.Demo;
|
||||||
using Ombi.Core.Engine.V2;
|
using Ombi.Core.Engine.V2;
|
||||||
using Ombi.Core.Processor;
|
using Ombi.Core.Processor;
|
||||||
using Ombi.Schedule.Jobs.Lidarr;
|
using Ombi.Schedule.Jobs.Lidarr;
|
||||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||||
using Ombi.Schedule.Jobs.SickRage;
|
using Ombi.Schedule.Jobs.SickRage;
|
||||||
using Ombi.Schedule.Processor;
|
using Ombi.Schedule.Processor;
|
||||||
using Ombi.Store.Entities;
|
|
||||||
|
|
||||||
namespace Ombi.DependencyInjection
|
namespace Ombi.DependencyInjection
|
||||||
{
|
{
|
||||||
|
@ -95,12 +95,16 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
||||||
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
||||||
services.AddTransient<IVoteEngine, VoteEngine>();
|
services.AddTransient<IVoteEngine, VoteEngine>();
|
||||||
|
services.AddTransient<IDemoMovieSearchEngine, DemoMovieSearchEngine>();
|
||||||
|
services.AddTransient<IDemoTvSearchEngine, DemoTvSearchEngine>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterEnginesV2(this IServiceCollection services)
|
public static void RegisterEnginesV2(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient<IMultiSearchEngine, MultiSearchEngine>();
|
services.AddTransient<IMultiSearchEngine, MultiSearchEngine>();
|
||||||
services.AddTransient<IMovieEngineV2, MovieSearchEngineV2>();
|
services.AddTransient<IMovieEngineV2, MovieSearchEngineV2>();
|
||||||
|
services.AddTransient<ITVSearchEngineV2, TvSearchEngineV2>();
|
||||||
|
services.AddTransient<ICalendarEngine, CalendarEngine>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterHttp(this IServiceCollection services)
|
public static void RegisterHttp(this IServiceCollection services)
|
||||||
|
@ -127,6 +131,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IOmbiService, OmbiService>();
|
services.AddTransient<IOmbiService, OmbiService>();
|
||||||
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
||||||
services.AddTransient<IPushoverApi, PushoverApi>();
|
services.AddTransient<IPushoverApi, PushoverApi>();
|
||||||
|
services.AddTransient<IGotifyApi, GotifyApi>();
|
||||||
services.AddTransient<IMattermostApi, MattermostApi>();
|
services.AddTransient<IMattermostApi, MattermostApi>();
|
||||||
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
|
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
|
||||||
services.AddTransient<IDogNzbApi, DogNzbApi>();
|
services.AddTransient<IDogNzbApi, DogNzbApi>();
|
||||||
|
@ -139,28 +144,28 @@ namespace Ombi.DependencyInjection
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterStore(this IServiceCollection services) {
|
public static void RegisterStore(this IServiceCollection services) {
|
||||||
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
services.AddDbContext<OmbiContext>();
|
||||||
services.AddEntityFrameworkSqlite().AddDbContext<SettingsContext>();
|
services.AddDbContext<SettingsContext>();
|
||||||
services.AddEntityFrameworkSqlite().AddDbContext<ExternalContext>();
|
services.AddDbContext<ExternalContext>();
|
||||||
|
|
||||||
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||||
services.AddScoped<ISettingsContext, SettingsContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
services.AddScoped<ISettingsContext, SettingsContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||||
services.AddScoped<IExternalContext, ExternalContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
services.AddScoped<IExternalContext, ExternalContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||||
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
services.AddScoped<ISettingsRepository, SettingsJsonRepository>();
|
||||||
services.AddTransient<ISettingsResolver, SettingsResolver>();
|
services.AddScoped<ISettingsResolver, SettingsResolver>();
|
||||||
services.AddTransient<IPlexContentRepository, PlexServerContentRepository>();
|
services.AddScoped<IPlexContentRepository, PlexServerContentRepository>();
|
||||||
services.AddTransient<IEmbyContentRepository, EmbyContentRepository>();
|
services.AddScoped<IEmbyContentRepository, EmbyContentRepository>();
|
||||||
services.AddTransient<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
services.AddScoped<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||||
|
|
||||||
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
|
services.AddScoped<ITvRequestRepository, TvRequestRepository>();
|
||||||
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
|
services.AddScoped<IMovieRequestRepository, MovieRequestRepository>();
|
||||||
services.AddTransient<IMusicRequestRepository, MusicRequestRepository>();
|
services.AddScoped<IMusicRequestRepository, MusicRequestRepository>();
|
||||||
services.AddTransient<IAuditRepository, AuditRepository>();
|
services.AddScoped<IAuditRepository, AuditRepository>();
|
||||||
services.AddTransient<IApplicationConfigRepository, ApplicationConfigRepository>();
|
services.AddScoped<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||||
services.AddTransient<ITokenRepository, TokenRepository>();
|
services.AddScoped<ITokenRepository, TokenRepository>();
|
||||||
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>));
|
services.AddScoped(typeof(ISettingsService<>), typeof(SettingsService<>));
|
||||||
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
|
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
|
||||||
services.AddTransient(typeof(IExternalRepository<>), typeof(ExternalRepository<>));
|
services.AddScoped(typeof(IExternalRepository<>), typeof(ExternalRepository<>));
|
||||||
}
|
}
|
||||||
public static void RegisterServices(this IServiceCollection services)
|
public static void RegisterServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +173,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<INotificationService, NotificationService>();
|
services.AddTransient<INotificationService, NotificationService>();
|
||||||
services.AddTransient<IEmailProvider, GenericEmailProvider>();
|
services.AddTransient<IEmailProvider, GenericEmailProvider>();
|
||||||
services.AddTransient<INotificationHelper, NotificationHelper>();
|
services.AddTransient<INotificationHelper, NotificationHelper>();
|
||||||
services.AddTransient<ICacheService, CacheService>();
|
services.AddSingleton<ICacheService, CacheService>();
|
||||||
|
|
||||||
services.AddTransient<IDiscordNotification, DiscordNotification>();
|
services.AddTransient<IDiscordNotification, DiscordNotification>();
|
||||||
services.AddTransient<IEmailNotification, EmailNotification>();
|
services.AddTransient<IEmailNotification, EmailNotification>();
|
||||||
|
@ -177,6 +182,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<ISlackNotification, SlackNotification>();
|
services.AddTransient<ISlackNotification, SlackNotification>();
|
||||||
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
||||||
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
||||||
|
services.AddTransient<IGotifyNotification, GotifyNotification>();
|
||||||
services.AddTransient<ITelegramNotification, TelegramNotification>();
|
services.AddTransient<ITelegramNotification, TelegramNotification>();
|
||||||
services.AddTransient<IMobileNotification, MobileNotification>();
|
services.AddTransient<IMobileNotification, MobileNotification>();
|
||||||
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
|
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
|
||||||
|
|
28
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
28
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class EmbyHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(UrlData))]
|
||||||
|
public string TestUrl(string mediaId, string url)
|
||||||
|
{
|
||||||
|
return EmbyHelper.GetEmbyMediaUrl(mediaId, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> UrlData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var mediaId = 1;
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_WithoutTrailingSlash");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com/").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "https://google.com/").Returns($"https://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_Https");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
src/Ombi.Helpers.Tests/HtmlHelperTests.cs
Normal file
41
src/Ombi.Helpers.Tests/HtmlHelperTests.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class HtmlHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(HtmlData))]
|
||||||
|
public string RemoveHtmlTests(string input)
|
||||||
|
{
|
||||||
|
return HtmlHelper.RemoveHtml(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> HtmlData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("<h1>hi</h1>").Returns("hi").SetName("Simple Html");
|
||||||
|
yield return new TestCaseData("<html><body><head></head><h1>hi</h1></body></html>").Returns("hi").SetName("Nested text inside Html");
|
||||||
|
yield return new TestCaseData("there is no html here").Returns("there is no html here").SetName("No Html");
|
||||||
|
yield return new TestCaseData("there is <b>some</b> html here").Returns("there is some html here").SetName("Html in middle");
|
||||||
|
yield return new TestCaseData("<a>there</a> <u>is</u> <b>lots</b> <i>html</i> <span>here</span>").Returns("there is lots html here").SetName("Html in everywhere");
|
||||||
|
yield return new TestCaseData("there is <span class=\"abc\">some</span> html here").Returns("there is some html here").SetName("Html in with classes");
|
||||||
|
yield return new TestCaseData("there is <span id=\"sometag\">some</span> html here").Returns("there is some html here").SetName("Html in with attribute");
|
||||||
|
yield return new TestCaseData("there is <span data-tag=\"sometag\" class=\"abc\">some</span> html here").Returns("there is some html here").SetName("Html in with attribute and class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> OtherData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (var data in HtmlData)
|
||||||
|
{
|
||||||
|
yield return data;
|
||||||
|
}
|
||||||
|
yield return new TestCaseData("xyz").Returns("xyz").SetName("More Tests");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="nunit" Version="3.11.0" />
|
<PackageReference Include="nunit" Version="3.11.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
120
src/Ombi.Helpers.Tests/PagnationHelperTests.cs
Normal file
120
src/Ombi.Helpers.Tests/PagnationHelperTests.cs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class PaginationHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(TestPageData))]
|
||||||
|
public void TestPaginationPages(int currentlyLoaded, int toLoad, int maxItemsPerPage, int[] expectedPages)
|
||||||
|
{
|
||||||
|
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||||
|
var pages = result.Select(x => x.Page).ToArray();
|
||||||
|
|
||||||
|
Assert.That(pages.Length, Is.EqualTo(expectedPages.Length), "Did not contain the correct amount of pages");
|
||||||
|
for (var i = 0; i < pages.Length; i++)
|
||||||
|
{
|
||||||
|
Assert.That(pages[i], Is.EqualTo(expectedPages[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> TestPageData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(0, 10, 20, new [] { 1 }).SetName("Pagination_Load_First_Page");
|
||||||
|
yield return new TestCaseData(20, 10, 20, new [] { 2 }).SetName("Pagination_Load_Second_Page");
|
||||||
|
yield return new TestCaseData(0, 20, 20, new [] { 1 }).SetName("Pagination_Load_Full_First_Page");
|
||||||
|
yield return new TestCaseData(20, 20, 20, new [] { 2 }).SetName("Pagination_Load_Full_Second_Page");
|
||||||
|
yield return new TestCaseData(10, 20, 20, new [] { 1, 2 }).SetName("Pagination_Load_Half_First_Page_And_Half_Second_Page");
|
||||||
|
yield return new TestCaseData(19, 20, 20, new[] { 1, 2 }).SetName("Pagination_Load_End_First_Page_And_Most_Second_Page");
|
||||||
|
yield return new TestCaseData(19, 40, 20, new[] { 1, 2, 3 }).SetName("Pagination_Load_End_First_Page_And_Most_Second_And_Third_Page");
|
||||||
|
yield return new TestCaseData(10, 10, 20, new[] { 1 }).SetName("Pagination_Load_Half_First_Page");
|
||||||
|
yield return new TestCaseData(10, 9, 20, new[] { 1 }).SetName("Pagination_Load_LessThan_Half_First_Page");
|
||||||
|
yield return new TestCaseData(20, 10, 20, new[] { 2 }).SetName("Pagination_Load_Half_Second_Page");
|
||||||
|
yield return new TestCaseData(20, 9, 20, new[] { 2 }).SetName("Pagination_Load_LessThan_Half_Second_Page");
|
||||||
|
yield return new TestCaseData(30, 10, 20, new[] { 2 }).SetName("Pagination_Load_All_Second_Page_With_Half_Take");
|
||||||
|
yield return new TestCaseData(49, 1, 50, new[] { 1 }).SetName("Pagination_Load_49_OutOf_50");
|
||||||
|
yield return new TestCaseData(49, 1, 100,new[] { 1 }).SetName("Pagination_Load_50_OutOf_100");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(CurrentPositionTestData))]
|
||||||
|
public void TestCurrentPositionOfPagination(int currentlyLoaded, int toLoad, int maxItemsPerPage, int expectedTake, int expectedSkip)
|
||||||
|
{
|
||||||
|
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||||
|
|
||||||
|
var first = result.FirstOrDefault();
|
||||||
|
Assert.That(first.Take, Is.EqualTo(expectedTake));
|
||||||
|
Assert.That(first.Skip, Is.EqualTo(expectedSkip));
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> CurrentPositionTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(0, 10, 20, 10, 0).SetName("PaginationPosition_Load_First_Half_Of_Page");
|
||||||
|
yield return new TestCaseData(10, 10, 20, 10, 10).SetName("PaginationPosition_Load_EndHalf_First_Page");
|
||||||
|
yield return new TestCaseData(19, 1, 20, 1, 19).SetName("PaginationPosition_Load_LastItem_Of_First_Page");
|
||||||
|
yield return new TestCaseData(20, 20, 300, 20, 20).SetName("PaginationPosition_Load_Full_Second_Page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(CurrentPositionMultiplePagesTestData))]
|
||||||
|
public void TestCurrentPositionOfPaginationWithMultiplePages(int currentlyLoaded, int toLoad, int maxItemsPerPage, List<MultiplePagesTestData> data)
|
||||||
|
{
|
||||||
|
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||||
|
|
||||||
|
foreach (var r in result)
|
||||||
|
{
|
||||||
|
// get result data for this page
|
||||||
|
var expectedPage = data.FirstOrDefault(x => x.Page == r.Page);
|
||||||
|
Assert.That(r.Take, Is.EqualTo(expectedPage.ExpectedTake));
|
||||||
|
Assert.That(r.Skip, Is.EqualTo(expectedPage.ExpectedSkip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> CurrentPositionMultiplePagesTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(10, 20, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 10, 10), new MultiplePagesTestData(2, 10, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_SecondHalf_FirstPage_FirstHalf_SecondPage");
|
||||||
|
yield return new TestCaseData(0, 40, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 20, 0), new MultiplePagesTestData(2, 20, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_Full_First_And_SecondPage");
|
||||||
|
yield return new TestCaseData(35, 15, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 5, 15), new MultiplePagesTestData(3, 10, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_EndSecondPage_Beginning_ThirdPage");
|
||||||
|
yield return new TestCaseData(18, 22, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 2, 18), new MultiplePagesTestData(2, 20, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_EndFirstPage_Full_SecondPage");
|
||||||
|
yield return new TestCaseData(38, 4, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 2, 18), new MultiplePagesTestData(3, 2, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_EndSecondPage_Some_ThirdPage");
|
||||||
|
yield return new TestCaseData(15, 20, 10, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 5, 5), new MultiplePagesTestData(3, 10, 0), new MultiplePagesTestData(4, 5, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_EndSecondPage_All_ThirdPage_Some_ForthPage");
|
||||||
|
yield return new TestCaseData(24, 12, 12, new List<MultiplePagesTestData> { new MultiplePagesTestData(3, 12, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_ThirdPage_Of_12");
|
||||||
|
yield return new TestCaseData(12, 12, 12, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 12, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_SecondPage_Of_12");
|
||||||
|
yield return new TestCaseData(40, 20, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(3, 20, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_FullThird_Page");
|
||||||
|
yield return new TestCaseData(240, 12, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(13, 12, 0) })
|
||||||
|
.SetName("PaginationPosition_Load_Page_13");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MultiplePagesTestData
|
||||||
|
{
|
||||||
|
public MultiplePagesTestData(int page, int take, int skip)
|
||||||
|
{
|
||||||
|
Page = page;
|
||||||
|
ExpectedTake = take;
|
||||||
|
ExpectedSkip = skip;
|
||||||
|
}
|
||||||
|
public int Page { get; set; }
|
||||||
|
public int ExpectedTake { get; set; }
|
||||||
|
public int ExpectedSkip { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
115
src/Ombi.Helpers.Tests/UriHelperTests.cs
Normal file
115
src/Ombi.Helpers.Tests/UriHelperTests.cs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UriHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(UrlData))]
|
||||||
|
public string ReturnUri(string uri)
|
||||||
|
{
|
||||||
|
return UriHelper.ReturnUri(uri).ToString();
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> UrlData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("https://google.com/").Returns($"https://google.com/").SetName("ReturnUri_With_HttpScheme");
|
||||||
|
yield return new TestCaseData("google.com/").Returns($"http://google.com/").SetName("ReturnUri_HttpScheme_Not_Provided");
|
||||||
|
yield return new TestCaseData("http://google.com:9090/").Returns($"http://google.com:9090/").SetName("ReturnUri_WithPort");
|
||||||
|
yield return new TestCaseData("https://google.com/").Returns($"https://google.com/").SetName("ReturnUri_With_HttpsScheme");
|
||||||
|
yield return new TestCaseData("https://hi.google.com/").Returns($"https://hi.google.com/").SetName("ReturnUri_With_SubDomain");
|
||||||
|
yield return new TestCaseData("https://google.com/hi").Returns($"https://google.com/hi").SetName("ReturnUri_With_Path");
|
||||||
|
yield return new TestCaseData("https://hi.google.com/hi").Returns($"https://hi.google.com/hi").SetName("ReturnUri_With_Path_And_SubDomain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(UrlWithPortData))]
|
||||||
|
public string ReturnUriWithPort(string uri, int port)
|
||||||
|
{
|
||||||
|
return UriHelper.ReturnUri(uri, port).ToString();
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> UrlWithPortData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
|
||||||
|
yield return new TestCaseData("https://google.com", 443).Returns($"https://google.com/").SetName("ReturnUri_With_HttpsPort");
|
||||||
|
yield return new TestCaseData("https://google.com/", 123).Returns($"https://google.com:123/").SetName("ReturnUri_With_HttpScheme_With_Port");
|
||||||
|
yield return new TestCaseData("google.com/", 80).Returns($"http://google.com/").SetName("ReturnUri_HttpScheme_Not_Provided_With_Port");
|
||||||
|
yield return new TestCaseData("https://google.com/", 7000).Returns($"https://google.com:7000/").SetName("ReturnUri_With_HttpsScheme_With_Port");
|
||||||
|
yield return new TestCaseData("https://hi.google.com/", 1).Returns($"https://hi.google.com:1/").SetName("ReturnUri_With_SubDomain_With_Port");
|
||||||
|
yield return new TestCaseData("https://google.com/hi", 443).Returns($"https://google.com/hi").SetName("ReturnUri_With_Path_With_Port");
|
||||||
|
yield return new TestCaseData("https://hi.google.com/hi", 443).Returns($"https://hi.google.com/hi").SetName("ReturnUri_With_Path_And_SubDomain_With_Port");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(UrlWithPortWithSSLData))]
|
||||||
|
public string ReturnUriWithPortAndSSL(string uri, int port, bool ssl)
|
||||||
|
{
|
||||||
|
return UriHelper.ReturnUri(uri, port, ssl).ToString();
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> UrlWithPortWithSSLData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (var d in UrlWithPortData)
|
||||||
|
{
|
||||||
|
var expected = (string)d.ExpectedResult;
|
||||||
|
var args = d.Arguments.ToList();
|
||||||
|
args.Add(true);
|
||||||
|
var newExpected = expected.Replace("http://", "https://");
|
||||||
|
if (args.Contains(80))
|
||||||
|
{
|
||||||
|
newExpected = expected;
|
||||||
|
}
|
||||||
|
d.TestName += "_With_SSL";
|
||||||
|
|
||||||
|
yield return new TestCaseData(args.ToArray()).Returns(newExpected).SetName(d.TestName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(UrlWithPortWithSSLDataCasing))]
|
||||||
|
public string ReturnUriWithPortAndSSLCasing(string uri, int port, bool ssl)
|
||||||
|
{
|
||||||
|
return UriHelper.ReturnUri(uri, port, ssl).ToString();
|
||||||
|
}
|
||||||
|
public static IEnumerable<TestCaseData> UrlWithPortWithSSLDataCasing
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (var d in UrlWithPortData)
|
||||||
|
{
|
||||||
|
if (d.TestName.Contains("_Path_"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var expected = (string)d.ExpectedResult;
|
||||||
|
var args = d.Arguments.ToList();
|
||||||
|
for (int i = 0; i < args.Count; i++)
|
||||||
|
{
|
||||||
|
if(args[i] is string)
|
||||||
|
{
|
||||||
|
args[i] = ((string)args[i]).ToUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.Add(true);
|
||||||
|
var newExpected = expected.Replace("http://", "https://");
|
||||||
|
if (args.Contains(80))
|
||||||
|
{
|
||||||
|
newExpected = expected;
|
||||||
|
}
|
||||||
|
d.TestName += "_With_SSL_ToUpper";
|
||||||
|
|
||||||
|
yield return new TestCaseData(args.ToArray()).Returns(newExpected).SetName(d.TestName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ namespace Ombi.Helpers
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (await _mutex.LockAsync())
|
//using (await _mutex.LockAsync())
|
||||||
{
|
{
|
||||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Ombi.Helpers
|
|
||||||
{
|
|
||||||
public class ClaimConverter : JsonConverter
|
|
||||||
{
|
|
||||||
public override bool CanConvert(Type objectType)
|
|
||||||
{
|
|
||||||
return (objectType == typeof(System.Security.Claims.Claim));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var claim = (System.Security.Claims.Claim)value;
|
|
||||||
JObject jo = new JObject();
|
|
||||||
jo.Add("Type", claim.Type);
|
|
||||||
jo.Add("Value", IsJson(claim.Value) ? new JRaw(claim.Value) : new JValue(claim.Value));
|
|
||||||
jo.Add("ValueType", claim.ValueType);
|
|
||||||
jo.Add("Issuer", claim.Issuer);
|
|
||||||
jo.Add("OriginalIssuer", claim.OriginalIssuer);
|
|
||||||
jo.WriteTo(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
JObject jo = JObject.Load(reader);
|
|
||||||
string type = (string)jo["Type"];
|
|
||||||
JToken token = jo["Value"];
|
|
||||||
string value = token.Type == JTokenType.String ? (string)token : token.ToString(Formatting.None);
|
|
||||||
string valueType = (string)jo["ValueType"];
|
|
||||||
string issuer = (string)jo["Issuer"];
|
|
||||||
string originalIssuer = (string)jo["OriginalIssuer"];
|
|
||||||
return new Claim(type, value, valueType, issuer, originalIssuer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsJson(string val)
|
|
||||||
{
|
|
||||||
return (val != null &&
|
|
||||||
(val.StartsWith("[") && val.EndsWith("]")) ||
|
|
||||||
(val.StartsWith("{") && val.EndsWith("}")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
11
src/Ombi.Helpers/DemoLists.cs
Normal file
11
src/Ombi.Helpers/DemoLists.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ombi.Config
|
||||||
|
{
|
||||||
|
public class DemoLists
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public int[] Movies { get; set; }
|
||||||
|
public int[] TvShows { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
13
src/Ombi.Helpers/DemoSingleton.cs
Normal file
13
src/Ombi.Helpers/DemoSingleton.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Ombi.Helpers
|
||||||
|
{
|
||||||
|
public class DemoSingleton
|
||||||
|
{
|
||||||
|
private static DemoSingleton instance;
|
||||||
|
|
||||||
|
private DemoSingleton() { }
|
||||||
|
|
||||||
|
public static DemoSingleton Instance => instance ?? (instance = new DemoSingleton());
|
||||||
|
|
||||||
|
public bool Demo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,4 @@
|
||||||
using System;
|
namespace Ombi.Helpers
|
||||||
using System.Globalization;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ombi.Helpers
|
|
||||||
{
|
{
|
||||||
public class EmbyHelper
|
public class EmbyHelper
|
||||||
{
|
{
|
||||||
|
@ -11,6 +6,10 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
if (customerServerUrl.HasValue())
|
if (customerServerUrl.HasValue())
|
||||||
{
|
{
|
||||||
|
if(!customerServerUrl.EndsWith("/"))
|
||||||
|
{
|
||||||
|
return $"{customerServerUrl}/#!/itemdetails.html?id={mediaId}";
|
||||||
|
}
|
||||||
return $"{customerServerUrl}#!/itemdetails.html?id={mediaId}";
|
return $"{customerServerUrl}#!/itemdetails.html?id={mediaId}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -14,6 +14,5 @@ namespace Ombi.Helpers
|
||||||
var step2 = Regex.Replace(step1, @"\s{2,}", " ");
|
var step2 = Regex.Replace(step1, @"\s{2,}", " ");
|
||||||
return step2;
|
return step2;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ombi.Helpers
|
namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
|
@ -21,5 +22,31 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
return new HashSet<T>(source, comparer);
|
return new HashSet<T>(source, comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
|
||||||
|
{
|
||||||
|
return source.Shuffle(new Random());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
|
||||||
|
{
|
||||||
|
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||||
|
if (rng == null) throw new ArgumentNullException(nameof(rng));
|
||||||
|
|
||||||
|
return source.ShuffleIterator(rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<T> ShuffleIterator<T>(
|
||||||
|
this IEnumerable<T> source, Random rng)
|
||||||
|
{
|
||||||
|
var buffer = source.ToList();
|
||||||
|
for (int i = 0; i < buffer.Count; i++)
|
||||||
|
{
|
||||||
|
int j = rng.Next(i, buffer.Count);
|
||||||
|
yield return buffer[j];
|
||||||
|
|
||||||
|
buffer[j] = buffer[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,6 +32,7 @@ namespace Ombi.Helpers
|
||||||
public static EventId MattermostNotification => new EventId(4004);
|
public static EventId MattermostNotification => new EventId(4004);
|
||||||
public static EventId PushoverNotification => new EventId(4005);
|
public static EventId PushoverNotification => new EventId(4005);
|
||||||
public static EventId TelegramNotifcation => new EventId(4006);
|
public static EventId TelegramNotifcation => new EventId(4006);
|
||||||
|
public static EventId GotifyNotification => new EventId(4007);
|
||||||
|
|
||||||
public static EventId TvSender => new EventId(5000);
|
public static EventId TvSender => new EventId(5000);
|
||||||
public static EventId SonarrSender => new EventId(5001);
|
public static EventId SonarrSender => new EventId(5001);
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
Slack = 5,
|
Slack = 5,
|
||||||
Mattermost = 6,
|
Mattermost = 6,
|
||||||
Mobile = 7,
|
Mobile = 7,
|
||||||
|
Gotify = 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,5 +15,6 @@
|
||||||
public const string Disabled = nameof(Disabled);
|
public const string Disabled = nameof(Disabled);
|
||||||
public const string ReceivesNewsletter = nameof(ReceivesNewsletter);
|
public const string ReceivesNewsletter = nameof(ReceivesNewsletter);
|
||||||
public const string ManageOwnRequests = nameof(ManageOwnRequests);
|
public const string ManageOwnRequests = nameof(ManageOwnRequests);
|
||||||
|
public const string EditCustomPage = nameof(EditCustomPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
64
src/Ombi.Helpers/PaginationHelper.cs
Normal file
64
src/Ombi.Helpers/PaginationHelper.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers
|
||||||
|
{
|
||||||
|
public static class PaginationHelper
|
||||||
|
{
|
||||||
|
public static List<PagesToLoad> GetNextPages(int currentlyLoaded, int toTake, int maxItemsPerPage)
|
||||||
|
{
|
||||||
|
var result = new List<PagesToLoad>();
|
||||||
|
|
||||||
|
var firstPage = currentlyLoaded / maxItemsPerPage + 1;
|
||||||
|
var startPos = currentlyLoaded % maxItemsPerPage + 1;
|
||||||
|
|
||||||
|
var lastItemIndex = currentlyLoaded + toTake - 1;
|
||||||
|
var lastPage = lastItemIndex / maxItemsPerPage + 1;
|
||||||
|
var stopPos = lastItemIndex % maxItemsPerPage + 1;
|
||||||
|
|
||||||
|
while (currentlyLoaded > maxItemsPerPage)
|
||||||
|
{
|
||||||
|
currentlyLoaded -= maxItemsPerPage;
|
||||||
|
}
|
||||||
|
if ((currentlyLoaded % maxItemsPerPage) == 0 && (currentlyLoaded % toTake) == 0)
|
||||||
|
{
|
||||||
|
currentlyLoaded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var page1 = new PagesToLoad { Page = firstPage, Skip = currentlyLoaded, Take = toTake };
|
||||||
|
|
||||||
|
if (toTake + startPos - 1 > maxItemsPerPage)
|
||||||
|
{
|
||||||
|
page1.Take = maxItemsPerPage - startPos + 1;
|
||||||
|
result.Add(page1);
|
||||||
|
|
||||||
|
for (var i = firstPage + 1; i < lastPage; i++)
|
||||||
|
{
|
||||||
|
var nextPage = new PagesToLoad { Page = i, Skip = 0, Take = maxItemsPerPage };
|
||||||
|
result.Add(nextPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pageN = new PagesToLoad { Page = lastPage, Skip = 0, Take = stopPos };
|
||||||
|
result.Add(pageN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (page1.Skip + page1.Take > maxItemsPerPage)
|
||||||
|
{
|
||||||
|
page1.Skip = 0;
|
||||||
|
}
|
||||||
|
result.Add(page1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PagesToLoad
|
||||||
|
{
|
||||||
|
public int Page { get; set; }
|
||||||
|
public int Take { get; set; }
|
||||||
|
public int Skip { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,46 +6,44 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
private const string Https = "Https";
|
private const string Https = "Https";
|
||||||
private const string Http = "Http";
|
private const string Http = "Http";
|
||||||
|
|
||||||
public static Uri ReturnUri(this string val)
|
public static Uri ReturnUri(this string val)
|
||||||
{
|
{
|
||||||
if (val == null)
|
if (val == null)
|
||||||
{
|
{
|
||||||
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
||||||
}
|
}
|
||||||
try
|
var uri = new UriBuilder();
|
||||||
|
|
||||||
|
if (val.StartsWith("http://", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
var uri = new UriBuilder();
|
uri = new UriBuilder(val);
|
||||||
|
|
||||||
if (val.StartsWith("http://", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
uri = new UriBuilder(val);
|
|
||||||
}
|
|
||||||
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
uri = new UriBuilder(val);
|
|
||||||
}
|
|
||||||
else if (val.Contains(":"))
|
|
||||||
{
|
|
||||||
var split = val.Split(':', '/');
|
|
||||||
int port;
|
|
||||||
int.TryParse(split[1], out port);
|
|
||||||
|
|
||||||
uri = split.Length == 3
|
|
||||||
? new UriBuilder(Http, split[0], port, "/" + split[2])
|
|
||||||
: new UriBuilder(Http, split[0], port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uri = new UriBuilder(Http, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri.Uri;
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
throw new Exception(exception.Message, exception);
|
uri = new UriBuilder(val);
|
||||||
}
|
}
|
||||||
|
else if (val.Contains(":"))
|
||||||
|
{
|
||||||
|
var split = val.Split(':', '/');
|
||||||
|
int port;
|
||||||
|
int.TryParse(split[1], out port);
|
||||||
|
|
||||||
|
uri = split.Length == 3
|
||||||
|
? new UriBuilder(Http, split[0], port, "/" + split[2])
|
||||||
|
: new UriBuilder(Http, split[0], port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(val.EndsWith("/"))
|
||||||
|
{
|
||||||
|
// Remove a trailing slash, since the URIBuilder adds one
|
||||||
|
val = val.Remove(val.Length - 1, 1);
|
||||||
|
}
|
||||||
|
uri = new UriBuilder(Http, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,37 +62,40 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
||||||
}
|
}
|
||||||
try
|
var uri = new UriBuilder();
|
||||||
{
|
|
||||||
var uri = new UriBuilder();
|
|
||||||
|
|
||||||
if (val.StartsWith("http://", StringComparison.Ordinal))
|
if (val.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
|
||||||
var split = val.Split('/');
|
|
||||||
uri = split.Length >= 4 ? new UriBuilder(Http, split[2], port, "/" + split[3]) : new UriBuilder(new Uri($"{val}:{port}"));
|
|
||||||
}
|
|
||||||
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var split = val.Split('/');
|
|
||||||
uri = split.Length >= 4
|
|
||||||
? new UriBuilder(Https, split[2], port, "/" + split[3])
|
|
||||||
: new UriBuilder(Https, split[2], port);
|
|
||||||
}
|
|
||||||
else if (ssl)
|
|
||||||
{
|
|
||||||
uri = new UriBuilder(Https, val, port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uri = new UriBuilder(Http, val, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri.Uri;
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
{
|
||||||
throw new Exception(exception.Message, exception);
|
var split = val.Split('/');
|
||||||
|
uri = split.Length >= 4 ? new UriBuilder(Http, split[2], port, "/" + split[3]) : new UriBuilder(new Uri($"{val}:{port}"));
|
||||||
}
|
}
|
||||||
|
else if (val.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var split = val.Split('/');
|
||||||
|
uri = split.Length >= 4
|
||||||
|
? new UriBuilder(Https, split[2], port, "/" + split[3])
|
||||||
|
: new UriBuilder(Https, split[2], port);
|
||||||
|
}
|
||||||
|
else if ((ssl || port == 443) && port != 80)
|
||||||
|
{
|
||||||
|
if (val.EndsWith("/"))
|
||||||
|
{
|
||||||
|
// Remove a trailing slash, since the URIBuilder adds one
|
||||||
|
val = val.Remove(val.Length - 1, 1);
|
||||||
|
}
|
||||||
|
uri = new UriBuilder(Https, val, port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (val.EndsWith("/"))
|
||||||
|
{
|
||||||
|
// Remove a trailing slash, since the URIBuilder adds one
|
||||||
|
val = val.Remove(val.Length - 1, 1);
|
||||||
|
}
|
||||||
|
uri = new UriBuilder(Http, val, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri ReturnUriWithSubDir(this string val, int port, bool ssl, string subDir)
|
public static Uri ReturnUriWithSubDir(this string val, int port, bool ssl, string subDir)
|
||||||
|
@ -112,7 +113,7 @@ namespace Ombi.Helpers
|
||||||
|
|
||||||
return uriBuilder.Uri;
|
return uriBuilder.Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ApplicationSettingsException : Exception
|
public class ApplicationSettingsException : Exception
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using AutoMapper;
|
|
||||||
using AutoMapper.Configuration;
|
using AutoMapper.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
@ -12,9 +11,9 @@ namespace Ombi.Mapping
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddOmbiMappingProfile(this IServiceCollection services)
|
public static IServiceCollection AddOmbiMappingProfile(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
System.Reflection.Assembly ass = typeof(AutoMapperProfile).GetTypeInfo().Assembly;
|
Assembly ass = typeof(AutoMapperProfile).GetTypeInfo().Assembly;
|
||||||
var assemblies = new List<Type>();
|
var assemblies = new List<Type>();
|
||||||
foreach (System.Reflection.TypeInfo ti in ass.DefinedTypes)
|
foreach (TypeInfo ti in ass.DefinedTypes)
|
||||||
{
|
{
|
||||||
if (ti.ImplementedInterfaces.Contains(typeof(IProfileConfiguration)))
|
if (ti.ImplementedInterfaces.Contains(typeof(IProfileConfiguration)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,8 @@ 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;
|
||||||
using Ombi.TheMovieDbApi.Models;
|
using Ombi.TheMovieDbApi.Models;
|
||||||
|
using Keywords = Ombi.Core.Models.Search.V2.Keywords;
|
||||||
|
using KeywordsValue = Ombi.Api.TheMovieDb.Models.KeywordsValue;
|
||||||
|
|
||||||
namespace Ombi.Mapping.Profiles
|
namespace Ombi.Mapping.Profiles
|
||||||
{
|
{
|
||||||
|
@ -86,6 +88,22 @@ namespace Ombi.Mapping.Profiles
|
||||||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCast, Ombi.Core.Models.Search.V2.FullMovieCastViewModel>().ReverseMap();
|
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCast, Ombi.Core.Models.Search.V2.FullMovieCastViewModel>().ReverseMap();
|
||||||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCrew, Ombi.Core.Models.Search.V2.FullMovieCrewViewModel>().ReverseMap();
|
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCrew, Ombi.Core.Models.Search.V2.FullMovieCrewViewModel>().ReverseMap();
|
||||||
CreateMap<Ombi.Api.TheMovieDb.Models.ExternalIds, Ombi.Core.Models.Search.V2.ExternalIds>().ReverseMap();
|
CreateMap<Ombi.Api.TheMovieDb.Models.ExternalIds, Ombi.Core.Models.Search.V2.ExternalIds>().ReverseMap();
|
||||||
|
CreateMap<BelongsToCollection, Ombi.Core.Models.Search.V2.CollectionsViewModel>().ReverseMap();
|
||||||
|
CreateMap<Api.TheMovieDb.Models.Keywords, Ombi.Core.Models.Search.V2.Keywords>().ReverseMap();
|
||||||
|
CreateMap<KeywordsValue, Ombi.Core.Models.Search.V2.KeywordsValue>().ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<Collections, Ombi.Core.Models.Search.V2.MovieCollectionsViewModel>()
|
||||||
|
.ForMember(x => x.Name, o => o.MapFrom(s => s.name))
|
||||||
|
.ForMember(x => x.Overview, o => o.MapFrom(s => s.overview))
|
||||||
|
.ForMember(x => x.Collection, o => o.MapFrom(s => s.parts));
|
||||||
|
|
||||||
|
CreateMap<Part, MovieCollection>()
|
||||||
|
.ForMember(x => x.Id, o => o.MapFrom(s => s.id))
|
||||||
|
.ForMember(x => x.Overview, o => o.MapFrom(s => s.overview))
|
||||||
|
.ForMember(x => x.PosterPath, o => o.MapFrom(s => s.poster_path))
|
||||||
|
.ForMember(x => x.Title, o => o.MapFrom(s => s.title));
|
||||||
|
|
||||||
|
CreateMap<SearchMovieViewModel, MovieCollection>().ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ namespace Ombi.Mapping.Profiles
|
||||||
CreateMap<UpdateSettingsViewModel, UpdateSettings>().ReverseMap();
|
CreateMap<UpdateSettingsViewModel, UpdateSettings>().ReverseMap();
|
||||||
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
|
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
|
||||||
CreateMap<NewsletterNotificationViewModel, NewsletterSettings>().ReverseMap();
|
CreateMap<NewsletterNotificationViewModel, NewsletterSettings>().ReverseMap();
|
||||||
|
CreateMap<GotifyNotificationViewModel, GotifySettings>().ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
82
src/Ombi.Mapping/Profiles/TvProfileV2.cs
Normal file
82
src/Ombi.Mapping/Profiles/TvProfileV2.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System.Globalization;
|
||||||
|
using AutoMapper;
|
||||||
|
using Ombi.Api.TvMaze.Models.V2;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Models.Search.V2;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
|
namespace Ombi.Mapping.Profiles
|
||||||
|
{
|
||||||
|
public class TvProfileV2 : Profile
|
||||||
|
{
|
||||||
|
public TvProfileV2()
|
||||||
|
{
|
||||||
|
CreateMap<FullSearch, SearchFullInfoTvShowViewModel>()
|
||||||
|
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.externals.thetvdb))
|
||||||
|
.ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.premiered))
|
||||||
|
.ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.externals.imdb))
|
||||||
|
.ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.network.name))
|
||||||
|
.ForMember(dest => dest.NetworkId, opts => opts.MapFrom(src => src.network.id.ToString()))
|
||||||
|
.ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.summary.RemoveHtml()))
|
||||||
|
.ForMember(dest => dest.Rating,
|
||||||
|
opts => opts.MapFrom(src => src.rating.average.ToString(CultureInfo.CurrentUICulture)))
|
||||||
|
.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.runtime.ToString()))
|
||||||
|
.ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id))
|
||||||
|
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.name))
|
||||||
|
.ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.network))
|
||||||
|
.ForMember(dest => dest.Images, opts => opts.MapFrom(src => src.image))
|
||||||
|
.ForMember(dest => dest.Cast, opts => opts.MapFrom(src => src._embedded.cast))
|
||||||
|
.ForMember(dest => dest.Crew, opts => opts.MapFrom(src => src._embedded.crew))
|
||||||
|
.ForMember(dest => dest.Banner,
|
||||||
|
opts => opts.MapFrom(src =>
|
||||||
|
!string.IsNullOrEmpty(src.image.medium)
|
||||||
|
? src.image.medium.Replace("http", "https")
|
||||||
|
: string.Empty))
|
||||||
|
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.status));
|
||||||
|
|
||||||
|
CreateMap<Network, NetworkViewModel>()
|
||||||
|
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||||
|
.ForMember(dest => dest.Country, opts => opts.MapFrom(src => src.country))
|
||||||
|
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Country, Core.Models.Search.V2.Country>()
|
||||||
|
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||||
|
.ForMember(dest => dest.Code, opts => opts.MapFrom(src => src.code))
|
||||||
|
.ForMember(dest => dest.Timezone, opts => opts.MapFrom(src => src.timezone));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Image, Images>()
|
||||||
|
.ForMember(dest => dest.Medium, opts => opts.MapFrom(src => src.medium))
|
||||||
|
.ForMember(dest => dest.Original, opts => opts.MapFrom(src => src.original));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Cast, CastViewModel>()
|
||||||
|
.ForMember(dest => dest.Character, opts => opts.MapFrom(src => src.character))
|
||||||
|
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||||
|
.ForMember(dest => dest.Voice, opts => opts.MapFrom(src => src.voice))
|
||||||
|
.ForMember(dest => dest.Self, opts => opts.MapFrom(src => src.self));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Person, PersonViewModel>()
|
||||||
|
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||||
|
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||||
|
.ForMember(dest => dest.Image, opts => opts.MapFrom(src => src.image))
|
||||||
|
.ForMember(dest => dest.Url, opts => opts.MapFrom(src => src.url));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Crew, CrewViewModel>()
|
||||||
|
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||||
|
.ForMember(dest => dest.Type, opts => opts.MapFrom(src => src.type));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Cast, CastViewModel>()
|
||||||
|
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||||
|
.ForMember(dest => dest.Self, opts => opts.MapFrom(src => src.self))
|
||||||
|
.ForMember(dest => dest.Voice, opts => opts.MapFrom(src => src.voice))
|
||||||
|
.ForMember(dest => dest.Character, opts => opts.MapFrom(src => src.character));
|
||||||
|
|
||||||
|
CreateMap<Api.TvMaze.Models.V2.Character, CharacterViewModel>()
|
||||||
|
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||||
|
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||||
|
.ForMember(dest => dest.Url, opts => opts.MapFrom(src => src.url))
|
||||||
|
.ForMember(dest => dest.Image, opts => opts.MapFrom(src => src.image));
|
||||||
|
|
||||||
|
CreateMap<SearchTvShowViewModel, SearchFullInfoTvShowViewModel>().ReverseMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ namespace Ombi.Notifications.Templates
|
||||||
if (string.IsNullOrEmpty(_templateLocation))
|
if (string.IsNullOrEmpty(_templateLocation))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "netcoreapp2.0", "Templates",
|
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "netcoreapp2.2", "Templates",
|
||||||
"BasicTemplate.html");
|
"BasicTemplate.html");
|
||||||
#else
|
#else
|
||||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "Templates","BasicTemplate.html");
|
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "Templates","BasicTemplate.html");
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||||
<PackageReference Include="Moq" Version="4.10.0" />
|
<PackageReference Include="Moq" Version="4.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
116
src/Ombi.Notifications/Agents/GotifyNotification.cs
Normal file
116
src/Ombi.Notifications/Agents/GotifyNotification.cs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Gotify;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public class GotifyNotification : BaseNotification<GotifySettings>, IGotifyNotification
|
||||||
|
{
|
||||||
|
public GotifyNotification(IGotifyApi api, ISettingsService<GotifySettings> sn, ILogger<GotifyNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Logger = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string NotificationName => "GotifyNotification";
|
||||||
|
|
||||||
|
private IGotifyApi Api { get; }
|
||||||
|
private ILogger<GotifyNotification> Logger { get; }
|
||||||
|
|
||||||
|
protected override bool ValidateConfiguration(GotifySettings settings)
|
||||||
|
{
|
||||||
|
return settings.Enabled && !string.IsNullOrEmpty(settings.BaseUrl) && !string.IsNullOrEmpty(settings.ApplicationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task NewRequest(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.NewRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override async Task NewIssue(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.Issue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task IssueComment(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.IssueComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task IssueResolved(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.IssueResolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AddedToRequestQueue(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.ItemAddedToFaultQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestDeclined(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestDeclined);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestApproved(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestApproved);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AvailableRequest(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Send(NotificationMessage model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Api.PushAsync(settings.BaseUrl, settings.ApplicationToken, model.Subject, model.Message, settings.Priority);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.GotifyNotification, e, "Failed to send Gotify notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Test(NotificationOptions model, GotifySettings settings)
|
||||||
|
{
|
||||||
|
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Run(NotificationOptions model, GotifySettings settings, NotificationType type)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Gotify, type, model);
|
||||||
|
if (parsed.Disabled)
|
||||||
|
{
|
||||||
|
Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Gotify}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public interface IGotifyNotification : INotification
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ namespace Ombi.Notifications.Agents
|
||||||
private void AddOtherInformation(NotificationOptions model, NotificationMessage notification,
|
private void AddOtherInformation(NotificationOptions model, NotificationMessage notification,
|
||||||
NotificationMessageContent parsed)
|
NotificationMessageContent parsed)
|
||||||
{
|
{
|
||||||
notification.Other.Add("image", parsed.Image);
|
notification.Other.Add("image", parsed?.Image ?? string.Empty);
|
||||||
notification.Other.Add("title", model.RequestType == RequestType.Movie ? MovieRequest.Title : TvRequest.Title);
|
notification.Other.Add("title", model.RequestType == RequestType.Movie ? MovieRequest.Title : TvRequest.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,6 @@ namespace Ombi.Notifications
|
||||||
MovieRepository = movie;
|
MovieRepository = movie;
|
||||||
TvRepository = tv;
|
TvRepository = tv;
|
||||||
CustomizationSettings = customization;
|
CustomizationSettings = customization;
|
||||||
Settings.ClearCache();
|
|
||||||
CustomizationSettings.ClearCache();
|
|
||||||
RequestSubscription = sub;
|
RequestSubscription = sub;
|
||||||
_log = log;
|
_log = log;
|
||||||
AlbumRepository = album;
|
AlbumRepository = album;
|
||||||
|
@ -55,14 +53,12 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
public async Task NotifyAsync(NotificationOptions model)
|
public async Task NotifyAsync(NotificationOptions model)
|
||||||
{
|
{
|
||||||
Settings.ClearCache();
|
|
||||||
var configuration = await GetConfiguration();
|
var configuration = await GetConfiguration();
|
||||||
await NotifyAsync(model, configuration);
|
await NotifyAsync(model, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task NotifyAsync(NotificationOptions model, Settings.Settings.Models.Settings settings)
|
public async Task NotifyAsync(NotificationOptions model, Settings.Settings.Models.Settings settings)
|
||||||
{
|
{
|
||||||
Settings.ClearCache();
|
|
||||||
if (settings == null) await NotifyAsync(model);
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
var notificationSettings = (T)settings;
|
var notificationSettings = (T)settings;
|
||||||
|
|
|
@ -4,7 +4,9 @@ using EnsureThat;
|
||||||
using MailKit.Net.Smtp;
|
using MailKit.Net.Smtp;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
|
using MimeKit.Utils;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
using Ombi.Notifications.Templates;
|
using Ombi.Notifications.Templates;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
|
@ -36,6 +38,15 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
var customization = await CustomizationSettings.GetSettingsAsync();
|
var customization = await CustomizationSettings.GetSettingsAsync();
|
||||||
var html = email.LoadTemplate(model.Subject, model.Message, null, customization.Logo);
|
var html = email.LoadTemplate(model.Subject, model.Message, null, customization.Logo);
|
||||||
|
|
||||||
|
var messageId = MimeUtils.GenerateMessageId();
|
||||||
|
if (customization.ApplicationUrl.HasValue())
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate(customization.ApplicationUrl, UriKind.RelativeOrAbsolute, out var url))
|
||||||
|
{
|
||||||
|
messageId = MimeUtils.GenerateMessageId(url.IdnHost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var textBody = string.Empty;
|
var textBody = string.Empty;
|
||||||
|
|
||||||
|
@ -49,7 +60,8 @@ namespace Ombi.Notifications
|
||||||
var message = new MimeMessage
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
Body = body.ToMessageBody(),
|
Body = body.ToMessageBody(),
|
||||||
Subject = model.Subject
|
Subject = model.Subject,
|
||||||
|
MessageId = messageId
|
||||||
};
|
};
|
||||||
message.From.Add(new MailboxAddress(string.IsNullOrEmpty(settings.SenderName) ? settings.SenderAddress : settings.SenderName, settings.SenderAddress));
|
message.From.Add(new MailboxAddress(string.IsNullOrEmpty(settings.SenderName) ? settings.SenderAddress : settings.SenderName, settings.SenderAddress));
|
||||||
message.To.Add(new MailboxAddress(model.To, model.To));
|
message.To.Add(new MailboxAddress(model.To, model.To));
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Notifications
|
||||||
public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
RequestId = req.Id.ToString();
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +68,7 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
|
||||||
|
RequestId = req.Id.ToString();
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +115,7 @@ namespace Ombi.Notifications
|
||||||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
RequestId = req.Id.ToString();
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -239,6 +241,7 @@ namespace Ombi.Notifications
|
||||||
public string UserPreference { get; set; }
|
public string UserPreference { get; set; }
|
||||||
public string DenyReason { get; set; }
|
public string DenyReason { get; set; }
|
||||||
public string AvailableDate { get; set; }
|
public string AvailableDate { get; set; }
|
||||||
|
public string RequestId { get; set; }
|
||||||
|
|
||||||
// System Defined
|
// System Defined
|
||||||
private string LongDate => DateTime.Now.ToString("D");
|
private string LongDate => DateTime.Now.ToString("D");
|
||||||
|
@ -275,6 +278,7 @@ namespace Ombi.Notifications
|
||||||
{nameof(UserPreference),UserPreference},
|
{nameof(UserPreference),UserPreference},
|
||||||
{nameof(DenyReason),DenyReason},
|
{nameof(DenyReason),DenyReason},
|
||||||
{nameof(AvailableDate),AvailableDate},
|
{nameof(AvailableDate),AvailableDate},
|
||||||
|
{nameof(RequestId),RequestId},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,11 +10,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Ensure.That" Version="7.0.0-pre32" />
|
<PackageReference Include="Ensure.That" Version="7.0.0-pre32" />
|
||||||
<PackageReference Include="MailKit" Version="2.0.5" />
|
<PackageReference Include="MailKit" Version="2.1.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Gotify\Ombi.Api.Gotify.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||||
|
|
|
@ -44,12 +44,12 @@ namespace Ombi.Schedule.Tests
|
||||||
new Issues
|
new Issues
|
||||||
{
|
{
|
||||||
Status = IssueStatus.Resolved,
|
Status = IssueStatus.Resolved,
|
||||||
ResovledDate = DateTime.Now.AddDays(-5).AddHours(-1)
|
ResovledDate = DateTime.UtcNow.AddDays(-5).AddHours(-8)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
Repo.Setup(x => x.GetAll()).Returns(issues.AsQueryable());
|
||||||
await Job.Start();
|
await Job.Start();
|
||||||
|
|
||||||
Assert.That(issues.First().Status, Is.EqualTo(IssueStatus.Deleted));
|
Assert.That(issues.First().Status, Is.EqualTo(IssueStatus.Deleted));
|
||||||
|
@ -57,7 +57,7 @@ namespace Ombi.Schedule.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task DoesNot_Delete_AnyIssues()
|
public async Task DoesNot_Delete_AllIssues()
|
||||||
{
|
{
|
||||||
var issues = new List<Issues>()
|
var issues = new List<Issues>()
|
||||||
{
|
{
|
||||||
|
@ -81,5 +81,31 @@ namespace Ombi.Schedule.Tests
|
||||||
Assert.That(issues[1].Status, Is.EqualTo(IssueStatus.Deleted));
|
Assert.That(issues[1].Status, Is.EqualTo(IssueStatus.Deleted));
|
||||||
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task DoesNot_Delete_AnyIssues()
|
||||||
|
{
|
||||||
|
var issues = new List<Issues>()
|
||||||
|
{
|
||||||
|
new Issues
|
||||||
|
{
|
||||||
|
Status = IssueStatus.Resolved,
|
||||||
|
ResovledDate = DateTime.Now.AddDays(-2)
|
||||||
|
},
|
||||||
|
new Issues
|
||||||
|
{
|
||||||
|
Status = IssueStatus.Resolved,
|
||||||
|
ResovledDate = DateTime.Now.AddDays(-4)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||||
|
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||||
|
await Job.Start();
|
||||||
|
|
||||||
|
Assert.That(issues[0].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||||
|
Assert.That(issues[1].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||||
|
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,11 +6,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||||
|
<PackageReference Include="MockQueryable.Moq" Version="1.1.0" />
|
||||||
<PackageReference Include="Moq" Version="4.10.0" />
|
<PackageReference Include="Moq" Version="4.10.0" />
|
||||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||||
using Castle.Components.DictionaryAdapter;
|
using Castle.Components.DictionaryAdapter;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using MockQueryable.Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Ombi.Core.Notifications;
|
using Ombi.Core.Notifications;
|
||||||
using Ombi.Schedule.Jobs.Plex;
|
using Ombi.Schedule.Jobs.Plex;
|
||||||
|
@ -68,7 +69,6 @@ namespace Ombi.Schedule.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[Ignore("EF IAsyncQueryProvider")]
|
|
||||||
public async Task ProcessTv_ShouldMark_Episode_Available_WhenInPlex()
|
public async Task ProcessTv_ShouldMark_Episode_Available_WhenInPlex()
|
||||||
{
|
{
|
||||||
var request = new ChildRequests
|
var request = new ChildRequests
|
||||||
|
@ -90,21 +90,25 @@ namespace Ombi.Schedule.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
RequestedUser = new OmbiUser
|
||||||
|
{
|
||||||
|
Email = "abc"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable());
|
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable().BuildMock().Object);
|
||||||
_repo.Setup(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
_repo.Setup(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
||||||
{
|
{
|
||||||
new PlexEpisode
|
new PlexEpisode
|
||||||
{
|
{
|
||||||
Series = new PlexServerContent
|
Series = new PlexServerContent
|
||||||
{
|
{
|
||||||
ImdbId = 1.ToString(),
|
TvDbId = 1.ToString(),
|
||||||
},
|
},
|
||||||
EpisodeNumber = 1,
|
EpisodeNumber = 1,
|
||||||
SeasonNumber = 2
|
SeasonNumber = 2
|
||||||
}
|
}
|
||||||
}.AsQueryable);
|
}.AsQueryable().BuildMock().Object);
|
||||||
_repo.Setup(x => x.Include(It.IsAny<IQueryable<PlexEpisode>>(),It.IsAny<Expression<Func<PlexEpisode, PlexServerContent>>>()));
|
_repo.Setup(x => x.Include(It.IsAny<IQueryable<PlexEpisode>>(),It.IsAny<Expression<Func<PlexEpisode, PlexServerContent>>>()));
|
||||||
|
|
||||||
await Checker.Start();
|
await Checker.Start();
|
||||||
|
|
|
@ -81,7 +81,6 @@ namespace Ombi.Schedule
|
||||||
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
|
||||||
RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s));
|
RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s));
|
||||||
RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s));
|
RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s));
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_episodeSync = epSync;
|
_episodeSync = epSync;
|
||||||
_metadata = metadata;
|
_metadata = metadata;
|
||||||
_settings.ClearCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ILogger<EmbyContentSync> _logger;
|
private readonly ILogger<EmbyContentSync> _logger;
|
||||||
|
|
|
@ -49,7 +49,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||||
_settings = s;
|
_settings = s;
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_avaliabilityChecker = checker;
|
_avaliabilityChecker = checker;
|
||||||
_settings.ClearCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ISettingsService<EmbySettings> _settings;
|
private readonly ISettingsService<EmbySettings> _settings;
|
||||||
|
|
|
@ -50,8 +50,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||||
_log = log;
|
_log = log;
|
||||||
_embySettings = embySettings;
|
_embySettings = embySettings;
|
||||||
_userManagementSettings = ums;
|
_userManagementSettings = ums;
|
||||||
_userManagementSettings.ClearCache();
|
|
||||||
_embySettings.ClearCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IEmbyApi _api;
|
private readonly IEmbyApi _api;
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Internal;
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.Lidarr;
|
using Ombi.Api.Lidarr;
|
||||||
using Ombi.Api.Radarr;
|
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Settings.Settings.Models.External;
|
using Ombi.Settings.Settings.Models.External;
|
||||||
using Ombi.Store.Context;
|
using Ombi.Store.Context;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Serilog;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace Ombi.Schedule.Jobs.Lidarr
|
namespace Ombi.Schedule.Jobs.Lidarr
|
||||||
|
@ -29,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_job = job;
|
_job = job;
|
||||||
_availability = availability;
|
_availability = availability;
|
||||||
_lidarrSettings.ClearCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue