mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -07:00
merge
This commit is contained in:
commit
0a4acb314c
221 changed files with 12313 additions and 15406 deletions
210
CHANGELOG.md
210
CHANGELOG.md
|
@ -1,5 +1,215 @@
|
|||
# Changelog
|
||||
|
||||
## v3.0.3587 (2018-08-19)
|
||||
|
||||
### **New Features**
|
||||
|
||||
- Added the ability to invite Plex Friends from the user management screen. [Jamie]
|
||||
|
||||
- Added rich notifications for mobile. [Jamie]
|
||||
|
||||
- Updater fixes. [Jamie]
|
||||
|
||||
- Added updater test mode. [Jamie Rees]
|
||||
|
||||
- Added a new API method to delete issue comments. [TidusJar]
|
||||
|
||||
- Updated @ngu/carousel to beta version to remove rxjs-compat dependency. [Matt Jeanes]
|
||||
|
||||
- Update to Angular 6/Webpack 4. [Matt Jeanes]
|
||||
|
||||
- Update CHANGELOG.md. [Jamie]
|
||||
|
||||
- Updated the way we create the wizard user, errors show now be fed back to the user. [Jamie]
|
||||
|
||||
- Added Brazillian Portuguese as a language and also Polish. [Jamie]
|
||||
|
||||
- Updated swagger. [Jamie]
|
||||
|
||||
- Updated to 2.1.1. [Jamie]
|
||||
|
||||
### **Fixes**
|
||||
|
||||
- #2408 Added the feature to delete comments on issues. [Jamie]
|
||||
|
||||
- New translations en.json (Swedish) [Jamie]
|
||||
|
||||
- New translations en.json (French) [Jamie]
|
||||
|
||||
- Fixed #2440. [TidusJar]
|
||||
|
||||
- Delete cake.config. [Chris Pritchard]
|
||||
|
||||
- Initial attempt at getting anime seriestype working. [Chris Pritchard]
|
||||
|
||||
- Add cake.config. [Chris Pritchard]
|
||||
|
||||
- Fixed the issue where we wouldn't correctly mark some shows as available when there was no provider id #2429. [Jamie]
|
||||
|
||||
- Fixed the 'loop' in the cacher #2429. [Jamie]
|
||||
|
||||
- Fixed #2427. [Jamie]
|
||||
|
||||
- Fixed #2424. [Jamie]
|
||||
|
||||
- Fixed #2409. [Jamie]
|
||||
|
||||
- More updater. [Jamie]
|
||||
|
||||
- Humanize the request type enum in notifications e.g. TvShow will now appear as "Tv Show" #2416. [TidusJar]
|
||||
|
||||
- Made the quality override and root folder override load when we load the show (It will now appear) [Jamie]
|
||||
|
||||
- Fixed #2415 where power users could not set the Sonarr Quality Override or Root Folder Override. [Jamie]
|
||||
|
||||
- #2371 Fixed the issue where certain actions would not setup the series correctly in Sonarr. [Jamie]
|
||||
|
||||
- Tightened up the security from an API perspecitve. [TidusJar]
|
||||
|
||||
- Stop the root folder and profile calls from erroring. [TidusJar]
|
||||
|
||||
- New translations en.json (Polish) [Jamie]
|
||||
|
||||
- New translations en.json (Polish) [Jamie]
|
||||
|
||||
- New translations en.json (Polish) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- Fixed all linting. [TidusJar]
|
||||
|
||||
- Comment out envparam stuff. [Matt Jeanes]
|
||||
|
||||
- Fixed prod build issue. [Matt Jeanes]
|
||||
|
||||
- Missed a tiny bit. [Matt Jeanes]
|
||||
|
||||
- Fix test. [Matt Jeanes]
|
||||
|
||||
- Fix test build. [Matt Jeanes]
|
||||
|
||||
- Linting + remove debug. [Matt Jeanes]
|
||||
|
||||
- Switch to Yarn and disable auto publish in release mode. [Matt Jeanes]
|
||||
|
||||
- Fix for #2409. [TidusJar]
|
||||
|
||||
- New translations en.json (Swedish) [Jamie]
|
||||
|
||||
- New translations en.json (Spanish) [Jamie]
|
||||
|
||||
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||
|
||||
- New translations en.json (Polish) [Jamie]
|
||||
|
||||
- New translations en.json (Norwegian) [Jamie]
|
||||
|
||||
- New translations en.json (Italian) [Jamie]
|
||||
|
||||
- New translations en.json (German) [Jamie]
|
||||
|
||||
- New translations en.json (French) [Jamie]
|
||||
|
||||
- New translations en.json (Dutch) [Jamie]
|
||||
|
||||
- New translations en.json (Danish) [Jamie]
|
||||
|
||||
- Possible fix for #2298. [D34DC3N73R]
|
||||
|
||||
- Fixed the text for #2370. [Jamie]
|
||||
|
||||
- Fixed where you couldn't bulk edit the limits to 0 #2318. [Jamie]
|
||||
|
||||
- Upgraded to .net 2.1.2 (Includes security fixes) [Jamie]
|
||||
|
||||
|
||||
## v3.0.3477 (2018-07-18)
|
||||
|
||||
### **New Features**
|
||||
|
||||
- Updated the Emby availability checker to bring it more in line with what we do with Plex. [TidusJar]
|
||||
|
||||
- Added the ability to impersonate a user when using the API Key. This allows people to use the API and request as a certain user. #2363. [Jamie Rees]
|
||||
|
||||
- Added more background images and it will loop through the available ones. [Jamie Rees]
|
||||
|
||||
- Added chunk hashing to resolve #2330. [Jamie Rees]
|
||||
|
||||
- Added API at /api/v1/status/info to get branch and version information #2331. [Jamie Rees]
|
||||
|
||||
- Update to .net 2.1.1. [Jamie]
|
||||
|
||||
### **Fixes**
|
||||
|
||||
- Fix #2322 caused by continue statement inside try catch block. [Anojh]
|
||||
|
||||
- Fixed #2367. [TidusJar]
|
||||
|
||||
- Fixed the issue where you could not delete a user #2365. [TidusJar]
|
||||
|
||||
- Another attempt to fix #2366. [Jamie Rees]
|
||||
|
||||
- Fixed the Plex OAuth warning. [Jamie]
|
||||
|
||||
- Revert "Fixed Plex OAuth, should no longer show Insecure warning" [Jamie Rees]
|
||||
|
||||
- Fixed Plex OAuth, should no longer show Insecure warning. [Jamie Rees]
|
||||
|
||||
- Fixed the View On Emby URL since the Link changed #2368. [Jamie Rees]
|
||||
|
||||
- Fixed the issue where episodes were not being marked as available in the search #2367. [Jamie Rees]
|
||||
|
||||
- Fixed #2371. [Jamie Rees]
|
||||
|
||||
- Fixed collection issues in Emby #2366. [Jamie Rees]
|
||||
|
||||
- Do not delete the Emby Information every time we run, let's keep the content now. [Jamie Rees]
|
||||
|
||||
- Emby Improvements: Batch up the amount we get from the server. [Jamie Rees]
|
||||
|
||||
- Log errors when they are uncaught. [Jamie Rees]
|
||||
|
||||
- Fix unclosed table tags causing overflow #2322. [Anojh]
|
||||
|
||||
- This should now fix #2350. [Jamie]
|
||||
|
||||
- Improve the validation around the Application URL. [Jamie Rees]
|
||||
|
||||
- Fixed #2341. [Jamie Rees]
|
||||
|
||||
- Stop spamming errors when FanArt doesn't have the image. [Jamie Rees]
|
||||
|
||||
- Fixed #2338. [Jamie Rees]
|
||||
|
||||
- Removed some logging statements. [Jamie Rees]
|
||||
|
||||
- Fixed the api key being case sensative #2350. [Jamie Rees]
|
||||
|
||||
- Improved the Emby API #2230 Thanks Luke! [Jamie Rees]
|
||||
|
||||
- Revert. [Jamie Rees]
|
||||
|
||||
- Fixed a small error in the Mobile Notification Provider. [Jamie Rees]
|
||||
|
||||
- Minor style tweaks. [Randall Bruder]
|
||||
|
||||
- Downgrade to .net core 2.0. [Jamie Rees]
|
||||
|
||||
- Downgrade Microsoft.AspNetCore.All package back to 2.0.8. [Jamie Rees]
|
||||
|
||||
- Removed old code. [Jamie Rees]
|
||||
|
||||
- Swap out the old way of validating the API key with a real middlewear this time. [Jamie Rees]
|
||||
|
||||
|
||||
## v3.0.3421 (2018-06-23)
|
||||
|
||||
### **New Features**
|
||||
|
|
10
appveyor.yml
10
appveyor.yml
|
@ -15,19 +15,19 @@ test: off
|
|||
after_build:
|
||||
- cmd: >-
|
||||
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\windows.zip"
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\windows.zip"
|
||||
|
||||
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\osx.tar.gz"
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\osx.tar.gz"
|
||||
|
||||
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\linux.tar.gz"
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\linux.tar.gz"
|
||||
|
||||
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\linux-arm.tar.gz"
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\linux-arm.tar.gz"
|
||||
|
||||
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\windows-32bit.zip"
|
||||
appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\windows-32bit.zip"
|
||||
|
||||
|
||||
# appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\linux-arm64.tar.gz"
|
||||
|
|
44
build.cake
44
build.cake
|
@ -1,10 +1,10 @@
|
|||
|
||||
#tool "nuget:?package=GitVersion.CommandLine"
|
||||
#addin "Cake.Gulp"
|
||||
#addin "nuget:?package=Cake.Npm&version=0.13.0"
|
||||
#addin "SharpZipLib"
|
||||
#addin nuget:?package=Cake.Compression&version=0.1.4
|
||||
#addin "Cake.Incubator"
|
||||
#addin "Cake.Yarn"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// ARGUMENTS
|
||||
|
@ -26,7 +26,7 @@ var csProj = "./src/Ombi/Ombi.csproj"; // Path to the project.csproj
|
|||
var solutionFile = "Ombi.sln"; // Solution file if needed
|
||||
GitVersion versionInfo = null;
|
||||
|
||||
var frameworkVer = "netcoreapp2.0";
|
||||
var frameworkVer = "netcoreapp2.1";
|
||||
|
||||
var buildSettings = new DotNetCoreBuildSettings
|
||||
{
|
||||
|
@ -122,36 +122,19 @@ Task("SetVersionInfo")
|
|||
|
||||
Task("NPM")
|
||||
.Does(() => {
|
||||
var settings = new NpmInstallSettings {
|
||||
LogLevel = NpmLogLevel.Silent,
|
||||
WorkingDirectory = webProjDir,
|
||||
Production = true
|
||||
};
|
||||
|
||||
NpmInstall(settings);
|
||||
Yarn.FromPath(webProjDir).Install();
|
||||
});
|
||||
|
||||
Task("Gulp Publish")
|
||||
.IsDependentOn("NPM")
|
||||
.Does(() => {
|
||||
|
||||
var runScriptSettings = new NpmRunScriptSettings {
|
||||
ScriptName="publish",
|
||||
WorkingDirectory = webProjDir,
|
||||
};
|
||||
|
||||
NpmRunScript(runScriptSettings);
|
||||
.Does(() => {
|
||||
Yarn.FromPath(webProjDir).RunScript("publish");
|
||||
});
|
||||
|
||||
Task("TSLint")
|
||||
.Does(() =>
|
||||
{
|
||||
var settings = new NpmRunScriptSettings {
|
||||
WorkingDirectory = webProjDir,
|
||||
ScriptName = "lint"
|
||||
};
|
||||
|
||||
NpmRunScript(settings);
|
||||
Yarn.FromPath(webProjDir).RunScript("lint");
|
||||
});
|
||||
|
||||
Task("PrePublish")
|
||||
|
@ -178,7 +161,7 @@ Task("Publish")
|
|||
.IsDependentOn("Publish-OSX")
|
||||
.IsDependentOn("Publish-Linux")
|
||||
.IsDependentOn("Publish-Linux-ARM")
|
||||
//.IsDependentOn("Publish-Linux-ARM-64Bit")
|
||||
.IsDependentOn("Publish-Linux-ARM-64Bit")
|
||||
.IsDependentOn("Package");
|
||||
|
||||
Task("Publish-Windows")
|
||||
|
@ -189,6 +172,8 @@ Task("Publish-Windows")
|
|||
|
||||
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
|
||||
CopyFile(buildDir + "/"+frameworkVer+"/win10-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/win10-x64/published/Swagger.xml");
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/win10-x64/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
@ -200,6 +185,9 @@ Task("Publish-Windows-32bit")
|
|||
|
||||
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
|
||||
CopyFile(buildDir + "/"+frameworkVer+"/win10-x86/Swagger.xml", buildDir + "/"+frameworkVer+"/win10-x86/published/Swagger.xml");
|
||||
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/win10-x86/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
@ -211,6 +199,8 @@ Task("Publish-OSX")
|
|||
|
||||
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
|
||||
CopyFile(buildDir + "/"+frameworkVer+"/osx-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/osx-x64/published/Swagger.xml");
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/osx-x64/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
@ -222,6 +212,8 @@ Task("Publish-Linux")
|
|||
|
||||
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
|
||||
CopyFile(buildDir + "/"+frameworkVer+"/linux-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/linux-x64/published/Swagger.xml");
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-x64/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
@ -235,6 +227,8 @@ Task("Publish-Linux-ARM")
|
|||
CopyFile(
|
||||
buildDir + "/"+frameworkVer+"/linux-arm/Swagger.xml",
|
||||
buildDir + "/"+frameworkVer+"/linux-arm/published/Swagger.xml");
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-arm/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
@ -248,6 +242,8 @@ Task("Publish-Linux-ARM-64Bit")
|
|||
CopyFile(
|
||||
buildDir + "/"+frameworkVer+"/linux-arm64/Swagger.xml",
|
||||
buildDir + "/"+frameworkVer+"/linux-arm64/published/Swagger.xml");
|
||||
|
||||
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-arm64/published/updater");
|
||||
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
|
||||
});
|
||||
|
||||
|
|
291
package-lock.json
generated
Normal file
291
package-lock.json
generated
Normal file
|
@ -0,0 +1,291 @@
|
|||
{
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"requires": {
|
||||
"sprintf-js": "1.0.3"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
|
||||
"requires": {
|
||||
"chalk": "1.1.3",
|
||||
"esutils": "2.0.2",
|
||||
"js-tokens": "3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "2.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"has-ansi": "2.0.0",
|
||||
"strip-ansi": "3.0.1",
|
||||
"supports-color": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"requires": {
|
||||
"balanced-match": "1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"supports-color": "5.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "1.9.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"requires": {
|
||||
"has-flag": "3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
|
||||
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"requires": {
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
||||
"requires": {
|
||||
"argparse": "1.0.10",
|
||||
"esprima": "4.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.11"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
|
||||
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
|
||||
"integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
|
||||
"requires": {
|
||||
"path-parse": "1.0.5"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz",
|
||||
"integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw=="
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz",
|
||||
"integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=",
|
||||
"requires": {
|
||||
"babel-code-frame": "6.26.0",
|
||||
"builtin-modules": "1.1.1",
|
||||
"chalk": "2.4.1",
|
||||
"commander": "2.15.1",
|
||||
"diff": "3.5.0",
|
||||
"glob": "7.1.2",
|
||||
"js-yaml": "3.12.0",
|
||||
"minimatch": "3.0.4",
|
||||
"resolve": "1.7.1",
|
||||
"semver": "5.5.0",
|
||||
"tslib": "1.9.2",
|
||||
"tsutils": "2.27.1"
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz",
|
||||
"integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==",
|
||||
"requires": {
|
||||
"tslib": "1.9.2"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,27 +91,31 @@ namespace Ombi.Api.Emby
|
|||
request.AddContentHeader("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
public async Task<EmbyItemContainer<MovieInformation>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
|
||||
public async Task<EmbyItemContainer<EmbyMovie>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
|
||||
{
|
||||
var request = new Request($"emby/users/{userId}/items?parentId={mediaId}", baseUrl, HttpMethod.Get);
|
||||
AddHeaders(request, apiKey);
|
||||
|
||||
return await Api.Request<EmbyItemContainer<MovieInformation>>(request);
|
||||
request.AddQueryString("Fields", "ProviderIds,Overview");
|
||||
|
||||
request.AddQueryString("VirtualItem", "False");
|
||||
|
||||
return await Api.Request<EmbyItemContainer<EmbyMovie>>(request);
|
||||
}
|
||||
|
||||
public async Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, string userId, string baseUri)
|
||||
public async Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, int startIndex, int count, string userId, string baseUri)
|
||||
{
|
||||
return await GetAll<EmbyMovie>("Movie", apiKey, userId, baseUri, true);
|
||||
return await GetAll<EmbyMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count);
|
||||
}
|
||||
|
||||
public async Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, string userId, string baseUri)
|
||||
public async Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, int startIndex, int count, string userId, string baseUri)
|
||||
{
|
||||
return await GetAll<EmbyEpisodes>("Episode", apiKey, userId, baseUri);
|
||||
return await GetAll<EmbyEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count);
|
||||
}
|
||||
|
||||
public async Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, string userId, string baseUri)
|
||||
public async Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, int startIndex, int count, string userId, string baseUri)
|
||||
{
|
||||
return await GetAll<EmbySeries>("Series", apiKey, userId, baseUri);
|
||||
return await GetAll<EmbySeries>("Series", apiKey, userId, baseUri, false, startIndex, count);
|
||||
}
|
||||
|
||||
public async Task<SeriesInformation> GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl)
|
||||
|
@ -145,7 +149,25 @@ namespace Ombi.Api.Emby
|
|||
request.AddQueryString("IncludeItemTypes", type);
|
||||
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds");
|
||||
|
||||
request.AddQueryString("VirtualItem","False");
|
||||
request.AddQueryString("VirtualItem", "False");
|
||||
|
||||
AddHeaders(request, apiKey);
|
||||
|
||||
|
||||
var obj = await Api.Request<EmbyItemContainer<T>>(request);
|
||||
return obj;
|
||||
}
|
||||
private async Task<EmbyItemContainer<T>> GetAll<T>(string type, string apiKey, string userId, string baseUri, bool includeOverview, int startIndex, int count)
|
||||
{
|
||||
var request = new Request($"emby/users/{userId}/items", baseUri, HttpMethod.Get);
|
||||
|
||||
request.AddQueryString("Recursive", true.ToString());
|
||||
request.AddQueryString("IncludeItemTypes", type);
|
||||
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds");
|
||||
request.AddQueryString("startIndex", startIndex.ToString());
|
||||
request.AddQueryString("limit", count.ToString());
|
||||
|
||||
request.AddQueryString("VirtualItem", "False");
|
||||
|
||||
AddHeaders(request, apiKey);
|
||||
|
||||
|
|
|
@ -14,12 +14,17 @@ namespace Ombi.Api.Emby
|
|||
Task<EmbyUser> LogIn(string username, string password, string apiKey, string baseUri);
|
||||
Task<EmbyConnectUser> LoginConnectUser(string username, string password);
|
||||
|
||||
Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, string userId, string baseUri);
|
||||
Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, string userId, string baseUri);
|
||||
Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, string userId, string baseUri);
|
||||
Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, int startIndex, int count, string userId,
|
||||
string baseUri);
|
||||
|
||||
Task<EmbyItemContainer<MovieInformation>> GetCollection(string mediaId, string apiKey, string userId,
|
||||
string baseUrl);
|
||||
Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, int startIndex, int count, string userId,
|
||||
string baseUri);
|
||||
|
||||
Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, int startIndex, int count, string userId,
|
||||
string baseUri);
|
||||
|
||||
Task<EmbyItemContainer<EmbyMovie>> GetCollection(string mediaId,
|
||||
string apiKey, string userId, string baseUrl);
|
||||
|
||||
Task<SeriesInformation> GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl);
|
||||
Task<MovieInformation> GetMovieInformation(string mediaId, string apiKey, string userId, string baseUrl);
|
||||
|
|
|
@ -6,6 +6,6 @@ namespace Ombi.Api.Notifications
|
|||
{
|
||||
public interface IOneSignalApi
|
||||
{
|
||||
Task<OneSignalNotificationResponse> PushNotification(List<string> playerIds, string message);
|
||||
Task<OneSignalNotificationResponse> PushNotification(List<string> playerIds, string message, bool isAdminNotification, int requestId, int requestType);
|
||||
}
|
||||
}
|
|
@ -4,18 +4,22 @@
|
|||
{
|
||||
public string app_id { get; set; }
|
||||
public string[] include_player_ids { get; set; }
|
||||
public Data data { get; set; }
|
||||
public object data { get; set; }
|
||||
public Button[] buttons { get; set; }
|
||||
public Contents contents { get; set; }
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string foo { get; set; }
|
||||
}
|
||||
|
||||
public class Contents
|
||||
{
|
||||
public string en { get; set; }
|
||||
}
|
||||
|
||||
public class Button
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string text { get; set; }
|
||||
//public string icon { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,10 @@
|
|||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Ombi.Api.Notifications
|
|||
private readonly IApplicationConfigRepository _appConfig;
|
||||
private const string ApiUrl = "https://onesignal.com/api/v1/notifications";
|
||||
|
||||
public async Task<OneSignalNotificationResponse> PushNotification(List<string> playerIds, string message)
|
||||
public async Task<OneSignalNotificationResponse> PushNotification(List<string> playerIds, string message, bool isAdminNotification, int requestId, int requestType)
|
||||
{
|
||||
if (!playerIds.Any())
|
||||
{
|
||||
|
@ -39,6 +39,17 @@ namespace Ombi.Api.Notifications
|
|||
include_player_ids = playerIds.ToArray()
|
||||
};
|
||||
|
||||
if (isAdminNotification)
|
||||
{
|
||||
// Add the action buttons
|
||||
body.data = new { requestid = requestId, requestType = requestType};
|
||||
body.buttons = new[]
|
||||
{
|
||||
new Button {id = "approve", text = "Approve Request"},
|
||||
new Button {id = "deny", text = "Deny Request"},
|
||||
};
|
||||
}
|
||||
|
||||
request.AddJsonBody(body);
|
||||
|
||||
var result = await _api.Request<OneSignalNotificationResponse>(request);
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Ombi.Api.Plex
|
|||
public interface IPlexApi
|
||||
{
|
||||
Task<PlexStatus> GetStatus(string authToken, string uri);
|
||||
Task<PlexLibrariesForMachineId> GetLibrariesForMachineId(string authToken, string machineId);
|
||||
Task<PlexAuthentication> SignIn(UserRequest user);
|
||||
Task<PlexServer> GetServer(string authToken);
|
||||
Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost);
|
||||
|
@ -22,8 +23,8 @@ namespace Ombi.Api.Plex
|
|||
Task<PlexFriends> GetUsers(string authToken);
|
||||
Task<PlexAccount> GetAccount(string authToken);
|
||||
Task<PlexMetadata> GetRecentlyAdded(string authToken, string uri, string sectionId);
|
||||
Task<OAuthPin> CreatePin();
|
||||
Task<OAuthPin> GetPin(int pinId);
|
||||
Uri GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard);
|
||||
Task<Uri> GetOAuthUrl(int pinId, string code, string applicationUrl);
|
||||
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
|
||||
}
|
||||
}
|
84
src/Ombi.Api.Plex/Models/PlexAdd.cs
Normal file
84
src/Ombi.Api.Plex/Models/PlexAdd.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Ombi.Api.Plex.Models
|
||||
{
|
||||
[XmlRoot(ElementName = "Section")]
|
||||
public class Section
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public string Id { get; set; }
|
||||
[XmlAttribute(AttributeName = "key")]
|
||||
public string Key { get; set; }
|
||||
[XmlAttribute(AttributeName = "title")]
|
||||
public string Title { get; set; }
|
||||
[XmlAttribute(AttributeName = "type")]
|
||||
public string Type { get; set; }
|
||||
[XmlAttribute(AttributeName = "shared")]
|
||||
public string Shared { get; set; }
|
||||
}
|
||||
|
||||
[XmlRoot(ElementName = "SharedServer")]
|
||||
public class SharedServer
|
||||
{
|
||||
[XmlElement(ElementName = "Section")]
|
||||
public List<Section> Section { get; set; }
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public string Id { get; set; }
|
||||
[XmlAttribute(AttributeName = "username")]
|
||||
public string Username { get; set; }
|
||||
[XmlAttribute(AttributeName = "email")]
|
||||
public string Email { get; set; }
|
||||
[XmlAttribute(AttributeName = "userID")]
|
||||
public string UserID { get; set; }
|
||||
[XmlAttribute(AttributeName = "accessToken")]
|
||||
public string AccessToken { get; set; }
|
||||
[XmlAttribute(AttributeName = "name")]
|
||||
public string Name { get; set; }
|
||||
[XmlAttribute(AttributeName = "acceptedAt")]
|
||||
public string AcceptedAt { get; set; }
|
||||
[XmlAttribute(AttributeName = "invitedAt")]
|
||||
public string InvitedAt { get; set; }
|
||||
[XmlAttribute(AttributeName = "allowSync")]
|
||||
public string AllowSync { get; set; }
|
||||
[XmlAttribute(AttributeName = "allowCameraUpload")]
|
||||
public string AllowCameraUpload { get; set; }
|
||||
[XmlAttribute(AttributeName = "allowChannels")]
|
||||
public string AllowChannels { get; set; }
|
||||
[XmlAttribute(AttributeName = "allowTuners")]
|
||||
public string AllowTuners { get; set; }
|
||||
[XmlAttribute(AttributeName = "owned")]
|
||||
public string Owned { get; set; }
|
||||
}
|
||||
|
||||
[XmlRoot(ElementName = "MediaContainer")]
|
||||
public class PlexAdd
|
||||
{
|
||||
[XmlElement(ElementName = "SharedServer")]
|
||||
public SharedServer SharedServer { get; set; }
|
||||
[XmlAttribute(AttributeName = "friendlyName")]
|
||||
public string FriendlyName { get; set; }
|
||||
[XmlAttribute(AttributeName = "identifier")]
|
||||
public string Identifier { get; set; }
|
||||
[XmlAttribute(AttributeName = "machineIdentifier")]
|
||||
public string MachineIdentifier { get; set; }
|
||||
[XmlAttribute(AttributeName = "size")]
|
||||
public string Size { get; set; }
|
||||
}
|
||||
|
||||
[XmlRoot(ElementName = "Response")]
|
||||
public class AddUserError
|
||||
{
|
||||
[XmlAttribute(AttributeName = "code")]
|
||||
public string Code { get; set; }
|
||||
[XmlAttribute(AttributeName = "status")]
|
||||
public string Status { get; set; }
|
||||
}
|
||||
|
||||
public class PlexAddWrapper
|
||||
{
|
||||
public PlexAdd Add { get; set; }
|
||||
public AddUserError Error { get; set; }
|
||||
public bool HasError => Error != null;
|
||||
}
|
||||
}
|
66
src/Ombi.Api.Plex/Models/PlexLibrariesForMachineId.cs
Normal file
66
src/Ombi.Api.Plex/Models/PlexLibrariesForMachineId.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
namespace Ombi.Api.Plex.Models
|
||||
{
|
||||
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[XmlRoot(ElementName = "Section")]
|
||||
public class SectionLite
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public string Id { get; set; }
|
||||
[XmlAttribute(AttributeName = "key")]
|
||||
public string Key { get; set; }
|
||||
[XmlAttribute(AttributeName = "type")]
|
||||
public string Type { get; set; }
|
||||
[XmlAttribute(AttributeName = "title")]
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
[XmlRoot(ElementName = "Server")]
|
||||
public class ServerLib
|
||||
{
|
||||
[XmlElement(ElementName = "Section")]
|
||||
public List<SectionLite> Section { get; set; }
|
||||
[XmlAttribute(AttributeName = "name")]
|
||||
public string Name { get; set; }
|
||||
[XmlAttribute(AttributeName = "address")]
|
||||
public string Address { get; set; }
|
||||
[XmlAttribute(AttributeName = "port")]
|
||||
public string Port { get; set; }
|
||||
[XmlAttribute(AttributeName = "version")]
|
||||
public string Version { get; set; }
|
||||
[XmlAttribute(AttributeName = "scheme")]
|
||||
public string Scheme { get; set; }
|
||||
[XmlAttribute(AttributeName = "host")]
|
||||
public string Host { get; set; }
|
||||
[XmlAttribute(AttributeName = "localAddresses")]
|
||||
public string LocalAddresses { get; set; }
|
||||
[XmlAttribute(AttributeName = "machineIdentifier")]
|
||||
public string MachineIdentifier { get; set; }
|
||||
[XmlAttribute(AttributeName = "createdAt")]
|
||||
public string CreatedAt { get; set; }
|
||||
[XmlAttribute(AttributeName = "updatedAt")]
|
||||
public string UpdatedAt { get; set; }
|
||||
[XmlAttribute(AttributeName = "owned")]
|
||||
public string Owned { get; set; }
|
||||
[XmlAttribute(AttributeName = "synced")]
|
||||
public string Synced { get; set; }
|
||||
}
|
||||
|
||||
[XmlRoot(ElementName = "MediaContainer")]
|
||||
public class PlexLibrariesForMachineId
|
||||
{
|
||||
[XmlElement(ElementName = "Server")]
|
||||
public ServerLib Server { get; set; }
|
||||
[XmlAttribute(AttributeName = "friendlyName")]
|
||||
public string FriendlyName { get; set; }
|
||||
[XmlAttribute(AttributeName = "identifier")]
|
||||
public string Identifier { get; set; }
|
||||
[XmlAttribute(AttributeName = "machineIdentifier")]
|
||||
public string MachineIdentifier { get; set; }
|
||||
[XmlAttribute(AttributeName = "size")]
|
||||
public string Size { get; set; }
|
||||
}
|
||||
}
|
|
@ -16,14 +16,16 @@ namespace Ombi.Api.Plex
|
|||
{
|
||||
public class PlexApi : IPlexApi
|
||||
{
|
||||
public PlexApi(IApi api, ISettingsService<CustomizationSettings> settings)
|
||||
public PlexApi(IApi api, ISettingsService<CustomizationSettings> settings, ISettingsService<PlexSettings> p)
|
||||
{
|
||||
Api = api;
|
||||
_custom = settings;
|
||||
_plexSettings = p;
|
||||
}
|
||||
|
||||
private IApi Api { get; }
|
||||
private readonly ISettingsService<CustomizationSettings> _custom;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
|
||||
private string _app;
|
||||
private string ApplicationName
|
||||
|
@ -39,7 +41,18 @@ namespace Ombi.Api.Plex
|
|||
}
|
||||
else
|
||||
{
|
||||
_app = settings.ApplicationName;
|
||||
// Check for non-ascii characters (New .Net Core HTTPLib does not allow this)
|
||||
var chars = settings.ApplicationName.ToCharArray();
|
||||
var hasNonAscii = false;
|
||||
foreach (var c in chars)
|
||||
{
|
||||
if (c > 128)
|
||||
{
|
||||
hasNonAscii = true;
|
||||
}
|
||||
}
|
||||
|
||||
_app = hasNonAscii ? "Ombi" : settings.ApplicationName;
|
||||
}
|
||||
|
||||
return _app;
|
||||
|
@ -69,7 +82,7 @@ namespace Ombi.Api.Plex
|
|||
};
|
||||
var request = new Request(SignInUri, string.Empty, HttpMethod.Post);
|
||||
|
||||
AddHeaders(request);
|
||||
await AddHeaders(request);
|
||||
request.AddJsonBody(userModel);
|
||||
|
||||
var obj = await Api.Request<PlexAuthentication>(request);
|
||||
|
@ -80,14 +93,14 @@ namespace Ombi.Api.Plex
|
|||
public async Task<PlexStatus> GetStatus(string authToken, string uri)
|
||||
{
|
||||
var request = new Request(uri, string.Empty, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexStatus>(request);
|
||||
}
|
||||
|
||||
public async Task<PlexAccount> GetAccount(string authToken)
|
||||
{
|
||||
var request = new Request(GetAccountUri, string.Empty, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexAccount>(request);
|
||||
}
|
||||
|
||||
|
@ -95,7 +108,7 @@ namespace Ombi.Api.Plex
|
|||
{
|
||||
var request = new Request(ServerUri, string.Empty, HttpMethod.Get, ContentType.Xml);
|
||||
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
|
||||
return await Api.Request<PlexServer>(request);
|
||||
}
|
||||
|
@ -103,17 +116,24 @@ namespace Ombi.Api.Plex
|
|||
public async Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost)
|
||||
{
|
||||
var request = new Request("library/sections", plexFullHost, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexContainer>(request);
|
||||
}
|
||||
|
||||
public async Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId)
|
||||
{
|
||||
var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexContainer>(request);
|
||||
}
|
||||
|
||||
public async Task<PlexLibrariesForMachineId> GetLibrariesForMachineId(string authToken, string machineId)
|
||||
{
|
||||
var request = new Request("", $"https://plex.tv/api/servers/{machineId}", HttpMethod.Get, ContentType.Xml);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexLibrariesForMachineId>(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
// 192.168.1.69:32400/library/metadata/3662/allLeaves
|
||||
// The metadata ratingkey should be in the Cache
|
||||
|
@ -128,21 +148,21 @@ namespace Ombi.Api.Plex
|
|||
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, int ratingKey)
|
||||
{
|
||||
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId)
|
||||
{
|
||||
var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey)
|
||||
{
|
||||
var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
|
@ -161,9 +181,9 @@ namespace Ombi.Api.Plex
|
|||
|
||||
request.AddQueryString("type", "4");
|
||||
AddLimitHeaders(request, start, retCount);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
|
||||
return await Api.Request<PlexContainer>(request);
|
||||
return await Api.Request<PlexContainer>(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -174,8 +194,8 @@ namespace Ombi.Api.Plex
|
|||
/// <returns></returns>
|
||||
public async Task<PlexFriends> GetUsers(string authToken)
|
||||
{
|
||||
var request = new Request(string.Empty,FriendsUri, HttpMethod.Get, ContentType.Xml);
|
||||
AddHeaders(request, authToken);
|
||||
var request = new Request(string.Empty, FriendsUri, HttpMethod.Get, ContentType.Xml);
|
||||
await AddHeaders(request, authToken);
|
||||
|
||||
return await Api.Request<PlexFriends>(request);
|
||||
}
|
||||
|
@ -183,43 +203,36 @@ namespace Ombi.Api.Plex
|
|||
public async Task<PlexMetadata> GetRecentlyAdded(string authToken, string uri, string sectionId)
|
||||
{
|
||||
var request = new Request($"library/sections/{sectionId}/recentlyAdded", uri, HttpMethod.Get);
|
||||
AddHeaders(request, authToken);
|
||||
await AddHeaders(request, authToken);
|
||||
AddLimitHeaders(request, 0, 50);
|
||||
|
||||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
public async Task<OAuthPin> CreatePin()
|
||||
{
|
||||
var request = new Request($"api/v2/pins", "https://plex.tv/", HttpMethod.Post);
|
||||
request.AddQueryString("strong", "true");
|
||||
AddHeaders(request);
|
||||
|
||||
return await Api.Request<OAuthPin>(request);
|
||||
}
|
||||
|
||||
public async Task<OAuthPin> GetPin(int pinId)
|
||||
{
|
||||
var request = new Request($"api/v2/pins/{pinId}", "https://plex.tv/", HttpMethod.Get);
|
||||
AddHeaders(request);
|
||||
await AddHeaders(request);
|
||||
|
||||
return await Api.Request<OAuthPin>(request);
|
||||
}
|
||||
|
||||
public Uri GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard)
|
||||
public async Task<Uri> GetOAuthUrl(int pinId, string code, string applicationUrl)
|
||||
{
|
||||
var request = new Request("auth#", "https://app.plex.tv", HttpMethod.Get);
|
||||
AddHeaders(request);
|
||||
var forwardUrl = wizard
|
||||
? new Request($"Wizard/OAuth/{pinId}", applicationUrl, HttpMethod.Get)
|
||||
: new Request($"Login/OAuth/{pinId}", applicationUrl, HttpMethod.Get);
|
||||
|
||||
request.AddQueryString("forwardUrl", forwardUrl.FullUri.ToString());
|
||||
await AddHeaders(request);
|
||||
|
||||
request.AddQueryString("pinID", pinId.ToString());
|
||||
request.AddQueryString("code", code);
|
||||
request.AddQueryString("context[device][product]", "Ombi");
|
||||
request.AddQueryString("context[device][product]", ApplicationName);
|
||||
request.AddQueryString("context[device][environment]", "bundled");
|
||||
request.AddQueryString("clientID", $"OmbiV3");
|
||||
request.AddQueryString("context[device][layout]", "desktop");
|
||||
request.AddQueryString("context[device][platform]", "Web");
|
||||
request.AddQueryString("context[device][device]", "Ombi (Web)");
|
||||
|
||||
var s = await GetSettings();
|
||||
await CheckInstallId(s);
|
||||
request.AddQueryString("clientID", s.InstallId.ToString("N"));
|
||||
|
||||
if (request.FullUri.Fragment.Equals("#"))
|
||||
{
|
||||
|
@ -233,26 +246,58 @@ namespace Ombi.Api.Plex
|
|||
return request.FullUri;
|
||||
}
|
||||
|
||||
public async Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs)
|
||||
{
|
||||
var request = new Request(string.Empty, $"https://plex.tv/api/servers/{serverId}/shared_servers", HttpMethod.Post, ContentType.Xml);
|
||||
await AddHeaders(request, authToken);
|
||||
request.AddJsonBody(new
|
||||
{
|
||||
server_id = serverId,
|
||||
shared_server = new
|
||||
{
|
||||
library_section_ids = libs.Length > 0 ? libs : new int[]{},
|
||||
invited_email = emailAddress
|
||||
},
|
||||
sharing_settings = new { }
|
||||
});
|
||||
var result = await Api.RequestContent(request);
|
||||
try
|
||||
{
|
||||
var add = Api.DeserializeXml<PlexAdd>(result);
|
||||
return new PlexAddWrapper{Add = add};
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
var error = Api.DeserializeXml<AddUserError>(result);
|
||||
return new PlexAddWrapper{Error = error};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the required headers and also the authorization header
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="authToken"></param>
|
||||
private void AddHeaders(Request request, string authToken)
|
||||
private async Task AddHeaders(Request request, string authToken)
|
||||
{
|
||||
request.AddHeader("X-Plex-Token", authToken);
|
||||
AddHeaders(request);
|
||||
await AddHeaders(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the main required headers to the Plex Request
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
private void AddHeaders(Request request)
|
||||
private async Task AddHeaders(Request request)
|
||||
{
|
||||
request.AddHeader("X-Plex-Client-Identifier", $"OmbiV3");
|
||||
var s = await GetSettings();
|
||||
await CheckInstallId(s);
|
||||
request.AddHeader("X-Plex-Client-Identifier", s.InstallId.ToString("N"));
|
||||
request.AddHeader("X-Plex-Product", ApplicationName);
|
||||
request.AddHeader("X-Plex-Version", "3");
|
||||
request.AddHeader("X-Plex-Device", "Ombi (Web)");
|
||||
request.AddHeader("X-Plex-Platform", "Web");
|
||||
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
}
|
||||
|
@ -262,5 +307,19 @@ namespace Ombi.Api.Plex
|
|||
request.AddHeader("X-Plex-Container-Start", from.ToString());
|
||||
request.AddHeader("X-Plex-Container-Size", to.ToString());
|
||||
}
|
||||
private async Task CheckInstallId(PlexSettings s)
|
||||
{
|
||||
if (s.InstallId == null || s.InstallId == Guid.Empty)
|
||||
{
|
||||
s.InstallId = Guid.NewGuid();
|
||||
await _plexSettings.SaveSettingsAsync(s);
|
||||
}
|
||||
}
|
||||
|
||||
private PlexSettings _settings;
|
||||
private async Task<PlexSettings> GetSettings()
|
||||
{
|
||||
return _settings ?? (_settings = await _plexSettings.GetSettingsAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Ombi.Api.Radarr
|
|||
tmdbId = tmdbId,
|
||||
qualityProfileId = qualityId,
|
||||
rootFolderPath = rootPath,
|
||||
titleSlug = title,
|
||||
titleSlug = title + year,
|
||||
monitored = true,
|
||||
year = year,
|
||||
minimumAvailability = minimumAvailability
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -6,6 +6,30 @@ namespace Ombi.Api.Sonarr.Models
|
|||
{
|
||||
public class Episode
|
||||
{
|
||||
public Episode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Episode(Episode ep)
|
||||
{
|
||||
seriesId = ep.seriesId;
|
||||
episodeFileId = ep.episodeFileId;
|
||||
seasonNumber = ep.seasonNumber;
|
||||
episodeNumber = ep.episodeNumber;
|
||||
title = ep.title;
|
||||
airDate = ep.airDate;
|
||||
airDateUtc = ep.airDateUtc;
|
||||
overview = ep.overview;
|
||||
hasFile = ep.hasFile;
|
||||
monitored = ep.monitored;
|
||||
unverifiedSceneNumbering = ep.unverifiedSceneNumbering;
|
||||
id = ep.id;
|
||||
absoluteEpisodeNumber = ep.absoluteEpisodeNumber;
|
||||
sceneAbsoluteEpisodeNumber = ep.sceneAbsoluteEpisodeNumber;
|
||||
sceneEpisodeNumber = ep.sceneEpisodeNumber;
|
||||
sceneSeasonNumber = ep.sceneSeasonNumber;
|
||||
}
|
||||
public int seriesId { get; set; }
|
||||
public int episodeFileId { get; set; }
|
||||
public int seasonNumber { get; set; }
|
||||
|
@ -27,6 +51,24 @@ namespace Ombi.Api.Sonarr.Models
|
|||
|
||||
public class Episodefile
|
||||
{
|
||||
public Episodefile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Episodefile(Episodefile e)
|
||||
{
|
||||
seriesId = e.seriesId;
|
||||
seasonNumber = e.seasonNumber;
|
||||
relativePath = e.relativePath;
|
||||
path = e.path;
|
||||
size = e.size;
|
||||
dateAdded = e.dateAdded;
|
||||
sceneName = e.sceneName;
|
||||
quality = new EpisodeQuality(e.quality);
|
||||
qualityCutoffNotMet = e.qualityCutoffNotMet;
|
||||
id = e.id;
|
||||
}
|
||||
public int seriesId { get; set; }
|
||||
public int seasonNumber { get; set; }
|
||||
public string relativePath { get; set; }
|
||||
|
@ -41,12 +83,32 @@ namespace Ombi.Api.Sonarr.Models
|
|||
|
||||
public class EpisodeQuality
|
||||
{
|
||||
public EpisodeQuality()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EpisodeQuality(EpisodeQuality e)
|
||||
{
|
||||
quality = new Quality(e.quality);
|
||||
revision = new Revision(e.revision);
|
||||
}
|
||||
public Quality quality { get; set; }
|
||||
public Revision revision { get; set; }
|
||||
}
|
||||
|
||||
public class Revision
|
||||
{
|
||||
public Revision()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Revision(Revision r)
|
||||
{
|
||||
version = r.version;
|
||||
real = r.real;
|
||||
}
|
||||
public int version { get; set; }
|
||||
public int real { get; set; }
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace Ombi.Api.Sonarr.Models
|
|||
public string cleanTitle { get; set; }
|
||||
public string imdbId { get; set; }
|
||||
public string titleSlug { get; set; }
|
||||
public string seriesType { get; set; }
|
||||
public int id { get; set; }
|
||||
public List<SonarrImage> images { get; set; }
|
||||
|
||||
|
|
|
@ -2,6 +2,16 @@ namespace Ombi.Api.Sonarr.Models
|
|||
{
|
||||
public class Quality
|
||||
{
|
||||
public Quality()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Quality(Quality q)
|
||||
{
|
||||
id = q.id;
|
||||
name = q.name;
|
||||
}
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
|
|
|
@ -80,15 +80,20 @@ namespace Ombi.Api
|
|||
else
|
||||
{
|
||||
// XML
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||
StringReader reader = new StringReader(receivedString);
|
||||
var value = (T)serializer.Deserialize(reader);
|
||||
return value;
|
||||
return DeserializeXml<T>(receivedString);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public T DeserializeXml<T>(string receivedString)
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||
StringReader reader = new StringReader(receivedString);
|
||||
var value = (T) serializer.Deserialize(reader);
|
||||
return value;
|
||||
}
|
||||
|
||||
public async Task<string> RequestContent(Request request)
|
||||
{
|
||||
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
||||
|
|
|
@ -7,5 +7,6 @@ namespace Ombi.Api
|
|||
Task Request(Request request);
|
||||
Task<T> Request<T>(Request request);
|
||||
Task<string> RequestContent(Request request);
|
||||
T DeserializeXml<T>(string receivedString);
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Polly" Version="5.8.0" />
|
||||
<PackageReference Include="Polly" Version="6.1.0" />
|
||||
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -9,7 +9,7 @@
|
|||
<PackageReference Include="Nunit" Version="3.8.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.7.2"></packagereference>
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -29,7 +29,10 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
{
|
||||
ProviderId = "123"
|
||||
});
|
||||
var search = new SearchMovieViewModel();
|
||||
var search = new SearchMovieViewModel()
|
||||
{
|
||||
TheMovieDbId = "123",
|
||||
};
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
|
|
|
@ -20,12 +20,6 @@ namespace Ombi.Core.Authentication
|
|||
private readonly IPlexApi _api;
|
||||
private readonly ISettingsService<CustomizationSettings> _customizationSettingsService;
|
||||
|
||||
public async Task<OAuthPin> RequestPin()
|
||||
{
|
||||
var pin = await _api.CreatePin();
|
||||
return pin;
|
||||
}
|
||||
|
||||
public async Task<string> GetAccessTokenFromPin(int pinId)
|
||||
{
|
||||
var pin = await _api.GetPin(pinId);
|
||||
|
@ -34,19 +28,6 @@ namespace Ombi.Core.Authentication
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
if (pin.authToken.IsNullOrEmpty())
|
||||
{
|
||||
// Looks like we do not have a pin yet, we should retry a few times.
|
||||
var retryCount = 0;
|
||||
var retryMax = 5;
|
||||
var retryWaitMs = 1000;
|
||||
while (pin.authToken.IsNullOrEmpty() && retryCount < retryMax)
|
||||
{
|
||||
retryCount++;
|
||||
await Task.Delay(retryWaitMs);
|
||||
pin = await _api.GetPin(pinId);
|
||||
}
|
||||
}
|
||||
return pin.authToken;
|
||||
}
|
||||
|
||||
|
@ -58,14 +39,14 @@ namespace Ombi.Core.Authentication
|
|||
public async Task<Uri> GetOAuthUrl(int pinId, string code, string websiteAddress = null)
|
||||
{
|
||||
var settings = await _customizationSettingsService.GetSettingsAsync();
|
||||
var url = _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl.IsNullOrEmpty() ? websiteAddress : settings.ApplicationUrl, false);
|
||||
var url = await _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl.IsNullOrEmpty() ? websiteAddress : settings.ApplicationUrl);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
public Uri GetWizardOAuthUrl(int pinId, string code, string websiteAddress)
|
||||
public async Task<Uri> GetWizardOAuthUrl(int pinId, string code, string websiteAddress)
|
||||
{
|
||||
var url = _api.GetOAuthUrl(pinId, code, websiteAddress, true);
|
||||
var url = await _api.GetOAuthUrl(pinId, code, websiteAddress);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
|
9
src/Ombi.Core/Engine/IUserStatsEngine.cs
Normal file
9
src/Ombi.Core/Engine/IUserStatsEngine.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public interface IUserStatsEngine
|
||||
{
|
||||
Task<UserStatsSummary> GetSummary(SummaryRequest request);
|
||||
}
|
||||
}
|
|
@ -15,13 +15,13 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<RequestEngineResult> DenyChildRequest(int requestId);
|
||||
Task<RequestsViewModel<TvRequests>> GetRequestsLite(int count, int position, OrderFilterModel type);
|
||||
Task<IEnumerable<TvRequests>> SearchTvRequest(string search);
|
||||
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search);
|
||||
Task<TvRequests> UpdateTvRequest(TvRequests request);
|
||||
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position);
|
||||
Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId);
|
||||
Task<ChildRequests> UpdateChildRequest(ChildRequests request);
|
||||
Task RemoveTvChild(int requestId);
|
||||
Task<RequestEngineResult> ApproveChildRequest(int id);
|
||||
Task<IEnumerable<TvRequests>> GetRequestsLite();
|
||||
Task UpdateQualityProfile(int requestId, int profileId);
|
||||
Task UpdateRootPath(int requestId, int rootPath);
|
||||
}
|
||||
}
|
|
@ -7,16 +7,10 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
public interface ITvSearchEngine
|
||||
{
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
|
||||
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> SearchTreeNode(string searchTerm);
|
||||
Task<TreeNode<SearchTvShowViewModel>> GetShowInformationTreeNode(int tvdbid);
|
||||
Task<SearchTvShowViewModel> GetShowInformation(int tvdbid);
|
||||
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> PopularTree();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Popular();
|
||||
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> AnticipatedTree();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
|
||||
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatchesTree();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
|
||||
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> TrendingTree();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Trending();
|
||||
}
|
||||
}
|
|
@ -452,6 +452,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
request.Available = true;
|
||||
request.MarkedAsAvailable = DateTime.Now;
|
||||
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
|
||||
await MovieRepository.Update(request);
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
|
||||
public class TreeNode<T>
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public T Data { get; set; }
|
||||
public List<TreeNode<T>> Children { get; set; }
|
||||
public bool Leaf { get; set; }
|
||||
public bool Expanded { get; set; }
|
||||
}
|
||||
|
||||
public class TreeNode<T,U>
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public T Data { get; set; }
|
||||
public List<TreeNode<U>> Children { get; set; }
|
||||
public bool Leaf { get; set; }
|
||||
public bool Expanded { get; set; }
|
||||
}
|
||||
}
|
|
@ -143,7 +143,7 @@ namespace Ombi.Core.Engine
|
|||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault())
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
|
||||
// Filter out children
|
||||
|
@ -156,8 +156,9 @@ namespace Ombi.Core.Engine
|
|||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault())
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
|
||||
}
|
||||
|
||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
|
@ -171,24 +172,30 @@ namespace Ombi.Core.Engine
|
|||
public async Task<RequestsViewModel<TvRequests>> GetRequestsLite(int count, int position, OrderFilterModel type)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<TvRequests> allRequests;
|
||||
List<TvRequests> allRequests = null;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await TvRepository.GetLite(shouldHide.UserId)
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
var tv = TvRepository.GetLite(shouldHide.UserId);
|
||||
if (tv.Any() && tv.Select(x => x.ChildRequests).Any())
|
||||
{
|
||||
allRequests = await tv.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault()).Skip(position).Take(count).ToListAsync();
|
||||
}
|
||||
|
||||
// Filter out children
|
||||
|
||||
FilterChildren(allRequests, shouldHide);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests = await TvRepository.GetLite()
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
var tv = TvRepository.GetLite();
|
||||
if (tv.Any() && tv.Select(x => x.ChildRequests).Any())
|
||||
{
|
||||
allRequests = await tv.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault()).Skip(position).Take(count).ToListAsync();
|
||||
}
|
||||
}
|
||||
if (allRequests == null)
|
||||
{
|
||||
return new RequestsViewModel<TvRequests>();
|
||||
}
|
||||
|
||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
|
||||
return new RequestsViewModel<TvRequests>
|
||||
|
@ -196,38 +203,6 @@ namespace Ombi.Core.Engine
|
|||
Collection = allRequests
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<TvRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await TvRepository.Get(shouldHide.UserId)
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.Where(x => x.ChildRequests.Any())
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
|
||||
FilterChildren(allRequests, shouldHide);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests = await TvRepository.Get()
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.Where(x => x.ChildRequests.Any())
|
||||
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
}
|
||||
|
||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
return ParseIntoTreeNode(allRequests);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TvRequests>> GetRequests()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -288,6 +263,10 @@ namespace Ombi.Core.Engine
|
|||
|
||||
private static void FilterChildren(IEnumerable<TvRequests> allRequests, HideResult shouldHide)
|
||||
{
|
||||
if (allRequests == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Filter out children
|
||||
foreach (var t in allRequests)
|
||||
{
|
||||
|
@ -350,21 +329,22 @@ namespace Ombi.Core.Engine
|
|||
return results;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search)
|
||||
public async Task UpdateRootPath(int requestId, int rootPath)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<TvRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = TvRepository.Get(shouldHide.UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests = TvRepository.Get();
|
||||
}
|
||||
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
|
||||
results.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
return ParseIntoTreeNode(results);
|
||||
var allRequests = TvRepository.Get();
|
||||
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
results.RootFolder = rootPath;
|
||||
|
||||
await TvRepository.Update(results);
|
||||
}
|
||||
|
||||
public async Task UpdateQualityProfile(int requestId, int profileId)
|
||||
{
|
||||
var allRequests = TvRepository.Get();
|
||||
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
results.QualityOverride = profileId;
|
||||
|
||||
await TvRepository.Update(results);
|
||||
}
|
||||
|
||||
public async Task<TvRequests> UpdateTvRequest(TvRequests request)
|
||||
|
@ -516,6 +496,7 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
request.Available = true;
|
||||
request.MarkedAsAvailable = DateTime.Now;
|
||||
foreach (var season in request.SeasonRequests)
|
||||
{
|
||||
foreach (var e in season.Episodes)
|
||||
|
@ -585,29 +566,7 @@ namespace Ombi.Core.Engine
|
|||
return await AfterRequest(model.ChildRequests.FirstOrDefault());
|
||||
}
|
||||
|
||||
private static List<TreeNode<TvRequests, List<ChildRequests>>> ParseIntoTreeNode(IEnumerable<TvRequests> result)
|
||||
{
|
||||
var node = new List<TreeNode<TvRequests, List<ChildRequests>>>();
|
||||
|
||||
foreach (var value in result)
|
||||
{
|
||||
node.Add(new TreeNode<TvRequests, List<ChildRequests>>
|
||||
{
|
||||
Data = value,
|
||||
Children = new List<TreeNode<List<ChildRequests>>>
|
||||
{
|
||||
new TreeNode<List<ChildRequests>>
|
||||
{
|
||||
Data = SortEpisodes(value.ChildRequests),
|
||||
Leaf = true
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||
{
|
||||
foreach (var value in items)
|
||||
{
|
||||
|
|
|
@ -59,11 +59,6 @@ namespace Ombi.Core.Engine
|
|||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> SearchTreeNode(string searchTerm)
|
||||
{
|
||||
var result = await Search(searchTerm);
|
||||
return result.Select(ParseIntoTreeNode).ToList();
|
||||
}
|
||||
public async Task<SearchTvShowViewModel> GetShowInformation(int tvdbid)
|
||||
{
|
||||
var show = await TvMazeApi.ShowLookupByTheTvDbId(tvdbid);
|
||||
|
@ -116,19 +111,6 @@ namespace Ombi.Core.Engine
|
|||
return await ProcessResult(mapped);
|
||||
}
|
||||
|
||||
public async Task<TreeNode<SearchTvShowViewModel>> GetShowInformationTreeNode(int tvdbid)
|
||||
{
|
||||
var result = await GetShowInformation(tvdbid);
|
||||
return ParseIntoTreeNode(result);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> PopularTree()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
||||
var processed = await ProcessResults(result);
|
||||
return processed.Select(ParseIntoTreeNode).ToList();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
||||
|
@ -136,12 +118,6 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> AnticipatedTree()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
||||
var processed = await ProcessResults(result);
|
||||
return processed.Select(ParseIntoTreeNode).ToList();
|
||||
}
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
||||
{
|
||||
|
||||
|
@ -150,12 +126,6 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatchesTree()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
||||
var processed = await ProcessResults(result);
|
||||
return processed.Select(ParseIntoTreeNode).ToList();
|
||||
}
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
||||
|
@ -163,13 +133,6 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> TrendingTree()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
||||
var processed = await ProcessResults(result);
|
||||
return processed.Select(ParseIntoTreeNode).ToList();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
||||
|
@ -177,22 +140,6 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
private static TreeNode<SearchTvShowViewModel> ParseIntoTreeNode(SearchTvShowViewModel result)
|
||||
{
|
||||
return new TreeNode<SearchTvShowViewModel>
|
||||
{
|
||||
Data = result,
|
||||
Children = new List<TreeNode<SearchTvShowViewModel>>
|
||||
{
|
||||
new TreeNode<SearchTvShowViewModel>
|
||||
{
|
||||
Data = result, Leaf = true
|
||||
}
|
||||
},
|
||||
Leaf = false
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
|
|
77
src/Ombi.Core/Engine/UserStatsEngine.cs
Normal file
77
src/Ombi.Core/Engine/UserStatsEngine.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class UserStatsEngine : IUserStatsEngine
|
||||
{
|
||||
public UserStatsEngine(OmbiUserManager um, IMovieRequestRepository movieRequest, ITvRequestRepository tvRequest)
|
||||
{
|
||||
_userManager = um;
|
||||
_movieRequest = movieRequest;
|
||||
_tvRequest = tvRequest;
|
||||
}
|
||||
|
||||
private readonly OmbiUserManager _userManager;
|
||||
private readonly IMovieRequestRepository _movieRequest;
|
||||
private readonly ITvRequestRepository _tvRequest;
|
||||
|
||||
public async Task<UserStatsSummary> GetSummary(SummaryRequest request)
|
||||
{
|
||||
// get all movie requests
|
||||
var movies = _movieRequest.GetWithUser();
|
||||
var filteredMovies = movies.Where(x => x.RequestedDate >= request.From && x.RequestedDate <= request.To);
|
||||
var tv = _tvRequest.GetLite();
|
||||
var children = tv.SelectMany(x =>
|
||||
x.ChildRequests.Where(c => c.RequestedDate >= request.From && c.RequestedDate <= request.To));
|
||||
|
||||
var moviesCount = filteredMovies.CountAsync();
|
||||
var childrenCount = children.CountAsync();
|
||||
var availableMovies =
|
||||
movies.Select(x => x.MarkedAsAvailable >= request.From && x.MarkedAsAvailable <= request.To).CountAsync();
|
||||
var availableChildren = tv.SelectMany(x =>
|
||||
x.ChildRequests.Where(c => c.MarkedAsAvailable >= request.From && c.MarkedAsAvailable <= request.To)).CountAsync();
|
||||
|
||||
var userMovie = filteredMovies.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync();
|
||||
var userTv = children.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
return new UserStatsSummary
|
||||
{
|
||||
TotalMovieRequests = await moviesCount,
|
||||
TotalTvRequests = await childrenCount,
|
||||
CompletedRequestsTv = await availableChildren,
|
||||
CompletedRequestsMovies = await availableMovies,
|
||||
MostRequestedUserMovie = (await userMovie).FirstOrDefault().RequestedUser,
|
||||
MostRequestedUserTv = (await userTv).FirstOrDefault().RequestedUser,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class SummaryRequest
|
||||
{
|
||||
public DateTime From { get; set; }
|
||||
public DateTime To { get; set; }
|
||||
}
|
||||
|
||||
public class UserStatsSummary
|
||||
{
|
||||
public int TotalRequests => TotalTvRequests + TotalMovieRequests;
|
||||
public int TotalMovieRequests { get; set; }
|
||||
public int TotalTvRequests { get; set; }
|
||||
public int TotalIssues { get; set; }
|
||||
public int CompletedRequestsMovies { get; set; }
|
||||
public int CompletedRequestsTv { get; set; }
|
||||
public int CompletedRequests => CompletedRequestsMovies + CompletedRequestsTv;
|
||||
public OmbiUser MostRequestedUserMovie { get; set; }
|
||||
public OmbiUser MostRequestedUserTv { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
|
||||
namespace Ombi.Core.Authentication
|
||||
{
|
||||
public interface IPlexOAuthManager
|
||||
{
|
||||
Task<string> GetAccessTokenFromPin(int pinId);
|
||||
Task<OAuthPin> RequestPin();
|
||||
Task<Uri> GetOAuthUrl(int pinId, string code, string websiteAddress = null);
|
||||
Uri GetWizardOAuthUrl(int pinId, string code, string websiteAddress);
|
||||
Task<Uri> GetWizardOAuthUrl(int pinId, string code, string websiteAddress);
|
||||
Task<PlexAccount> GetAccount(string accessToken);
|
||||
}
|
||||
}
|
|
@ -12,9 +12,9 @@
|
|||
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.19" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="2.0.0-preview1-final" />
|
||||
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
@ -59,10 +61,19 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
EmbyEpisode epExists = null;
|
||||
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.ProviderId == item.ProviderId.ToString());
|
||||
|
||||
if (item.HasImdb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber
|
||||
&& e.ImdbId == item.ImdbId);
|
||||
} if (item.HasTvDb && epExists == null)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber
|
||||
&& e.Series.TvDbId == item.TvDbId);
|
||||
} if (item.HasTheMovieDb && epExists == null)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber
|
||||
&& e.TheMovieDbId == item.TheMovieDbId);
|
||||
}
|
||||
|
||||
if (epExists != null)
|
||||
{
|
||||
|
|
|
@ -120,6 +120,7 @@ namespace Ombi.Core.Senders
|
|||
|
||||
int qualityToUse;
|
||||
string rootFolderPath;
|
||||
string seriesType;
|
||||
|
||||
if (model.SeriesType == SeriesType.Anime)
|
||||
{
|
||||
|
@ -128,6 +129,8 @@ namespace Ombi.Core.Senders
|
|||
// TODO make this overrideable via the UI
|
||||
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s);
|
||||
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
||||
seriesType = "anime";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -136,6 +139,7 @@ namespace Ombi.Core.Senders
|
|||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||
// TODO make this overrideable via the UI
|
||||
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
|
||||
seriesType = "standard";
|
||||
}
|
||||
|
||||
if (model.ParentRequest.QualityOverride.HasValue)
|
||||
|
@ -163,27 +167,18 @@ namespace Ombi.Core.Senders
|
|||
rootFolderPath = rootFolderPath,
|
||||
qualityProfileId = qualityToUse,
|
||||
titleSlug = model.ParentRequest.Title,
|
||||
seriesType = seriesType,
|
||||
addOptions = new AddOptions
|
||||
{
|
||||
ignoreEpisodesWithFiles = true, // There shouldn't be any episodes with files, this is a new season
|
||||
ignoreEpisodesWithoutFiles = true, // We want all missing
|
||||
ignoreEpisodesWithFiles = false, // There shouldn't be any episodes with files, this is a new season
|
||||
ignoreEpisodesWithoutFiles = false, // We want all missing
|
||||
searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly.
|
||||
}
|
||||
};
|
||||
|
||||
// Montitor the correct seasons,
|
||||
// If we have that season in the model then it's monitored!
|
||||
var seasonsToAdd = new List<Season>();
|
||||
for (var i = 0; i < model.ParentRequest.TotalSeasons + 1; i++)
|
||||
{
|
||||
var index = i;
|
||||
var season = new Season
|
||||
{
|
||||
seasonNumber = i,
|
||||
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index && x.SeasonNumber != 0)
|
||||
};
|
||||
seasonsToAdd.Add(season);
|
||||
}
|
||||
var seasonsToAdd = GetSeasonsToCreate(model);
|
||||
newSeries.seasons = seasonsToAdd;
|
||||
var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
|
||||
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
|
||||
|
@ -237,7 +232,7 @@ namespace Ombi.Core.Senders
|
|||
{
|
||||
var sonarrEp = sonarrEpList.FirstOrDefault(x =>
|
||||
x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber);
|
||||
if (sonarrEp != null)
|
||||
if (sonarrEp != null && !sonarrEp.monitored)
|
||||
{
|
||||
sonarrEp.monitored = true;
|
||||
episodesToUpdate.Add(sonarrEp);
|
||||
|
@ -245,22 +240,64 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
}
|
||||
var seriesChanges = false;
|
||||
|
||||
foreach (var season in model.SeasonRequests)
|
||||
{
|
||||
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber);
|
||||
var sonarrEpCount = sonarrSeason.Count();
|
||||
var ourRequestCount = season.Episodes.Count;
|
||||
|
||||
var existingSeason =
|
||||
result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
||||
if (existingSeason == null)
|
||||
{
|
||||
Logger.LogError("There was no season numer {0} in Sonarr for title {1}", season.SeasonNumber, model.ParentRequest.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (sonarrEpCount == ourRequestCount)
|
||||
{
|
||||
// We have the same amount of requests as all of the episodes in the season.
|
||||
var existingSeason =
|
||||
result.seasons.First(x => x.seasonNumber == season.SeasonNumber);
|
||||
existingSeason.monitored = true;
|
||||
seriesChanges = true;
|
||||
|
||||
if (!existingSeason.monitored)
|
||||
{
|
||||
existingSeason.monitored = true;
|
||||
seriesChanges = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure this season is set to monitored
|
||||
if (!existingSeason.monitored)
|
||||
{
|
||||
// We need to monitor it, problem being is all episodes will now be monitored
|
||||
// So we need to monior the series but unmonitor every episode
|
||||
// Except the episodes that are already monitored before we update the series (we do not want to unmonitor episodes that are monitored beforehand)
|
||||
existingSeason.monitored = true;
|
||||
var sea = result.seasons.FirstOrDefault(x => x.seasonNumber == existingSeason.seasonNumber);
|
||||
sea.monitored = true;
|
||||
//var previouslyMonitoredEpisodes = sonarrEpList.Where(x =>
|
||||
// x.seasonNumber == existingSeason.seasonNumber && x.monitored).Select(x => x.episodeNumber).ToList(); // We probably don't actually care about this
|
||||
result = await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri);
|
||||
var epToUnmonitor = new List<Episode>();
|
||||
var newEpList = sonarrEpList.ConvertAll(ep => new Episode(ep)); // Clone it so we don't modify the orignal member
|
||||
foreach (var ep in newEpList.Where(x => x.seasonNumber == existingSeason.seasonNumber).ToList())
|
||||
{
|
||||
//if (previouslyMonitoredEpisodes.Contains(ep.episodeNumber))
|
||||
//{
|
||||
// // This was previously monitored.
|
||||
// continue;
|
||||
//}
|
||||
ep.monitored = false;
|
||||
epToUnmonitor.Add(ep);
|
||||
}
|
||||
|
||||
foreach (var epToUpdate in epToUnmonitor)
|
||||
{
|
||||
await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri);
|
||||
}
|
||||
}
|
||||
// Now update the episodes that need updating
|
||||
foreach (var epToUpdate in episodesToUpdate.Where(x => x.seasonNumber == season.SeasonNumber))
|
||||
{
|
||||
|
@ -280,6 +317,24 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
}
|
||||
|
||||
private static List<Season> GetSeasonsToCreate(ChildRequests model)
|
||||
{
|
||||
// Let's get a list of seasons just incase we need to change it
|
||||
var seasonsToUpdate = new List<Season>();
|
||||
for (var i = 0; i < model.ParentRequest.TotalSeasons + 1; i++)
|
||||
{
|
||||
var index = i;
|
||||
var sea = new Season
|
||||
{
|
||||
seasonNumber = i,
|
||||
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index && x.SeasonNumber != 0)
|
||||
};
|
||||
seasonsToUpdate.Add(sea);
|
||||
}
|
||||
|
||||
return seasonsToUpdate;
|
||||
}
|
||||
|
||||
private async Task<bool> SendToSickRage(ChildRequests model, SickRageSettings settings, string qualityId = null)
|
||||
{
|
||||
var tvdbid = model.ParentRequest.TvDbId;
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<ITvRequestEngine, TvRequestEngine>();
|
||||
services.AddTransient<ITvSearchEngine, TvSearchEngine>();
|
||||
services.AddTransient<IRuleEvaluator, RuleEvaluator>();
|
||||
services.AddTransient<IUserStatsEngine, UserStatsEngine>();
|
||||
services.AddTransient<IMovieSender, MovieSender>();
|
||||
services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>();
|
||||
services.AddTransient<ITvSender, TvSender>();
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ombi.Helpers
|
|||
public static string GetEmbyMediaUrl(string mediaId)
|
||||
{
|
||||
var url =
|
||||
$"http://app.emby.media/itemdetails.html?id={mediaId}";
|
||||
$"http://app.emby.media/#!/itemdetails.html?id={mediaId}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EasyCrypto" Version="3.3.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
|
||||
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
||||
|
|
|
@ -182,14 +182,16 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{@RECENTLYADDED}
|
||||
{@RECENTLYADDED}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer" style="clear: both; padding-top: 10px; text-align: center; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
||||
<tr>
|
||||
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
|
||||
Powered by <a href="https://github.com/tidusjar/Ombi" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Ombi</a>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nunit" Version="3.8.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.7.2"></packagereference>
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
||||
<PackageReference Include="Moq" Version="4.7.99" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
// Get admin devices
|
||||
var playerIds = await GetAdmins(NotificationType.NewRequest);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model, true);
|
||||
}
|
||||
|
||||
protected override async Task NewIssue(NotificationOptions model, MobileNotificationSettings settings)
|
||||
|
@ -75,7 +75,7 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
// Get admin devices
|
||||
var playerIds = await GetAdmins(NotificationType.Issue);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
protected override async Task IssueComment(NotificationOptions model, MobileNotificationSettings settings)
|
||||
|
@ -97,13 +97,13 @@ namespace Ombi.Notifications.Agents
|
|||
{
|
||||
// Send to user
|
||||
var playerIds = GetUsers(model, NotificationType.IssueComment);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send to admin
|
||||
var playerIds = await GetAdmins(NotificationType.IssueComment);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ namespace Ombi.Notifications.Agents
|
|||
// Send to user
|
||||
var playerIds = GetUsers(model, NotificationType.IssueResolved);
|
||||
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
|
||||
|
@ -149,7 +149,7 @@ namespace Ombi.Notifications.Agents
|
|||
};
|
||||
// Get admin devices
|
||||
var playerIds = await GetAdmins(NotificationType.Test);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
protected override async Task RequestDeclined(NotificationOptions model, MobileNotificationSettings settings)
|
||||
|
@ -168,7 +168,7 @@ namespace Ombi.Notifications.Agents
|
|||
// Send to user
|
||||
var playerIds = GetUsers(model, NotificationType.RequestDeclined);
|
||||
await AddSubscribedUsers(playerIds);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
protected override async Task RequestApproved(NotificationOptions model, MobileNotificationSettings settings)
|
||||
|
@ -188,7 +188,7 @@ namespace Ombi.Notifications.Agents
|
|||
var playerIds = GetUsers(model, NotificationType.RequestApproved);
|
||||
|
||||
await AddSubscribedUsers(playerIds);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
protected override async Task AvailableRequest(NotificationOptions model, MobileNotificationSettings settings)
|
||||
|
@ -207,20 +207,20 @@ namespace Ombi.Notifications.Agents
|
|||
var playerIds = GetUsers(model, NotificationType.RequestAvailable);
|
||||
|
||||
await AddSubscribedUsers(playerIds);
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
protected override Task Send(NotificationMessage model, MobileNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected async Task Send(List<string> playerIds, NotificationMessage model, MobileNotificationSettings settings)
|
||||
protected async Task Send(List<string> playerIds, NotificationMessage model, MobileNotificationSettings settings, NotificationOptions requestModel, bool isAdminNotification = false)
|
||||
{
|
||||
if (playerIds == null || !playerIds.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var response = await _api.PushNotification(playerIds, model.Message);
|
||||
var response = await _api.PushNotification(playerIds, model.Message, isAdminNotification, requestModel.RequestId, (int)requestModel.RequestType);
|
||||
_logger.LogDebug("Sent message to {0} recipients with message id {1}", response.recipients, response.id);
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ namespace Ombi.Notifications.Agents
|
|||
}
|
||||
|
||||
var playerIds = user.NotificationUserIds.Select(x => x.PlayerId).ToList();
|
||||
await Send(playerIds, notification, settings);
|
||||
await Send(playerIds, notification, settings, model);
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetAdmins(NotificationType type)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Humanizer;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
|
@ -39,7 +40,7 @@ namespace Ombi.Notifications
|
|||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.ToString();
|
||||
Type = req?.RequestType.Humanize();
|
||||
}
|
||||
Overview = req?.Overview;
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
|
@ -91,7 +92,7 @@ namespace Ombi.Notifications
|
|||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.ToString();
|
||||
Type = req?.RequestType.Humanize();
|
||||
}
|
||||
|
||||
Overview = req?.ParentRequest.Overview;
|
||||
|
@ -161,7 +162,7 @@ namespace Ombi.Notifications
|
|||
IssueSubject = opts.Substitutes.TryGetValue("IssueSubject", out val) ? val : string.Empty;
|
||||
NewIssueComment = opts.Substitutes.TryGetValue("NewIssueComment", out val) ? val : string.Empty;
|
||||
UserName = opts.Substitutes.TryGetValue("IssueUser", out val) ? val : string.Empty;
|
||||
Type = opts.Substitutes.TryGetValue("RequestType", out val) ? val : string.Empty;
|
||||
Type = opts.Substitutes.TryGetValue("RequestType", out val) ? val.Humanize() : string.Empty;
|
||||
}
|
||||
|
||||
// User Defined
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ensure.That" Version="7.0.0-pre32" />
|
||||
<PackageReference Include="MailKit" Version="2.0.3" />
|
||||
<PackageReference Include="MailKit" Version="2.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.2" />
|
||||
<PackageReference Include="Moq" Version="4.7.99" />
|
||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.8.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.7.0"></packagereference>
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
_log.LogInformation("We have found the request {0} on Emby, sending the notification", movie?.Title ?? string.Empty);
|
||||
|
||||
movie.Available = true;
|
||||
movie.MarkedAsAvailable = DateTime.Now;
|
||||
if (movie.Available)
|
||||
{
|
||||
var recipient = movie.RequestedUser.Email.HasValue() ? movie.RequestedUser.Email : string.Empty;
|
||||
|
@ -121,24 +122,53 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
foreach (var child in tv)
|
||||
{
|
||||
IQueryable<EmbyEpisode> seriesEpisodes;
|
||||
if (child.ParentRequest.TvDbId > 0)
|
||||
|
||||
var useImdb = false;
|
||||
var useTvDb = false;
|
||||
if (child.ParentRequest.ImdbId.HasValue())
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.TvDbId == child.ParentRequest.TvDbId.ToString());
|
||||
useImdb = true;
|
||||
}
|
||||
else if(child.ParentRequest.ImdbId.HasValue())
|
||||
|
||||
if (child.ParentRequest.TvDbId.ToString().HasValue())
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.ImdbId == child.ParentRequest.ImdbId);
|
||||
useTvDb = true;
|
||||
}
|
||||
else
|
||||
|
||||
var tvDbId = child.ParentRequest.TvDbId;
|
||||
var imdbId = child.ParentRequest.ImdbId;
|
||||
IQueryable<EmbyEpisode> seriesEpisodes = null;
|
||||
if (useImdb)
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
|
||||
}
|
||||
|
||||
if (useTvDb && (seriesEpisodes == null || !seriesEpisodes.Any()))
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
|
||||
}
|
||||
|
||||
if (seriesEpisodes == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seriesEpisodes.Any())
|
||||
{
|
||||
// Let's try and match the series by name
|
||||
seriesEpisodes = embyEpisodes.Where(x =>
|
||||
x.Series.Title.Equals(child.Title, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
foreach (var season in child.SeasonRequests)
|
||||
{
|
||||
foreach (var episode in season.Episodes)
|
||||
{
|
||||
if (episode.Available)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var foundEp = await seriesEpisodes.FirstOrDefaultAsync(
|
||||
x => x.EpisodeNumber == episode.EpisodeNumber &&
|
||||
x.SeasonNumber == episode.Season.SeasonNumber);
|
||||
|
@ -156,13 +186,14 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
// We have fulfulled this request!
|
||||
child.Available = true;
|
||||
child.MarkedAsAvailable = DateTime.Now;
|
||||
BackgroundJob.Enqueue(() => _notificationService.Publish(new NotificationOptions
|
||||
{
|
||||
DateTime = DateTime.Now,
|
||||
NotificationType = NotificationType.RequestAvailable,
|
||||
RequestId = child.ParentRequestId,
|
||||
RequestId = child.Id,
|
||||
RequestType = RequestType.TvShow,
|
||||
Recipient = child.RequestedUser.Email,
|
||||
Recipient = child.RequestedUser.Email
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,40 +68,96 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
if (!ValidateSettings(server))
|
||||
return;
|
||||
|
||||
await _repo.ExecuteSql("DELETE FROM EmbyEpisode");
|
||||
await _repo.ExecuteSql("DELETE FROM EmbyContent");
|
||||
//await _repo.ExecuteSql("DELETE FROM EmbyEpisode");
|
||||
//await _repo.ExecuteSql("DELETE FROM EmbyContent");
|
||||
|
||||
var movies = await _api.GetAllMovies(server.ApiKey, 0, 200, server.AdministratorId, server.FullUri);
|
||||
var totalCount = movies.TotalRecordCount;
|
||||
var processed = 1;
|
||||
|
||||
var movies = await _api.GetAllMovies(server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
var mediaToAdd = new HashSet<EmbyContent>();
|
||||
foreach (var movie in movies.Items)
|
||||
{
|
||||
// Regular movie
|
||||
await ProcessMovies(movie, mediaToAdd);
|
||||
}
|
||||
// TV Time
|
||||
var tv = await _api.GetAllShows(server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
|
||||
foreach (var tvShow in tv.Items)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tvShow.ProviderIds?.Tvdb))
|
||||
while (processed < totalCount)
|
||||
{
|
||||
foreach (var movie in movies.Items)
|
||||
{
|
||||
Log.Error("Provider Id on tv {0} is null", tvShow.Name);
|
||||
continue;
|
||||
if (movie.Type.Equals("boxset", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var movieInfo =
|
||||
await _api.GetCollection(movie.Id, server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
foreach (var item in movieInfo.Items)
|
||||
{
|
||||
await ProcessMovies(item, mediaToAdd);
|
||||
}
|
||||
|
||||
processed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
processed++;
|
||||
// Regular movie
|
||||
await ProcessMovies(movie, mediaToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
var existingTv = await _repo.GetByEmbyId(tvShow.Id);
|
||||
if (existingTv == null)
|
||||
mediaToAdd.Add(new EmbyContent
|
||||
// Get the next batch
|
||||
movies = await _api.GetAllMovies(server.ApiKey, processed, 200, server.AdministratorId, server.FullUri);
|
||||
await _repo.AddRange(mediaToAdd);
|
||||
mediaToAdd.Clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TV Time
|
||||
var tv = await _api.GetAllShows(server.ApiKey, 0, 200, server.AdministratorId, server.FullUri);
|
||||
var totalTv = tv.TotalRecordCount;
|
||||
processed = 1;
|
||||
while (processed < totalTv)
|
||||
{
|
||||
foreach (var tvShow in tv.Items)
|
||||
{
|
||||
try
|
||||
{
|
||||
TvDbId = tvShow.ProviderIds?.Tvdb,
|
||||
ImdbId = tvShow.ProviderIds?.Imdb,
|
||||
TheMovieDbId = tvShow.ProviderIds?.Tmdb,
|
||||
Title = tvShow.Name,
|
||||
Type = EmbyMediaType.Series,
|
||||
EmbyId = tvShow.Id,
|
||||
Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id),
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
processed++;
|
||||
if (string.IsNullOrEmpty(tvShow.ProviderIds?.Tvdb))
|
||||
{
|
||||
_logger.LogInformation("Provider Id on tv {0} is null", tvShow.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingTv = await _repo.GetByEmbyId(tvShow.Id);
|
||||
if (existingTv == null)
|
||||
{
|
||||
_logger.LogDebug("Adding new TV Show {0}", tvShow.Name);
|
||||
mediaToAdd.Add(new EmbyContent
|
||||
{
|
||||
TvDbId = tvShow.ProviderIds?.Tvdb,
|
||||
ImdbId = tvShow.ProviderIds?.Imdb,
|
||||
TheMovieDbId = tvShow.ProviderIds?.Tmdb,
|
||||
Title = tvShow.Name,
|
||||
Type = EmbyMediaType.Series,
|
||||
EmbyId = tvShow.Id,
|
||||
Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id),
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("We already have TV Show {0}", tvShow.Name);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// Get the next batch
|
||||
tv = await _api.GetAllShows(server.ApiKey, processed, 200, server.AdministratorId, server.FullUri);
|
||||
await _repo.AddRange(mediaToAdd);
|
||||
mediaToAdd.Clear();
|
||||
}
|
||||
|
||||
if (mediaToAdd.Any())
|
||||
|
@ -112,8 +168,10 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
// Check if it exists
|
||||
var existingMovie = await _repo.GetByEmbyId(movieInfo.Id);
|
||||
|
||||
if (existingMovie == null)
|
||||
var alreadyGoingToAdd = content.Any(x => x.EmbyId == movieInfo.Id);
|
||||
if (existingMovie == null && !alreadyGoingToAdd)
|
||||
{
|
||||
_logger.LogDebug("Adding new movie {0}", movieInfo.Name);
|
||||
content.Add(new EmbyContent
|
||||
{
|
||||
ImdbId = movieInfo.ProviderIds.Imdb,
|
||||
|
@ -124,6 +182,12 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
Url = EmbyHelper.GetEmbyMediaUrl(movieInfo.Id),
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have this
|
||||
_logger.LogDebug("We already have movie {0}", movieInfo.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateSettings(EmbyServers server)
|
||||
|
|
|
@ -73,37 +73,51 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
private async Task CacheEpisodes(EmbyServers server)
|
||||
{
|
||||
var allEpisodes = await _api.GetAllEpisodes(server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
var epToAdd = new List<EmbyEpisode>();
|
||||
|
||||
foreach (var ep in allEpisodes.Items)
|
||||
var allEpisodes = await _api.GetAllEpisodes(server.ApiKey, 0, 200, server.AdministratorId, server.FullUri);
|
||||
var total = allEpisodes.TotalRecordCount;
|
||||
var processed = 1;
|
||||
var epToAdd = new HashSet<EmbyEpisode>();
|
||||
while (processed < total)
|
||||
{
|
||||
// Let's make sure we have the parent request, stop those pesky forign key errors,
|
||||
// Damn me having data integrity
|
||||
var parent = await _repo.GetByEmbyId(ep.SeriesId);
|
||||
if (parent == null)
|
||||
foreach (var ep in allEpisodes.Items)
|
||||
{
|
||||
_logger.LogInformation("The episode {0} does not relate to a series, so we cannot save this", ep.Name);
|
||||
continue;
|
||||
processed++;
|
||||
// Let's make sure we have the parent request, stop those pesky forign key errors,
|
||||
// Damn me having data integrity
|
||||
var parent = await _repo.GetByEmbyId(ep.SeriesId);
|
||||
if (parent == null)
|
||||
{
|
||||
_logger.LogInformation("The episode {0} does not relate to a series, so we cannot save this",
|
||||
ep.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingEpisode = await _repo.GetEpisodeByEmbyId(ep.Id);
|
||||
// Make sure it's not in the hashset too
|
||||
var existingInList = epToAdd.Any(x => x.EmbyId == ep.Id);
|
||||
|
||||
if (existingEpisode == null && !existingInList)
|
||||
{
|
||||
_logger.LogDebug("Adding new episode {0} to parent {1}", ep.Name, ep.SeriesName);
|
||||
// add it
|
||||
epToAdd.Add(new EmbyEpisode
|
||||
{
|
||||
EmbyId = ep.Id,
|
||||
EpisodeNumber = ep.IndexNumber,
|
||||
SeasonNumber = ep.ParentIndexNumber,
|
||||
ParentId = ep.SeriesId,
|
||||
TvDbId = ep.ProviderIds.Tvdb,
|
||||
TheMovieDbId = ep.ProviderIds.Tmdb,
|
||||
ImdbId = ep.ProviderIds.Imdb,
|
||||
Title = ep.Name,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var existingEpisode = await _repo.GetEpisodeByEmbyId(ep.Id);
|
||||
if (existingEpisode == null)
|
||||
{
|
||||
// add it
|
||||
epToAdd.Add(new EmbyEpisode
|
||||
{
|
||||
EmbyId = ep.Id,
|
||||
EpisodeNumber = ep.IndexNumber,
|
||||
SeasonNumber = ep.ParentIndexNumber,
|
||||
ParentId = ep.SeriesId,
|
||||
TvDbId = ep.ProviderIds.Tvdb,
|
||||
TheMovieDbId = ep.ProviderIds.Tmdb,
|
||||
ImdbId = ep.ProviderIds.Imdb,
|
||||
Title = ep.Name,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
await _repo.AddRange(epToAdd);
|
||||
epToAdd.Clear();
|
||||
allEpisodes = await _api.GetAllEpisodes(server.ApiKey, processed, 200, server.AdministratorId, server.FullUri);
|
||||
}
|
||||
|
||||
if (epToAdd.Any())
|
||||
|
|
|
@ -492,41 +492,42 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var orderedTv = series.OrderByDescending(x => x.AddedAt);
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
if (!t.HasTvDb)
|
||||
{
|
||||
// We may need to use themoviedb for the imdbid or their own id to get info
|
||||
if (t.HasTheMovieDb)
|
||||
{
|
||||
int.TryParse(t.TheMovieDbId, out var movieId);
|
||||
var externals = await _movieApi.GetTvExternals(movieId);
|
||||
if (externals == null || externals.tvdb_id <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
t.TvDbId = externals.tvdb_id.ToString();
|
||||
}
|
||||
// WE could check the below but we need to get the moviedb and then perform the above, let the metadata job figure this out.
|
||||
//else if(t.HasImdb)
|
||||
//{
|
||||
// // Check the imdbid
|
||||
// var externals = await _movieApi.Find(t.ImdbId, ExternalSource.imdb_id);
|
||||
// if (externals?.tv_results == null || externals.tv_results.Length <= 0)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// t.TvDbId = externals.tv_results.FirstOrDefault()..ToString();
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
int.TryParse(t.TvDbId, out var tvdbId);
|
||||
var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId);
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!t.HasTvDb)
|
||||
{
|
||||
// We may need to use themoviedb for the imdbid or their own id to get info
|
||||
if (t.HasTheMovieDb)
|
||||
{
|
||||
int.TryParse(t.TheMovieDbId, out var movieId);
|
||||
var externals = await _movieApi.GetTvExternals(movieId);
|
||||
if (externals == null || externals.tvdb_id <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
t.TvDbId = externals.tvdb_id.ToString();
|
||||
}
|
||||
// WE could check the below but we need to get the moviedb and then perform the above, let the metadata job figure this out.
|
||||
//else if(t.HasImdb)
|
||||
//{
|
||||
// // Check the imdbid
|
||||
// var externals = await _movieApi.Find(t.ImdbId, ExternalSource.imdb_id);
|
||||
// if (externals?.tv_results == null || externals.tv_results.Length <= 0)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// t.TvDbId = externals.tv_results.FirstOrDefault()..ToString();
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
int.TryParse(t.TvDbId, out var tvdbId);
|
||||
var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId);
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
|
@ -588,7 +589,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -676,20 +677,20 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var orderedTv = series.OrderByDescending(x => x.AddedAt);
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
if (!t.TvDbId.HasValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int.TryParse(t.TvDbId, out var tvdbId);
|
||||
var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId);
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!t.TvDbId.HasValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int.TryParse(t.TvDbId, out var tvdbId);
|
||||
var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId);
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
|
@ -752,7 +753,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
AddGenres(sb, $"Genres: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
Logger.LogDebug(LoggingEvents.Updater, "Starting Update job");
|
||||
|
||||
var settings = await Settings.GetSettingsAsync();
|
||||
if (!settings.AutoUpdateEnabled)
|
||||
if (!settings.AutoUpdateEnabled && !settings.TestMode)
|
||||
{
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Auto update is not enabled");
|
||||
return;
|
||||
|
@ -83,7 +83,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
var productVersion = AssemblyHelper.GetRuntimeVersion();
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Product Version {0}", productVersion);
|
||||
|
||||
var serverVersion = string.Empty;
|
||||
try
|
||||
{
|
||||
var productArray = GetVersion();
|
||||
|
@ -96,13 +96,17 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
Logger.LogDebug(LoggingEvents.Updater, "Branch {0}", branch);
|
||||
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Looking for updates now");
|
||||
//TODO this fails because the branch = featureupdater when it should be feature/updater
|
||||
var updates = await Processor.Process(branch);
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Updates: {0}", updates);
|
||||
var serverVersion = updates.UpdateVersionString;
|
||||
|
||||
|
||||
serverVersion = updates.UpdateVersionString;
|
||||
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Service Version {0}", updates.UpdateVersionString);
|
||||
|
||||
if (!serverVersion.Equals(version, StringComparison.CurrentCultureIgnoreCase))
|
||||
|
||||
if (!serverVersion.Equals(version, StringComparison.CurrentCultureIgnoreCase) || settings.TestMode)
|
||||
{
|
||||
// Let's download the correct zip
|
||||
var desc = RuntimeInformation.OSDescription;
|
||||
|
@ -135,7 +139,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
if (process == Architecture.Arm)
|
||||
{
|
||||
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("arm.", CompareOptions.IgnoreCase));
|
||||
} else if (process == Architecture.Arm64)
|
||||
}
|
||||
else if (process == Architecture.Arm64)
|
||||
{
|
||||
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("arm64.", CompareOptions.IgnoreCase));
|
||||
}
|
||||
|
@ -206,33 +211,35 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
updaterExtension = ".exe";
|
||||
}
|
||||
var updaterFile = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
|
||||
"TempUpdate", $"Ombi.Updater{updaterExtension}");
|
||||
"TempUpdate", "updater", $"Ombi.Updater{updaterExtension}");
|
||||
|
||||
// Make sure the file is an executable
|
||||
ExecLinuxCommand($"chmod +x {updaterFile}");
|
||||
//ExecLinuxCommand($"chmod +x {updaterFile}");
|
||||
|
||||
|
||||
// There must be an update
|
||||
var start = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = false, // Ignored if UseShellExecute is set to true
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true, // Ignored if UseShellExecute is set to true
|
||||
FileName = updaterFile,
|
||||
Arguments = GetArgs(settings),
|
||||
WorkingDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "TempUpdate"),
|
||||
};
|
||||
if (settings.Username.HasValue())
|
||||
//if (settings.Username.HasValue())
|
||||
//{
|
||||
// start.UserName = settings.Username;
|
||||
//}
|
||||
//if (settings.Password.HasValue())
|
||||
//{
|
||||
// start.Password = settings.Password.ToSecureString();
|
||||
//}
|
||||
using (var proc = new Process { StartInfo = start })
|
||||
{
|
||||
start.UserName = settings.Username;
|
||||
proc.Start();
|
||||
}
|
||||
if (settings.Password.HasValue())
|
||||
{
|
||||
start.Password = settings.Password.ToSecureString();
|
||||
}
|
||||
var proc = new Process { StartInfo = start };
|
||||
|
||||
|
||||
proc.Start();
|
||||
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Bye bye");
|
||||
}
|
||||
}
|
||||
|
@ -254,10 +261,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"--applicationPath \"{currentLocation}\" --processname \"{processName}\" ");
|
||||
if (settings.WindowsService)
|
||||
{
|
||||
sb.Append($"--windowsServiceName \"{settings.WindowsServiceName}\" ");
|
||||
}
|
||||
//if (settings.WindowsService)
|
||||
//{
|
||||
// sb.Append($"--windowsServiceName \"{settings.WindowsServiceName}\" ");
|
||||
//}
|
||||
var sb2 = new StringBuilder();
|
||||
if (url?.Value.HasValue() ?? false)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ombi.Schedule.Jobs.Plex.Models
|
|||
public IEnumerable<int> Content { get; set; }
|
||||
public IEnumerable<int> Episodes { get; set; }
|
||||
|
||||
public bool HasProcessedContent => Content.Any();
|
||||
public bool HasProcessedEpisodes => Episodes.Any();
|
||||
public bool HasProcessedContent => Content?.Any() ?? false;
|
||||
public bool HasProcessedEpisodes => Episodes?.Any() ?? false;
|
||||
}
|
||||
}
|
|
@ -79,11 +79,16 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
|
||||
}
|
||||
if (useTvDb)
|
||||
if (useTvDb && (seriesEpisodes == null || !seriesEpisodes.Any()) )
|
||||
{
|
||||
seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
|
||||
}
|
||||
|
||||
if (seriesEpisodes == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seriesEpisodes.Any())
|
||||
{
|
||||
// Let's try and match the series by name
|
||||
|
@ -118,6 +123,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
// We have fulfulled this request!
|
||||
child.Available = true;
|
||||
child.MarkedAsAvailable = DateTime.Now;
|
||||
_backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions
|
||||
{
|
||||
DateTime = DateTime.Now,
|
||||
|
@ -158,6 +164,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
|
||||
movie.Available = true;
|
||||
movie.MarkedAsAvailable = DateTime.Now;
|
||||
if (movie.Available)
|
||||
{
|
||||
_backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions
|
||||
|
|
|
@ -150,9 +150,9 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
var retVal = new ProcessedContent();
|
||||
var contentProcessed = new Dictionary<int, int>();
|
||||
var episodesProcessed = new List<int>();
|
||||
Logger.LogInformation("Getting all content from server {0}", servers.Name);
|
||||
Logger.LogDebug("Getting all content from server {0}", servers.Name);
|
||||
var allContent = await GetAllContent(servers, recentlyAddedSearch);
|
||||
Logger.LogInformation("We found {0} items", allContent.Count);
|
||||
Logger.LogDebug("We found {0} items", allContent.Count);
|
||||
|
||||
// Let's now process this.
|
||||
var contentToAdd = new HashSet<PlexServerContent>();
|
||||
|
@ -163,7 +163,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Logger.LogInformation("Found some episodes, this must be a recently added sync");
|
||||
Logger.LogDebug("Found some episodes, this must be a recently added sync");
|
||||
var count = 0;
|
||||
foreach (var epInfo in content.Metadata ?? new Metadata[]{})
|
||||
{
|
||||
|
@ -208,7 +208,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
// Process Shows
|
||||
Logger.LogInformation("Processing TV Shows");
|
||||
Logger.LogDebug("Processing TV Shows");
|
||||
var count = 0;
|
||||
foreach (var show in content.Metadata ?? new Metadata[] { })
|
||||
{
|
||||
|
@ -237,7 +237,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Logger.LogInformation("Processing Movies");
|
||||
Logger.LogDebug("Processing Movies");
|
||||
foreach (var movie in content?.Metadata ?? new Metadata[] { })
|
||||
{
|
||||
// Let's check if we have this movie
|
||||
|
@ -251,7 +251,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
//var existing = await Repo.GetByKey(movie.ratingKey);
|
||||
if (existing != null)
|
||||
{
|
||||
Logger.LogInformation("We already have movie {0}", movie.title);
|
||||
Logger.LogDebug("We already have movie {0}", movie.title);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
await Repo.Delete(hasSameKey);
|
||||
}
|
||||
|
||||
Logger.LogInformation("Adding movie {0}", movie.title);
|
||||
Logger.LogDebug("Adding movie {0}", movie.title);
|
||||
var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
||||
movie.ratingKey);
|
||||
var providerIds = PlexHelper.GetProviderIdFromPlexGuid(metaData.MediaContainer.Metadata
|
||||
|
@ -381,6 +381,19 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
|
||||
if (existingContent != null)
|
||||
{
|
||||
// Let's make sure that we have some sort of ID e.g. Imdbid for this,
|
||||
// Looks like it's possible to not have an Id for a show
|
||||
// I suspect we cached that show just as it was added to Plex.
|
||||
|
||||
if (!existingContent.HasImdb && !existingContent.HasTheMovieDb && !existingContent.HasTvDb)
|
||||
{
|
||||
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
||||
existingContent.Key);
|
||||
GetProviderIds(showMetadata, existingContent);
|
||||
|
||||
await Repo.Update(existingContent);
|
||||
}
|
||||
|
||||
// Just check the key
|
||||
if (existingKey != null)
|
||||
{
|
||||
|
@ -421,7 +434,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
try
|
||||
{
|
||||
Logger.LogInformation("We already have show {0} checking for new seasons",
|
||||
Logger.LogDebug("We already have show {0} checking for new seasons",
|
||||
existingContent.Title);
|
||||
// Ok so we have it, let's check if there are any new seasons
|
||||
var itemAdded = false;
|
||||
|
@ -472,16 +485,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
try
|
||||
{
|
||||
Logger.LogInformation("New show {0}, so add it", show.title);
|
||||
Logger.LogDebug("New show {0}, so add it", show.title);
|
||||
|
||||
// Get the show metadata... This sucks since the `metadata` var contains all information about the show
|
||||
// But it does not contain the `guid` property that we need to pull out thetvdb id...
|
||||
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
||||
show.ratingKey);
|
||||
var providerIds =
|
||||
PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault()
|
||||
.guid);
|
||||
|
||||
|
||||
var item = new PlexServerContent
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
|
@ -492,20 +502,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey),
|
||||
Seasons = new List<PlexSeasonsContent>()
|
||||
};
|
||||
if (providerIds.Type == ProviderType.ImdbId)
|
||||
{
|
||||
item.ImdbId = providerIds.ImdbId;
|
||||
}
|
||||
|
||||
if (providerIds.Type == ProviderType.TheMovieDbId)
|
||||
{
|
||||
item.TheMovieDbId = providerIds.TheMovieDb;
|
||||
}
|
||||
|
||||
if (providerIds.Type == ProviderType.TvDbId)
|
||||
{
|
||||
item.TvDbId = providerIds.TheTvDb;
|
||||
}
|
||||
GetProviderIds(showMetadata, item);
|
||||
|
||||
// Let's just double check to make sure we do not have it now we have some id's
|
||||
var existingImdb = false;
|
||||
|
@ -547,6 +544,27 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
}
|
||||
|
||||
private static void GetProviderIds(PlexMetadata showMetadata, PlexServerContent existingContent)
|
||||
{
|
||||
var providerIds =
|
||||
PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault()
|
||||
.guid);
|
||||
if (providerIds.Type == ProviderType.ImdbId)
|
||||
{
|
||||
existingContent.ImdbId = providerIds.ImdbId;
|
||||
}
|
||||
|
||||
if (providerIds.Type == ProviderType.TheMovieDbId)
|
||||
{
|
||||
existingContent.TheMovieDbId = providerIds.TheMovieDb;
|
||||
}
|
||||
|
||||
if (providerIds.Type == ProviderType.TvDbId)
|
||||
{
|
||||
existingContent.TvDbId = providerIds.TheTvDb;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the library sections.
|
||||
/// If the user has specified only certain libraries then we will only look for those
|
||||
|
@ -573,7 +591,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
.Select(x => x.Key.ToString()).ToList();
|
||||
if (!keys.Contains(dir.key))
|
||||
{
|
||||
Logger.LogInformation("Lib {0} is not monitored, so skipping", dir.key);
|
||||
Logger.LogDebug("Lib {0} is not monitored, so skipping", dir.key);
|
||||
// We are not monitoring this lib
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache");
|
||||
foreach (var s in sonarrSeries)
|
||||
{
|
||||
if (!s.monitored)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_log.LogDebug("Syncing series: {0}", s.title);
|
||||
var episodes = await _api.GetEpisodes(s.id, settings.ApiKey, settings.FullUri);
|
||||
var monitoredEpisodes = episodes.Where(x => x.monitored || x.hasFile);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
|
||||
namespace Ombi.Core.Settings.Models.External
|
||||
|
@ -6,6 +7,10 @@ namespace Ombi.Core.Settings.Models.External
|
|||
public sealed class PlexSettings : Ombi.Settings.Settings.Models.Settings
|
||||
{
|
||||
public bool Enable { get; set; }
|
||||
/// <summary>
|
||||
/// This is the ClientId for OAuth
|
||||
/// </summary>
|
||||
public Guid InstallId { get; set; }
|
||||
public List<PlexServers> Servers { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@
|
|||
public string ScriptLocation { get; set; }
|
||||
public string WindowsServiceName { get; set; }
|
||||
public bool WindowsService { get; set; }
|
||||
public bool TestMode { get; set; }
|
||||
}
|
||||
}
|
|
@ -183,7 +183,7 @@ namespace Ombi.Store.Context
|
|||
notificationToAdd = new NotificationTemplates
|
||||
{
|
||||
NotificationType = notificationType,
|
||||
Message = "Hello! You {Title} on {ApplicationName}! This is now available! :)",
|
||||
Message = "Hello! Your request for {Title} on {ApplicationName}! This is now available! :)",
|
||||
Subject = "{ApplicationName}: {Title} is now available!",
|
||||
Agent = agent,
|
||||
Enabled = true,
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Ombi.Store.Entities
|
|||
{
|
||||
public enum RequestType
|
||||
{
|
||||
TvShow,
|
||||
Movie
|
||||
TvShow = 0,
|
||||
Movie = 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,13 @@ namespace Ombi.Store.Entities.Requests
|
|||
{
|
||||
public string Title { get; set; }
|
||||
public bool Approved { get; set; }
|
||||
public DateTime MarkedAsApproved { get; set; }
|
||||
public DateTime RequestedDate { get; set; }
|
||||
public bool Available { get; set; }
|
||||
public DateTime? MarkedAsAvailable { get; set; }
|
||||
public string RequestedUserId { get; set; }
|
||||
public bool? Denied { get; set; }
|
||||
public DateTime MarkedAsDenied { get; set; }
|
||||
public string DeniedReason { get; set; }
|
||||
public RequestType RequestType { get; set; }
|
||||
|
||||
|
|
981
src/Ombi.Store/Migrations/20180703200952_EmbyUrlFix.Designer.cs
generated
Normal file
981
src/Ombi.Store/Migrations/20180703200952_EmbyUrlFix.Designer.cs
generated
Normal file
|
@ -0,0 +1,981 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180703200952_EmbyUrlFix")]
|
||||
partial class EmbyUrlFix
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int?>("EpisodeNumber");
|
||||
|
||||
b.Property<int?>("SeasonNumber");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestSubscription");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
20
src/Ombi.Store/Migrations/20180703200952_EmbyUrlFix.cs
Normal file
20
src/Ombi.Store/Migrations/20180703200952_EmbyUrlFix.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class EmbyUrlFix : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
@"UPDATE EmbyContent SET Url = replace( Url, 'http://app.emby.media/itemdetails.html', 'http://app.emby.media/#!/itemdetails.html' ) WHERE Url LIKE 'http://app.emby.media/itemdetails.html%';");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
988
src/Ombi.Store/Migrations/20180730085903_UserStats.Designer.cs
generated
Normal file
988
src/Ombi.Store/Migrations/20180730085903_UserStats.Designer.cs
generated
Normal file
|
@ -0,0 +1,988 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Ombi.Store.Context;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180730085903_UserStats")]
|
||||
partial class UserStats
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int?>("EpisodeNumber");
|
||||
|
||||
b.Property<int?>("SeasonNumber");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestSubscription");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
72
src/Ombi.Store/Migrations/20180730085903_UserStats.cs
Normal file
72
src/Ombi.Store/Migrations/20180730085903_UserStats.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class UserStats : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsApproved",
|
||||
table: "MovieRequests",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsAvailable",
|
||||
table: "MovieRequests",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsDenied",
|
||||
table: "MovieRequests",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsApproved",
|
||||
table: "ChildRequests",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsAvailable",
|
||||
table: "ChildRequests",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "MarkedAsDenied",
|
||||
table: "ChildRequests",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsApproved",
|
||||
table: "MovieRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsAvailable",
|
||||
table: "MovieRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsDenied",
|
||||
table: "MovieRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsApproved",
|
||||
table: "ChildRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsAvailable",
|
||||
table: "ChildRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MarkedAsDenied",
|
||||
table: "ChildRequests");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,9 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
|
@ -20,7 +14,7 @@ namespace Ombi.Store.Migrations
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
|
||||
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
|
@ -481,6 +475,12 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
@ -595,6 +595,12 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.9" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.1.1" />
|
||||
<PackageReference Include="Moq" Version="4.7.99" />
|
||||
<PackageReference Include="Nunit" Version="3.8.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.7.0"></packagereference>
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ombi.Updater
|
|||
ProcessInfo GetCurrentProcess();
|
||||
int GetCurrentProcessId();
|
||||
ProcessInfo GetProcessById(int id);
|
||||
void Kill(StartupOptions opts);
|
||||
bool Kill(StartupOptions opts);
|
||||
void KillAll(string processName);
|
||||
void SetPriority(int processId, ProcessPriorityClass priority);
|
||||
void WaitForExit(Process process);
|
||||
|
|
|
@ -22,29 +22,23 @@ namespace Ombi.Updater
|
|||
{
|
||||
// Kill Ombi Process
|
||||
var p = new ProcessProvider();
|
||||
bool killed = false;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
p.Kill(opt);
|
||||
killed = p.Kill(opt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
// Make sure the process has been killed
|
||||
while (p.FindProcessByName(opt.ProcessName).Any())
|
||||
if (!killed)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
_log.LogDebug("Found another process called {0}, KILLING!", opt.ProcessName);
|
||||
var proc = p.FindProcessByName(opt.ProcessName).FirstOrDefault();
|
||||
if (proc != null)
|
||||
{
|
||||
_log.LogDebug($"[{proc.Id}] - {proc.Name} - Path: {proc.StartPath}");
|
||||
opt.OmbiProcessId = proc.Id;
|
||||
p.Kill(opt);
|
||||
}
|
||||
|
||||
_log.LogDebug("Couldn't kill the ombi process");
|
||||
return;
|
||||
}
|
||||
|
||||
_log.LogDebug("Starting to move the files");
|
||||
|
@ -111,21 +105,23 @@ namespace Ombi.Updater
|
|||
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||
location = Path.GetDirectoryName(location);
|
||||
_log.LogDebug("We are currently in dir {0}", location);
|
||||
var updatedLocation = Directory.GetParent(location).FullName;
|
||||
_log.LogDebug("The files are in {0}", updatedLocation); // Since the updater is a folder deeper
|
||||
_log.LogDebug("Ombi is installed at {0}", options.ApplicationPath);
|
||||
|
||||
//Now Create all of the directories
|
||||
foreach (string dirPath in Directory.GetDirectories(location, "*",
|
||||
foreach (string dirPath in Directory.GetDirectories(updatedLocation, "*",
|
||||
SearchOption.AllDirectories))
|
||||
{
|
||||
var newDir = dirPath.Replace(location, options.ApplicationPath);
|
||||
var newDir = dirPath.Replace(updatedLocation, options.ApplicationPath);
|
||||
Directory.CreateDirectory(newDir);
|
||||
_log.LogDebug("Created dir {0}", newDir);
|
||||
}
|
||||
//Copy all the files & Replaces any files with the same name
|
||||
foreach (string currentPath in Directory.GetFiles(location, "*.*",
|
||||
foreach (string currentPath in Directory.GetFiles(updatedLocation, "*.*",
|
||||
SearchOption.AllDirectories))
|
||||
{
|
||||
var newFile = currentPath.Replace(location, options.ApplicationPath);
|
||||
var newFile = currentPath.Replace(updatedLocation, options.ApplicationPath);
|
||||
File.Copy(currentPath, newFile, true);
|
||||
_log.LogDebug("Replaced file {0}", newFile);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win10-x64;win10-x86;osx-x64;ubuntu-x64;debian.8-x64;centos.7-x64;linux-x64;linux-arm;linux-arm64;</RuntimeIdentifiers>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
||||
<FileVersion>3.0.0.0</FileVersion>
|
||||
<Version></Version>
|
||||
|
@ -12,14 +12,14 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" />
|
||||
<PackageReference Include="Serilog" Version="2.6.0-dev-00892" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="3.2.0" />
|
||||
|
|
|
@ -73,33 +73,32 @@ namespace Ombi.Updater
|
|||
process.PriorityClass = priority;
|
||||
}
|
||||
|
||||
public void Kill(StartupOptions opts)
|
||||
public bool Kill(StartupOptions opts)
|
||||
{
|
||||
if (opts.IsWindowsService)
|
||||
{
|
||||
Console.WriteLine("Stopping Service {0}", opts.WindowsServiceName);
|
||||
var process = new Process();
|
||||
var startInfo =
|
||||
new ProcessStartInfo
|
||||
{
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
FileName = "cmd.exe",
|
||||
Arguments = $"/C net stop \"{opts.WindowsServiceName}\""
|
||||
};
|
||||
process.StartInfo = startInfo;
|
||||
process.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (opts.IsWindowsService)
|
||||
//{
|
||||
// Console.WriteLine("Stopping Service {0}", opts.WindowsServiceName);
|
||||
// var process = new Process();
|
||||
// var startInfo =
|
||||
// new ProcessStartInfo
|
||||
// {
|
||||
// WindowStyle = ProcessWindowStyle.Hidden,
|
||||
// FileName = "cmd.exe",
|
||||
// Arguments = $"/C net stop \"{opts.WindowsServiceName}\""
|
||||
// };
|
||||
// process.StartInfo = startInfo;
|
||||
// process.Start();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
var process = Process.GetProcesses().FirstOrDefault(p => p.ProcessName == opts.ProcessName);
|
||||
|
||||
if (process == null)
|
||||
{
|
||||
Console.WriteLine("Cannot find process with name: {0}", opts.ProcessName);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
process.Refresh();
|
||||
|
||||
|
||||
if (process.Id > 0)
|
||||
{
|
||||
|
@ -108,8 +107,12 @@ namespace Ombi.Updater
|
|||
Console.WriteLine("[{0}]: Waiting for exit", process.Id);
|
||||
process.WaitForExit();
|
||||
Console.WriteLine("[{0}]: Process terminated successfully", process.Id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
//}
|
||||
}
|
||||
|
||||
public void KillAll(string processName)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"profiles": {
|
||||
"Ombi.Updater": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "--applicationPath \\\"C:\\\\Users\\\\Jamie\\\\Source\\\\Repos\\\\Ombi\\\\src\\\\Ombi\\\\bin\\\\Debug\\\\netcoreapp2.0\\\" --processname \\\"Ombi\\\" --startupArgs http://*:5000"
|
||||
"commandLineArgs": "--applicationPath \"C:\\_git\\ombi\\src\\Ombi.Updater\\bin\\Debug\\netcoreapp2.0\" --processname \"Ombi\""
|
||||
}
|
||||
}
|
||||
}
|
23
src/Ombi/.gitignore
vendored
23
src/Ombi/.gitignore
vendored
|
@ -1,23 +1,10 @@
|
|||
/wwwroot/css/**
|
||||
/wwwroot/fonts/**
|
||||
/wwwroot/lib/**
|
||||
/wwwroot/maps/**
|
||||
/wwwroot/dist/**
|
||||
/wwwroot/*.js.map
|
||||
/wwwroot/*.js
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/bower_components
|
||||
|
||||
# misc
|
||||
node_modules
|
||||
bin
|
||||
obj
|
||||
wwwroot/dist
|
||||
*.log
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage/*
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
#/typings
|
||||
/systemjs.config.js*
|
||||
/Logs/**
|
||||
**.db
|
||||
|
|
15
src/Ombi/.vscode/tasks.json
vendored
15
src/Ombi/.vscode/tasks.json
vendored
|
@ -4,7 +4,7 @@
|
|||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "restore",
|
||||
"label": "restore",
|
||||
"command": "npm",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
|
@ -14,7 +14,16 @@
|
|||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"taskName": "build",
|
||||
"label": "clean",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"clean"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
|
@ -27,7 +36,7 @@
|
|||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"taskName": "lint",
|
||||
"label": "lint",
|
||||
"type": "shell",
|
||||
"command": "npm",
|
||||
"args": [
|
||||
|
|
|
@ -94,9 +94,31 @@ namespace Ombi
|
|||
}
|
||||
else
|
||||
{
|
||||
var identity = new GenericIdentity("API");
|
||||
var principal = new GenericPrincipal(identity, new[] { "Admin", "ApiUser" });
|
||||
context.User = principal;
|
||||
// Check if we have a UserName header if so we can impersonate that user
|
||||
if (context.Request.Headers.Keys.Contains("UserName", StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var username = context.Request.Headers["UserName"].FirstOrDefault();
|
||||
var um = context.RequestServices.GetService<OmbiUserManager>();
|
||||
var user = await um.Users.FirstOrDefaultAsync(x =>
|
||||
x.UserName.Equals(username, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (user == null)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
await context.Response.WriteAsync("Invalid User");
|
||||
await next.Invoke(context);
|
||||
}
|
||||
var roles = await um.GetRolesAsync(user);
|
||||
var identity = new GenericIdentity(user.UserName);
|
||||
var principal = new GenericPrincipal(identity, roles.ToArray());
|
||||
context.User = principal;
|
||||
}
|
||||
else
|
||||
{
|
||||
var identity = new GenericIdentity("API");
|
||||
var principal = new GenericPrincipal(identity, new[] { "Admin", "ApiUser" });
|
||||
context.User = principal;
|
||||
}
|
||||
|
||||
await next.Invoke(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { animate, style, transition, trigger } from "@angular/animations";
|
||||
import { AnimationEntryMetadata } from "@angular/core";
|
||||
import { AnimationTriggerMetadata } from "@angular/animations";
|
||||
|
||||
export const fadeInOutAnimation: AnimationEntryMetadata = trigger("fadeInOut", [
|
||||
export const fadeInOutAnimation: AnimationTriggerMetadata = trigger("fadeInOut", [
|
||||
transition(":enter", [ // :enter is alias to 'void => *'
|
||||
style({ opacity: 0 }),
|
||||
animate(1000, style({ opacity: 1 })),
|
||||
|
|
|
@ -134,6 +134,12 @@
|
|||
<li [ngClass]="{'active': 'no' === translate.currentLang}">
|
||||
<a (click)="translate.use('no')" [translate]="'NavigationBar.Language.Norwegian'"></a>
|
||||
</li>
|
||||
<li [ngClass]="{'active': 'pt' === translate.currentLang}">
|
||||
<a (click)="translate.use('pt')" [translate]="'NavigationBar.Language.BrazillianPortuguese'"></a>
|
||||
</li>
|
||||
<li [ngClass]="{'active': 'pl' === translate.currentLang}">
|
||||
<a (click)="translate.use('pl')" [translate]="'NavigationBar.Language.Polish'"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -33,20 +33,20 @@ export class AppComponent implements OnInit {
|
|||
private readonly jobService: JobService,
|
||||
public readonly translate: TranslateService,
|
||||
private readonly identityService: IdentityService,
|
||||
private readonly platformLocation: PlatformLocation) {
|
||||
private readonly platformLocation: PlatformLocation) {
|
||||
|
||||
const base = this.platformLocation.getBaseHrefFromDOM();
|
||||
const base = this.platformLocation.getBaseHrefFromDOM();
|
||||
if (base.length > 1) {
|
||||
__webpack_public_path__ = base + "/dist/";
|
||||
}
|
||||
|
||||
this.translate.addLangs(["en", "de", "fr","da","es","it","nl","sv","no"]);
|
||||
this.translate.addLangs(["en", "de", "fr", "da", "es", "it", "nl", "sv", "no", "pl", "pt"]);
|
||||
// this language will be used as a fallback when a translation isn't found in the current language
|
||||
this.translate.setDefaultLang("en");
|
||||
|
||||
|
||||
// See if we can match the supported langs with the current browser lang
|
||||
const browserLang: string = translate.getBrowserLang();
|
||||
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no/) ? browserLang : "en");
|
||||
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no|pl|pt/) ? browserLang : "en");
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
|
@ -88,8 +88,8 @@ export class AppComponent implements OnInit {
|
|||
|
||||
public openMobileApp(event: any) {
|
||||
event.preventDefault();
|
||||
if(!this.customizationSettings.applicationUrl) {
|
||||
this.notificationService.warning("Mobile","Please ask your admin to setup the Application URL!");
|
||||
if (!this.customizationSettings.applicationUrl) {
|
||||
this.notificationService.warning("Mobile", "Please ask your admin to setup the Application URL!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import {CommonModule, PlatformLocation} from "@angular/common";
|
||||
import {HttpClient, HttpClientModule} from "@angular/common/http";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||
import {HttpModule} from "@angular/http";
|
||||
import {MatButtonModule, MatCardModule, MatInputModule, MatTabsModule} from "@angular/material";
|
||||
import {BrowserModule} from "@angular/platform-browser";
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import { CommonModule, PlatformLocation } from "@angular/common";
|
||||
import { HttpClient, HttpClientModule } from "@angular/common/http";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { HttpModule } from "@angular/http";
|
||||
import { MatButtonModule, MatCardModule, MatInputModule, MatTabsModule } from "@angular/material";
|
||||
import { BrowserModule } from "@angular/platform-browser";
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { JwtModule } from "@auth0/angular-jwt";
|
||||
|
||||
|
@ -15,7 +15,7 @@ import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
|
|||
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
||||
import { CookieService } from "ng2-cookies";
|
||||
import { GrowlModule } from "primeng/components/growl/growl";
|
||||
import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule,DialogModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng";
|
||||
import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule, DialogModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng";
|
||||
|
||||
// Components
|
||||
import { AppComponent } from "./app.component";
|
||||
|
@ -36,7 +36,7 @@ import { ImageService } from "./services";
|
|||
import { LandingPageService } from "./services";
|
||||
import { NotificationService } from "./services";
|
||||
import { SettingsService } from "./services";
|
||||
import { IssuesService, JobService, StatusService } from "./services";
|
||||
import { IssuesService, JobService, PlexTvService, StatusService } from "./services";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "*", component: PageNotFoundComponent },
|
||||
|
@ -67,6 +67,14 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
|
|||
return new TranslateHttpLoader(http, "/translations/", `.json?v=${version}`);
|
||||
}
|
||||
|
||||
export function JwtTokenGetter() {
|
||||
const token = localStorage.getItem("id_token");
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes),
|
||||
|
@ -89,18 +97,12 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
|
|||
CaptchaModule,
|
||||
TooltipModule,
|
||||
ConfirmDialogModule,
|
||||
CommonModule,
|
||||
CommonModule,
|
||||
JwtModule.forRoot({
|
||||
config: {
|
||||
tokenGetter: () => {
|
||||
const token = localStorage.getItem("id_token");
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
return token;
|
||||
},
|
||||
tokenGetter: JwtTokenGetter,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
|
@ -119,7 +121,7 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
|
|||
TokenResetPasswordComponent,
|
||||
CookieComponent,
|
||||
LoginOAuthComponent,
|
||||
],
|
||||
],
|
||||
providers: [
|
||||
NotificationService,
|
||||
AuthService,
|
||||
|
@ -133,6 +135,7 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
|
|||
CookieService,
|
||||
JobService,
|
||||
IssuesService,
|
||||
PlexTvService,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
export interface IUserLogin {
|
||||
import { IPlexPin } from "../interfaces";
|
||||
|
||||
export interface IUserLogin {
|
||||
username: string;
|
||||
password: string;
|
||||
rememberMe: boolean;
|
||||
usePlexOAuth: boolean;
|
||||
plexTvPin: IPlexPin;
|
||||
}
|
||||
|
||||
export interface ILocalUser {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { PlatformLocation } from "@angular/common";
|
||||
import { PlatformLocation } from "@angular/common";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { JwtHelperService } from "@auth0/angular-jwt";
|
||||
import { Observable } from "rxjs/Rx";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { ServiceHelpers } from "../services";
|
||||
import { ILocalUser, IUserLogin } from "./IUserLogin";
|
||||
|
@ -26,13 +26,13 @@ export class AuthService extends ServiceHelpers {
|
|||
return this.http.post<boolean>(`${this.url}/requirePassword`, JSON.stringify(login), {headers: this.headers});
|
||||
}
|
||||
|
||||
public loggedIn() {
|
||||
public loggedIn() {
|
||||
const token: string = this.jwtHelperService.tokenGetter();
|
||||
|
||||
|
||||
if (!token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const tokenExpired: boolean = this.jwtHelperService.isTokenExpired(token);
|
||||
return !tokenExpired;
|
||||
}
|
||||
|
@ -53,9 +53,9 @@ export class AuthService extends ServiceHelpers {
|
|||
} else {
|
||||
u.roles.push(roles);
|
||||
}
|
||||
return <ILocalUser>u;
|
||||
return <ILocalUser> u;
|
||||
}
|
||||
return <ILocalUser>{};
|
||||
return <ILocalUser> { };
|
||||
}
|
||||
|
||||
public hasRole(role: string): boolean {
|
||||
|
|
|
@ -11,7 +11,7 @@ export class CookieComponent implements OnInit {
|
|||
|
||||
public ngOnInit() {
|
||||
const cookie = this.cookieService.getAll();
|
||||
if(cookie.Auth) {
|
||||
if (cookie.Auth) {
|
||||
const jwtVal = cookie.Auth;
|
||||
localStorage.setItem("id_token", jwtVal);
|
||||
this.router.navigate(["search"]);
|
||||
|
|
|
@ -46,6 +46,7 @@ export interface IIssueComments {
|
|||
}
|
||||
|
||||
export interface IIssuesChat {
|
||||
id: number;
|
||||
comment: string;
|
||||
date: Date;
|
||||
username: string;
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
user: IPlexUser;
|
||||
}
|
||||
|
||||
export interface IPlexPin {
|
||||
id: number;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface IPlexOAuthViewModel {
|
||||
wizard: boolean;
|
||||
pin: IPlexPin;
|
||||
}
|
||||
|
||||
export interface IPlexOAuthAccessToken {
|
||||
accessToken: string;
|
||||
}
|
||||
|
@ -24,6 +34,19 @@ export interface IPlexLibResponse {
|
|||
data: IPlexLibraries;
|
||||
}
|
||||
|
||||
export interface IPlexLibSimpleResponse {
|
||||
successful: boolean;
|
||||
message: string;
|
||||
data: IPlexSection[];
|
||||
}
|
||||
|
||||
export interface IPlexSection {
|
||||
id: string;
|
||||
key: string;
|
||||
type: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface IMediaContainer {
|
||||
directory: IDirectory[];
|
||||
}
|
||||
|
@ -39,6 +62,28 @@ export interface IPlexServerViewModel {
|
|||
servers: IPlexServerResult;
|
||||
}
|
||||
|
||||
export interface IPlexServerAddViewModel {
|
||||
success: boolean;
|
||||
servers: IPlexServersAdd[];
|
||||
}
|
||||
|
||||
export interface IPlexServersAdd {
|
||||
serverId: number;
|
||||
machineId: string;
|
||||
serverName: string;
|
||||
}
|
||||
|
||||
export interface IPlexUserViewModel {
|
||||
username: string;
|
||||
machineIdentifier: string;
|
||||
libsSelected: number[];
|
||||
}
|
||||
|
||||
export interface IPlexUserAddResponse {
|
||||
success: boolean;
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface IPlexServerResult {
|
||||
friendlyName: string;
|
||||
machineIdentifier: string;
|
||||
|
|
|
@ -20,7 +20,7 @@ export interface IRecentlyAddedTvShows extends IRecentlyAddedMovies {
|
|||
|
||||
export interface IRecentlyAddedRangeModel {
|
||||
from: Date;
|
||||
to: Date;
|
||||
to: Date;
|
||||
}
|
||||
|
||||
export enum RecentlyAddedType {
|
||||
|
|
|
@ -71,6 +71,10 @@ export interface ITvRequests {
|
|||
status: string;
|
||||
childRequests: IChildRequests[];
|
||||
qualityOverride: number;
|
||||
background: any;
|
||||
totalSeasons: number;
|
||||
tvDbId: number;
|
||||
open: boolean; // THIS IS FOR THE UI
|
||||
|
||||
// For UI display
|
||||
qualityOverrideTitle: string;
|
||||
|
|
|
@ -28,8 +28,16 @@ export interface ISearchTvResult {
|
|||
available: boolean;
|
||||
plexUrl: string;
|
||||
embyUrl: string;
|
||||
quality: string;
|
||||
firstSeason: boolean;
|
||||
latestSeason: boolean;
|
||||
theTvDbId: string;
|
||||
subscribed: boolean;
|
||||
showSubscribe: boolean;
|
||||
fullyAvailable: boolean;
|
||||
partlyAvailable: boolean;
|
||||
background: any;
|
||||
open: boolean; // THIS IS FOR THE UI
|
||||
}
|
||||
|
||||
export interface ITvRequestViewModel {
|
||||
|
|
|
@ -27,6 +27,7 @@ export interface IUpdateSettings extends ISettings {
|
|||
windowsService: boolean;
|
||||
windowsServiceName: string;
|
||||
isWindows: boolean;
|
||||
testMode: boolean;
|
||||
}
|
||||
|
||||
export interface IEmbySettings extends ISettings {
|
||||
|
|
|
@ -23,6 +23,11 @@ export interface ICreateWizardUser {
|
|||
usePlexAdminAccount: boolean;
|
||||
}
|
||||
|
||||
export interface IWizardUserResult {
|
||||
result: boolean;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
export enum UserType {
|
||||
LocalUser = 1,
|
||||
PlexUser = 2,
|
||||
|
|
|
@ -51,15 +51,17 @@
|
|||
<div *ngIf="comments" class="panel-body msg_container_base">
|
||||
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
<p [translate]="'Issues.NoComments'"></p>
|
||||
|
||||
<div class="messages msg_sent">
|
||||
<p [translate]="'Issues.NoComments'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
|
||||
<div class="messages msg_sent"> <i *ngIf="isAdmin" style="float:right;" class="fa fa-times" aria-hidden="true" (click)="deleteComment(comment.id)"></i>
|
||||
<p>{{comment.comment}}</p>
|
||||
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
|
||||
</div>
|
||||
|
|
|
@ -37,10 +37,10 @@ export class IssueDetailsComponent implements OnInit {
|
|||
private notificationService: NotificationService,
|
||||
private imageService: ImageService,
|
||||
private sanitizer: DomSanitizer,
|
||||
private readonly platformLocation: PlatformLocation) {
|
||||
private readonly platformLocation: PlatformLocation) {
|
||||
this.route.params
|
||||
.subscribe((params: any) => {
|
||||
this.issueId = parseInt(params.id);
|
||||
this.issueId = parseInt(params.id);
|
||||
});
|
||||
|
||||
this.isAdmin = this.authService.hasRole("Admin") || this.authService.hasRole("PowerUser");
|
||||
|
@ -53,8 +53,8 @@ export class IssueDetailsComponent implements OnInit {
|
|||
this.defaultPoster = "../../../images/";
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
|
||||
public ngOnInit() {
|
||||
this.issueService.getIssue(this.issueId).subscribe(x => {
|
||||
this.issue = {
|
||||
comments: x.comments,
|
||||
|
@ -63,8 +63,8 @@ export class IssueDetailsComponent implements OnInit {
|
|||
issueCategoryId: x.issueCategoryId,
|
||||
subject: x.subject,
|
||||
description: x.description,
|
||||
status:x.status,
|
||||
resolvedDate:x.resolvedDate,
|
||||
status: x.status,
|
||||
resolvedDate: x.resolvedDate,
|
||||
title: x.title,
|
||||
requestType: x.requestType,
|
||||
requestId: x.requestId,
|
||||
|
@ -97,6 +97,13 @@ export class IssueDetailsComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
public deleteComment(id: number) {
|
||||
this.issueService.deleteComment(id).subscribe(x => {
|
||||
this.loadComments();
|
||||
this.notificationService.success("Comment Deleted");
|
||||
});
|
||||
}
|
||||
|
||||
private loadComments() {
|
||||
this.issueService.getComments(this.issueId).subscribe(x => this.comments = x);
|
||||
}
|
||||
|
@ -117,7 +124,7 @@ export class IssueDetailsComponent implements OnInit {
|
|||
|
||||
} else {
|
||||
this.imageService.getTvBackground(Number(issue.providerId)).subscribe(x => {
|
||||
if(x) {
|
||||
if (x) {
|
||||
this.backgroundPath = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + x + ")");
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ export class IssuesComponent implements OnInit {
|
|||
|
||||
constructor(private issueService: IssuesService) { }
|
||||
|
||||
public ngOnInit() {
|
||||
this.getPending();
|
||||
public ngOnInit() {
|
||||
this.getPending();
|
||||
this.getInProg();
|
||||
this.getResolved();
|
||||
this.issueService.getIssuesCount().subscribe(x => this.count = x);
|
||||
|
@ -61,5 +61,4 @@ export class IssuesComponent implements OnInit {
|
|||
this.resolvedIssues = x;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export class IssuesTableComponent {
|
|||
@Input() public issues: IIssues[];
|
||||
@Input() public totalRecords: number;
|
||||
|
||||
@Output() public changePage = new EventEmitter<IPagenator>();
|
||||
@Output() public changePage = new EventEmitter<IPagenator>();
|
||||
|
||||
public IssueStatus = IssueStatus;
|
||||
|
||||
|
@ -47,7 +47,7 @@ export class IssuesTableComponent {
|
|||
//event.rows = Number of rows to display in new page
|
||||
//event.page = Index of the new page
|
||||
//event.pageCount = Total number of pages
|
||||
|
||||
|
||||
this.changePage.emit(event);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { TranslateService } from "@ngx-translate/core";
|
|||
import { PlatformLocation } from "@angular/common";
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
import { IAuthenticationSettings, ICustomizationSettings } from "../interfaces";
|
||||
import { NotificationService } from "../services";
|
||||
import { NotificationService, PlexTvService } from "../services";
|
||||
import { SettingsService } from "../services";
|
||||
import { StatusService } from "../services";
|
||||
|
||||
|
@ -30,9 +30,10 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
public landingFlag: boolean;
|
||||
public baseUrl: string;
|
||||
public loginWithOmbi: boolean;
|
||||
|
||||
public pinTimer: any;
|
||||
|
||||
public get appName(): string {
|
||||
if(this.customizationSettings.applicationName) {
|
||||
if (this.customizationSettings.applicationName) {
|
||||
return this.customizationSettings.applicationName;
|
||||
} else {
|
||||
return "Ombi";
|
||||
|
@ -40,13 +41,14 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
}
|
||||
|
||||
private timer: any;
|
||||
|
||||
private clientId: string;
|
||||
|
||||
private errorBody: string;
|
||||
private errorValidation: string;
|
||||
|
||||
constructor(private authService: AuthService, private router: Router, private notify: NotificationService, private status: StatusService,
|
||||
private fb: FormBuilder, private settingsService: SettingsService, private images: ImageService, private sanitizer: DomSanitizer,
|
||||
private route: ActivatedRoute, private location: PlatformLocation, private readonly translate: TranslateService) {
|
||||
private route: ActivatedRoute, private location: PlatformLocation, private translate: TranslateService, private plexTv: PlexTvService) {
|
||||
this.route.params
|
||||
.subscribe((params: any) => {
|
||||
this.landingFlag = params.landing;
|
||||
|
@ -71,20 +73,21 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
}
|
||||
});
|
||||
|
||||
if(authService.loggedIn()) {
|
||||
if (authService.loggedIn()) {
|
||||
this.router.navigate(["search"]);
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
this.settingsService.getAuthentication().subscribe(x => this.authenticationSettings = x);
|
||||
this.settingsService.getClientId().subscribe(x => this.clientId = x);
|
||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(-10deg, transparent 20%, rgba(0,0,0,0.7) 20.0%, rgba(0,0,0,0.7) 80.0%, transparent 80%),url(" + x.url + ")");
|
||||
});
|
||||
this.timer = setInterval(() => {
|
||||
this.cycleBackground();
|
||||
}, 10000);
|
||||
}, 7000);
|
||||
|
||||
const base = this.location.getBaseHrefFromDOM();
|
||||
if (base.length > 1) {
|
||||
|
@ -101,9 +104,9 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
return;
|
||||
}
|
||||
const value = form.value;
|
||||
const user = { password: value.password, username: value.username, rememberMe: value.rememberMe, usePlexOAuth: false };
|
||||
const user = { password: value.password, username: value.username, rememberMe: value.rememberMe, usePlexOAuth: false, plexTvPin: { id: 0, code: "" } };
|
||||
this.authService.requiresPassword(user).subscribe(x => {
|
||||
if(x && this.authenticationSettings.allowNoPassword) {
|
||||
if (x && this.authenticationSettings.allowNoPassword) {
|
||||
// Looks like this user requires a password
|
||||
this.authenticationSettings.allowNoPassword = false;
|
||||
return;
|
||||
|
@ -113,6 +116,7 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
localStorage.setItem("id_token", x.access_token);
|
||||
|
||||
if (this.authService.loggedIn()) {
|
||||
this.ngOnDestroy();
|
||||
this.router.navigate(["search"]);
|
||||
} else {
|
||||
this.notify.error(this.errorBody);
|
||||
|
@ -123,28 +127,58 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
}
|
||||
|
||||
public oauth() {
|
||||
this.authService.login({usePlexOAuth: true, password:"",rememberMe:true,username:""}).subscribe(x => {
|
||||
if (window.frameElement) {
|
||||
// in frame
|
||||
window.open(x.url, "_blank");
|
||||
} else {
|
||||
// not in frame
|
||||
window.location.href = x.url;
|
||||
}
|
||||
this.plexTv.GetPin(this.clientId, this.appName).subscribe((pin: any) => {
|
||||
|
||||
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
|
||||
|
||||
window.open(x.url, "_blank", `toolbar=0,
|
||||
location=0,
|
||||
status=0,
|
||||
menubar=0,
|
||||
scrollbars=1,
|
||||
resizable=1,
|
||||
width=500,
|
||||
height=500`);
|
||||
|
||||
this.pinTimer = setInterval(() => {
|
||||
this.notify.info("Authenticating", "Loading... Please Wait");
|
||||
this.getPinResult(x.pinId);
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public getPinResult(pinId: number) {
|
||||
this.authService.oAuth(pinId).subscribe(x => {
|
||||
if(x.access_token) {
|
||||
localStorage.setItem("id_token", x.access_token);
|
||||
|
||||
if (this.authService.loggedIn()) {
|
||||
this.ngOnDestroy();
|
||||
this.router.navigate(["search"]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}, err => {
|
||||
this.notify.error(err.statusText);
|
||||
|
||||
this.router.navigate(["login"]);
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
clearInterval(this.timer);
|
||||
clearInterval(this.pinTimer);
|
||||
}
|
||||
|
||||
private cycleBackground() {
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = "";
|
||||
});
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = this.sanitizer
|
||||
.bypassSecurityTrustStyle("linear-gradient(-10deg, transparent 20%, rgba(0,0,0,0.7) 20.0%, rgba(0,0,0,0.7) 80.0%, transparent 80%), url(" + x.url + ")");
|
||||
});
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = "";
|
||||
});
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = this.sanitizer
|
||||
.bypassSecurityTrustStyle("linear-gradient(-10deg, transparent 20%, rgba(0,0,0,0.7) 20.0%, rgba(0,0,0,0.7) 80.0%, transparent 80%), url(" + x.url + ")");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ export class LoginOAuthComponent implements OnInit {
|
|||
this.route.params
|
||||
.subscribe((params: any) => {
|
||||
this.pin = params.pin;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -26,21 +25,20 @@ export class LoginOAuthComponent implements OnInit {
|
|||
|
||||
public auth() {
|
||||
this.authService.oAuth(this.pin).subscribe(x => {
|
||||
if(x.access_token) {
|
||||
if (x.access_token) {
|
||||
localStorage.setItem("id_token", x.access_token);
|
||||
|
||||
if (this.authService.loggedIn()) {
|
||||
this.router.navigate(["search"]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(x.errorMessage) {
|
||||
if (x.errorMessage) {
|
||||
this.error = x.errorMessage;
|
||||
}
|
||||
|
||||
}, err => {
|
||||
this.notify.error(err.statusText);
|
||||
|
||||
this.router.navigate(["login"]);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
|||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
import { ICustomizationSettings } from "../interfaces";
|
||||
import { IdentityService, ImageService,NotificationService, SettingsService } from "../services";
|
||||
import { IdentityService, ImageService, NotificationService, SettingsService } from "../services";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./resetpassword.component.html",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { NguCarousel } from "@ngu/carousel";
|
||||
import { NguCarouselConfig } from "@ngu/carousel";
|
||||
|
||||
import { ImageService, RecentlyAddedService } from "../services";
|
||||
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "./../interfaces";
|
||||
|
@ -41,13 +41,13 @@ export class RecentlyAddedComponent implements OnInit {
|
|||
public range: Date[];
|
||||
|
||||
public groupTv: boolean = false;
|
||||
|
||||
|
||||
// https://github.com/sheikalthaf/ngu-carousel
|
||||
public carouselTile: NguCarousel;
|
||||
|
||||
public carouselTile: NguCarouselConfig;
|
||||
|
||||
constructor(private recentlyAddedService: RecentlyAddedService,
|
||||
private imageService: ImageService) {}
|
||||
|
||||
|
||||
public ngOnInit() {
|
||||
this.getMovies();
|
||||
this.getShows();
|
||||
|
@ -67,10 +67,10 @@ export class RecentlyAddedComponent implements OnInit {
|
|||
}
|
||||
|
||||
public close() {
|
||||
if(this.range.length < 2) {
|
||||
if (this.range.length < 2) {
|
||||
return;
|
||||
}
|
||||
if(!this.range[1]) {
|
||||
if (!this.range[1]) {
|
||||
// If we do not have a second date then just set it to now
|
||||
this.range[1] = new Date();
|
||||
}
|
||||
|
@ -82,13 +82,13 @@ export class RecentlyAddedComponent implements OnInit {
|
|||
}
|
||||
|
||||
private getShows() {
|
||||
if(this.groupTv) {
|
||||
if (this.groupTv) {
|
||||
this.recentlyAddedService.getRecentlyAddedTvGrouped().subscribe(x => {
|
||||
this.tv = x;
|
||||
|
||||
|
||||
this.tv.forEach((t) => {
|
||||
this.imageService.getTvPoster(t.tvDbId).subscribe(p => {
|
||||
if(p) {
|
||||
if (p) {
|
||||
t.posterPath = p;
|
||||
}
|
||||
});
|
||||
|
@ -97,10 +97,10 @@ export class RecentlyAddedComponent implements OnInit {
|
|||
} else {
|
||||
this.recentlyAddedService.getRecentlyAddedTv().subscribe(x => {
|
||||
this.tv = x;
|
||||
|
||||
|
||||
this.tv.forEach((t) => {
|
||||
this.imageService.getTvPoster(t.tvDbId).subscribe(p => {
|
||||
if(p) {
|
||||
if (p) {
|
||||
t.posterPath = p;
|
||||
}
|
||||
});
|
||||
|
@ -114,11 +114,11 @@ export class RecentlyAddedComponent implements OnInit {
|
|||
this.movies = x;
|
||||
|
||||
this.movies.forEach((movie) => {
|
||||
if(movie.theMovieDbId) {
|
||||
if (movie.theMovieDbId) {
|
||||
this.imageService.getMoviePoster(movie.theMovieDbId).subscribe(p => {
|
||||
movie.posterPath = p;
|
||||
});
|
||||
} else if(movie.imdbId) {
|
||||
} else if (movie.imdbId) {
|
||||
this.imageService.getMoviePoster(movie.imdbId).subscribe(p => {
|
||||
movie.posterPath = p;
|
||||
});
|
||||
|
|
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