mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-12 15:30:39 -04:00
Compare commits
1 Commits
v4.0.1.581
...
native-the
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
315c2e1b88 |
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: Bug Report
|
||||
title: "[BUG]: "
|
||||
description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Reddit or Discord first'
|
||||
labels: ['Type: Bug', 'Status: Needs Triage']
|
||||
body:
|
||||
@@ -63,11 +64,12 @@ body:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Trace Logs?
|
||||
label: Anything else?
|
||||
description: |
|
||||
Trace Logs (https://wiki.servarr.com/radarr/troubleshooting#logging-and-log-files)
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
***Generally speaking, all bug reports must have trace logs provided.***
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
|
||||
validations:
|
||||
required: true
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: Feature Request
|
||||
title: "[FEAT]: "
|
||||
description: 'Suggest an idea for Radarr'
|
||||
labels: ['Type: Feature Request', 'Status: Needs Triage']
|
||||
body:
|
||||
|
||||
45
README.md
45
README.md
@@ -1,21 +1,19 @@
|
||||
# Radarr
|
||||
|
||||
[](https://dev.azure.com/Radarr/Radarr/_build/latest?definitionId=1&branchName=develop)
|
||||
[](https://translate.servarr.com/engage/radarr/?utm_source=widget)
|
||||
[](https://translate.servarr.com/engage/radarr/?utm_source=widget)
|
||||
[](https://wiki.servarr.com/radarr/installation#docker)
|
||||

|
||||
[](#backers)
|
||||
[](#backers)
|
||||
[](#sponsors)
|
||||
[](#mega-sponsors)
|
||||
|
||||
Radarr is a movie collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new movies and will interface with clients and indexers to grab, sort, and rename them. It can also be configured to automatically upgrade the quality of existing files in the library when a better quality format becomes available.
|
||||
Note that only one type of a given movie is supported. If you want both an 4k version and 1080p version of a given movie you will need multiple instances.
|
||||
|
||||
## Major Features Include
|
||||
## Major Features Include:
|
||||
|
||||
* Adding new movies with lots of information, such as trailers, ratings, etc.
|
||||
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
||||
* Can watch for better quality of the movies you have and do an automatic upgrade. *e.g. from DVD to Blu-Ray*
|
||||
* Can watch for better quality of the movies you have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
|
||||
* Automatic failed download handling will try another release if one fails
|
||||
* Manual search so you can pick any release or to see why a release was not downloaded automatically
|
||||
* Full integration with SABnzbd and NZBGet
|
||||
@@ -23,60 +21,53 @@ Note that only one type of a given movie is supported. If you want both an 4k ve
|
||||
* Automatically importing downloaded movies
|
||||
* Recognizing Special Editions, Director's Cut, etc.
|
||||
* Identifying releases with hardcoded subs
|
||||
* Identifying releases with AKA movie names
|
||||
* SABnzbd, NZBGet, QBittorrent, Deluge, rTorrent, Transmission, uTorrent, and other download clients are supported and integrated
|
||||
* Full integration with Kodi and Plex (notifications, library updates)
|
||||
* QBittorrent, Deluge, rTorrent, Transmission, uTorrent, and other download clients are supported
|
||||
* Full integration with Kodi, Plex (notification, library update)
|
||||
* A beautiful UI
|
||||
* Importing Metadata such as trailers or subtitles
|
||||
* Adding metadata such as posters and information for Kodi and others to use
|
||||
* Advanced customization for profiles, such that Radarr will always download the copy you want
|
||||
* A beautiful UI
|
||||
|
||||
## Support
|
||||
|
||||
[](https://wiki.servarr.com/radarr)
|
||||
[](https://radarr.video/discord)
|
||||
[](https://www.reddit.com/r/Radarr)
|
||||
|
||||
Note: GitHub Issues are for Bugs and Feature Requests Only
|
||||
|
||||
[](https://radarr.video/discord)
|
||||
[](https://www.reddit.com/r/Radarr)
|
||||
[](https://github.com/Radarr/Radarr/issues)
|
||||
[](https://wiki.servarr.com/radarr)
|
||||
|
||||
## Contributors & Developers
|
||||
|
||||
[API Documentation](https://radarr.video/docs/api/)
|
||||
|
||||
This project exists thanks to all the people who contribute.
|
||||
- [Contribute (GitHub)](CONTRIBUTING.md)
|
||||
- [Contribution (Wiki Article)](https://wiki.servarr.com/radarr/contributing)
|
||||
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
||||
<a href="https://github.com/Radarr/Radarr/graphs/contributors"><img src="https://opencollective.com/Radarr/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
[](https://github.com/Radarr/Radarr/graphs/contributors)
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Radarr#backer)
|
||||
|
||||
[](https://opencollective.com/Radarr#backer)
|
||||
<img src="https://opencollective.com/Radarr/backers.svg?width=890"></a>
|
||||
|
||||
## Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/Radarr#sponsor)
|
||||
|
||||
[](https://opencollective.com/Radarr#sponsor)
|
||||
<img src="https://opencollective.com/Radarr/sponsors.svg?width=890"></a>
|
||||
|
||||
## Mega Sponsors
|
||||
|
||||
[](https://opencollective.com/Radarr#mega-sponsor)
|
||||
<img src="https://opencollective.com/Radarr/tiers/mega-sponsor.svg?width=890"></a>
|
||||
|
||||
## JetBrains
|
||||
|
||||
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
||||
|
||||
* [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
||||
* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||
|
||||
### License
|
||||
|
||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||
* Copyright 2010-2022
|
||||
* Copyright 2010-2021
|
||||
|
||||
@@ -7,13 +7,13 @@ variables:
|
||||
outputFolder: './_output'
|
||||
artifactsFolder: './_artifacts'
|
||||
testsFolder: './_tests'
|
||||
majorVersion: '4.0.1'
|
||||
majorVersion: '4.0.0'
|
||||
minorVersion: $[counter('minorVersion', 2000)]
|
||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||
sentryOrg: 'servarr'
|
||||
sentryUrl: 'https://sentry.servarr.com'
|
||||
dotnetVersion: '6.0.101'
|
||||
dotnetVersion: '5.0.401'
|
||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||
|
||||
trigger:
|
||||
@@ -111,23 +111,23 @@ stages:
|
||||
artifact: '$(osName)Backend'
|
||||
displayName: Publish Backend
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net6.0/win-x64/publish'
|
||||
- publish: '$(testsFolder)/net5.0/win-x64/publish'
|
||||
artifact: WindowsCoreTests
|
||||
displayName: Publish Windows Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net6.0/linux-x64/publish'
|
||||
- publish: '$(testsFolder)/net5.0/linux-x64/publish'
|
||||
artifact: LinuxCoreTests
|
||||
displayName: Publish Linux Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
|
||||
- publish: '$(testsFolder)/net5.0/linux-musl-x64/publish'
|
||||
artifact: LinuxMuslCoreTests
|
||||
displayName: Publish Linux Musl Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish'
|
||||
- publish: '$(testsFolder)/net5.0/freebsd-x64/publish'
|
||||
artifact: FreebsdCoreTests
|
||||
displayName: Publish FreeBSD Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net6.0/osx-x64/publish'
|
||||
- publish: '$(testsFolder)/net5.0/osx-x64/publish'
|
||||
artifact: MacCoreTests
|
||||
displayName: Publish MacOS Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
@@ -203,12 +203,12 @@ stages:
|
||||
- bash: ./build.sh --packages
|
||||
displayName: Create Packages
|
||||
- bash: |
|
||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x86
|
||||
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net5.0 //DRuntime=win-x86
|
||||
cp setup/output/Radarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||
displayName: Create .NET Core Windows installer
|
||||
- bash: |
|
||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x64
|
||||
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net5.0 //DRuntime=win-x64
|
||||
cp setup/output/Radarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||
displayName: Create .NET Core Windows installer
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
artifact: 'WindowsInstaller'
|
||||
@@ -251,44 +251,29 @@ stages:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x64.zip'
|
||||
archiveType: 'zip'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/win-x64/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create Windows x86 Core zip
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x86.zip'
|
||||
archiveType: 'zip'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/win-x86/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create MacOS x64 Core app
|
||||
displayName: Create MacOS Core app
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-x64.zip'
|
||||
archiveType: 'zip'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/macos-app/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create MacOS x64 Core tar
|
||||
displayName: Create MacOS Core tar
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-core-x64.tar.gz'
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create MacOS arm64 Core app
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-arm64.zip'
|
||||
archiveType: 'zip'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create MacOS arm64 Core tar
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-core-arm64.tar.gz'
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/macos/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create Linux Core tar
|
||||
inputs:
|
||||
@@ -296,7 +281,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create Linux Musl Core tar
|
||||
inputs:
|
||||
@@ -304,7 +289,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create ARM32 Linux Core tar
|
||||
inputs:
|
||||
@@ -312,15 +297,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create ARM32 Linux Musl Core tar
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).linux-musl-core-arm.tar.gz'
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-arm/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create ARM64 Linux Core tar
|
||||
inputs:
|
||||
@@ -328,7 +305,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create ARM64 Linux Musl Core tar
|
||||
inputs:
|
||||
@@ -336,7 +313,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create FreeBSD Core Core tar
|
||||
inputs:
|
||||
@@ -344,7 +321,7 @@ stages:
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net6.0
|
||||
rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net5.0
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
artifact: 'Packages'
|
||||
displayName: Publish Packages
|
||||
@@ -889,8 +866,8 @@ stages:
|
||||
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
||||
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
||||
- bash: |
|
||||
./build.sh --backend -f net6.0 -r win-x64
|
||||
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage
|
||||
./build.sh --backend -f net5.0 -r win-x64
|
||||
TEST_DIR=_tests/net5.0/win-x64/publish/ ./test.sh Windows Unit Coverage
|
||||
displayName: Coverage Unit Tests
|
||||
- task: SonarCloudAnalyze@1
|
||||
condition: eq(variables['System.PullRequest.IsFork'], 'False')
|
||||
|
||||
54
build.sh
54
build.sh
@@ -129,7 +129,7 @@ PackageLinux()
|
||||
|
||||
echo "Adding Radarr.Mono to UpdatePackage"
|
||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||
if [ "$framework" = "net6.0" ]; then
|
||||
if [ "$framework" = "net5.0" ]; then
|
||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||
fi
|
||||
@@ -140,13 +140,12 @@ PackageLinux()
|
||||
PackageMacOS()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
ProgressStart "Creating MacOS Package for $framework $runtime"
|
||||
ProgressStart "Creating MacOS Package for $framework"
|
||||
|
||||
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
||||
local folder=$artifactsFolder/macos/$framework/Radarr
|
||||
|
||||
PackageFiles "$folder" "$framework" "$runtime"
|
||||
PackageFiles "$folder" "$framework" "osx-x64"
|
||||
|
||||
echo "Removing Service helpers"
|
||||
rm -f $folder/ServiceUninstall.*
|
||||
@@ -157,7 +156,7 @@ PackageMacOS()
|
||||
|
||||
echo "Adding Radarr.Mono to UpdatePackage"
|
||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||
if [ "$framework" = "net6.0" ]; then
|
||||
if [ "$framework" = "net5.0" ]; then
|
||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||
fi
|
||||
@@ -168,11 +167,10 @@ PackageMacOS()
|
||||
PackageMacOSApp()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
ProgressStart "Creating macOS App Package for $framework $runtime"
|
||||
ProgressStart "Creating macOS App Package for $framework"
|
||||
|
||||
local folder="$artifactsFolder/$runtime-app/$framework"
|
||||
local folder=$artifactsFolder/macos-app/$framework
|
||||
|
||||
rm -rf $folder
|
||||
mkdir -p $folder
|
||||
@@ -180,7 +178,7 @@ PackageMacOSApp()
|
||||
mkdir -p $folder/Radarr.app/Contents/MacOS
|
||||
|
||||
echo "Copying Binaries"
|
||||
cp -r $artifactsFolder/$runtime/$framework/Radarr/* $folder/Radarr.app/Contents/MacOS
|
||||
cp -r $artifactsFolder/macos/$framework/Radarr/* $folder/Radarr.app/Contents/MacOS
|
||||
|
||||
echo "Removing Update Folder"
|
||||
rm -r $folder/Radarr.app/Contents/MacOS/Radarr.Update
|
||||
@@ -227,8 +225,8 @@ Package()
|
||||
PackageWindows "$framework" "$runtime"
|
||||
;;
|
||||
osx)
|
||||
PackageMacOS "$framework" "$runtime"
|
||||
PackageMacOSApp "$framework" "$runtime"
|
||||
PackageMacOS "$framework"
|
||||
PackageMacOSApp "$framework"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -328,14 +326,14 @@ then
|
||||
Build
|
||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||
then
|
||||
PackageTests "net6.0" "win-x64"
|
||||
PackageTests "net6.0" "win-x86"
|
||||
PackageTests "net6.0" "linux-x64"
|
||||
PackageTests "net6.0" "linux-musl-x64"
|
||||
PackageTests "net6.0" "osx-x64"
|
||||
PackageTests "net5.0" "win-x64"
|
||||
PackageTests "net5.0" "win-x86"
|
||||
PackageTests "net5.0" "linux-x64"
|
||||
PackageTests "net5.0" "linux-musl-x64"
|
||||
PackageTests "net5.0" "osx-x64"
|
||||
if [ "$ENABLE_BSD" = "YES" ];
|
||||
then
|
||||
PackageTests "net6.0" "freebsd-x64"
|
||||
PackageTests "net5.0" "freebsd-x64"
|
||||
fi
|
||||
else
|
||||
PackageTests "$FRAMEWORK" "$RID"
|
||||
@@ -364,19 +362,17 @@ then
|
||||
|
||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||
then
|
||||
Package "net6.0" "win-x64"
|
||||
Package "net6.0" "win-x86"
|
||||
Package "net6.0" "linux-x64"
|
||||
Package "net6.0" "linux-musl-x64"
|
||||
Package "net6.0" "linux-arm64"
|
||||
Package "net6.0" "linux-musl-arm64"
|
||||
Package "net6.0" "linux-arm"
|
||||
Package "net6.0" "linux-musl-arm"
|
||||
Package "net6.0" "osx-x64"
|
||||
Package "net6.0" "osx-arm64"
|
||||
Package "net5.0" "win-x64"
|
||||
Package "net5.0" "win-x86"
|
||||
Package "net5.0" "linux-x64"
|
||||
Package "net5.0" "linux-musl-x64"
|
||||
Package "net5.0" "linux-arm64"
|
||||
Package "net5.0" "linux-musl-arm64"
|
||||
Package "net5.0" "linux-arm"
|
||||
Package "net5.0" "osx-x64"
|
||||
if [ "$ENABLE_BSD" = "YES" ];
|
||||
then
|
||||
Package "net6.0" "freebsd-x64"
|
||||
Package "net5.0" "freebsd-x64"
|
||||
fi
|
||||
else
|
||||
Package "$FRAMEWORK" "$RID"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
],
|
||||
"ignoreFiles": [
|
||||
"frontend/src/Styles/scaffolding.css",
|
||||
"**/Theme.Park/**/*.css",
|
||||
"**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
|
||||
@@ -124,6 +124,20 @@ module.exports = (env) => {
|
||||
{
|
||||
source: 'frontend/src/Content/robots.txt',
|
||||
destination: path.join(distFolder, 'Content/robots.txt')
|
||||
},
|
||||
|
||||
// Theme.Park
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park')
|
||||
},
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/Themes/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park/Themes')
|
||||
},
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/Resources/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park/Resources')
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -243,6 +257,19 @@ module.exports = (env) => {
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(png)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
emitFile: false,
|
||||
name: 'Content/Theme.Park/Resources/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class Blocklist extends Component {
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label={translate('RemoveSelected')}
|
||||
label="Remove Selected"
|
||||
iconName={icons.REMOVE}
|
||||
isDisabled={!selectedIds.length}
|
||||
isSpinning={isRemoving}
|
||||
|
||||
@@ -25,7 +25,6 @@ function HistoryDetails(props) {
|
||||
releaseGroup,
|
||||
nzbInfoUrl,
|
||||
downloadClient,
|
||||
downloadClientName,
|
||||
downloadId,
|
||||
age,
|
||||
ageHours,
|
||||
@@ -33,8 +32,6 @@ function HistoryDetails(props) {
|
||||
publishedDate
|
||||
} = data;
|
||||
|
||||
const downloadClientNameInfo = downloadClientName ?? downloadClient;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
@@ -74,12 +71,11 @@ function HistoryDetails(props) {
|
||||
}
|
||||
|
||||
{
|
||||
downloadClientNameInfo ?
|
||||
!!downloadClient &&
|
||||
<DescriptionListItem
|
||||
title={translate('DownloadClient')}
|
||||
data={downloadClientNameInfo}
|
||||
/> :
|
||||
null
|
||||
data={downloadClient}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -161,7 +161,7 @@ class AddNewMovie extends Component {
|
||||
{translate('YouCanAlsoSearch')}
|
||||
</div>
|
||||
<div>
|
||||
<Link to="https://wiki.servarr.com/radarr/faq#why-can-i-not-add-a-new-movie-to-radarr">
|
||||
<Link to="https://wiki.servarr.com/radarr/faq#why-cant-i-add-a-new-movie-to-radarr">
|
||||
{translate('CantFindMovie')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -183,7 +183,7 @@ class AddNewMovieSearchResult extends Component {
|
||||
<div>
|
||||
<Label size={sizes.LARGE}>
|
||||
<HeartRating
|
||||
ratings={ratings}
|
||||
rating={ratings.value}
|
||||
iconSize={13}
|
||||
/>
|
||||
</Label>
|
||||
|
||||
29
frontend/src/App/ThemeSelector.js
Normal file
29
frontend/src/App/ThemeSelector.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const theme = window.Radarr.theme;
|
||||
|
||||
function ThemeSelector({ children }) {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
theme !== 'default' &&
|
||||
<>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href={'/Content/Theme.Park/radarr-base.css'}
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href={`/Content/Theme.Park/Themes/${theme}.css`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeSelector.propTypes = {
|
||||
children: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default ThemeSelector;
|
||||
@@ -43,15 +43,15 @@ class CalendarEvent extends Component {
|
||||
const link = `/movie/${titleSlug}`;
|
||||
const eventType = [];
|
||||
|
||||
if (inCinemas && moment(date).isSame(moment(inCinemas), 'day')) {
|
||||
if (moment(date).isSame(moment(inCinemas), 'day')) {
|
||||
eventType.push('Cinemas');
|
||||
}
|
||||
|
||||
if (physicalRelease && moment(date).isSame(moment(physicalRelease), 'day')) {
|
||||
if (moment(date).isSame(moment(physicalRelease), 'day')) {
|
||||
eventType.push('Physical');
|
||||
}
|
||||
|
||||
if (digitalRelease && moment(date).isSame(moment(digitalRelease), 'day')) {
|
||||
if (moment(date).isSame(moment(digitalRelease), 'day')) {
|
||||
eventType.push('Digital');
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,4 @@
|
||||
color: #3a3f51;
|
||||
font-size: 21px;
|
||||
line-height: inherit;
|
||||
|
||||
&.small {
|
||||
color: #909293;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import styles from './FieldSet.css';
|
||||
|
||||
class FieldSet extends Component {
|
||||
@@ -11,14 +9,13 @@ class FieldSet extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
size,
|
||||
legend,
|
||||
children
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<fieldset className={styles.fieldSet}>
|
||||
<legend className={classNames(styles.legend, (size === sizes.SMALL) && styles.small)}>
|
||||
<legend className={styles.legend}>
|
||||
{legend}
|
||||
</legend>
|
||||
{children}
|
||||
@@ -29,13 +26,8 @@ class FieldSet extends Component {
|
||||
}
|
||||
|
||||
FieldSet.propTypes = {
|
||||
size: PropTypes.oneOf(sizes.all).isRequired,
|
||||
legend: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
FieldSet.defaultProps = {
|
||||
size: sizes.MEDIUM
|
||||
};
|
||||
|
||||
export default FieldSet;
|
||||
|
||||
@@ -166,9 +166,7 @@ class FilterBuilderModalContent extends Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.label}>
|
||||
{translate('Filters')}
|
||||
</div>
|
||||
<div className={styles.label}>Filters</div>
|
||||
|
||||
<div className={styles.rows}>
|
||||
{
|
||||
|
||||
@@ -6,7 +6,8 @@ import SelectInput from './SelectInput';
|
||||
const availabilityOptions = [
|
||||
{ key: 'announced', value: translate('Announced') },
|
||||
{ key: 'inCinemas', value: translate('InCinemas') },
|
||||
{ key: 'released', value: translate('Released') }
|
||||
{ key: 'released', value: translate('Released') },
|
||||
{ key: 'preDB', value: translate('PreDB') }
|
||||
];
|
||||
|
||||
function AvailabilitySelectInput(props) {
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchDownloadClients } from 'Store/Actions/settingsActions';
|
||||
import sortByName from 'Utilities/Array/sortByName';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.downloadClients,
|
||||
(state, { includeAny }) => includeAny,
|
||||
(state, { protocol }) => protocol,
|
||||
(downloadClients, includeAny, protocolFilter) => {
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items
|
||||
} = downloadClients;
|
||||
|
||||
const filteredItems = items.filter((item) => item.protocol === protocolFilter);
|
||||
|
||||
const values = _.map(filteredItems.sort(sortByName), (downloadClient) => {
|
||||
return {
|
||||
key: downloadClient.id,
|
||||
value: downloadClient.name
|
||||
};
|
||||
});
|
||||
|
||||
if (includeAny) {
|
||||
values.unshift({
|
||||
key: 0,
|
||||
value: '(Any)'
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
values
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchDownloadClients: fetchDownloadClients
|
||||
};
|
||||
|
||||
class DownloadClientSelectInputConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.isPopulated) {
|
||||
this.props.dispatchFetchDownloadClients();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onChange = ({ name, value }) => {
|
||||
this.props.onChange({ name, value: parseInt(value) });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EnhancedSelectInput
|
||||
{...this.props}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DownloadClientSelectInputConnector.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
includeAny: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
dispatchFetchDownloadClients: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
DownloadClientSelectInputConnector.defaultProps = {
|
||||
includeAny: false,
|
||||
protocol: 'torrent'
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientSelectInputConnector);
|
||||
@@ -8,7 +8,6 @@ import AvailabilitySelectInput from './AvailabilitySelectInput';
|
||||
import CaptchaInputConnector from './CaptchaInputConnector';
|
||||
import CheckInput from './CheckInput';
|
||||
import DeviceInputConnector from './DeviceInputConnector';
|
||||
import DownloadClientSelectInputConnector from './DownloadClientSelectInputConnector';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
|
||||
import FormInputHelpText from './FormInputHelpText';
|
||||
@@ -74,9 +73,6 @@ function getComponent(type) {
|
||||
case inputTypes.INDEXER_FLAGS_SELECT:
|
||||
return IndexerFlagsSelectInputConnector;
|
||||
|
||||
case inputTypes.DOWNLOAD_CLIENT_SELECT:
|
||||
return DownloadClientSelectInputConnector;
|
||||
|
||||
case inputTypes.LANGUAGE_SELECT:
|
||||
return LanguageSelectInputConnector;
|
||||
|
||||
@@ -117,6 +113,8 @@ function FormInputGroup(props) {
|
||||
helpTexts,
|
||||
helpTextWarning,
|
||||
helpLink,
|
||||
inlineLink,
|
||||
tooltip,
|
||||
pending,
|
||||
errors,
|
||||
warnings,
|
||||
@@ -186,6 +184,9 @@ function FormInputGroup(props) {
|
||||
!checkInput && helpText &&
|
||||
<FormInputHelpText
|
||||
text={helpText}
|
||||
link={inlineLink}
|
||||
tooltip={tooltip}
|
||||
isWarning={!!inlineLink}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -267,6 +268,8 @@ FormInputGroup.propTypes = {
|
||||
helpTexts: PropTypes.arrayOf(PropTypes.string),
|
||||
helpTextWarning: PropTypes.string,
|
||||
helpLink: PropTypes.string,
|
||||
inlineLink: PropTypes.string,
|
||||
tooltip: PropTypes.string,
|
||||
pending: PropTypes.bool,
|
||||
errors: PropTypes.arrayOf(PropTypes.object),
|
||||
warnings: PropTypes.arrayOf(PropTypes.object)
|
||||
|
||||
@@ -64,7 +64,6 @@ function ProviderFieldFormGroup(props) {
|
||||
label,
|
||||
helpText,
|
||||
helpLink,
|
||||
placeholder,
|
||||
value,
|
||||
type,
|
||||
advanced,
|
||||
@@ -97,7 +96,6 @@ function ProviderFieldFormGroup(props) {
|
||||
label={label}
|
||||
helpText={helpText}
|
||||
helpLink={helpLink}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
values={getSelectValues(selectOptions)}
|
||||
errors={errors}
|
||||
@@ -123,7 +121,6 @@ ProviderFieldFormGroup.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
helpText: PropTypes.string,
|
||||
helpLink: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
type: PropTypes.string.isRequired,
|
||||
advanced: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.image {
|
||||
align-content: center;
|
||||
.heart {
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
color: $themeRed;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +0,0 @@
|
||||
.image {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +0,0 @@
|
||||
.image {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styles from './RottenTomatoRating.css';
|
||||
|
||||
class RottenTomatoRating extends PureComponent {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
ratings,
|
||||
hideIcon,
|
||||
iconSize
|
||||
} = this.props;
|
||||
|
||||
const rtRotten = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ1LjE4NSA0NDQuNjg0Yy03OS4zNjkgNC4xNjctOTUuNTg3LTg2LjY1Mi0xMjYuNzI2LTg2LjAwNi0xMy4yNjguMjc5LTIzLjcyNiAxNC4xNTEtMTkuMTMzIDMwLjMyIDIuNTI1IDguODg4IDkuNTMgMjEuOTIzIDEzLjk0NCAzMC4wMTEgMTUuNTcgMjguNTQ0LTcuNDQ3IDYwLjg0NS0zNC4zODMgNjMuNTc3LTQ0Ljc2IDQuNTQtNjMuNDMzLTIxLjQyNi02Mi4yNzgtNDguMDA3IDEuMy0yOS44NCAyNi42LTYwLjMzMS42NS03My4zMDUtMjcuMTk0LTEzLjU5Ny00OS4zMDEgMzkuNTcyLTc1LjMyNSA1MS40MzktMjMuNTUzIDEwLjc0MS01Ni4yNDggMi40MTMtNjcuODcyLTIzLjc0MS04LjE2NC0xOC4zNzktNi42OC01My43NjggMjkuNjctNjcuMjcgMjIuNzA2LTguNDMzIDczLjMwNSAxMS4wMjkgNzUuOS0xMy42MjMgMi45OTItMjguNDE2LTUzLjE1NS0zMC44MTItNzAuMDYtMzcuNjI2LTI5LjkxMi0xMi4wNTUtNDcuNTY3LTM3Ljg1LTMzLjczNC02NS41MjIgMTAuMzc4LTIwLjc1NyA0MC45MTUtMjkuMjAzIDY0LjIyMy0yMC4xMSAyNy45MjIgMTAuODkyIDMyLjQwNCAzOS44NTMgNDYuNzEgNTEuODk3IDEyLjMyNCAxMC4zOCAyOS4xOSAxMS42OCA0MC4yMiA0LjU0MyA4LjEzNS01LjI2NSAxMC44NDMtMTYuODI4IDcuNzc0LTI3LjM5LTQuMDctMTQuMDIzLTE0Ljg3NS0yMi43NzMtMjUuNDE1LTMxLjM0Ni0xOC43NTgtMTUuMjQ5LTQ1LjI0LTI4LjM2LTI5LjIyMi02OS45ODMgMTMuMTMtMzQuMTEgNTEuNjQyLTM1LjM0IDUxLjY0Mi0zNS4zNCAxNS4zLTEuNzIgMjkuMDAyIDIuOSA0MC4xNjcgMTIuODc1IDE0LjkyNyAxMy4zMzUgMTcuODM0IDMxLjE2IDE1LjMzNiA1MC4xNzYtMi4yODMgMTcuMzU4LTguNDI2IDMyLjU2LTExLjYzIDQ5Ljc1OS0zLjcxNyAxOS45NjYgNi45NTQgNDAuMDg2IDI3LjI0OSA0MC44NjkgMjYuNjk0IDEuMDMxIDM0LjY5OC0xOS40ODYgMzcuOTY0LTMyLjQ5MiA0Ljc4Mi0xOS4wMjggMTEuMDU4LTM2LjY5NCAyOC43MTgtNDcuODIgMjUuMzQ2LTE1Ljk3IDYwLjU1Mi0xMi40NyA3Ni44ODYgMTguMjIyIDEyLjkyIDI0LjI4NCA4Ljc3MiA1Ny43MTUtMTEuMDQ3IDc1Ljk3LTguODkyIDguMTg4LTE5LjU4NCAxMS4wNzUtMzEuMTQ4IDExLjE1Ni0xNi41ODUuMTE3LTMzLjE2Mi0uMjktNDguNTU2IDcuNDcxLTEwLjQ4IDUuMjgxLTE1LjA0NyAxMy44ODgtMTUuMDQ1IDI1LjQyMyAwIDExLjI0MiA1Ljg1MyAxOC41ODUgMTUuMzM2IDIzLjM2MyAxNy44NiA5LjAwMyAzNy41NzcgMTAuODQzIDU2Ljg3MSAxNC4yMjIgMjcuOTggNC45IDUyLjU4MSAxNC43NTUgNjguMzc1IDQwLjcyLjE0Mi4yMjguMjguNDU4LjQxNS42OSAxOC4xMzkgMzAuNzQxLS44MzEgNzUuMDA1LTM2LjQ3NiA3Ni44NzgiIGZpbGw9IiMwQUM4NTUiLz48L3N2Zz4=';
|
||||
const rtFresh = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNDc4LjI5IDI5Ni45OGMtMy45OS02My45NjYtMzYuNTItMTExLjgyLTg1LjQ2OC0xMzguNTggMC4yNzggMS41Ni0xLjEwOSAzLjUwOC0yLjY4OCAyLjgxOC0zMi4wMTYtMTQuMDA2LTg2LjMyOCAzMS4zMi0xMjQuMjggNy41ODQgMC4yODUgOC41MTktMS4zNzggNTAuMDcyLTU5LjkxNCA1Mi40ODMtMS4zODIgMC4wNTYtMi4xNDItMS4zNTUtMS4yNjgtMi4zNTQgNy44MjgtOC45MjkgMTUuNzMyLTMxLjUzNSA0LjM2Ny00My41ODYtMjQuMzM4IDIxLjgxLTM4LjQ3MiAzMC4wMTctODUuMTM4IDE5LjE4Ni0yOS44NzggMzEuMjQxLTQ2LjgwOSA3NC00My40ODUgMTI3LjI2IDYuNzggMTA4Ljc0IDEwOC42MyAxNzAuODkgMjExLjE5IDE2NC40OSAxMDIuNTYtNi4zOTUgMTkzLjQ3LTgwLjU3MiAxODYuNjgtMTg5LjMxIiBmaWxsPSIjRkEzMjBBIi8+PHBhdGggZD0iTTI5MS4zNzUgMTMyLjI5M2MyMS4wNzUtNS4wMjMgODEuNjkzLS40OSAxMDEuMTE0IDI1LjI3NCAxLjE2NiAxLjU0NS0uNDc1IDQuNDY4LTIuMzU1IDMuNjQ4LTMyLjAxNi0xNC4wMDYtODYuMzI4IDMxLjMyLTEyNC4yODIgNy41ODQuMjg1IDguNTE5LTEuMzc4IDUwLjA3Mi01OS45MTQgNTIuNDgzLTEuMzgyLjA1Ni0yLjE0Mi0xLjM1NS0xLjI2OC0yLjM1NCA3LjgyOC04LjkyOSAxNS43My0zMS41MzUgNC4zNjctNDMuNTg2LTI2LjUxMiAyMy43NTgtNDAuODg0IDMxLjM5Mi05OC40MjYgMTUuODM4LTEuODgzLS41MDgtMS4yNDEtMy41MzUuNzYyLTQuMjk4IDEwLjg3Ni00LjE1NyAzNS41MTUtMjIuMzYxIDU4LjgyNC0zMC4zODUgNC40MzgtMS41MjYgOC44NjItMi43MSAxMy4xOC0zLjQtMjUuNjY1LTIuMjkzLTM3LjIzNS01Ljg2Mi01My41NTktMy40LTEuNzg5LjI3LTMuMDA0LTEuODEzLTEuODk1LTMuMjQxIDIxLjk5NS0yOC4zMzIgNjIuNTEzLTM2Ljg4OCA4Ny41MTItMjEuODM3LTE1LjQxLTE5LjA5NC0yNy40OC0zNC4zMjEtMjcuNDgtMzQuMzIxbDI4LjYwMS0xNi4yNDZzMTEuODE3IDI2LjQgMjAuNDE0IDQ1LjYxNGMyMS4yNzUtMzEuNDM1IDYwLjg2LTM0LjMzNiA3Ny41ODUtMTIuMDMzLjk5MiAxLjMyNi0uMDQ1IDMuMjEtMS43MDIgMy4xNzEtMTMuNjEyLS4zMzEtMjEuMTA3IDEyLjA1LTIxLjY3NSAyMS40NjZsLjE5Ny4wMjMiIGZpbGw9IiMwMDkxMkQiLz48L3N2Zz4=';
|
||||
|
||||
const rating = ratings.rottenTomatoes;
|
||||
|
||||
let ratingString = '0%';
|
||||
|
||||
if (rating) {
|
||||
ratingString = `${rating.value}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
!hideIcon &&
|
||||
<img
|
||||
className={styles.image}
|
||||
src={rating.value > 50 ? rtFresh : rtRotten}
|
||||
style={{
|
||||
height: `${iconSize}px`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
{ratingString}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RottenTomatoRating.propTypes = {
|
||||
ratings: PropTypes.object.isRequired,
|
||||
iconSize: PropTypes.number.isRequired,
|
||||
hideIcon: PropTypes.bool
|
||||
};
|
||||
|
||||
RottenTomatoRating.defaultProps = {
|
||||
iconSize: 14
|
||||
};
|
||||
|
||||
export default RottenTomatoRating;
|
||||
@@ -1,5 +0,0 @@
|
||||
.image {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styles from './TmdbRating.css';
|
||||
|
||||
class TmdbRating extends PureComponent {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
ratings,
|
||||
hideIcon,
|
||||
iconSize
|
||||
} = this.props;
|
||||
|
||||
const tmdbImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTAuMjQgODEuNTIiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeTE9IjQwLjc2IiB4Mj0iMTkwLjI0IiB5Mj0iNDAuNzYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM5MGNlYTEiLz48c3RvcCBvZmZzZXQ9Ii41NiIgc3RvcC1jb2xvcj0iIzNjYmVjOSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwYjNlNSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGQ9Ik0xMDUuNjcgMzYuMDZoNjYuOWExNy42NyAxNy42NyAwIDAwMTcuNjctMTcuNjZBMTcuNjcgMTcuNjcgMCAwMDE3Mi41Ny43M2gtNjYuOUExNy42NyAxNy42NyAwIDAwODggMTguNGExNy42NyAxNy42NyAwIDAwMTcuNjcgMTcuNjZ6bS04OCA0NWg3Ni45YTE3LjY3IDE3LjY3IDAgMDAxNy42Ny0xNy42NiAxNy42NyAxNy42NyAwIDAwLTE3LjY3LTE3LjY3aC03Ni45QTE3LjY3IDE3LjY3IDAgMDAwIDYzLjRhMTcuNjcgMTcuNjcgMCAwMDE3LjY3IDE3LjY2em0tNy4yNi00NS42NGg3LjhWNi45MmgxMC4xVjBoLTI4djYuOWgxMC4xem0yOC4xIDBoNy44VjguMjVoLjFsOSAyNy4xNWg2bDkuMy0yNy4xNWguMVYzNS40aDcuOFYwSDY2Ljc2bC04LjIgMjMuMWgtLjFMNTAuMzEgMGgtMTEuOHptMTEzLjkyIDIwLjI1YTE1LjA3IDE1LjA3IDAgMDAtNC41Mi01LjUyIDE4LjU3IDE4LjU3IDAgMDAtNi42OC0zLjA4IDMzLjU0IDMzLjU0IDAgMDAtOC4wNy0xaC0xMS43djM1LjRoMTIuNzVhMjQuNTggMjQuNTggMCAwMDcuNTUtMS4xNSAxOS4zNCAxOS4zNCAwIDAwNi4zNS0zLjMyIDE2LjI3IDE2LjI3IDAgMDA0LjM3LTUuNSAxNi45MSAxNi45MSAwIDAwMS42My03LjU4IDE4LjUgMTguNSAwIDAwLTEuNjgtOC4yNXpNMTQ1IDY4LjZhOC44IDguOCAwIDAxLTIuNjQgMy40IDEwLjcgMTAuNyAwIDAxLTQgMS44MiAyMS41NyAyMS41NyAwIDAxLTUgLjU1aC00LjA1di0yMWg0LjZhMTcgMTcgMCAwMTQuNjcuNjMgMTEuNjYgMTEuNjYgMCAwMTMuODggMS44N0E5LjE0IDkuMTQgMCAwMTE0NSA1OWE5Ljg3IDkuODcgMCAwMTEgNC41MiAxMS44OSAxMS44OSAwIDAxLTEgNS4wOHptNDQuNjMtLjEzYTggOCAwIDAwLTEuNTgtMi42MiA4LjM4IDguMzggMCAwMC0yLjQyLTEuODUgMTAuMzEgMTAuMzEgMCAwMC0zLjE3LTF2LS4xYTkuMjIgOS4yMiAwIDAwNC40Mi0yLjgyIDcuNDMgNy40MyAwIDAwMS42OC01IDguNDIgOC40MiAwIDAwLTEuMTUtNC42NSA4LjA5IDguMDkgMCAwMC0zLTIuNzIgMTIuNTYgMTIuNTYgMCAwMC00LjE4LTEuMyAzMi44NCAzMi44NCAwIDAwLTQuNjItLjMzaC0xMy4ydjM1LjRoMTQuNWEyMi40MSAyMi40MSAwIDAwNC43Mi0uNSAxMy41MyAxMy41MyAwIDAwNC4yOC0xLjY1IDkuNDIgOS40MiAwIDAwMy4xLTMgOC41MiA4LjUyIDAgMDAxLjItNC42OCA5LjM5IDkuMzkgMCAwMC0uNTUtMy4xOHptLTE5LjQyLTE1Ljc1aDUuM2ExMCAxMCAwIDAxMS44NS4xOCA2LjE4IDYuMTggMCAwMTEuNy41NyAzLjM5IDMuMzkgMCAwMTEuMjIgMS4xMyAzLjIyIDMuMjIgMCAwMS40OCAxLjgyIDMuNjMgMy42MyAwIDAxLS40MyAxLjggMy40IDMuNCAwIDAxLTEuMTIgMS4yIDQuOTIgNC45MiAwIDAxLTEuNTguNjUgNy41MSA3LjUxIDAgMDEtMS43Ny4yaC01LjY1em0xMS43MiAyMGEzLjkgMy45IDAgMDEtMS4yMiAxLjMgNC42NCA0LjY0IDAgMDEtMS42OC43IDguMTggOC4xOCAwIDAxLTEuODIuMmgtN3YtOGg1LjlhMTUuMzUgMTUuMzUgMCAwMTIgLjE1IDguNDcgOC40NyAwIDAxMi4wNS41NSA0IDQgMCAwMTEuNTcgMS4xOCAzLjExIDMuMTEgMCAwMS42MyAyIDMuNzEgMy43MSAwIDAxLS40MyAxLjkyeiIgZmlsbD0idXJsKCNhKSIvPjwvc3ZnPg==';
|
||||
|
||||
const rating = ratings.tmdb;
|
||||
|
||||
let ratingString = '0%';
|
||||
|
||||
if (rating) {
|
||||
ratingString = `${rating.value * 10}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={`${rating.votes} votes`}>
|
||||
{
|
||||
!hideIcon &&
|
||||
<img
|
||||
className={styles.image}
|
||||
src={tmdbImage}
|
||||
style={{
|
||||
height: `${iconSize}px`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
{ratingString}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TmdbRating.propTypes = {
|
||||
ratings: PropTypes.object.isRequired,
|
||||
iconSize: PropTypes.number.isRequired,
|
||||
hideIcon: PropTypes.bool
|
||||
};
|
||||
|
||||
TmdbRating.defaultProps = {
|
||||
iconSize: 14
|
||||
};
|
||||
|
||||
export default TmdbRating;
|
||||
BIN
frontend/src/Content/Theme.Park/Resources/blur-noise.png
Normal file
BIN
frontend/src/Content/Theme.Park/Resources/blur-noise.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
30
frontend/src/Content/Theme.Park/Themes/aquamarine.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/aquamarine.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(ellipse at center, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #009688;
|
||||
--button-color-hover: #12afa0;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 18, 175, 160;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #0ed2bf;
|
||||
--link-color-hover: #36e7d6;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #009688; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: rgb(21, 213, 194);
|
||||
--petio-spinner: invert(39%) sepia(98%) saturate(527%) hue-rotate(129deg) brightness(94%) contrast(101%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 18, 175, 160;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/dark.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/dark.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(circle, #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: #2d2d2d;
|
||||
|
||||
--button-color: #7a7a7a;
|
||||
--button-color-hover: #9b9b9b;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 170, 170, 170;
|
||||
--accent-color-hover: rgba(255, 255, 255, 0.45);
|
||||
--link-color: #7a7a7a;
|
||||
--link-color-hover: #fff;
|
||||
--label-text-color: black;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #6b5; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #e5a00d;
|
||||
--petio-spinner: invert(35%) sepia(12%) saturate(4%) hue-rotate(2deg) brightness(104%) contrast(86%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 255, 255, 255;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/dracula.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/dracula.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #282a36;
|
||||
|
||||
--modal-bg-color: #1e2029;
|
||||
--modal-header-color: #1e2029;
|
||||
--modal-footer-color: #1e2029;
|
||||
|
||||
--drop-down-menu-bg: #1e2029;
|
||||
|
||||
--button-color: #bd93f9;
|
||||
--button-color-hover: #ff79c6;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 80, 250, 123;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #ff79c6;
|
||||
--link-color-hover: #8be9fd;
|
||||
--label-text-color: #282a36;
|
||||
|
||||
--text:#6272a4;
|
||||
--text-hover: #95adfa;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #50fa7b; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #bd93f9;
|
||||
--petio-spinner: invert(79%) sepia(27%) saturate(1033%) hue-rotate(74deg) brightness(104%) contrast(96%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 80, 250, 123;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/hotline.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/hotline.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: linear-gradient(90deg, rgba(247,101,184,1) 0%, rgba(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #f98dc9;
|
||||
--button-color-hover: #ff4cb1;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 249, 141, 201;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color:rgb(255, 179, 222);
|
||||
--link-color-hover: #d7fffe;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #f98dc9; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #f765b8;
|
||||
--petio-spinner: invert(78%) sepia(17%) saturate(4447%) hue-rotate(290deg) brightness(109%) contrast(95%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 215,255,254;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/hotpink.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/hotpink.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(45deg, #fb3f62 0%, #204c80 37%, #004249 97%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: #204c80;
|
||||
|
||||
--button-color: #fb3f62;
|
||||
--button-color-hover: #cd4164;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 251, 63, 98;
|
||||
--accent-color-hover: rgba(var(--accent-color), .8);
|
||||
--link-color: rgb(0, 255, 157);
|
||||
--link-color-hover: rgba(0, 255, 157, 0.8);
|
||||
--label-text-color: #282a36;
|
||||
|
||||
--text:#eee;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
--arr-queue-color: rgb(0, 255, 157);
|
||||
--plex-poster-unwatched: #fb3f62;
|
||||
--petio-spinner: invert(29%) sepia(87%) saturate(2199%) hue-rotate(331deg) brightness(115%) contrast(97%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 251, 63, 98;
|
||||
}
|
||||
|
||||
30
frontend/src/Content/Theme.Park/Themes/nord.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/nord.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #2E3440;
|
||||
|
||||
--modal-bg-color: #3B4252;
|
||||
--modal-header-color: #434C5E;
|
||||
--modal-footer-color: #434C5E;
|
||||
|
||||
--drop-down-menu-bg: #3B4252;
|
||||
|
||||
--button-color: #79b8ca;
|
||||
--button-color-hover: #6a9daf;
|
||||
--button-text: #2E3440;
|
||||
--button-text-hover: #D8DEE9;
|
||||
|
||||
--accent-color: 121, 184, 202;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #81A1C1;
|
||||
--link-color-hover: #88C0D0;
|
||||
--label-text-color: #222730;
|
||||
|
||||
--text:#D8DEE9;
|
||||
--text-hover: #ECEFF4;
|
||||
--text-muted: #81A1C1;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #A3BE8C; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #D08770;
|
||||
--petio-spinner: invert(83%) sepia(9%) saturate(1787%) hue-rotate(156deg) brightness(85%) contrast(83%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 121, 184, 202;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/organizr.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/organizr.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #1f1f1f;
|
||||
|
||||
--modal-bg-color: #333;
|
||||
--modal-header-color: #232323;
|
||||
--modal-footer-color: #232323;
|
||||
|
||||
--drop-down-menu-bg: #1b1b1b;
|
||||
|
||||
--button-color: #2cabe3;
|
||||
--button-color-hover: #298fbc;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 44, 171, 227;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #2cabe3;
|
||||
--link-color-hover: #3cc5ff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#96a2b4;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #2cabe3; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #2cabe3;
|
||||
--petio-spinner: invert(65%) sepia(83%) saturate(2026%) hue-rotate(167deg) brightness(90%) contrast(97%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 44, 171, 227;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/overseerr.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/overseerr.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(360deg, hsl(221, 39%, 11%) 65%, hsl(215, 28%, 17%) 100%);
|
||||
|
||||
--modal-bg-color: #1f2937;
|
||||
--modal-header-color: #1f2937;
|
||||
--modal-footer-color: #1f2937;
|
||||
|
||||
--drop-down-menu-bg: #374151;
|
||||
|
||||
--button-color: #4f46e5;
|
||||
--button-color-hover: #6366f1;
|
||||
--button-text: #e5e7eb;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 167, 139, 250;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #6366f1;
|
||||
--link-color-hover: #a78bfa;
|
||||
--label-text-color: #000;
|
||||
|
||||
--text: #d1d5db;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #9ca3af;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #6366f1; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #6366f1;
|
||||
--petio-spinner: invert(24%) sepia(59%) saturate(3411%) hue-rotate(237deg) brightness(91%) contrast(96%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 98, 116, 145;
|
||||
}
|
||||
28
frontend/src/Content/Theme.Park/Themes/plex.css
Normal file
28
frontend/src/Content/Theme.Park/Themes/plex.css
Normal file
@@ -0,0 +1,28 @@
|
||||
:root {
|
||||
--main-bg-color: url("Resources/blur-noise.png") repeat scroll 0% 0%, radial-gradient(circle at 0% 100%, rgba(54, 66, 84, 0.55) 0%, rgba(54, 66, 84, 0.043) 70%, rgba(54, 66, 84, 0) 80%), radial-gradient(circle at 100% 100%, rgba(113, 135, 153, 0.55) 0%, rgba(113, 135, 153, 0.043) 70%, rgba(113, 135, 153, 0) 80%), radial-gradient(circle at 100% 0%, rgba(54, 66, 84, 0.55) 0%, rgba(54, 66, 84, 0.043) 70%, rgba(54, 66, 84, 0) 80%), radial-gradient(circle at 0% 0%, rgba(91, 114, 135, 0.55) 0%, rgba(91, 114, 135, 0.043) 70%, rgba(91, 114, 135, 0) 80%), rgb(0, 0, 0) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: #1f2326;
|
||||
--modal-header-color: #1f2326;
|
||||
--modal-footer-color: #323232;
|
||||
|
||||
--drop-down-menu-bg: #191a1c;
|
||||
|
||||
--button-color: #cc7b19;
|
||||
--button-color-hover: #e59029;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 229, 160, 13;
|
||||
--accent-color-hover: #ffc107;
|
||||
--link-color: #e5a00d;
|
||||
--link-color-hover: #fff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
--arr-queue-color: #27c24c;
|
||||
--petio-spinner: invert(0%) sepia(0%) saturate(100%) hue-rotate(0deg) brightness(100%) contrast(100%);
|
||||
--gitea-color-primary-dark-4: 255, 193, 7;
|
||||
}
|
||||
124
frontend/src/Content/Theme.Park/Themes/radarr-darker.css
Normal file
124
frontend/src/Content/Theme.Park/Themes/radarr-darker.css
Normal file
@@ -0,0 +1,124 @@
|
||||
:root {
|
||||
--main-bg-color: #454545;
|
||||
|
||||
--modal-bg-color: #595959;
|
||||
--modal-header-color: #595959;
|
||||
--modal-footer-color: #595959;
|
||||
|
||||
--drop-down-menu-bg: #606060;
|
||||
|
||||
--button-color: #5899eb;
|
||||
--button-color-hover: #4b91ea;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 255, 194, 48;
|
||||
--accent-color-hover: rgb(255, 194, 48, .8);
|
||||
--link-color: rgb(255, 194, 48);
|
||||
--link-color-hover: rgb(255, 194, 48, .8);
|
||||
--label-text-color: #eee;
|
||||
|
||||
--text: #ccc;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #5d9cec;
|
||||
--side-menu-active: #333333;
|
||||
--scroller-hover: #606060;
|
||||
--scroller: #707070;
|
||||
--border-color: #606060;
|
||||
--label-color: #707070;
|
||||
--label-info: #5d9cec;
|
||||
--header-color: #464b51;
|
||||
--side-menu-color: #595959;
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
|
||||
[class*="PageHeader-header-"] {
|
||||
background-color: var(--header-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[class*="PageToolbar-toolbar-"] {
|
||||
background-color: #707070;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* SIDE MENU */
|
||||
|
||||
[class*="PageSidebar-sidebar-"] {
|
||||
background-color: var(--side-menu-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-link-]:focus {
|
||||
color: rgb(var(--accent-color)) !important;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-isActiveLink-] {
|
||||
color: var(--link-color) !important;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-isActiveParentLink-] {
|
||||
background-color: var(--side-menu-active);
|
||||
}
|
||||
|
||||
/* SCROLLER */
|
||||
[class*=ImportSeriesSelectSeries-results-]::-webkit-scrollbar-thumb:hover,
|
||||
[class*=OverlayScroller-thumb-]:hover {
|
||||
background-color: var(--scroller-hover) !important;
|
||||
}
|
||||
|
||||
[class*="OverlayScroller-thumb-"],
|
||||
[class*=Scroller-scroller-]::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scroller) !important;
|
||||
}
|
||||
|
||||
/* MODALS */
|
||||
|
||||
[class*=ModalHeader-modalHeader-],
|
||||
[class*=FieldSet-legend-] {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
[class*=ModalFooter-modalFooter-] {
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* LABLES */
|
||||
|
||||
[class*="Label-default-"] {
|
||||
border-color: var(--label-color);
|
||||
background-color: var(--label-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
[class*="Label-info-"]:not([class*="PageSidebarItem-status-"] [class*="Label-info-"]) {
|
||||
border-color: var(--label-info);
|
||||
background-color: var(--label-info);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* SETTINGS */
|
||||
|
||||
[class*=Settings-link-] {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* SEARCH DROP DOWN */
|
||||
|
||||
[class*="MovieSearchInput-containerOpen-"] [class*="MovieSearchInput-movieContainer-"] {
|
||||
border: 1px solid var(--drop-down-menu-bg);
|
||||
background-color: var(--drop-down-menu-bg);
|
||||
box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%);
|
||||
color: #e1e2e3;
|
||||
}
|
||||
|
||||
/* SERIES PAGE */
|
||||
|
||||
[class*="MovieIndexPoster-controls-"] {
|
||||
background-color: var(--label-color) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/space-gray.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/space-gray.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(ellipse at center, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #607D8B;
|
||||
--button-color-hover: #81a6b7;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 129, 166, 183;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #81a6b7;
|
||||
--link-color-hover: #9adfff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#bbb;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #81a6b7; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #70aeca;
|
||||
--petio-spinner: invert(50%) sepia(31%) saturate(341%) hue-rotate(155deg) brightness(88%) contrast(85%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 129, 166, 183;
|
||||
}
|
||||
1101
frontend/src/Content/Theme.Park/radarr-base.css
Normal file
1101
frontend/src/Content/Theme.Park/radarr-base.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,7 @@ function getInfoRowProps(row, props) {
|
||||
return {
|
||||
title: translate('Ratings'),
|
||||
iconName: icons.HEART,
|
||||
label: `${props.ratings.tmdb.value * 10}%`
|
||||
label: `${props.ratings.value * 10}%`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ function DiscoverMoviePosterInfo(props) {
|
||||
return (
|
||||
<div className={styles.info}>
|
||||
<HeartRating
|
||||
ratings={ratings}
|
||||
rating={ratings.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -129,7 +129,7 @@ DiscoverMoviePosterInfo.propTypes = {
|
||||
digitalRelease: PropTypes.string,
|
||||
physicalRelease: PropTypes.string,
|
||||
runtime: PropTypes.number,
|
||||
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
ratings: PropTypes.object,
|
||||
sortKey: PropTypes.string.isRequired,
|
||||
showRelativeDates: PropTypes.bool.isRequired,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
|
||||
@@ -246,7 +246,7 @@ class DiscoverMovieRow extends Component {
|
||||
className={styles[name]}
|
||||
>
|
||||
<HeartRating
|
||||
ratings={ratings}
|
||||
rating={ratings.value}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
@@ -373,7 +373,7 @@ DiscoverMovieRow.propTypes = {
|
||||
digitalRelease: PropTypes.string,
|
||||
runtime: PropTypes.number,
|
||||
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
ratings: PropTypes.object.isRequired,
|
||||
certification: PropTypes.string,
|
||||
collection: PropTypes.object,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
||||
@@ -13,7 +13,6 @@ export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
|
||||
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
|
||||
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
|
||||
export const LANGUAGE_SELECT = 'languageSelect';
|
||||
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
|
||||
export const SELECT = 'select';
|
||||
export const DYNAMIC_SELECT = 'dynamicSelect';
|
||||
export const TAG = 'tag';
|
||||
@@ -36,7 +35,6 @@ export const all = [
|
||||
PASSWORD,
|
||||
PATH,
|
||||
QUALITY_PROFILE_SELECT,
|
||||
DOWNLOAD_CLIENT_SELECT,
|
||||
ROOT_FOLDER_SELECT,
|
||||
INDEXER_FLAGS_SELECT,
|
||||
LANGUAGE_SELECT,
|
||||
|
||||
@@ -19,7 +19,6 @@ import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
|
||||
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
||||
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
@@ -41,11 +40,6 @@ const columns = [
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'releaseGroup',
|
||||
label: translate('ReleaseGroup'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: translate('Quality'),
|
||||
@@ -89,7 +83,6 @@ const SELECT = 'select';
|
||||
const MOVIE = 'movie';
|
||||
const LANGUAGE = 'language';
|
||||
const QUALITY = 'quality';
|
||||
const RELEASE_GROUP = 'releaseGroup';
|
||||
|
||||
class InteractiveImportModalContent extends Component {
|
||||
|
||||
@@ -209,11 +202,10 @@ class InteractiveImportModalContent extends Component {
|
||||
const errorMessage = getErrorMessage(error, translate('UnableToLoadManualImportItems'));
|
||||
|
||||
const bulkSelectOptions = [
|
||||
{ key: SELECT, value: translate('SelectDotDot'), disabled: true },
|
||||
{
|
||||
key: SELECT, value: translate('SelectDotDot'), disabled: true },
|
||||
{ key: LANGUAGE, value: translate('SelectLanguage') },
|
||||
{ key: QUALITY, value: translate('SelectQuality') },
|
||||
{ key: RELEASE_GROUP, value: translate('SelectReleaseGroup') }
|
||||
];
|
||||
{ key: QUALITY, value: translate('SelectQuality') }];
|
||||
|
||||
if (allowMovieChange) {
|
||||
bulkSelectOptions.splice(1, 0, {
|
||||
@@ -380,13 +372,6 @@ class InteractiveImportModalContent extends Component {
|
||||
real={false}
|
||||
onModalClose={this.onSelectModalClose}
|
||||
/>
|
||||
|
||||
<SelectReleaseGroupModal
|
||||
isOpen={selectModalOpen === RELEASE_GROUP}
|
||||
ids={selectedIds}
|
||||
releaseGroup=""
|
||||
onModalClose={this.onSelectModalClose}
|
||||
/>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,8 +110,7 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
const {
|
||||
movie,
|
||||
quality,
|
||||
languages,
|
||||
releaseGroup
|
||||
languages
|
||||
} = item;
|
||||
|
||||
if (!movie) {
|
||||
@@ -133,7 +132,6 @@ class InteractiveImportModalContentConnector extends Component {
|
||||
path: item.path,
|
||||
folderName: item.folderName,
|
||||
movieId: movie.id,
|
||||
releaseGroup,
|
||||
quality,
|
||||
languages,
|
||||
downloadId: this.props.downloadId
|
||||
|
||||
@@ -11,7 +11,6 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
||||
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
||||
import MovieLanguage from 'Movie/MovieLanguage';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
@@ -29,7 +28,6 @@ class InteractiveImportRow extends Component {
|
||||
|
||||
this.state = {
|
||||
isSelectMovieModalOpen: false,
|
||||
isSelectReleaseGroupModalOpen: false,
|
||||
isSelectQualityModalOpen: false,
|
||||
isSelectLanguageModalOpen: false
|
||||
};
|
||||
@@ -105,10 +103,6 @@ class InteractiveImportRow extends Component {
|
||||
this.setState({ isSelectMovieModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectReleaseGroupPress = () => {
|
||||
this.setState({ isSelectReleaseGroupModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectQualityPress = () => {
|
||||
this.setState({ isSelectQualityModalOpen: true });
|
||||
}
|
||||
@@ -122,11 +116,6 @@ class InteractiveImportRow extends Component {
|
||||
this.selectRowAfterChange(changed);
|
||||
}
|
||||
|
||||
onSelectReleaseGroupModalClose = (changed) => {
|
||||
this.setState({ isSelectReleaseGroupModalOpen: false });
|
||||
this.selectRowAfterChange(changed);
|
||||
}
|
||||
|
||||
onSelectQualityModalClose = (changed) => {
|
||||
this.setState({ isSelectQualityModalOpen: false });
|
||||
this.selectRowAfterChange(changed);
|
||||
@@ -148,7 +137,6 @@ class InteractiveImportRow extends Component {
|
||||
movie,
|
||||
quality,
|
||||
languages,
|
||||
releaseGroup,
|
||||
size,
|
||||
rejections,
|
||||
isReprocessing,
|
||||
@@ -159,8 +147,7 @@ class InteractiveImportRow extends Component {
|
||||
const {
|
||||
isSelectMovieModalOpen,
|
||||
isSelectQualityModalOpen,
|
||||
isSelectLanguageModalOpen,
|
||||
isSelectReleaseGroupModalOpen
|
||||
isSelectLanguageModalOpen
|
||||
} = this.state;
|
||||
|
||||
const movieTitle = movie ? movie.title + ( movie.year > 0 ? ` (${movie.year})` : '') : '';
|
||||
@@ -168,7 +155,6 @@ class InteractiveImportRow extends Component {
|
||||
const showMoviePlaceholder = isSelected && !movie;
|
||||
const showQualityPlaceholder = isSelected && !quality;
|
||||
const showLanguagePlaceholder = isSelected && !languages && !isReprocessing;
|
||||
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
@@ -195,17 +181,6 @@ class InteractiveImportRow extends Component {
|
||||
}
|
||||
</TableRowCellButton>
|
||||
|
||||
<TableRowCellButton
|
||||
title={translate('ClickToChangeReleaseGroup')}
|
||||
onPress={this.onSelectReleaseGroupPress}
|
||||
>
|
||||
{
|
||||
showReleaseGroupPlaceholder ?
|
||||
<InteractiveImportRowCellPlaceholder /> :
|
||||
releaseGroup
|
||||
}
|
||||
</TableRowCellButton>
|
||||
|
||||
<TableRowCellButton
|
||||
className={styles.quality}
|
||||
title={translate('ClickToChangeQuality')}
|
||||
@@ -293,13 +268,6 @@ class InteractiveImportRow extends Component {
|
||||
onModalClose={this.onSelectMovieModalClose}
|
||||
/>
|
||||
|
||||
<SelectReleaseGroupModal
|
||||
isOpen={isSelectReleaseGroupModalOpen}
|
||||
ids={[id]}
|
||||
releaseGroup={releaseGroup ?? ''}
|
||||
onModalClose={this.onSelectReleaseGroupModalClose}
|
||||
/>
|
||||
|
||||
<SelectQualityModal
|
||||
isOpen={isSelectQualityModalOpen}
|
||||
ids={[id]}
|
||||
@@ -328,7 +296,6 @@ InteractiveImportRow.propTypes = {
|
||||
movie: PropTypes.object,
|
||||
quality: PropTypes.object,
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
releaseGroup: PropTypes.string,
|
||||
size: PropTypes.number.isRequired,
|
||||
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isReprocessing: PropTypes.bool,
|
||||
|
||||
@@ -128,7 +128,7 @@ class SelectLanguageModalContent extends Component {
|
||||
kind={kinds.SUCCESS}
|
||||
onPress={this.onLanguageSelect}
|
||||
>
|
||||
{translate('SelectLanguages')}
|
||||
{translate('SelectLanguges')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import SelectReleaseGroupModalContentConnector from './SelectReleaseGroupModalContentConnector';
|
||||
|
||||
class SelectReleaseGroupModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SelectReleaseGroupModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectReleaseGroupModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectReleaseGroupModal;
|
||||
@@ -1,99 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class SelectReleaseGroupModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
const {
|
||||
releaseGroup
|
||||
} = props;
|
||||
|
||||
this.state = {
|
||||
releaseGroup
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onReleaseGroupChange = ({ value }) => {
|
||||
this.setState({ releaseGroup: value });
|
||||
}
|
||||
|
||||
onReleaseGroupSelect = () => {
|
||||
this.props.onReleaseGroupSelect(this.state);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
releaseGroup
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{translate('ManualImportSetReleaseGroup')}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('ReleaseGroup')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="releaseGroup"
|
||||
value={releaseGroup}
|
||||
onChange={this.onReleaseGroupChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
kind={kinds.SUCCESS}
|
||||
onPress={this.onReleaseGroupSelect}
|
||||
>
|
||||
{translate('SetReleaseGroup')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectReleaseGroupModalContent.propTypes = {
|
||||
releaseGroup: PropTypes.string.isRequired,
|
||||
onReleaseGroupSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectReleaseGroupModalContent;
|
||||
@@ -1,54 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import SelectReleaseGroupModalContent from './SelectReleaseGroupModalContent';
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems,
|
||||
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems
|
||||
};
|
||||
|
||||
class SelectReleaseGroupModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onReleaseGroupSelect = ({ releaseGroup }) => {
|
||||
const {
|
||||
ids,
|
||||
dispatchUpdateInteractiveImportItems,
|
||||
dispatchReprocessInteractiveImportItems
|
||||
} = this.props;
|
||||
|
||||
dispatchUpdateInteractiveImportItems({
|
||||
ids,
|
||||
releaseGroup
|
||||
});
|
||||
|
||||
dispatchReprocessInteractiveImportItems({ ids });
|
||||
|
||||
this.props.onModalClose(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SelectReleaseGroupModalContent
|
||||
{...this.props}
|
||||
onReleaseGroupSelect={this.onReleaseGroupSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectReleaseGroupModalContentConnector.propTypes = {
|
||||
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(SelectReleaseGroupModalContentConnector);
|
||||
@@ -155,7 +155,7 @@ DeleteMovieModalContent.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
path: PropTypes.string.isRequired,
|
||||
hasFile: PropTypes.bool.isRequired,
|
||||
sizeOnDisk: PropTypes.number.isRequired,
|
||||
sizeOnDisk: PropTypes.string.isRequired,
|
||||
onDeletePress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 375px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
@@ -41,8 +41,8 @@
|
||||
.poster {
|
||||
flex-shrink: 0;
|
||||
margin-right: 35px;
|
||||
width: 217px;
|
||||
height: 319px;
|
||||
width: 200px;
|
||||
height: 294px;
|
||||
}
|
||||
|
||||
.info {
|
||||
|
||||
@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import TextTruncate from 'react-text-truncate';
|
||||
import HeartRating from 'Components/HeartRating';
|
||||
import Icon from 'Components/Icon';
|
||||
import ImdbRating from 'Components/ImdbRating';
|
||||
import InfoLabel from 'Components/InfoLabel';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import Marquee from 'Components/Marquee';
|
||||
@@ -16,8 +16,6 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import RottenTomatoRating from 'Components/RottenTomatoRating';
|
||||
import TmdbRating from 'Components/TmdbRating';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
||||
@@ -451,6 +449,17 @@ class MovieDetails extends Component {
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
!!ratings &&
|
||||
<span className={styles.rating}>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
iconSize={20}
|
||||
hideHeart={isSmallScreen}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
<span className={styles.links}>
|
||||
<Tooltip
|
||||
@@ -492,36 +501,6 @@ class MovieDetails extends Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.details}>
|
||||
{
|
||||
!!ratings.tmdb &&
|
||||
<span className={styles.rating}>
|
||||
<TmdbRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
!!ratings.imdb &&
|
||||
<span className={styles.rating}>
|
||||
<ImdbRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
!!ratings.rottenTomatoes &&
|
||||
<span className={styles.rating}>
|
||||
<RottenTomatoRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className={styles.detailsLabels}>
|
||||
<InfoLabel
|
||||
className={styles.detailsInfoLabel}
|
||||
|
||||
@@ -67,7 +67,8 @@ class MovieHistoryRow extends Component {
|
||||
data,
|
||||
isMarkingAsFailed,
|
||||
shortDateFormat,
|
||||
timeFormat
|
||||
timeFormat,
|
||||
onMarkAsFailedPress
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
@@ -142,7 +143,7 @@ class MovieHistoryRow extends Component {
|
||||
isMarkingAsFailed={isMarkingAsFailed}
|
||||
shortDateFormat={shortDateFormat}
|
||||
timeFormat={timeFormat}
|
||||
onMarkAsFailedPress={this.onMarkAsFailedPress}
|
||||
onMarkAsFailedPress={onMarkAsFailedPress}
|
||||
onModalClose={this.onDetailsModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
|
||||
@@ -101,15 +101,6 @@ function MovieIndexSortMenu(props) {
|
||||
{translate('DigitalRelease')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="ratings"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Ratings')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="path"
|
||||
sortKey={sortKey}
|
||||
|
||||
@@ -332,7 +332,7 @@ class MovieIndexRow extends Component {
|
||||
className={styles[name]}
|
||||
>
|
||||
<HeartRating
|
||||
ratings={ratings}
|
||||
rating={ratings.value}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ export function getMovieStatusDetails(status) {
|
||||
let statusDetails = {
|
||||
icon: icons.ANNOUNCED,
|
||||
title: translate('Announced'),
|
||||
message: translate('AnnouncedMsg')
|
||||
message: translate('AnnoucedMsg')
|
||||
};
|
||||
|
||||
if (status === 'deleted') {
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.rightButtons {
|
||||
justify-content: flex-end;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.addSpecification {
|
||||
composes: customFormat from '~./CustomFormat.css';
|
||||
|
||||
|
||||
@@ -198,25 +198,26 @@ class EditCustomFormatModalContent extends Component {
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<div className={styles.rightButtons}>
|
||||
{
|
||||
id &&
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onDeleteCustomFormatPress}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
}
|
||||
{
|
||||
id &&
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onDeleteCustomFormatPress}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
}
|
||||
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
onPress={this.onImportPress}
|
||||
>
|
||||
{translate('Import')}
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
!id &&
|
||||
<Button
|
||||
className={styles.deleteButton}
|
||||
onPress={this.onImportPress}
|
||||
>
|
||||
{translate('Import')}
|
||||
</Button>
|
||||
}
|
||||
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -14,7 +13,7 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditDownloadClientModalContent.css';
|
||||
|
||||
@@ -46,10 +45,7 @@ class EditDownloadClientModalContent extends Component {
|
||||
implementationName,
|
||||
name,
|
||||
enable,
|
||||
protocol,
|
||||
priority,
|
||||
removeCompletedDownloads,
|
||||
removeFailedDownloads,
|
||||
fields,
|
||||
message
|
||||
} = item;
|
||||
@@ -140,38 +136,6 @@ class EditDownloadClientModalContent extends Component {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FieldSet
|
||||
size={sizes.SMALL}
|
||||
legend={translate('CompletedDownloadHandling')}
|
||||
>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveCompleted')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeCompletedDownloads"
|
||||
helpText={translate('RemoveCompletedDownloadsHelpText')}
|
||||
{...removeCompletedDownloads}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
protocol.value !== 'torrent' &&
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFailed')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeFailedDownloads"
|
||||
helpText={translate('RemoveFailedDownloadsHelpText')}
|
||||
{...removeFailedDownloads}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
}
|
||||
</FieldSet>
|
||||
|
||||
</Form>
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function DownloadClientOptions(props) {
|
||||
@@ -35,15 +34,11 @@ function DownloadClientOptions(props) {
|
||||
}
|
||||
|
||||
{
|
||||
hasSettings && !isFetching && !error && advancedSettings &&
|
||||
hasSettings && !isFetching && !error &&
|
||||
<div>
|
||||
<FieldSet legend={translate('CompletedDownloadHandling')}>
|
||||
<Form>
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>{translate('Enable')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
@@ -55,6 +50,22 @@ function DownloadClientOptions(props) {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>{translate('Remove')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeCompletedDownloads"
|
||||
helpText={translate('RemoveCompletedDownloadsHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.removeCompletedDownloads}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
@@ -91,10 +102,23 @@ function DownloadClientOptions(props) {
|
||||
{...settings.autoRedownloadFailed}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>{translate('Remove')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeFailedDownloads"
|
||||
helpText={translate('RemoveFailedDownloadsHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.removeFailedDownloads}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('RemoveDownloadsAlert')}
|
||||
</Alert>
|
||||
</FieldSet>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -51,15 +51,9 @@ class RemotePathMappings extends Component {
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.remotePathMappingsHeader}>
|
||||
<div className={styles.host}>
|
||||
{translate('Host')}
|
||||
</div>
|
||||
<div className={styles.path}>
|
||||
{translate('RemotePath')}
|
||||
</div>
|
||||
<div className={styles.path}>
|
||||
{translate('LocalPath')}
|
||||
</div>
|
||||
<div className={styles.host}>Host</div>
|
||||
<div className={styles.path}>Remote Path</div>
|
||||
<div className={styles.path}>Local Path</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -2,16 +2,16 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import EditImportListExclusionModalContentConnector from './EditImportListExclusionModalContentConnector';
|
||||
import EditImportExclusionModalContentConnector from './EditImportExclusionModalContentConnector';
|
||||
|
||||
function EditImportListExclusionModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
return (
|
||||
<Modal
|
||||
size={sizes.MEDIUM}
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<EditImportListExclusionModalContentConnector
|
||||
<EditImportExclusionModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
@@ -19,9 +19,9 @@ function EditImportListExclusionModal({ isOpen, onModalClose, ...otherProps }) {
|
||||
);
|
||||
}
|
||||
|
||||
EditImportListExclusionModal.propTypes = {
|
||||
EditImportExclusionModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default EditImportListExclusionModal;
|
||||
export default EditImportExclusionModal;
|
||||
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||
import EditImportListExclusionModal from './EditImportListExclusionModal';
|
||||
import EditImportExclusionModal from './EditImportExclusionModal';
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
@@ -12,7 +12,7 @@ const mapDispatchToProps = {
|
||||
clearPendingChanges
|
||||
};
|
||||
|
||||
class EditImportListExclusionModalConnector extends Component {
|
||||
class EditImportExclusionModalConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
@@ -27,7 +27,7 @@ class EditImportListExclusionModalConnector extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EditImportListExclusionModal
|
||||
<EditImportExclusionModal
|
||||
{...this.props}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
@@ -35,9 +35,9 @@ class EditImportListExclusionModalConnector extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
EditImportListExclusionModalConnector.propTypes = {
|
||||
EditImportExclusionModalConnector.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
clearPendingChanges: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditImportListExclusionModalConnector);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditImportExclusionModalConnector);
|
||||
@@ -13,9 +13,9 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditImportListExclusionModalContent.css';
|
||||
import styles from './EditImportExclusionModalContent.css';
|
||||
|
||||
function EditImportListExclusionModalContent(props) {
|
||||
function EditImportExclusionModalContent(props) {
|
||||
const {
|
||||
id,
|
||||
isFetching,
|
||||
@@ -130,7 +130,7 @@ function EditImportListExclusionModalContent(props) {
|
||||
);
|
||||
}
|
||||
|
||||
EditImportListExclusionModalContent.propTypes = {
|
||||
EditImportExclusionModalContent.propTypes = {
|
||||
id: PropTypes.number,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
@@ -143,4 +143,4 @@ EditImportListExclusionModalContent.propTypes = {
|
||||
onDeleteImportExclusionPress: PropTypes.func
|
||||
};
|
||||
|
||||
export default EditImportListExclusionModalContent;
|
||||
export default EditImportExclusionModalContent;
|
||||
@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { saveImportExclusion, setImportExclusionValue } from 'Store/Actions/settingsActions';
|
||||
import selectSettings from 'Store/Selectors/selectSettings';
|
||||
import EditImportListExclusionModalContent from './EditImportListExclusionModalContent';
|
||||
import EditImportExclusionModalContent from './EditImportExclusionModalContent';
|
||||
|
||||
const newImportExclusion = {
|
||||
movieTitle: '',
|
||||
@@ -97,7 +97,7 @@ class EditImportExclusionModalContentConnector extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EditImportListExclusionModalContent
|
||||
<EditImportExclusionModalContent
|
||||
{...this.props}
|
||||
onSavePress={this.onSavePress}
|
||||
onInputChange={this.onInputChange}
|
||||
@@ -8,14 +8,12 @@
|
||||
}
|
||||
|
||||
.movieTitle {
|
||||
@add-mixin truncate;
|
||||
|
||||
flex: 0 0 600px;
|
||||
flex: 0 0 400px;
|
||||
}
|
||||
|
||||
.tmdbId,
|
||||
.movieYear {
|
||||
flex: 0 0 70px;
|
||||
flex: 0 0 200px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@@ -6,10 +6,10 @@ import Link from 'Components/Link/Link';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
|
||||
import styles from './ImportListExclusion.css';
|
||||
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
|
||||
import styles from './ImportExclusion.css';
|
||||
|
||||
class ImportListExclusion extends Component {
|
||||
class ImportExclusion extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -78,7 +78,7 @@ class ImportListExclusion extends Component {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<EditImportListExclusionModalConnector
|
||||
<EditImportExclusionModalConnector
|
||||
id={id}
|
||||
isOpen={this.state.isEditImportExclusionModalOpen}
|
||||
onModalClose={this.onEditImportExclusionModalClose}
|
||||
@@ -99,7 +99,7 @@ class ImportListExclusion extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
ImportListExclusion.propTypes = {
|
||||
ImportExclusion.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
movieTitle: PropTypes.string.isRequired,
|
||||
tmdbId: PropTypes.number.isRequired,
|
||||
@@ -107,9 +107,9 @@ ImportListExclusion.propTypes = {
|
||||
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
ImportListExclusion.defaultProps = {
|
||||
ImportExclusion.defaultProps = {
|
||||
// The drag preview will not connect the drag handle.
|
||||
connectDragSource: (node) => node
|
||||
};
|
||||
|
||||
export default ImportListExclusion;
|
||||
export default ImportExclusion;
|
||||
@@ -1,16 +1,16 @@
|
||||
.importListExclusionsHeader {
|
||||
.importExclusionsHeader {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 0 0 600px;
|
||||
flex: 0 0 400px;
|
||||
}
|
||||
|
||||
.tmdbId,
|
||||
.movieYear {
|
||||
flex: 0 0 70px;
|
||||
flex: 0 0 200px;
|
||||
}
|
||||
|
||||
.addImportExclusion {
|
||||
@@ -6,11 +6,11 @@ import Link from 'Components/Link/Link';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
|
||||
import ImportListExclusion from './ImportListExclusion';
|
||||
import styles from './ImportListExclusions.css';
|
||||
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
|
||||
import ImportExclusion from './ImportExclusion';
|
||||
import styles from './ImportExclusions.css';
|
||||
|
||||
class ImportListExclusions extends Component {
|
||||
class ImportExclusions extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -50,23 +50,17 @@ class ImportListExclusions extends Component {
|
||||
errorMessage={translate('UnableToLoadListExclusions')}
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.importListExclusionsHeader}>
|
||||
<div className={styles.tmdbId}>
|
||||
TMDb Id
|
||||
</div>
|
||||
<div className={styles.title}>
|
||||
{translate('Title')}
|
||||
</div>
|
||||
<div className={styles.movieYear}>
|
||||
{translate('Year')}
|
||||
</div>
|
||||
<div className={styles.importExclusionsHeader}>
|
||||
<div className={styles.tmdbId}>TMDB Id</div>
|
||||
<div className={styles.title}>Title</div>
|
||||
<div className={styles.movieYear}>Year</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{
|
||||
items.map((item, index) => {
|
||||
return (
|
||||
<ImportListExclusion
|
||||
<ImportExclusion
|
||||
key={item.id}
|
||||
{...item}
|
||||
{...otherProps}
|
||||
@@ -87,7 +81,7 @@ class ImportListExclusions extends Component {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<EditImportListExclusionModalConnector
|
||||
<EditImportExclusionModalConnector
|
||||
isOpen={this.state.isAddImportExclusionModalOpen}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
@@ -98,11 +92,11 @@ class ImportListExclusions extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
ImportListExclusions.propTypes = {
|
||||
ImportExclusions.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ImportListExclusions;
|
||||
export default ImportExclusions;
|
||||
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { deleteImportExclusion, fetchImportExclusions } from 'Store/Actions/settingsActions';
|
||||
import ImportListExclusions from './ImportListExclusions';
|
||||
import ImportExclusions from './ImportExclusions';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
@@ -42,7 +42,7 @@ class ImportExclusionsConnector extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ImportListExclusions
|
||||
<ImportExclusions
|
||||
{...this.state}
|
||||
{...this.props}
|
||||
onConfirmDeleteImportExclusion={this.onConfirmDeleteImportExclusion}
|
||||
@@ -7,7 +7,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import ImportListExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
|
||||
import ImportExclusionsConnector from './ImportExclusions/ImportExclusionsConnector';
|
||||
import ImportListsConnector from './ImportLists/ImportListsConnector';
|
||||
import ImportListOptionsConnector from './Options/ImportListOptionsConnector';
|
||||
|
||||
@@ -86,7 +86,7 @@ class ImportListSettings extends Component {
|
||||
onChildStateChange={this.onChildStateChange}
|
||||
/>
|
||||
|
||||
<ImportListExclusionsConnector />
|
||||
<ImportExclusionsConnector />
|
||||
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
|
||||
@@ -45,9 +45,7 @@ function EditIndexerModalContent(props) {
|
||||
supportsSearch,
|
||||
tags,
|
||||
fields,
|
||||
priority,
|
||||
protocol,
|
||||
downloadClientId
|
||||
priority
|
||||
} = item;
|
||||
|
||||
return (
|
||||
@@ -156,25 +154,8 @@ function EditIndexerModalContent(props) {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>{translate('DownloadClient')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.DOWNLOAD_CLIENT_SELECT}
|
||||
name="downloadClientId"
|
||||
helpText={translate('IndexerDownloadClientHelpText')}
|
||||
{...downloadClientId}
|
||||
includeAny={true}
|
||||
protocol={protocol.value}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Tags')}</FormLabel>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
|
||||
@@ -85,7 +85,7 @@ function IndexerOptions(props) {
|
||||
type={inputTypes.CHECK}
|
||||
name="preferIndexerFlags"
|
||||
helpText={translate('PreferIndexerFlagsHelpText')}
|
||||
helpLink="https://wiki.servarr.com/radarr/settings#indexer-flags"
|
||||
helpLink="https://wiki.servarr.com/Definitions#Indexer_Flags"
|
||||
onChange={onInputChange}
|
||||
{...settings.preferIndexerFlags}
|
||||
/>
|
||||
|
||||
@@ -147,8 +147,7 @@ class NamingModal extends Component {
|
||||
|
||||
{ token: '{MediaInfo VideoCodec}', example: 'x264' },
|
||||
{ token: '{MediaInfo VideoBitDepth}', example: '10' },
|
||||
{ token: '{MediaInfo VideoDynamicRange}', example: 'HDR' },
|
||||
{ token: '{MediaInfo VideoDynamicRangeType}', example: 'DV HDR10' }
|
||||
{ token: '{MediaInfo VideoDynamicRange}', example: 'HDR' }
|
||||
];
|
||||
|
||||
const releaseGroupTokens = [
|
||||
|
||||
@@ -63,7 +63,6 @@ class Notification extends Component {
|
||||
onMovieFileDelete,
|
||||
onMovieFileDeleteForUpgrade,
|
||||
onHealthIssue,
|
||||
onApplicationUpdate,
|
||||
supportsOnGrab,
|
||||
supportsOnDownload,
|
||||
supportsOnUpgrade,
|
||||
@@ -71,8 +70,7 @@ class Notification extends Component {
|
||||
supportsOnMovieDelete,
|
||||
supportsOnMovieFileDelete,
|
||||
supportsOnMovieFileDeleteForUpgrade,
|
||||
supportsOnHealthIssue,
|
||||
supportsOnApplicationUpdate
|
||||
supportsOnHealthIssue
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -125,14 +123,6 @@ class Notification extends Component {
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
supportsOnApplicationUpdate && onApplicationUpdate ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
{translate('OnApplicationUpdate')}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
supportsOnMovieDelete && onMovieDelete ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
@@ -158,7 +148,7 @@ class Notification extends Component {
|
||||
}
|
||||
|
||||
{
|
||||
!onGrab && !onDownload && !onRename && !onHealthIssue && !onApplicationUpdate && !onMovieDelete && !onMovieFileDelete ?
|
||||
!onGrab && !onDownload && !onRename && !onHealthIssue && !onMovieDelete && !onMovieFileDelete ?
|
||||
<Label
|
||||
kind={kinds.DISABLED}
|
||||
outline={true}
|
||||
@@ -200,7 +190,6 @@ Notification.propTypes = {
|
||||
onMovieFileDelete: PropTypes.bool.isRequired,
|
||||
onMovieFileDeleteForUpgrade: PropTypes.bool.isRequired,
|
||||
onHealthIssue: PropTypes.bool.isRequired,
|
||||
onApplicationUpdate: PropTypes.bool.isRequired,
|
||||
supportsOnGrab: PropTypes.bool.isRequired,
|
||||
supportsOnDownload: PropTypes.bool.isRequired,
|
||||
supportsOnMovieDelete: PropTypes.bool.isRequired,
|
||||
@@ -209,7 +198,6 @@ Notification.propTypes = {
|
||||
supportsOnUpgrade: PropTypes.bool.isRequired,
|
||||
supportsOnRename: PropTypes.bool.isRequired,
|
||||
supportsOnHealthIssue: PropTypes.bool.isRequired,
|
||||
supportsOnApplicationUpdate: PropTypes.bool.isRequired,
|
||||
onConfirmDeleteNotification: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ function NotificationEventItems(props) {
|
||||
onMovieFileDelete,
|
||||
onMovieFileDeleteForUpgrade,
|
||||
onHealthIssue,
|
||||
onApplicationUpdate,
|
||||
supportsOnGrab,
|
||||
supportsOnDownload,
|
||||
supportsOnUpgrade,
|
||||
@@ -31,7 +30,6 @@ function NotificationEventItems(props) {
|
||||
supportsOnMovieDelete,
|
||||
supportsOnMovieFileDelete,
|
||||
supportsOnMovieFileDeleteForUpgrade,
|
||||
supportsOnApplicationUpdate,
|
||||
supportsOnHealthIssue,
|
||||
includeHealthWarnings
|
||||
} = item;
|
||||
@@ -152,17 +150,6 @@ function NotificationEventItems(props) {
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="onApplicationUpdate"
|
||||
helpText={translate('OnApplicationUpdateHelpText')}
|
||||
isDisabled={!supportsOnApplicationUpdate.value}
|
||||
{...onApplicationUpdate}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormGroup>
|
||||
|
||||
@@ -82,18 +82,10 @@ class DelayProfiles extends Component {
|
||||
>
|
||||
<div>
|
||||
<div className={styles.delayProfilesHeader}>
|
||||
<div className={styles.column}>
|
||||
{translate('Protocol')}
|
||||
</div>
|
||||
<div className={styles.column}>
|
||||
{translate('UsenetDelay')}
|
||||
</div>
|
||||
<div className={styles.column}>
|
||||
{translate('TorrentDelay')}
|
||||
</div>
|
||||
<div className={styles.tags}>
|
||||
{translate('Tags')}
|
||||
</div>
|
||||
<div className={styles.column}>Protocol</div>
|
||||
<div className={styles.column}>Usenet Delay</div>
|
||||
<div className={styles.column}>Torrent Delay</div>
|
||||
<div className={styles.tags}>Tags</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.delayProfiles}>
|
||||
|
||||
@@ -25,15 +25,9 @@ class QualityDefinitions extends Component {
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.quality}>
|
||||
{translate('Quality')}
|
||||
</div>
|
||||
<div className={styles.title}>
|
||||
{translate('Title')}
|
||||
</div>
|
||||
<div className={styles.sizeLimit}>
|
||||
{translate('SizeLimit')}
|
||||
</div>
|
||||
<div className={styles.quality}>Quality</div>
|
||||
<div className={styles.title}>Title</div>
|
||||
<div className={styles.sizeLimit}>Size Limit</div>
|
||||
|
||||
{
|
||||
advancedSettings ?
|
||||
|
||||
@@ -152,7 +152,7 @@ function TagDetailsModalContent(props) {
|
||||
|
||||
{
|
||||
indexers.length ?
|
||||
<FieldSet legend={translate('Indexers')}>
|
||||
<FieldSet legend="Indexers">
|
||||
{
|
||||
indexers.map((item) => {
|
||||
return (
|
||||
|
||||
@@ -48,6 +48,21 @@ export const movieRuntimeFormatOptions = [
|
||||
{ key: 'minutes', value: '75 mins' }
|
||||
];
|
||||
|
||||
export const themeOptions = [
|
||||
{ key: 'default', value: 'Default' },
|
||||
{ key: 'aquamarine', value: 'Aquamarine' },
|
||||
{ key: 'dark', value: 'Dark' },
|
||||
{ key: 'dracula', value: 'Dracula' },
|
||||
{ key: 'hotline', value: 'Hotline' },
|
||||
{ key: 'hotpink', value: 'Hotpink' },
|
||||
{ key: 'nord', value: 'Nord' },
|
||||
{ key: 'organizr', value: 'Organizr' },
|
||||
{ key: 'overseerr', value: 'Overseerr' },
|
||||
{ key: 'plex', value: 'Plex' },
|
||||
{ key: 'radarr-darker', value: 'Radarr Darker' },
|
||||
{ key: 'space-gray', value: 'Space Gray' }
|
||||
];
|
||||
|
||||
class UISettings extends Component {
|
||||
|
||||
//
|
||||
@@ -184,6 +199,21 @@ class UISettings extends Component {
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend={translate('Style')}>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Theme')}</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="theme"
|
||||
helpText={translate('ThemeHelpText', ['Theme.Park'])}
|
||||
inlineLink="https://github.com/GilbN/theme.park"
|
||||
tooltip="Theme.Park Github"
|
||||
helpTextWarning={translate('ThemeHelpTextWarning')}
|
||||
values={themeOptions}
|
||||
onChange={onInputChange}
|
||||
{...settings.theme}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SettingsEnableColorImpairedMode')}</FormLabel>
|
||||
<FormInputGroup
|
||||
|
||||
@@ -109,7 +109,6 @@ export default {
|
||||
selectedSchema.onMovieDelete = selectedSchema.supportsOnMovieDelete;
|
||||
selectedSchema.onMovieFileDelete = selectedSchema.supportsOnMovieFileDelete;
|
||||
selectedSchema.onMovieFileDeleteForUpgrade = selectedSchema.supportsOnMovieFileDeleteForUpgrade;
|
||||
selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate;
|
||||
|
||||
return selectedSchema;
|
||||
});
|
||||
|
||||
@@ -200,7 +200,7 @@ export const defaultState = {
|
||||
ratings: function(item) {
|
||||
const { ratings = {} } = item;
|
||||
|
||||
return ratings.tmdb? ratings.tmdb.value : 0;
|
||||
return ratings.value;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -330,23 +330,8 @@ export const defaultState = {
|
||||
valueType: filterBuilderValueTypes.MINIMUM_AVAILABILITY
|
||||
},
|
||||
{
|
||||
name: 'tmdbRating',
|
||||
label: translate('TmdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'tmdbVotes',
|
||||
label: translate('TmdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbRating',
|
||||
label: translate('ImdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbVotes',
|
||||
label: translate('ImdbVotes'),
|
||||
name: 'ratings',
|
||||
label: 'Rating',
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
@@ -615,7 +600,6 @@ export const actionHandlers = handleThunks({
|
||||
const promise = createAjaxRequest({
|
||||
url: '/exclusions/bulk',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(exclusions)
|
||||
}).request;
|
||||
|
||||
|
||||
@@ -148,10 +148,9 @@ export const actionHandlers = handleThunks({
|
||||
return {
|
||||
id,
|
||||
path: item.path,
|
||||
movieId: item.movie ? item.movie.id : undefined,
|
||||
movieId: item.movie.id,
|
||||
quality: item.quality,
|
||||
languages: item.languages,
|
||||
releaseGroup: item.releaseGroup,
|
||||
downloadId: item.downloadId
|
||||
};
|
||||
});
|
||||
|
||||
@@ -131,38 +131,10 @@ export const filterPredicates = {
|
||||
return dateFilterPredicate(item.digitalRelease, filterValue, type);
|
||||
},
|
||||
|
||||
tmdbRating: function(item, filterValue, type) {
|
||||
ratings: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
const rating = item.ratings.tmdb ? item.ratings.tmdb.value : 0;
|
||||
|
||||
return predicate(rating * 10, filterValue);
|
||||
},
|
||||
|
||||
tmdbVotes: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
const rating = item.ratings.tmdb ? item.ratings.tmdb.votes : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
},
|
||||
|
||||
imdbRating: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
console.log(item.ratings);
|
||||
|
||||
const rating = item.ratings.imdb ? item.ratings.imdb.value : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
},
|
||||
|
||||
imdbVotes: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
const rating = item.ratings.imdb ? item.ratings.imdb.votes : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
return predicate(item.ratings.value * 10, filterValue);
|
||||
},
|
||||
|
||||
qualityCutoffNotMet: function(item) {
|
||||
|
||||
@@ -209,7 +209,7 @@ export const defaultState = {
|
||||
ratings: function(item) {
|
||||
const { ratings = {} } = item;
|
||||
|
||||
return ratings.tmdb? ratings.tmdb.value : 0;
|
||||
return ratings.value;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -357,23 +357,8 @@ export const defaultState = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'tmdbRating',
|
||||
label: translate('TmdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'tmdbVotes',
|
||||
label: translate('TmdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbRating',
|
||||
label: translate('ImdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbVotes',
|
||||
label: translate('ImdbVotes'),
|
||||
name: 'ratings',
|
||||
label: translate('Ratings'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ const paged = `${section}.paged`;
|
||||
|
||||
export const defaultState = {
|
||||
options: {
|
||||
includeUnknownMovieItems: true
|
||||
includeUnknownMovieItems: false
|
||||
},
|
||||
|
||||
status: {
|
||||
|
||||
@@ -100,7 +100,7 @@ export default function createSentryMiddleware() {
|
||||
return;
|
||||
}
|
||||
|
||||
const dsn = isProduction ? 'https://7794f2858478485ea337fb5535624fbd@sentry.servarr.com/12' :
|
||||
const dsn = isProduction ? 'https://b0fb75c38ef4487dbf742f79c4ba62d2@sentry.servarr.com/12' :
|
||||
'https://da610619280249f891ec3ee306906793@sentry.servarr.com/13';
|
||||
|
||||
sentry.init({
|
||||
|
||||
@@ -19,7 +19,6 @@ function getInternalLink(source) {
|
||||
case 'IndexerRssCheck':
|
||||
case 'IndexerSearchCheck':
|
||||
case 'IndexerStatusCheck':
|
||||
case 'IndexerJackettAllCheck':
|
||||
case 'IndexerLongTermStatusCheck':
|
||||
return (
|
||||
<IconButton
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createBrowserHistory } from 'history';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import ThemeSelector from 'App/ThemeSelector';
|
||||
import createAppStore from 'Store/createAppStore';
|
||||
import App from './App/App';
|
||||
|
||||
@@ -13,9 +14,11 @@ const history = createBrowserHistory();
|
||||
const store = createAppStore(history);
|
||||
|
||||
render(
|
||||
<App
|
||||
store={store}
|
||||
history={history}
|
||||
/>,
|
||||
<ThemeSelector>
|
||||
<App
|
||||
store={store}
|
||||
history={history}
|
||||
/>
|
||||
</ThemeSelector>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
10
package.json
10
package.json
@@ -30,7 +30,7 @@
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.3",
|
||||
"@fortawesome/react-fontawesome": "0.1.14",
|
||||
"@microsoft/signalr": "6.0.1",
|
||||
"@microsoft/signalr": "5.0.10",
|
||||
"@sentry/browser": "6.13.2",
|
||||
"@sentry/integrations": "6.13.2",
|
||||
"classnames": "2.3.1",
|
||||
@@ -82,7 +82,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.13.16",
|
||||
"@babel/eslint-parser": "7.13.14",
|
||||
"@babel/plugin-proposal-class-properties": "7.13.0",
|
||||
"@babel/plugin-proposal-decorators": "7.13.15",
|
||||
"@babel/plugin-proposal-export-default-from": "7.12.13",
|
||||
@@ -95,6 +94,7 @@
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/preset-env": "7.13.15",
|
||||
"@babel/preset-react": "7.13.13",
|
||||
"@babel/eslint-parser": "7.13.14",
|
||||
"autoprefixer": "10.2.5",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-inline-classnames": "2.0.1",
|
||||
@@ -125,12 +125,12 @@
|
||||
"run-sequence": "2.2.1",
|
||||
"streamqueue": "1.1.2",
|
||||
"style-loader": "2.0.0",
|
||||
"stylelint": "13.13.0",
|
||||
"stylelint-order": "4.1.0",
|
||||
"url-loader": "4.1.1",
|
||||
"webpack": "5.35.1",
|
||||
"webpack-cli": "4.6.0",
|
||||
"webpack-livereload-plugin": "3.0.1",
|
||||
"worker-loader": "3.0.8"
|
||||
"worker-loader": "3.0.8",
|
||||
"stylelint": "13.13.0",
|
||||
"stylelint-order": "4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
<!-- Common to all Radarr Projects -->
|
||||
<PropertyGroup>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;osx-x64;osx-arm64;linux-x64;linux-musl-x64;linux-arm;linux-musl-arm;linux-arm64;linux-musl-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;osx-x64;linux-x64;linux-musl-x64;linux-arm;linux-arm64;linux-musl-arm64</RuntimeIdentifiers>
|
||||
|
||||
<RadarrRootDir>$(MSBuildThisFileDirectory)..\</RadarrRootDir>
|
||||
|
||||
@@ -90,13 +89,13 @@
|
||||
|
||||
<!-- Standard testing packages -->
|
||||
<ItemGroup Condition="'$(TestProject)'=='true'">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="NunitXml.TestLogger" Version="2.1.62" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TestProject)'=='true' and '$(TargetFramework)'=='net6.0'">
|
||||
<ItemGroup Condition="'$(TestProject)'=='true' and '$(TargetFramework)'=='net5.0'">
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.4-preview.27.ge7cb7c3b40" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net5.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NBuilder" Version="6.1.0" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net5.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Selenium.Support" Version="3.141.0" />
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
@@ -16,11 +15,8 @@ using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.Http.Dispatchers;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Common.TPL;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Security;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
using HttpClient = NzbDrone.Common.Http.HttpClient;
|
||||
|
||||
namespace NzbDrone.Common.Test.Http
|
||||
{
|
||||
@@ -35,8 +31,6 @@ namespace NzbDrone.Common.Test.Http
|
||||
private string _httpBinHost;
|
||||
private string _httpBinHost2;
|
||||
|
||||
private System.Net.Http.HttpClient _httpClient = new ();
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void FixtureSetUp()
|
||||
{
|
||||
@@ -44,7 +38,7 @@ namespace NzbDrone.Common.Test.Http
|
||||
var mainHost = "httpbin.servarr.com";
|
||||
|
||||
// Use mirrors for tests that use two hosts
|
||||
var candidates = new[] { "httpbin1.servarr.com" };
|
||||
var candidates = new[] { "eu.httpbin.org", /* "httpbin.org", */ "www.httpbin.org" };
|
||||
|
||||
// httpbin.org is broken right now, occassionally redirecting to https if it's unavailable.
|
||||
_httpBinHost = mainHost;
|
||||
@@ -52,20 +46,29 @@ namespace NzbDrone.Common.Test.Http
|
||||
|
||||
TestLogger.Info($"{candidates.Length} TestSites available.");
|
||||
|
||||
_httpBinSleep = 10;
|
||||
_httpBinSleep = _httpBinHosts.Length < 2 ? 100 : 10;
|
||||
}
|
||||
|
||||
private bool IsTestSiteAvailable(string site)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = _httpClient.GetAsync($"https://{site}/get").GetAwaiter().GetResult();
|
||||
var req = WebRequest.Create($"https://{site}/get") as HttpWebRequest;
|
||||
var res = req.GetResponse() as HttpWebResponse;
|
||||
if (res.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
res = _httpClient.GetAsync($"https://{site}/status/429").GetAwaiter().GetResult();
|
||||
try
|
||||
{
|
||||
req = WebRequest.Create($"https://{site}/status/429") as HttpWebRequest;
|
||||
res = req.GetResponse() as HttpWebResponse;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
res = ex.Response as HttpWebResponse;
|
||||
}
|
||||
|
||||
if (res == null || res.StatusCode != (HttpStatusCode)429)
|
||||
{
|
||||
@@ -92,13 +95,10 @@ namespace NzbDrone.Common.Test.Http
|
||||
Mocker.GetMock<IOsInfo>().Setup(c => c.Name).Returns("TestOS");
|
||||
Mocker.GetMock<IOsInfo>().Setup(c => c.Version).Returns("9.0.0");
|
||||
|
||||
Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(CertificateValidationType.Enabled);
|
||||
|
||||
Mocker.SetConstant<IUserAgentBuilder>(Mocker.Resolve<UserAgentBuilder>());
|
||||
|
||||
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
|
||||
Mocker.SetConstant<ICreateManagedWebProxy>(Mocker.Resolve<ManagedWebProxyFactory>());
|
||||
Mocker.SetConstant<ICertificateValidationService>(new X509CertificateValidationService(Mocker.GetMock<IConfigService>().Object, TestLogger));
|
||||
Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>());
|
||||
Mocker.SetConstant<IEnumerable<IHttpRequestInterceptor>>(Array.Empty<IHttpRequestInterceptor>());
|
||||
Mocker.SetConstant<IHttpDispatcher>(Mocker.Resolve<TDispatcher>());
|
||||
@@ -138,28 +138,6 @@ namespace NzbDrone.Common.Test.Http
|
||||
response.Content.Should().NotBeNullOrWhiteSpace();
|
||||
}
|
||||
|
||||
[TestCase(CertificateValidationType.Enabled)]
|
||||
[TestCase(CertificateValidationType.DisabledForLocalAddresses)]
|
||||
public void bad_ssl_should_fail_when_remote_validation_enabled(CertificateValidationType validationType)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(validationType);
|
||||
var request = new HttpRequest($"https://expired.badssl.com");
|
||||
|
||||
Assert.Throws<HttpRequestException>(() => Subject.Execute(request));
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void bad_ssl_should_pass_if_remote_validation_disabled()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(CertificateValidationType.Disabled);
|
||||
|
||||
var request = new HttpRequest($"https://expired.badssl.com");
|
||||
|
||||
Subject.Execute(request);
|
||||
ExceptionVerification.ExpectedErrors(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_typed_get()
|
||||
{
|
||||
@@ -184,44 +162,15 @@ namespace NzbDrone.Common.Test.Http
|
||||
response.Resource.Data.Should().Be(message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_post_with_content_type()
|
||||
[TestCase("gzip")]
|
||||
public void should_execute_get_using_gzip(string compression)
|
||||
{
|
||||
var message = "{ my: 1 }";
|
||||
|
||||
var request = new HttpRequest($"https://{_httpBinHost}/post");
|
||||
request.SetContent(message);
|
||||
request.Headers.ContentType = "application/json";
|
||||
|
||||
var response = Subject.Post<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Data.Should().Be(message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_get_using_gzip()
|
||||
{
|
||||
var request = new HttpRequest($"https://{_httpBinHost}/gzip");
|
||||
var request = new HttpRequest($"https://{_httpBinHost}/{compression}");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers["Accept-Encoding"].ToString().Should().Contain("gzip");
|
||||
|
||||
response.Resource.Headers["Accept-Encoding"].ToString().Should().Be(compression);
|
||||
response.Resource.Gzipped.Should().BeTrue();
|
||||
response.Resource.Brotli.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_get_using_brotli()
|
||||
{
|
||||
var request = new HttpRequest($"https://{_httpBinHost}/brotli");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers["Accept-Encoding"].ToString().Should().Contain("br");
|
||||
|
||||
response.Resource.Gzipped.Should().BeFalse();
|
||||
response.Resource.Brotli.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase(HttpStatusCode.Unauthorized)]
|
||||
@@ -388,38 +337,13 @@ namespace NzbDrone.Common.Test.Http
|
||||
{
|
||||
var file = GetTempFilePath();
|
||||
|
||||
Assert.Throws<HttpException>(() => Subject.DownloadFile("https://download.sonarr.tv/wrongpath", file));
|
||||
Assert.Throws<WebException>(() => Subject.DownloadFile("https://download.sonarr.tv/wrongpath", file));
|
||||
|
||||
File.Exists(file).Should().BeFalse();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_write_redirect_content_to_stream()
|
||||
{
|
||||
var file = GetTempFilePath();
|
||||
|
||||
using (var fileStream = new FileStream(file, FileMode.Create))
|
||||
{
|
||||
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
||||
request.AllowAutoRedirect = false;
|
||||
request.ResponseStream = fileStream;
|
||||
|
||||
var response = Subject.Get(request);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Moved);
|
||||
}
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
|
||||
File.Exists(file).Should().BeTrue();
|
||||
|
||||
var fileInfo = new FileInfo(file);
|
||||
|
||||
fileInfo.Length.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_send_cookie()
|
||||
{
|
||||
@@ -819,7 +743,7 @@ namespace NzbDrone.Common.Test.Http
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeDataString(malformedCookie)}";
|
||||
string url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}";
|
||||
|
||||
var requestSet = new HttpRequest(url);
|
||||
requestSet.AllowAutoRedirect = false;
|
||||
@@ -849,7 +773,6 @@ namespace NzbDrone.Common.Test.Http
|
||||
public string Url { get; set; }
|
||||
public string Data { get; set; }
|
||||
public bool Gzipped { get; set; }
|
||||
public bool Brotli { get; set; }
|
||||
}
|
||||
|
||||
public class HttpCookieResource
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
||||
[TestCase("Hardlinking episode file: /home/mySecret/Downloads to /media/abc.mkv")]
|
||||
[TestCase("Hardlink '/home/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")]
|
||||
[TestCase("https://notifiarr.com/notifier.php: api=1234530f-422f-4aac-b6b3-01233210aaaa&radarr_health_issue_message=Download")]
|
||||
[TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")]
|
||||
|
||||
// Announce URLs (passkeys) Magnet & Tracker
|
||||
[TestCase(@"magnet_uri"":""magnet:?xt=urn:btih:9pr04sgkillroyimaveql2tyu8xyui&dn=&tr=https%3a%2f%2fxxx.yyy%2f9pr04sg601233210imaveql2tyu8xyui%2fannounce""}")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net5.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NzbDrone.Host\Radarr.Host.csproj" />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user