Merge branch 'feature/v4' into l10n_feature/v4

pull/3890/head
Jamie 3 years ago committed by GitHub
commit 6194f35bd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -77,8 +77,8 @@ stages:
- task: GitHubRelease@1
inputs:
gitHubConnection: 'github.com_tidusjar'
repositoryName: 'tidusjar/Ombi.Releases'
gitHubConnection: 'PAT'
repositoryName: 'Ombi-io/Ombi.Releases'
action: 'create'
target: 'c7fcbb77b58aef1076d635a9ef99e4374abc8672'
tagSource: 'userSpecifiedTag'

@ -5,7 +5,7 @@ steps:
displayName: 'Use .NET Core sdk '
inputs:
packageType: 'sdk'
version: '3.x'
version: '5.x'
- task: Yarn@3
displayName: 'Install UI Dependancies'
@ -18,7 +18,7 @@ steps:
inputs:
projectDirectory: '$(UiLocation)'
arguments: 'run build'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(UiLocation)dist'
@ -31,4 +31,4 @@ steps:
command: 'custom'
projects: '$(TestProject)'
custom: 'test'
continueOnError: false
continueOnError: false

@ -3,13 +3,13 @@ steps:
displayName: 'Use .NET Core sdk '
inputs:
packageType: 'sdk'
version: '3.x'
version: '5.x'
- task: DotNetCoreInstaller@1
displayName: 'Use .NET Core sdk for versioning'
inputs:
packageType: 'sdk'
version: '2.1.x'
version: '3.1.x'
- task: PowerShell@2
displayName: 'Set Version'
@ -24,23 +24,23 @@ steps:
inputs:
command: 'publish'
publishWebProjects: true
arguments: '-c $(BuildConfiguration) -r "$(runtime)" -o $(Build.ArtifactStagingDirectory)/$(runtime)'
arguments: '-c $(BuildConfiguration) -r "$(runtime)" -o $(Build.ArtifactStagingDirectory)/$(runtime) --self-contained true -p:PublishSingleFile=true'
zipAfterPublish: false
modifyOutputPath: false
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'angular_dist'
targetPath: '$(Build.ArtifactStagingDirectory)/angular_dist'
- task: CopyFiles@2
displayName: 'Copy Angular App $(runtime)'
inputs:
SourceFolder: '$(Build.ArtifactStagingDirectory)/angular_dist'
Contents: '**'
TargetFolder: '$(Build.ArtifactStagingDirectory)/$(runtime)/ClientApp/dist'
- task: ArchiveFiles@2
displayName: 'Zip $(runtime)'
inputs:
@ -49,7 +49,7 @@ steps:
archiveType: $(compression)
archiveFile: '$(Build.ArtifactStagingDirectory)/$(runtime).$(format)'
replaceExistingArchive: true
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/$(runtime).$(format)'

@ -12,7 +12,7 @@ variables:
value: "**/*.Tests.csproj"
- name: "NetCoreVersion"
value: "3.1"
value: "5.0"
- name: "PublishLocation"
value: "$(Build.SourcesDirectory)/src/Ombi/bin/Release/netcoreapp$(NetCoreVersion)"

@ -1,12 +0,0 @@

param([String]$env='local')
"Environment: " + $env | Write-Output;
"Build Version: " + $env:APPVEYOR_BUILD_VERSION | Write-Output;
"Base Path: " + $env:APPVEYOR_BUILD_FOLDER | Write-Output;
$appSettingsPath = $env:APPVEYOR_BUILD_FOLDER + '\src\Ombi\appsettings.json'
$appSettings = Get-Content $appSettingsPath -raw
$appSettings = $appSettings.Replace("{{VERSIONNUMBER}}",$env:APPVEYOR_BUILD_VERSION);
$appSettings = $appSettings.Replace("{{BRANCH}}",$env:APPVEYOR_REPO_BRANCH);
Set-Content -Path $appSettingsPath -Value $appSettings

@ -1,306 +0,0 @@
#tool "nuget:?package=GitVersion.CommandLine&version=5.0.1"
#addin nuget:?package=SharpZipLib&version=1.2.0
#addin nuget:?package=Cake.Compression&version=0.2.3
#addin "Cake.Incubator&version=5.1.0"
#addin nuget:?package=Cake.Yarn&version=0.4.6
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
//////////////////////////////////////////////////////////////////////
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////
var buildDir = "./src/Ombi/bin/" + configuration;
var nodeModulesDir ="./src/Ombi/ClientApp/node_modules/";
var wwwRootDistDir = "./src/Ombi/wwwroot/dist/";
var projDir = "./src/"; // Project Directory
var webProjDir = "./src/Ombi";
var uiProjectDir = "./src/Ombi/ClientApp";
var csProj = "./src/Ombi/Ombi.csproj"; // Path to the project.csproj
var solutionFile = "Ombi.sln"; // Solution file if needed
GitVersion versionInfo = null;
var frameworkVer = "netcoreapp3.0";
var buildSettings = new DotNetCoreBuildSettings
{
Framework = frameworkVer,
Configuration = "Release",
OutputDirectory = Directory(buildDir),
};
var publishSettings = new DotNetCorePublishSettings
{
Framework = frameworkVer,
Configuration = "Release",
OutputDirectory = Directory(buildDir),
};
var artifactsFolder = buildDir + "/"+frameworkVer+"/";
var windowsArtifactsFolder = artifactsFolder + "win10-x64/published";
var windows32BitArtifactsFolder = artifactsFolder + "win10-x86/published";
var osxArtifactsFolder = artifactsFolder + "osx-x64/published";
var linuxArtifactsFolder = artifactsFolder + "linux-x64/published";
var linuxArmArtifactsFolder = artifactsFolder + "linux-arm/published";
var linuxArm64BitArtifactsFolder = artifactsFolder + "linux-arm64/published";
//////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////
Task("Clean")
.Does(() =>
{
CleanDirectory(buildDir);
//CleanDirectory(nodeModulesDir);
CleanDirectory(wwwRootDistDir);
});
Task("SetVersionInfo")
.IsDependentOn("Clean")
.Does(() =>
{
var settings = new GitVersionSettings {
RepositoryPath = ".",
};
if (AppVeyor.IsRunningOnAppVeyor) {
settings.Branch = AppVeyor.Environment.Repository.Branch;
} else {
settings.Branch = "master";
}
versionInfo = GitVersion(settings);
// Information("GitResults -> {0}", versionInfo.Dump());
//Information(@"Build:{0}",AppVeyor.Environment.Build.Dump());
var buildVersion = string.Empty;
if(string.IsNullOrEmpty(AppVeyor.Environment.Build.Version))
{
buildVersion = "3.0.000";
} else{
buildVersion = AppVeyor.Environment.Build.Version;
}
if(versionInfo.BranchName.Contains("_"))
{
versionInfo.BranchName = versionInfo.BranchName.Replace("_","-");
}
var fullVer = buildVersion + "-" + versionInfo.BranchName;
if(versionInfo.PreReleaseTag.Contains("PullRequest"))
{
fullVer = buildVersion + "-PR";
}
if(fullVer.Contains("_"))
{
fullVer = fullVer.Replace("_","");
}
if(fullVer.Contains("/"))
{
fullVer = fullVer.Replace("/","");
}
buildSettings.ArgumentCustomization = args => args.Append("/p:SemVer=" + versionInfo.AssemblySemVer);
buildSettings.ArgumentCustomization = args => args.Append("/p:FullVer=" + fullVer);
publishSettings.ArgumentCustomization = args => args.Append("/p:SemVer=" + versionInfo.AssemblySemVer);
publishSettings.ArgumentCustomization = args => args.Append("/p:FullVer=" + fullVer);
//buildSettings.VersionSuffix = versionInfo.BranchName;
//publishSettings.VersionSuffix = versionInfo.BranchName;
});
Task("NPM")
.Does(() => {
Yarn.FromPath(uiProjectDir).Install();
});
Task("Gulp Publish")
.IsDependentOn("NPM")
.Does(() => {
Yarn.FromPath(uiProjectDir).RunScript("build");
});
Task("TSLint")
.Does(() =>
{
//Yarn.FromPath(uiProjectDir).RunScript("lint");
});
Task("PrePublish")
.IsDependentOn("SetVersionInfo");
//.IsDependentOn("Gulp Publish") // these are done in the main csproj
//.IsDependentOn("TSLint");
Task("Package")
.Does(() =>
{
Zip(windowsArtifactsFolder +"/",artifactsFolder + "windows.zip");
Zip(windows32BitArtifactsFolder +"/",artifactsFolder + "windows-32bit.zip");
GZipCompress(osxArtifactsFolder, artifactsFolder + "osx.tar.gz");
GZipCompress(linuxArtifactsFolder, artifactsFolder + "linux.tar.gz");
GZipCompress(linuxArmArtifactsFolder, artifactsFolder + "linux-arm.tar.gz");
GZipCompress(linuxArm64BitArtifactsFolder, artifactsFolder + "linux-arm64.tar.gz");
});
Task("Publish")
.IsDependentOn("Upload-Test-Results")
.IsDependentOn("PrePublish")
.IsDependentOn("Publish-Windows")
.IsDependentOn("Publish-Windows-32bit")
.IsDependentOn("Publish-OSX")
.IsDependentOn("Publish-Linux")
.IsDependentOn("Publish-Linux-ARM")
.IsDependentOn("Publish-Linux-ARM-64Bit")
.IsDependentOn("Package");
Task("Publish-Windows")
.Does(() =>
{
publishSettings.Runtime = "win10-x64";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/win10-x64/published");
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);
});
Task("Publish-Windows-32bit")
.Does(() =>
{
publishSettings.Runtime = "win10-x86";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer+"/win10-x86/published");
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);
});
Task("Publish-OSX")
.Does(() =>
{
publishSettings.Runtime = "osx-x64";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer+"/osx-x64/published");
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);
});
Task("Publish-Linux")
.Does(() =>
{
publishSettings.Runtime = "linux-x64";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer+"/linux-x64/published");
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);
});
Task("Publish-Linux-ARM")
.Does(() =>
{
publishSettings.Runtime = "linux-arm";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer+"/linux-arm/published");
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
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);
});
Task("Publish-Linux-ARM-64Bit")
.Does(() =>
{
publishSettings.Runtime = "linux-arm64";
publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer+"/linux-arm64/published");
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
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);
});
Task("Run-Unit-Tests")
.Does(() =>
{
var settings = new DotNetCoreTestSettings
{
ArgumentCustomization = args => args.Append("--logger \"trx;LogFileName=Test.trx\""),
Configuration = "Release"
};
var projectFiles = GetFiles("./**/*Tests.csproj");
foreach(var file in projectFiles)
{
DotNetCoreTest(file.FullPath, settings);
}
});
Task("Upload-Test-Results")
.IsDependentOn("Run-Unit-Tests")
.ContinueOnError()
.Does(() => {
});
Task("Run-Server-Build")
.Does(() =>
{
var settings = new DotNetCoreBuildSettings
{
Framework = frameworkVer,
Configuration = "Release",
OutputDirectory = Directory(buildDir)
};
DotNetCoreBuild(csProj, settings);
});
Task("Run-UI-Build")
.IsDependentOn("PrePublish");
//////////////////////////////////////////////////////////////////////
// TASK TARGETS
//////////////////////////////////////////////////////////////////////
Task("Default")
.IsDependentOn("Publish");
Task("Build")
.IsDependentOn("SetVersionInfo")
.IsDependentOn("Upload-Test-Results")
.IsDependentOn("Run-Server-Build");
// .IsDependentOn("Run-UI-Build");
//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////
RunTarget(target);

@ -1,242 +0,0 @@
##########################################################################
# This is the Cake bootstrapper script for PowerShell.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
<#
.SYNOPSIS
This is a Powershell script to bootstrap a Cake build.
.DESCRIPTION
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
and execute your Cake build script with the parameters you provide.
.PARAMETER Script
The build script to execute.
.PARAMETER Target
The build script target to run.
.PARAMETER Configuration
The build configuration to use.
.PARAMETER Verbosity
Specifies the amount of information to be displayed.
.PARAMETER ShowDescription
Shows description about tasks.
.PARAMETER DryRun
Performs a dry run.
.PARAMETER SkipToolPackageRestore
Skips restoring of packages.
.PARAMETER ScriptArgs
Remaining arguments are added here.
.LINK
https://cakebuild.net
#>
[CmdletBinding()]
Param(
[string]$Script = "build.cake",
[string]$Target,
[string]$Configuration,
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity,
[switch]$ShowDescription,
[Alias("WhatIf", "Noop")]
[switch]$DryRun,
[switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$ScriptArgs
)
# Attempt to set highest encryption available for SecurityProtocol.
# PowerShell will not set this by default (until maybe .NET 4.6.x). This
# will typically produce a message for PowerShell v2 (just an info
# message though)
try {
# Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48)
# Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't
# exist in .NET 4.0, even though they are addressable if .NET 4.5+ is
# installed (.NET 4.5 is an in-place upgrade).
[System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48
} catch {
Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3'
}
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
function MD5HashFile([string] $filePath)
{
if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
{
return $null
}
[System.IO.Stream] $file = $null;
[System.Security.Cryptography.MD5] $md5 = $null;
try
{
$md5 = [System.Security.Cryptography.MD5]::Create()
$file = [System.IO.File]::OpenRead($filePath)
return [System.BitConverter]::ToString($md5.ComputeHash($file))
}
finally
{
if ($file -ne $null)
{
$file.Dispose()
}
}
}
function GetProxyEnabledWebClient
{
$wc = New-Object System.Net.WebClient
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$wc.Proxy = $proxy
return $wc
}
Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
}
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
# Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
Write-Verbose -Message "Creating tools directory..."
New-Item -Path $TOOLS_DIR -Type directory | out-null
}
# Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..."
try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG)
} catch {
Throw "Could not download packages.config."
}
}
# Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
}
}
# Try download NuGet.exe if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..."
try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile($NUGET_URL, $NUGET_EXE)
} catch {
Throw "Could not download NuGet.exe."
}
}
# Save nuget.exe path to environment to be available to child processed
$ENV:NUGET_EXE = $NUGET_EXE
# Restore tools from NuGet?
if(-Not $SkipToolPackageRestore.IsPresent) {
Push-Location
Set-Location $TOOLS_DIR
# Check for changes in packages.config and remove installed tools if true.
[string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
Write-Verbose -Message "Missing or changed package.config hash..."
Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery |
Remove-Item -Recurse
}
Write-Verbose -Message "Restoring tools from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occurred while restoring NuGet tools."
}
else
{
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occurred while restoring NuGet addins."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
Write-Verbose -Message "Restoring modules from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occurred while restoring NuGet modules."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Make sure that Cake has been installed.
if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE"
}
# Build Cake arguments
$cakeArguments = @("$Script");
if ($Target) { $cakeArguments += "-target=$Target" }
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
if ($ShowDescription) { $cakeArguments += "-showdescription" }
if ($DryRun) { $cakeArguments += "-dryrun" }
$cakeArguments += $ScriptArgs
# Start Cake
Write-Host "Running build script..."
&$CAKE_EXE $cakeArguments
exit $LASTEXITCODE

@ -1,101 +0,0 @@
#!/usr/bin/env bash
##########################################################################
# This is the Cake bootstrapper script for Linux and OS X.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
# Define directories.
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
TOOLS_DIR=$SCRIPT_DIR/tools
NUGET_EXE=$TOOLS_DIR/nuget.exe
CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe
PACKAGES_CONFIG=$TOOLS_DIR/packages.config
PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum
# Define md5sum or md5 depending on Linux/OSX
MD5_EXE=
if [[ "$(uname -s)" == "Darwin" ]]; then
MD5_EXE="md5 -r"
else
MD5_EXE="md5sum"
fi
# Define default arguments.
SCRIPT="build.cake"
TARGET="Default"
CONFIGURATION="Release"
VERBOSITY="verbose"
DRYRUN=
SHOW_VERSION=false
SCRIPT_ARGUMENTS=()
# Parse arguments.
for i in "$@"; do
case $1 in
-s|--script) SCRIPT="$2"; shift ;;
-t|--target) TARGET="$2"; shift ;;
-c|--configuration) CONFIGURATION="$2"; shift ;;
-v|--verbosity) VERBOSITY="$2"; shift ;;
-d|--dryrun) DRYRUN="-dryrun" ;;
--version) SHOW_VERSION=true ;;
--) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
*) SCRIPT_ARGUMENTS+=("$1") ;;
esac
shift
done
# Make sure the tools folder exist.
if [ ! -d "$TOOLS_DIR" ]; then
mkdir "$TOOLS_DIR"
fi
# Make sure that packages.config exist.
if [ ! -f "$TOOLS_DIR/packages.config" ]; then
echo "Downloading packages.config..."
curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages
if [ $? -ne 0 ]; then
echo "An error occurred while downloading packages.config."
exit 1
fi
fi
# Download NuGet if it does not exist.
if [ ! -f "$NUGET_EXE" ]; then
echo "Downloading NuGet..."
curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
if [ $? -ne 0 ]; then
echo "An error occurred while downloading nuget.exe."
exit 1
fi
fi
# Restore tools from NuGet.
pushd "$TOOLS_DIR" >/dev/null
if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then
find . -type d ! -name . | xargs rm -rf
fi
mono "$NUGET_EXE" install -ExcludeVersion
if [ $? -ne 0 ]; then
echo "Could not restore NuGet packages."
exit 1
fi
$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
popd >/dev/null
# Make sure that Cake has been installed.
if [ ! -f "$CAKE_EXE" ]; then
echo "Could not find Cake.exe at '$CAKE_EXE'."
exit 1
fi
# Start Cake
if $SHOW_VERSION; then
exec mono "$CAKE_EXE" -version
else
exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
fi

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

@ -25,10 +25,6 @@ namespace Ombi.Api.Emby
public IEmbyApi CreateClient(EmbySettings settings)
{
if (settings.IsJellyfin)
{
return new JellyfinApi(_api);
}
return new EmbyApi(_api);
}
}

@ -5,15 +5,8 @@
public string LocalAddress { get; set; }
public string ServerName { get; set; }
public string Version { get; set; }
/// <summary>
/// Only populated for Jellyfin
/// </summary>
public string ProductName { get; set; }
public bool IsJellyfin => !string.IsNullOrEmpty(ProductName) && ProductName.Contains("Jellyfin");
public string OperatingSystem { get; set; }
public string Id { get; set; }
}
}
}

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

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Api.Jellyfin.Models;
using Ombi.Api.Jellyfin.Models.Media.Tv;
using Ombi.Api.Jellyfin.Models.Movie;
namespace Ombi.Api.Jellyfin
{
public interface IBaseJellyfinApi
{
Task<JellyfinSystemInfo> GetSystemInformation(string apiKey, string baseUrl);
Task<List<JellyfinUser>> GetUsers(string baseUri, string apiKey);
Task<JellyfinUser> LogIn(string username, string password, string apiKey, string baseUri);
Task<JellyfinItemContainer<JellyfinMovie>> GetAllMovies(string apiKey, int startIndex, int count, string userId,
string baseUri);
Task<JellyfinItemContainer<JellyfinEpisodes>> GetAllEpisodes(string apiKey, int startIndex, int count, string userId,
string baseUri);
Task<JellyfinItemContainer<JellyfinSeries>> GetAllShows(string apiKey, int startIndex, int count, string userId,
string baseUri);
Task<JellyfinItemContainer<JellyfinMovie>> 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);
Task<EpisodeInformation> GetEpisodeInformation(string mediaId, string apiKey, string userId, string baseUrl);
Task<PublicInfo> GetPublicInformation(string baseUrl);
}
}

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Ombi.Api.Jellyfin.Models;
namespace Ombi.Api.Jellyfin
{
public interface IJellyfinApi : IBaseJellyfinApi
{
Task<JellyfinConnectUser> LoginConnectUser(string username, string password);
}
}

@ -3,14 +3,14 @@ using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Internal;
using Newtonsoft.Json;
using Ombi.Api.Emby.Models;
using Ombi.Api.Emby.Models.Media.Tv;
using Ombi.Api.Emby.Models.Movie;
using Ombi.Api.Jellyfin.Models;
using Ombi.Api.Jellyfin.Models.Media.Tv;
using Ombi.Api.Jellyfin.Models.Movie;
using Ombi.Helpers;
namespace Ombi.Api.Emby
namespace Ombi.Api.Jellyfin
{
public class JellyfinApi : IEmbyApi
public class JellyfinApi : IJellyfinApi
{
public JellyfinApi(IApi api)
{
@ -20,27 +20,27 @@ namespace Ombi.Api.Emby
private IApi Api { get; }
/// <summary>
/// Returns all users from the Emby Instance
/// Returns all users from the Jellyfin Instance
/// </summary>
/// <param name="baseUri"></param>
/// <param name="apiKey"></param>
public async Task<List<EmbyUser>> GetUsers(string baseUri, string apiKey)
public async Task<List<JellyfinUser>> GetUsers(string baseUri, string apiKey)
{
var request = new Request("users", baseUri, HttpMethod.Get);
AddHeaders(request, apiKey);
var obj = await Api.Request<List<EmbyUser>>(request);
var obj = await Api.Request<List<JellyfinUser>>(request);
return obj;
}
public async Task<EmbySystemInfo> GetSystemInformation(string apiKey, string baseUrl)
public async Task<JellyfinSystemInfo> GetSystemInformation(string apiKey, string baseUrl)
{
var request = new Request("System/Info", baseUrl, HttpMethod.Get);
AddHeaders(request, apiKey);
var obj = await Api.Request<EmbySystemInfo>(request);
var obj = await Api.Request<JellyfinSystemInfo>(request);
return obj;
}
@ -56,7 +56,7 @@ namespace Ombi.Api.Emby
return obj;
}
public async Task<EmbyUser> LogIn(string username, string password, string apiKey, string baseUri)
public async Task<JellyfinUser> LogIn(string username, string password, string apiKey, string baseUri)
{
var request = new Request("users/authenticatebyname", baseUri, HttpMethod.Post);
var body = new
@ -71,11 +71,11 @@ namespace Ombi.Api.Emby
$"MediaBrowser Client=\"Ombi\", Device=\"Ombi\", DeviceId=\"v3\", Version=\"v3\"");
AddHeaders(request, apiKey);
var obj = await Api.Request<EmbyUser>(request);
var obj = await Api.Request<JellyfinUser>(request);
return obj;
}
public async Task<EmbyItemContainer<EmbyMovie>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
public async Task<JellyfinItemContainer<JellyfinMovie>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
{
var request = new Request($"users/{userId}/items?parentId={mediaId}", baseUrl, HttpMethod.Get);
AddHeaders(request, apiKey);
@ -84,22 +84,22 @@ namespace Ombi.Api.Emby
request.AddQueryString("IsVirtualItem", "False");
return await Api.Request<EmbyItemContainer<EmbyMovie>>(request);
return await Api.Request<JellyfinItemContainer<JellyfinMovie>>(request);
}
public async Task<EmbyItemContainer<EmbyMovie>> GetAllMovies(string apiKey, int startIndex, int count, string userId, string baseUri)
public async Task<JellyfinItemContainer<JellyfinMovie>> GetAllMovies(string apiKey, int startIndex, int count, string userId, string baseUri)
{
return await GetAll<EmbyMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count);
return await GetAll<JellyfinMovie>("Movie", apiKey, userId, baseUri, true, startIndex, count);
}
public async Task<EmbyItemContainer<EmbyEpisodes>> GetAllEpisodes(string apiKey, int startIndex, int count, string userId, string baseUri)
public async Task<JellyfinItemContainer<JellyfinEpisodes>> GetAllEpisodes(string apiKey, int startIndex, int count, string userId, string baseUri)
{
return await GetAll<EmbyEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count);
return await GetAll<JellyfinEpisodes>("Episode", apiKey, userId, baseUri, false, startIndex, count);
}
public async Task<EmbyItemContainer<EmbySeries>> GetAllShows(string apiKey, int startIndex, int count, string userId, string baseUri)
public async Task<JellyfinItemContainer<JellyfinSeries>> GetAllShows(string apiKey, int startIndex, int count, string userId, string baseUri)
{
return await GetAll<EmbySeries>("Series", apiKey, userId, baseUri, false, startIndex, count);
return await GetAll<JellyfinSeries>("Series", apiKey, userId, baseUri, false, startIndex, count);
}
public async Task<SeriesInformation> GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl)
@ -126,7 +126,7 @@ namespace Ombi.Api.Emby
return JsonConvert.DeserializeObject<T>(response);
}
private async Task<EmbyItemContainer<T>> GetAll<T>(string type, string apiKey, string userId, string baseUri, bool includeOverview = false)
private async Task<JellyfinItemContainer<T>> GetAll<T>(string type, string apiKey, string userId, string baseUri, bool includeOverview = false)
{
var request = new Request($"users/{userId}/items", baseUri, HttpMethod.Get);
@ -139,10 +139,10 @@ namespace Ombi.Api.Emby
AddHeaders(request, apiKey);
var obj = await Api.Request<EmbyItemContainer<T>>(request);
var obj = await Api.Request<JellyfinItemContainer<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)
private async Task<JellyfinItemContainer<T>> GetAll<T>(string type, string apiKey, string userId, string baseUri, bool includeOverview, int startIndex, int count)
{
var request = new Request($"users/{userId}/items", baseUri, HttpMethod.Get);
@ -157,7 +157,7 @@ namespace Ombi.Api.Emby
AddHeaders(request, apiKey);
var obj = await Api.Request<EmbyItemContainer<T>>(request);
var obj = await Api.Request<JellyfinItemContainer<T>>(request);
return obj;
}
@ -172,7 +172,7 @@ namespace Ombi.Api.Emby
req.AddHeader("Device", "Ombi");
}
public Task<EmbyConnectUser> LoginConnectUser(string username, string password)
public Task<JellyfinConnectUser> LoginConnectUser(string username, string password)
{
throw new System.NotImplementedException();
}

@ -0,0 +1,37 @@
using Ombi.Api;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using System.Threading.Tasks;
namespace Ombi.Api.Jellyfin
{
public class JellyfinApiFactory : IJellyfinApiFactory
{
private readonly ISettingsService<JellyfinSettings> _jellyfinSettings;
private readonly IApi _api;
// TODO, if we need to derive futher, need to rework
public JellyfinApiFactory(ISettingsService<JellyfinSettings> jellyfinSettings, IApi api)
{
_jellyfinSettings = jellyfinSettings;
_api = api;
}
public async Task<IJellyfinApi> CreateClient()
{
var settings = await _jellyfinSettings.GetSettingsAsync();
return CreateClient(settings);
}
public IJellyfinApi CreateClient(JellyfinSettings settings)
{
return new JellyfinApi(_api);
}
}
public interface IJellyfinApiFactory
{
Task<IJellyfinApi> CreateClient();
IJellyfinApi CreateClient(JellyfinSettings settings);
}
}

@ -0,0 +1,45 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: JellyfinConfiguration.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinConfiguration
{
public bool PlayDefaultAudioTrack { get; set; }
public bool DisplayMissingEpisodes { get; set; }
public bool DisplayUnairedEpisodes { get; set; }
public object[] GroupedFolders { get; set; }
public string SubtitleMode { get; set; }
public bool DisplayCollectionsView { get; set; }
public bool EnableLocalPassword { get; set; }
public object[] OrderedViews { get; set; }
public object[] LatestItemsExcludes { get; set; }
public bool HidePlayedInLatest { get; set; }
public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; }
public bool EnableNextEpisodeAutoPlay { get; set; }
}
}

@ -0,0 +1,47 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: JellyfinConnectUser.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinConnectUser
{
public string AccessToken { get; set; }
public User User { get; set; }
}
public class User
{
public string Id { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string IsActive { get; set; }
public string ImageUrl { get; set; }
public object IsSupporter { get; set; }
public object ExpDate { get; set; }
}
}

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinItemContainer<T>
{
public List<T> Items { get; set; }
public int TotalRecordCount { get; set; }
}
}

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

@ -0,0 +1,59 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: JellyfinPolicy.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinPolicy
{
public bool IsAdministrator { get; set; }
public bool IsHidden { get; set; }
public bool IsDisabled { get; set; }
public object[] BlockedTags { get; set; }
public bool EnableUserPreferenceAccess { get; set; }
public object[] AccessSchedules { get; set; }
public object[] BlockUnratedItems { get; set; }
public bool EnableRemoteControlOfOtherUsers { get; set; }
public bool EnableSharedDeviceControl { get; set; }
public bool EnableLiveTvManagement { get; set; }
public bool EnableLiveTvAccess { get; set; }
public bool EnableMediaPlayback { get; set; }
public bool EnableAudioPlaybackTranscoding { get; set; }
public bool EnableVideoPlaybackTranscoding { get; set; }
public bool EnablePlaybackRemuxing { get; set; }
public bool EnableContentDeletion { get; set; }
public bool EnableContentDownloading { get; set; }
public bool EnableSync { get; set; }
public bool EnableSyncTranscoding { get; set; }
public object[] EnabledDevices { get; set; }
public bool EnableAllDevices { get; set; }
public object[] EnabledChannels { get; set; }
public bool EnableAllChannels { get; set; }
public object[] EnabledFolders { get; set; }
public bool EnableAllFolders { get; set; }
public int InvalidLoginAttemptCount { get; set; }
public bool EnablePublicSharing { get; set; }
}
}

@ -0,0 +1,63 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: JellyfinSystemInfo.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinSystemInfo
{
public string SystemUpdateLevel { get; set; }
public string OperatingSystemDisplayName { get; set; }
public bool SupportsRunningAsService { get; set; }
public string MacAddress { get; set; }
public bool HasPendingRestart { get; set; }
public bool SupportsLibraryMonitor { get; set; }
public object[] InProgressInstallations { get; set; }
public int WebSocketPortNumber { get; set; }
public object[] CompletedInstallations { get; set; }
public bool CanSelfRestart { get; set; }
public bool CanSelfUpdate { get; set; }
public object[] FailedPluginAssemblies { get; set; }
public string ProgramDataPath { get; set; }
public string ItemsByNamePath { get; set; }
public string CachePath { get; set; }
public string LogPath { get; set; }
public string InternalMetadataPath { get; set; }
public string TranscodingTempPath { get; set; }
public int HttpServerPortNumber { get; set; }
public bool SupportsHttps { get; set; }
public int HttpsPortNumber { get; set; }
public bool HasUpdateAvailable { get; set; }
public bool SupportsAutoRunAtStartup { get; set; }
public string EncoderLocationType { get; set; }
public string SystemArchitecture { get; set; }
public string LocalAddress { get; set; }
public string WanAddress { get; set; }
public string ServerName { get; set; }
public string Version { get; set; }
public string OperatingSystem { get; set; }
public string Id { get; set; }
}
}

@ -0,0 +1,47 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: JellyfinUser.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinUser
{
public string Name { get; set; }
public string ServerId { get; set; }
public string ConnectUserName { get; set; }
public string ConnectLinkType { get; set; }
public string Id { get; set; }
public bool HasPassword { get; set; }
public bool HasConfiguredPassword { get; set; }
public bool HasConfiguredEasyPassword { get; set; }
public DateTime LastLoginDate { get; set; }
public DateTime LastActivityDate { get; set; }
public JellyfinConfiguration Configuration { get; set; }
public JellyfinPolicy Policy { get; set; }
}
}

@ -0,0 +1,7 @@
namespace Ombi.Api.Jellyfin.Models
{
public class JellyfinUserLogin
{
public JellyfinUser User { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinChapter
{
public long StartPositionTicks { get; set; }
public string Name { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinExternalurl
{
public string Name { get; set; }
public string Url { get; set; }
}
}

@ -0,0 +1,10 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinImagetags
{
public string Primary { get; set; }
public string Logo { get; set; }
public string Thumb { get; set; }
public string Banner { get; set; }
}
}

@ -0,0 +1,30 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinMediasource
{
public string Protocol { get; set; }
public string Id { get; set; }
public string Path { get; set; }
public string Type { get; set; }
public string Container { get; set; }
public string Name { get; set; }
public bool IsRemote { get; set; }
public string ETag { get; set; }
public long RunTimeTicks { get; set; }
public bool ReadAtNativeFramerate { get; set; }
public bool SupportsTranscoding { get; set; }
public bool SupportsDirectStream { get; set; }
public bool SupportsDirectPlay { get; set; }
public bool IsInfiniteStream { get; set; }
public bool RequiresOpening { get; set; }
public bool RequiresClosing { get; set; }
public bool SupportsProbing { get; set; }
public string VideoType { get; set; }
public JellyfinMediastream[] MediaStreams { get; set; }
public object[] PlayableStreamFileNames { get; set; }
public object[] Formats { get; set; }
public int Bitrate { get; set; }
public int DefaultAudioStreamIndex { get; set; }
}
}

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

@ -0,0 +1,11 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinPerson
{
public string Name { get; set; }
public string Id { get; set; }
public string Role { get; set; }
public string Type { get; set; }
public string PrimaryImageTag { get; set; }
}
}

@ -0,0 +1,13 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinProviderids
{
public string Tmdb { get; set; }
public string Imdb { get; set; }
public string TmdbCollection { get; set; }
public string Tvdb { get; set; }
public string Zap2It { get; set; }
public string TvRage { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinRemotetrailer
{
public string Url { get; set; }
public string Name { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinStudio
{
public string Name { get; set; }
public string Id { get; set; }
}
}

@ -0,0 +1,15 @@
using System;
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinUserdata
{
public double PlaybackPositionTicks { get; set; }
public int PlayCount { get; set; }
public bool IsFavorite { get; set; }
public bool Played { get; set; }
public string Key { get; set; }
public DateTime LastPlayedDate { get; set; }
public int UnplayedItemCount { get; set; }
}
}

@ -0,0 +1,34 @@
using System;
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class JellyfinMovie
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Container { get; set; }
public DateTime PremiereDate { get; set; }
public object[] ProductionLocations { get; set; }
public string OfficialRating { get; set; }
public float CommunityRating { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public string VideoType { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public bool HasSubtitles { get; set; }
public int CriticRating { get; set; }
public string Overview { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
}
}

@ -0,0 +1,60 @@
using System;
namespace Ombi.Api.Jellyfin.Models.Movie
{
public class MovieInformation
{
public string Name { get; set; }
public string OriginalTitle { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string Container { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public JellyfinExternalurl[] ExternalUrls { get; set; }
public JellyfinMediasource[] MediaSources { get; set; }
public string[] ProductionLocations { get; set; }
public string Path { get; set; }
public string OfficialRating { get; set; }
public string Overview { get; set; }
public string[] Taglines { get; set; }
public string[] Genres { get; set; }
public float CommunityRating { get; set; }
public int VoteCount { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public JellyfinRemotetrailer[] RemoteTrailers { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public JellyfinPerson[] People { get; set; }
public JellyfinStudio[] Studios { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public string DisplayPreferencesId { get; set; }
public object[] Tags { get; set; }
public string[] Keywords { get; set; }
public JellyfinMediastream[] MediaStreams { get; set; }
public string VideoType { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public JellyfinChapter[] Chapters { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public string HomePageUrl { get; set; }
public int Budget { get; set; }
public float Revenue { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

@ -0,0 +1,71 @@
using System;
using Ombi.Api.Jellyfin.Models.Movie;
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class EpisodeInformation
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string Container { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public JellyfinExternalurl[] ExternalUrls { get; set; }
public JellyfinMediasource[] MediaSources { get; set; }
public string Path { get; set; }
public string Overview { get; set; }
public object[] Taglines { get; set; }
public object[] Genres { get; set; }
public string[] SeriesGenres { get; set; }
public float CommunityRating { get; set; }
public int VoteCount { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; }
public int ParentIndexNumber { get; set; }
public object[] RemoteTrailers { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public object[] People { get; set; }
public object[] Studios { get; set; }
public string ParentLogoItemId { get; set; }
public string ParentBackdropItemId { get; set; }
public string[] ParentBackdropImageTags { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public string SeriesName { get; set; }
public string SeriesId { get; set; }
public string SeasonId { get; set; }
public string DisplayPreferencesId { get; set; }
public object[] Tags { get; set; }
public object[] Keywords { get; set; }
public string SeriesPrimaryImageTag { get; set; }
public string SeasonName { get; set; }
public JellyfinMediastream[] MediaStreams { get; set; }
public string VideoType { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public object[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public string ParentLogoImageTag { get; set; }
public string SeriesStudio { get; set; }
public JellyfinSeriesstudioinfo SeriesStudioInfo { get; set; }
public string ParentThumbItemId { get; set; }
public string ParentThumbImageTag { get; set; }
public JellyfinChapter[] Chapters { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

@ -0,0 +1,45 @@
using Ombi.Api.Jellyfin.Models.Movie;
using System;
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class JellyfinEpisodes
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Container { get; set; }
public DateTime PremiereDate { get; set; }
public float CommunityRating { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; }
public int? IndexNumberEnd { get; set; }
public int ParentIndexNumber { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public string ParentLogoItemId { get; set; }
public string ParentBackdropItemId { get; set; }
public string[] ParentBackdropImageTags { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public string SeriesName { get; set; }
public string SeriesId { get; set; }
public string SeasonId { get; set; }
public string SeriesPrimaryImageTag { get; set; }
public string SeasonName { get; set; }
public string VideoType { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public object[] BackdropImageTags { get; set; }
public string ParentLogoImageTag { get; set; }
public string ParentThumbItemId { get; set; }
public string ParentThumbImageTag { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public bool HasSubtitles { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class JellyfinRemotetrailer
{
public string Url { get; set; }
public string Name { get; set; }
}
}

@ -0,0 +1,32 @@
using Ombi.Api.Jellyfin.Models.Movie;
using System;
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class JellyfinSeries
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public DateTime PremiereDate { get; set; }
public string OfficialRating { get; set; }
public float CommunityRating { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public int ChildCount { get; set; }
public string Status { get; set; }
public string AirTime { get; set; }
public string[] AirDays { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public string LocationType { get; set; }
public DateTime EndDate { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class JellyfinSeriesstudioinfo
{
public string Name { get; set; }
public string Id { get; set; }
}
}

@ -0,0 +1,59 @@
using System;
using Ombi.Api.Jellyfin.Models.Movie;
namespace Ombi.Api.Jellyfin.Models.Media.Tv
{
public class SeriesInformation
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateLastMediaAdded { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public JellyfinExternalurl[] ExternalUrls { get; set; }
public string Path { get; set; }
public string OfficialRating { get; set; }
public string Overview { get; set; }
public string ShortOverview { get; set; }
public object[] Taglines { get; set; }
public string[] Genres { get; set; }
public float CommunityRating { get; set; }
public int VoteCount { get; set; }
public long CumulativeRunTimeTicks { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public JellyfinRemotetrailer[] RemoteTrailers { get; set; }
public JellyfinProviderids ProviderIds { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public JellyfinPerson[] People { get; set; }
public JellyfinStudio[] Studios { get; set; }
public int LocalTrailerCount { get; set; }
public JellyfinUserdata UserData { get; set; }
public int RecursiveItemCount { get; set; }
public int ChildCount { get; set; }
public string DisplayPreferencesId { get; set; }
public string Status { get; set; }
public string AirTime { get; set; }
public string[] AirDays { get; set; }
public object[] Tags { get; set; }
public object[] Keywords { get; set; }
public JellyfinImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public string LocationType { get; set; }
public string HomePageUrl { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

@ -0,0 +1,12 @@
namespace Ombi.Api.Jellyfin.Models
{
public class PublicInfo
{
public string LocalAddress { get; set; }
public string ServerName { get; set; }
public string Version { get; set; }
public string OperatingSystem { get; set; }
public string Id { get; set; }
}
}

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
<PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
</ItemGroup>
</Project>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>

@ -2,6 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
using Hqub.MusicBrainz.API.Entities;
using Hqub.MusicBrainz.API.Entities.Collections;
using Ombi.Api.MusicBrainz.Models;
namespace Ombi.Api.MusicBrainz
@ -11,6 +12,7 @@ namespace Ombi.Api.MusicBrainz
Task<IEnumerable<Artist>> SearchArtist(string artistQuery);
Task<IEnumerable<Release>> GetReleaseForArtist(string artistId);
Task<Artist> GetArtistInformation(string artistId);
Task<Release> GetAlbumInformation(string albumId);
Task<ReleaseGroupArt> GetCoverArtForReleaseGroup(string musicBrainzId, CancellationToken token);
}
}

@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using Hqub.MusicBrainz.API;
using Hqub.MusicBrainz.API.Entities;
using Hqub.MusicBrainz.API.Entities.Collections;
using Newtonsoft.Json;
using Ombi.Api.MusicBrainz.Models;
@ -20,6 +21,12 @@ namespace Ombi.Api.MusicBrainz
_api = api;
}
public Task<Release> GetAlbumInformation(string albumId)
{
var album = Release.GetAsync(albumId);
return album;
}
public async Task<IEnumerable<Artist>> SearchArtist(string artistQuery)
{
var artist = await Artist.SearchAsync(artistQuery, 10);

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

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

@ -135,16 +135,15 @@ namespace Ombi.Api.Plex
}
/// <summary>
// 192.168.1.69:32400/library/metadata/3662/allLeaves
// The metadata ratingkey should be in the Cache
// Search for it and then call the above with the Directory.RatingKey
// THEN! We need the episode metadata using result.Vide.Key ("/library/metadata/3664")
// We then have the GUID which contains the TVDB ID plus the season and episode number: guid="com.plexapp.agents.thetvdb://269586/2/8?lang=en"
/// 192.168.1.69:32400/library/metadata/3662/allLeaves
/// The metadata ratingkey should be in the Cache
/// Search for it and then call the above with the Directory.RatingKey
/// THEN! We need the episode metadata using result.Vide.Key ("/library/metadata/3664")
/// We then have the GUID which contains the TVDB ID plus the season and episode number: guid="com.plexapp.agents.thetvdb://269586/2/8?lang=en"
/// </summary>
/// <param name="authToken"></param>
/// <param name="plexFullHost"></param>
/// <param name="ratingKey"></param>
/// <returns></returns>
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, int ratingKey)
{
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
@ -308,7 +307,7 @@ namespace Ombi.Api.Plex
}
private async Task CheckInstallId(PlexSettings s)
{
if (s.InstallId == null || s.InstallId == Guid.Empty)
if (s?.InstallId == Guid.Empty || s.InstallId == Guid.Empty)
{
s.InstallId = Guid.NewGuid();
await _plexSettings.SaveSettingsAsync(s);

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

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

@ -0,0 +1,14 @@
using Ombi.Api.RottenTomatoes.Models;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ombi.Api.RottenTomatoes
{
public interface IRottenTomatoesApi
{
Task<MovieRatings> GetMovieRatings(string movieName, int movieYear);
Task<TvRatings> GetTvRatings(string showName, int showYear);
}
}

@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace Ombi.Api.RottenTomatoes.Models
{
public class RottenTomatoesMovieResponse
{
public int total { get; set; }
public List<Movie> movies { get; set; }
}
public class Movie
{
public string id { get; set; }
public string title { get; set; }
public int year { get; set; }
public string mpaa_rating { get; set; }
public object runtime { get; set; }
public string critics_consensus { get; set; }
public MovieRatings ratings { get; set; }
public Links links { get; set; }
}
public class MovieRatings
{
public string critics_rating { get; set; }
public int critics_score { get; set; }
public string audience_rating { get; set; }
public int audience_score { get; set; }
}
public class Links
{
public string alternate { get; set; }
}
}

@ -0,0 +1,20 @@
namespace Ombi.Api.RottenTomatoes.Models
{
public class RottenTomatoesTvResponse
{
public int tvCount { get; set; }
public TvSeries[] tvSeries { get; set; }
}
public class TvSeries
{
public string title { get; set; }
public int startYear { get; set; }
public int endYear { get; set; }
public string url { get; set; }
public string meterClass { get; set; }
public int meterScore { get; set; }
public string image { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.RottenTomatoes.Models
{
public class TvRatings
{
public string Class { get; set; }
public int Score { get; set; }
}
}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,56 @@
using Ombi.Api.RottenTomatoes.Models;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ombi.Api.RottenTomatoes
{
public class RottenTomatoesApi : IRottenTomatoesApi
{
public RottenTomatoesApi(IApi api)
{
_api = api;
}
private string Endpoint => "https://www.rottentomatoes.com/api/private";
private IApi _api { get; }
public async Task<MovieRatings> GetMovieRatings(string movieName, int movieYear)
{
var request = new Request("/v1.0/movies", Endpoint, HttpMethod.Get);
request.AddHeader("Accept", "application/json");
request.AddQueryString("q", movieName);
var result = await _api.Request<RottenTomatoesMovieResponse>(request);
var movieFound = result.movies.FirstOrDefault(x => x.year == movieYear);
if (movieFound == null)
{
return null;
}
return movieFound.ratings;
}
public async Task<TvRatings> GetTvRatings(string showName, int showYear)
{
var request = new Request("/v2.0/search/", Endpoint, HttpMethod.Get);
request.AddHeader("Accept", "application/json");
request.AddQueryString("q", showName);
request.AddQueryString("limit", 10.ToString());
var result = await _api.Request<RottenTomatoesTvResponse>(request);
var showFound = result.tvSeries.FirstOrDefault(x => x.startYear == showYear);
if (showFound == null)
{
return null;
}
return new TvRatings
{
Class = showFound.meterClass,
Score = showFound.meterScore
};
}
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

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

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

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

@ -1,4 +1,5 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -48,7 +49,18 @@ namespace Ombi.Api.Trakt
public async Task<TraktShow> GetTvExtendedInfo(string imdbId)
{
return await Client.Shows.GetShowAsync(imdbId, TraktExtendedOption.Full);
try
{
return await Client.Shows.GetShowAsync(imdbId, TraktExtendedOption.Full);
}
catch (Exception e)
{
// Ignore the exception since the information returned from this API is optional.
Console.WriteLine($"Failed to retrieve extended tv information from Trakt. IMDbId: '{imdbId}'.");
Console.WriteLine(e);
}
return null;
}
}
}

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

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

@ -5,7 +5,7 @@ using System.Threading.Tasks;
namespace Ombi.Api
{
public static class HttpRequestExtnesions
public static class HttpRequestExtensions
{
public static async Task<HttpRequestMessage> Clone(this HttpRequestMessage request)
{
@ -14,9 +14,9 @@ namespace Ombi.Api
Content = await request.Content.Clone(),
Version = request.Version
};
foreach (KeyValuePair<string, object> prop in request.Properties)
foreach (KeyValuePair<string, object> prop in request.Options)
{
clone.Properties.Add(prop);
clone.Options.TryAdd(prop.Key, prop.Value);
}
foreach (KeyValuePair<string, IEnumerable<string>> header in request.Headers)
{

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version></Version>
@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Polly" Version="7.1.0" />
</ItemGroup>

@ -30,7 +30,7 @@ namespace Ombi.Core.Tests.Authentication
AuthenticationSettings.Setup(x => x.GetSettingsAsync())
.ReturnsAsync(new AuthenticationSettings());
_um = new OmbiUserManager(UserStore.Object, null, null, null, null, null, null, null, null,
PlexApi.Object, null, null, AuthenticationSettings.Object);
PlexApi.Object, null, null, null, null, AuthenticationSettings.Object);
}
public OmbiUserManager _um { get; set; }

@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.11.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="Nunit" Version="3.12.0" />
<PackageReference Include="NUnit.ConsoleRunner" Version="3.11.1" />
@ -16,7 +17,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.7.1"></packagereference>
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.8.0"></packagereference>
</ItemGroup>
<ItemGroup>

@ -54,14 +54,15 @@ namespace Ombi.Core.Tests.Rule.Search
{
new EmbyServers
{
ServerHostname = "http://test.com/"
ServerHostname = "http://test.com/",
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
{
ProviderId = "123",
EmbyId = 1.ToString()
EmbyId = 1.ToString(),
});
var search = new SearchMovieViewModel()
{
@ -70,7 +71,7 @@ namespace Ombi.Core.Tests.Rule.Search
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/#!/item?id=1"));
Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/web/index.html#!/item?id=1&serverId=8"));
}
[Test]
@ -83,7 +84,8 @@ namespace Ombi.Core.Tests.Rule.Search
{
new EmbyServers
{
ServerHostname = string.Empty
ServerHostname = string.Empty,
ServerId = "8"
}
}
});
@ -99,7 +101,7 @@ namespace Ombi.Core.Tests.Rule.Search
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/#!/item?id=1"));
Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/web/index.html#!/item?id=1&serverId=8"));
}
[Test]
@ -113,4 +115,4 @@ namespace Ombi.Core.Tests.Rule.Search
Assert.False(search.Available);
}
}
}
}

@ -0,0 +1,119 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Rules.Search;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Tests.Rule.Search
{
public class JellyfinAvailabilityRuleTests
{
[SetUp]
public void Setup()
{
ContextMock = new Mock<IJellyfinContentRepository>();
SettingsMock = new Mock<ISettingsService<JellyfinSettings>>();
Rule = new JellyfinAvailabilityRule(ContextMock.Object, SettingsMock.Object);
}
private JellyfinAvailabilityRule Rule { get; set; }
private Mock<IJellyfinContentRepository> ContextMock { get; set; }
private Mock<ISettingsService<JellyfinSettings>> SettingsMock { get; set; }
[Test]
public async Task Movie_ShouldBe_Available_WhenFoundInJellyfin()
{
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings());
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{
ProviderId = "123"
});
var search = new SearchMovieViewModel()
{
TheMovieDbId = "123",
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.True(search.Available);
}
[Test]
public async Task Movie_Has_Custom_Url_When_Specified_In_Settings()
{
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings
{
Enable = true,
Servers = new List<JellyfinServers>
{
new JellyfinServers
{
ServerHostname = "http://test.com/",
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{
ProviderId = "123",
JellyfinId = 1.ToString(),
});
var search = new SearchMovieViewModel()
{
TheMovieDbId = "123",
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.That(search.JellyfinUrl, Is.EqualTo("http://test.com/web/index.html#!/details?id=1&serverId=8"));
}
[Test]
public async Task Movie_Uses_Default_Url_When()
{
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings
{
Enable = true,
Servers = new List<JellyfinServers>
{
new JellyfinServers
{
Ip = "8080",
Port = 9090,
ServerHostname = string.Empty,
ServerId = "8"
}
}
});
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new JellyfinContent
{
ProviderId = "123",
JellyfinId = 1.ToString()
});
var search = new SearchMovieViewModel()
{
TheMovieDbId = "123",
};
var result = await Rule.Execute(search);
Assert.True(result.Success);
}
[Test]
public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInJellyfin()
{
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).Returns(Task.FromResult(default(JellyfinContent)));
var search = new SearchMovieViewModel();
var result = await Rule.Execute(search);
Assert.True(result.Success);
Assert.False(search.Available);
}
}
}

@ -0,0 +1,94 @@
using NUnit.Framework;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Helpers;
using Ombi.Store.Entities;
using System.Collections.Generic;
namespace Ombi.Core.Tests
{
[TestFixture]
public class WatchProviderParserTests
{
[TestCase("GB", TestName = "UpperCase")]
[TestCase("gb", TestName = "LowerCase")]
[TestCase("gB", TestName = "MixedCase")]
public void GetValidStreamData(string streamingCountry)
{
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
{
Results = new Results
{
GB = new WatchProviderData()
{
StreamInformation = new List<StreamData>
{
new StreamData
{
provider_name = "Netflix",
display_priority = 0,
logo_path = "logo",
provider_id = 8
}
}
}
}
}, new OmbiUser { StreamingCountry = streamingCountry });
Assert.That(result[0].provider_name, Is.EqualTo("Netflix"));
}
[TestCase("GB", TestName = "Missing_UpperCase")]
[TestCase("gb", TestName = "Missing_LowerCase")]
[TestCase("gB", TestName = "Missing_MixedCase")]
public void GetMissingStreamData(string streamingCountry)
{
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
{
Results = new Results
{
AR = new WatchProviderData()
{
StreamInformation = new List<StreamData>
{
new StreamData
{
provider_name = "Netflix",
display_priority = 0,
logo_path = "logo",
provider_id = 8
}
}
}
}
}, new OmbiUser { StreamingCountry = streamingCountry });
Assert.That(result, Is.Empty);
}
[Test]
public void GetInvalidStreamData()
{
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
{
Results = new Results
{
AR = new WatchProviderData()
{
StreamInformation = new List<StreamData>
{
new StreamData
{
provider_name = "Netflix",
display_priority = 0,
logo_path = "logo",
provider_id = 8
}
}
}
}
}, new OmbiUser { StreamingCountry = "BLAH" });
Assert.That(result, Is.Empty);
}
}
}

@ -33,6 +33,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Ombi.Api.Emby;
using Ombi.Api.Jellyfin;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Core.Settings;
@ -49,18 +50,24 @@ namespace Ombi.Core.Authentication
IPasswordHasher<OmbiUser> passwordHasher, IEnumerable<IUserValidator<OmbiUser>> userValidators,
IEnumerable<IPasswordValidator<OmbiUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<OmbiUser>> logger, IPlexApi plexApi,
IEmbyApiFactory embyApi, ISettingsService<EmbySettings> embySettings, ISettingsService<AuthenticationSettings> auth)
IEmbyApiFactory embyApi, ISettingsService<EmbySettings> embySettings,
IJellyfinApiFactory jellyfinApi, ISettingsService<JellyfinSettings> jellyfinSettings,
ISettingsService<AuthenticationSettings> auth)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
_plexApi = plexApi;
_embyApi = embyApi;
_jellyfinApi = jellyfinApi;
_embySettings = embySettings;
_jellyfinSettings = jellyfinSettings;
_authSettings = auth;
}
private readonly IPlexApi _plexApi;
private readonly IEmbyApiFactory _embyApi;
private readonly IJellyfinApiFactory _jellyfinApi;
private readonly ISettingsService<EmbySettings> _embySettings;
private readonly ISettingsService<JellyfinSettings> _jellyfinSettings;
private readonly ISettingsService<AuthenticationSettings> _authSettings;
public override async Task<bool> CheckPasswordAsync(OmbiUser user, string password)
@ -83,6 +90,10 @@ namespace Ombi.Core.Authentication
{
return await CheckEmbyPasswordAsync(user, password);
}
if (user.UserType == UserType.JellyfinUser)
{
return await CheckJellyfinPasswordAsync(user, password);
}
return false;
}
@ -185,5 +196,36 @@ namespace Ombi.Core.Authentication
}
return false;
}
/// <summary>
/// Sign the user into Jellyfin
/// <remarks>We do not check if the user is in the owners "friends" since they must have a local user account to get this far.
/// We also have to try and authenticate them with every server, the first server that work we just say it was a success</remarks>
/// </summary>
/// <param name="user"></param>
/// <param name="password"></param>
/// <returns></returns>
private async Task<bool> CheckJellyfinPasswordAsync(OmbiUser user, string password)
{
var jellyfinSettings = await _jellyfinSettings.GetSettingsAsync();
var client = _jellyfinApi.CreateClient(jellyfinSettings);
foreach (var server in jellyfinSettings.Servers)
{
try
{
var result = await client.LogIn(user.UserName, password, server.ApiKey, server.FullUri);
if (result != null)
{
return true;
}
}
catch (Exception e)
{
Logger.LogError(e, "Jellyfin Login Failed");
}
}
return false;
}
}
}
}

@ -15,6 +15,8 @@ using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine
{
@ -179,6 +181,12 @@ namespace Ombi.Core.Engine
return user.Language;
}
protected async Task<List<StreamData>> GetUserWatchProvider(WatchProviders providers)
{
var user = await GetUser();
return WatchProviderParser.GetUserWatchProviders(providers, user);
}
private OmbiSettings ombiSettings;
protected async Task<OmbiSettings> GetOmbiSettings()
{

@ -50,7 +50,7 @@ namespace Ombi.Core.Engine.Demo
return null;
}
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
new public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
{
var rand = new Random();
var responses = new List<SearchMovieViewModel>();
@ -72,18 +72,18 @@ namespace Ombi.Core.Engine.Demo
return responses;
}
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
new public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
{
return await NowPlayingMovies();
}
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
new public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
{
return await NowPlayingMovies();
}
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
new public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
{
return await NowPlayingMovies();

@ -35,7 +35,7 @@ namespace Ombi.Core.Engine.Demo
private readonly DemoLists _demoLists;
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string search)
new public async Task<IEnumerable<SearchTvShowViewModel>> Search(string search)
{
var searchResult = await TvMazeApi.Search(search);

@ -26,5 +26,6 @@ namespace Ombi.Core.Engine.Interfaces
int ResultLimit { get; set; }
Task<MovieFullInfoViewModel> GetMovieInfoByImdbId(string imdbId, CancellationToken requestAborted);
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
}
}

@ -9,5 +9,6 @@ namespace Ombi.Core.Engine.Interfaces
Task<ArtistInformation> GetArtistInformation(string artistId);
Task<ArtistInformation> GetArtistInformationByRequestId(int requestId);
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
Task<ReleaseGroup> GetAlbum(string albumId);
}
}

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Ombi.Core.Models.Search.V2;
namespace Ombi.Core
@ -7,5 +9,6 @@ namespace Ombi.Core
{
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId);
Task<IEnumerable<StreamingData>> GetStreamInformation(int tvDbId, int tvMazeId, CancellationToken cancellationToken);
}
}

@ -67,6 +67,22 @@ namespace Ombi.Core.Engine
$"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}";
var userDetails = await GetUser();
var canRequestOnBehalf = false;
if (model.RequestOnBehalf.HasValue())
{
canRequestOnBehalf = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
if (!canRequestOnBehalf)
{
return new RequestEngineResult
{
Result = false,
Message = "You do not have the correct permissions to request on behalf of users!",
ErrorMessage = $"You do not have the correct permissions to request on behalf of users!"
};
}
}
var requestModel = new MovieRequests
{
@ -82,7 +98,7 @@ namespace Ombi.Core.Engine
Status = movieInfo.Status,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUserId = userDetails.Id,
RequestedUserId = canRequestOnBehalf ? model.RequestOnBehalf : userDetails.Id,
Background = movieInfo.BackdropPath,
LangCode = model.LanguageCode,
RequestedByAlias = model.RequestedByAlias
@ -103,7 +119,7 @@ namespace Ombi.Core.Engine
if (requestModel.Approved) // The rules have auto approved this
{
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName);
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf);
if (requestEngineResult.Result)
{
var result = await ApproveMovie(requestModel);
@ -124,7 +140,7 @@ namespace Ombi.Core.Engine
// If there are no providers then it's successful but movie has not been sent
}
return await AddMovieRequest(requestModel, fullMovieName);
return await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf);
}
@ -270,7 +286,7 @@ namespace Ombi.Core.Engine
allRequests = allRequests.Where(x => x.Available);
break;
case RequestStatus.Denied:
allRequests = allRequests.Where(x => x.Denied.HasValue && x.Denied.Value && !x.Available);
allRequests = allRequests.Where(x => x.Denied.HasValue && x.Denied.Value && !x.Available);
break;
default:
break;
@ -429,7 +445,7 @@ namespace Ombi.Core.Engine
public async Task<MovieRequests> GetRequest(int requestId)
{
var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync();
await CheckForSubscription(new HideResult(), new List<MovieRequests>{request });
await CheckForSubscription(new HideResult(), new List<MovieRequests> { request });
return request;
}
@ -654,19 +670,19 @@ namespace Ombi.Core.Engine
};
}
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName)
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName, string requestOnBehalf)
{
await MovieRepository.Add(model);
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (result.Success)
{
{
await NotificationHelper.NewRequest(model);
}
await _requestLog.Add(new RequestLog
{
UserId = (await GetUser()).Id,
UserId = requestOnBehalf.HasValue() ? requestOnBehalf : (await GetUser()).Id,
RequestDate = DateTime.UtcNow,
RequestId = model.Id,
RequestType = RequestType.Movie,

@ -13,38 +13,43 @@ namespace Ombi.Core.Engine
{
public class RecentlyAddedEngine : IRecentlyAddedEngine
{
public RecentlyAddedEngine(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> recentlyAdded)
public RecentlyAddedEngine(IPlexContentRepository plex, IEmbyContentRepository emby, IJellyfinContentRepository jellyfin, IRepository<RecentlyAddedLog> recentlyAdded)
{
_plex = plex;
_emby = emby;
_jellyfin = jellyfin;
_recentlyAddedLog = recentlyAdded;
}
private readonly IPlexContentRepository _plex;
private readonly IEmbyContentRepository _emby;
private readonly IJellyfinContentRepository _jellyfin;
private readonly IRepository<RecentlyAddedLog> _recentlyAddedLog;
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(DateTime from, DateTime to)
{
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie && x.AddedAt > from && x.AddedAt < to);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedMovies(plexMovies, embyMovies).Take(30);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies).Take(30);
}
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies()
{
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie);
return GetRecentlyAddedMovies(plexMovies, embyMovies);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies);
}
public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(DateTime from, DateTime to, bool groupBySeason)
{
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show && x.AddedAt > from && x.AddedAt < to);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series && x.AddedAt > from && x.AddedAt < to);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedTv(plexTv, embyTv, groupBySeason).Take(30);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason).Take(30);
}
@ -52,14 +57,16 @@ namespace Ombi.Core.Engine
{
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series);
return GetRecentlyAddedTv(plexTv, embyTv, groupBySeason);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason);
}
public async Task<bool> UpdateRecentlyAddedDatabase()
{
var plexContent = _plex.GetAll().Include(x => x.Episodes);
var embyContent = _emby.GetAll().Include(x => x.Episodes);
var jellyfinContent = _jellyfin.GetAll().Include(x => x.Episodes);
var recentlyAddedLog = new HashSet<RecentlyAddedLog>();
foreach (var p in plexContent)
{
@ -136,17 +143,56 @@ namespace Ombi.Core.Engine
}
}
}
foreach (var e in jellyfinContent)
{
if (e.TheMovieDbId.IsNullOrEmpty())
{
continue;
}
if (e.Type == JellyfinMediaType.Movie)
{
recentlyAddedLog.Add(new RecentlyAddedLog
{
AddedAt = DateTime.Now,
Type = RecentlyAddedType.Jellyfin,
ContentId = int.Parse(e.TheMovieDbId),
ContentType = ContentType.Parent
});
}
else
{
// Add the episodes
foreach (var ep in e.Episodes)
{
if (ep.Series.TvDbId.IsNullOrEmpty())
{
continue;
}
recentlyAddedLog.Add(new RecentlyAddedLog
{
AddedAt = DateTime.Now,
Type = RecentlyAddedType.Jellyfin,
ContentId = int.Parse(ep.Series.TvDbId),
ContentType = ContentType.Episode,
EpisodeNumber = ep.EpisodeNumber,
SeasonNumber = ep.SeasonNumber
});
}
}
}
await _recentlyAddedLog.AddRange(recentlyAddedLog);
return true;
}
private IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(IQueryable<PlexServerContent> plexTv, IQueryable<EmbyContent> embyTv,
private IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(IQueryable<PlexServerContent> plexTv, IQueryable<EmbyContent> embyTv, IQueryable<JellyfinContent> jellyfinTv,
bool groupBySeason)
{
var model = new HashSet<RecentlyAddedTvModel>();
TransformPlexShows(plexTv, model);
TransformEmbyShows(embyTv, model);
TransformJellyfinShows(jellyfinTv, model);
if (groupBySeason)
{
@ -156,11 +202,12 @@ namespace Ombi.Core.Engine
return model;
}
private IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(IQueryable<PlexServerContent> plexMovies, IQueryable<EmbyContent> embyMovies)
private IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(IQueryable<PlexServerContent> plexMovies, IQueryable<EmbyContent> embyMovies, IQueryable<JellyfinContent> jellyfinMovies)
{
var model = new HashSet<RecentlyAddedMovieModel>();
TransformPlexMovies(plexMovies, model);
TransformEmbyMovies(embyMovies, model);
TransformJellyfinMovies(jellyfinMovies, model);
return model;
}
@ -181,6 +228,22 @@ namespace Ombi.Core.Engine
}
}
private static void TransformJellyfinMovies(IQueryable<JellyfinContent> jellyfinMovies, HashSet<RecentlyAddedMovieModel> model)
{
foreach (var jellyfin in jellyfinMovies)
{
model.Add(new RecentlyAddedMovieModel
{
Id = jellyfin.Id,
ImdbId = jellyfin.ImdbId,
TheMovieDbId = jellyfin.TheMovieDbId,
TvDbId = jellyfin.TvDbId,
AddedAt = jellyfin.AddedAt,
Title = jellyfin.Title,
});
}
}
private static void TransformPlexMovies(IQueryable<PlexServerContent> plexMovies, HashSet<RecentlyAddedMovieModel> model)
{
foreach (var plex in plexMovies)
@ -244,5 +307,26 @@ namespace Ombi.Core.Engine
}
}
}
private static void TransformJellyfinShows(IQueryable<JellyfinContent> jellyfinShows, HashSet<RecentlyAddedTvModel> model)
{
foreach (var jellyfin in jellyfinShows)
{
foreach (var episode in jellyfin.Episodes)
{
model.Add(new RecentlyAddedTvModel
{
Id = jellyfin.Id,
ImdbId = jellyfin.ImdbId,
TvDbId = jellyfin.TvDbId,
TheMovieDbId = jellyfin.TheMovieDbId,
AddedAt = jellyfin.AddedAt,
Title = jellyfin.Title,
EpisodeNumber = episode.EpisodeNumber,
SeasonNumber = episode.SeasonNumber
});
}
}
}
}
}

@ -51,12 +51,28 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
{
var user = await GetUser();
var canRequestOnBehalf = false;
if (tv.RequestOnBehalf.HasValue())
{
canRequestOnBehalf = await UserManager.IsInRoleAsync(user, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(user, OmbiRoles.Admin);
if (!canRequestOnBehalf)
{
return new RequestEngineResult
{
Result = false,
Message = "You do not have the correct permissions to request on behalf of users!",
ErrorMessage = $"You do not have the correct permissions to request on behalf of users!"
};
}
}
var tvBuilder = new TvShowRequestBuilder(TvApi, MovieDbApi);
(await tvBuilder
.GetShowInfo(tv.TvDbId))
.CreateTvList(tv)
.CreateChild(tv, user.Id);
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id);
await tvBuilder.BuildEpisodes(tv);
@ -124,12 +140,12 @@ namespace Ombi.Core.Engine
ErrorMessage = "This has already been requested"
};
}
return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest);
return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest, tv.RequestOnBehalf);
}
// This is a new request
var newRequest = tvBuilder.CreateNewRequest(tv);
return await AddRequest(newRequest.NewRequest);
return await AddRequest(newRequest.NewRequest, tv.RequestOnBehalf);
}
public async Task<RequestsViewModel<TvRequests>> GetRequests(int count, int position, OrderFilterModel type)
@ -736,21 +752,21 @@ namespace Ombi.Core.Engine
}
}
private async Task<RequestEngineResult> AddExistingRequest(ChildRequests newRequest, TvRequests existingRequest)
private async Task<RequestEngineResult> AddExistingRequest(ChildRequests newRequest, TvRequests existingRequest, string requestOnBehalf)
{
// Add the child
existingRequest.ChildRequests.Add(newRequest);
await TvRepository.Update(existingRequest);
return await AfterRequest(newRequest);
return await AfterRequest(newRequest, requestOnBehalf);
}
private async Task<RequestEngineResult> AddRequest(TvRequests model)
private async Task<RequestEngineResult> AddRequest(TvRequests model, string requestOnBehalf)
{
await TvRepository.Add(model);
// This is a new request so we should only have 1 child
return await AfterRequest(model.ChildRequests.FirstOrDefault());
return await AfterRequest(model.ChildRequests.FirstOrDefault(), requestOnBehalf);
}
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
@ -766,7 +782,7 @@ namespace Ombi.Core.Engine
}
private async Task<RequestEngineResult> AfterRequest(ChildRequests model)
private async Task<RequestEngineResult> AfterRequest(ChildRequests model, string requestOnBehalf)
{
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (sendRuleResult.Success)
@ -776,7 +792,7 @@ namespace Ombi.Core.Engine
await _requestLog.Add(new RequestLog
{
UserId = (await GetUser()).Id,
UserId = requestOnBehalf.HasValue() ? requestOnBehalf : (await GetUser()).Id,
RequestDate = DateTime.UtcNow,
RequestId = model.Id,
RequestType = RequestType.TvShow,

@ -27,7 +27,7 @@ namespace Ombi.Core.Engine.V2
private readonly IMovieRequestRepository _movieRepo;
private readonly ITvRequestRepository _tvRepo;
public async Task<List<CalendarViewModel>> GetCalendarData()
public Task<List<CalendarViewModel>> GetCalendarData()
{
var viewModel = new List<CalendarViewModel>();
var movies = _movieRepo.GetAll().Where(x =>
@ -78,7 +78,7 @@ namespace Ombi.Core.Engine.V2
});
}
return viewModel;
return Task.FromResult(viewModel);
}
private string GetBackgroundColor(BaseRequest req)

@ -249,6 +249,26 @@ namespace Ombi.Core.Engine.V2
return result;
}
public async Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken)
{
var providers = await MovieApi.GetMovieWatchProviders(movieDbId, cancellationToken);
var results = await GetUserWatchProvider(providers);
var data = new List<StreamingData>();
foreach (var result in results)
{
data.Add(new StreamingData
{
Logo = result.logo_path,
Order = result.display_priority,
StreamingProvider = result.provider_name
});
}
return data;
}
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
IEnumerable<MovieSearchResult> movies)
{
@ -287,6 +307,7 @@ namespace Ombi.Core.Engine.V2
mapped.Requested = viewMovie.Requested;
mapped.PlexUrl = viewMovie.PlexUrl;
mapped.EmbyUrl = viewMovie.EmbyUrl;
mapped.JellyfinUrl = viewMovie.JellyfinUrl;
mapped.Subscribed = viewMovie.Subscribed;
mapped.ShowSubscribe = viewMovie.ShowSubscribe;

@ -5,6 +5,7 @@ using System.Linq;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Ombi.Api.Lidarr;
using Ombi.Api.Lidarr.Models;
using Ombi.Api.MusicBrainz;
@ -41,6 +42,21 @@ namespace Ombi.Core.Engine.V2
_lidarrApi = lidarrApi;
}
public async Task<ReleaseGroup> GetAlbum(string albumId)
{
var g = await _musicBrainzApi.GetAlbumInformation(albumId);
var release = new ReleaseGroup
{
ReleaseType = g.ReleaseGroup.PrimaryType,
Id = g.Id,
Title = g.Title,
ReleaseDate = g.ReleaseGroup.FirstReleaseDate,
};
await RunSearchRules(release);
return release;
}
public async Task<ArtistInformation> GetArtistInformation(string artistId)
{
var artist = await _musicBrainzApi.GetArtistInformation(artistId);
@ -84,12 +100,19 @@ namespace Ombi.Core.Engine.V2
if (lidarrArtistTask != null)
{
var artistResult = await lidarrArtistTask;
info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Logo = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("logo", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Poster = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("poster", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.FanArt = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("fanart", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Overview = artistResult.overview;
try
{
var artistResult = await lidarrArtistTask;
info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Logo = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("logo", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Poster = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("poster", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.FanArt = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("fanart", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
info.Overview = artistResult.overview;
}
catch (JsonSerializationException)
{
// swallow, Lidarr probably doesn't have this artist
}
}
return info;
@ -118,7 +141,7 @@ namespace Ombi.Core.Engine.V2
return new AlbumArt();
}
public async Task<ArtistInformation> GetArtistInformationByRequestId(int requestId)
{
var request = await RequestService.MusicRequestRepository.Find(requestId);

@ -19,6 +19,8 @@ using Ombi.Core.Settings;
using Ombi.Store.Repository;
using TraktSharp.Entities;
using Microsoft.EntityFrameworkCore;
using System.Threading;
using Ombi.Api.TheMovieDb;
namespace Ombi.Core.Engine.V2
{
@ -27,15 +29,17 @@ namespace Ombi.Core.Engine.V2
private readonly ITvMazeApi _tvMaze;
private readonly IMapper _mapper;
private readonly ITraktApi _traktApi;
private readonly IMovieDbApi _movieApi;
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s,
IRepository<RequestSubscription> sub)
IRepository<RequestSubscription> sub, IMovieDbApi movieApi)
: base(identity, service, r, um, memCache, s, sub)
{
_tvMaze = tvMaze;
_mapper = mapper;
_traktApi = trakt;
_movieApi = movieApi;
}
@ -106,6 +110,39 @@ namespace Ombi.Core.Engine.V2
return await ProcessResult(mapped, traktInfoTask);
}
public async Task<IEnumerable<StreamingData>> GetStreamInformation(int tvDbId, int tvMazeId, CancellationToken cancellationToken)
{
var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvMazeId,
async () => await _tvMaze.ShowLookupByTheTvDbId(tvMazeId), DateTime.Now.AddHours(12));
if (tvdbshow == null)
{
return null;
}
/// this is a best effort guess since TV maze do not provide the TheMovieDbId
var movieDbResults = await _movieApi.SearchTv(tvdbshow.name, tvdbshow.premiered.Substring(0, 4));
var potential = movieDbResults.FirstOrDefault();
tvDbId = potential.Id;
// end guess
var providers = await _movieApi.GetTvWatchProviders(tvDbId, cancellationToken);
var results = await GetUserWatchProvider(providers);
var data = new List<StreamingData>();
foreach (var result in results)
{
data.Add(new StreamingData
{
Logo = result.logo_path,
Order = result.display_priority,
StreamingProvider = result.provider_name
});
}
return data;
}
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
{
var retVal = new List<SearchTvShowViewModel>();
@ -141,7 +178,7 @@ namespace Ombi.Core.Engine.V2
{
item.Images.Medium = item.Images.Medium.ToHttpsUrl();
}
if (item.Cast?.Any() ?? false)
{
foreach (var cast in item.Cast)

@ -0,0 +1,35 @@
using Ombi.Api.TheMovieDb.Models;
using Ombi.Store.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ombi.Core.Helpers
{
public static class WatchProviderParser
{
public static List<StreamData> GetUserWatchProviders(WatchProviders providers, OmbiUser user)
{
var data = new List<StreamData>();
if (providers?.Results == null)
{
return data;
}
var resultsProp = providers.Results.GetType().GetProperties();
var matchingStreamingCountry = resultsProp.FirstOrDefault(x => x.Name.Equals(user.StreamingCountry, StringComparison.InvariantCultureIgnoreCase));
if (matchingStreamingCountry == null)
{
return data;
}
var result = (WatchProviderData)matchingStreamingCountry.GetValue(providers.Results);
if (result == null || result.StreamInformation == null)
{
return data;
}
return result.StreamInformation;
}
}
}

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

Loading…
Cancel
Save